diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index d71dfc3b..60cfd9d7 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -50,6 +50,8 @@ class singleWorker(StoppableThread): def __init__(self): super(singleWorker, self).__init__(name="singleWorker") + self.digestAlg = config.safeGet( + 'bitmessagesettings', 'digestalg', 'sha256') proofofwork.init() def stopThread(self): @@ -368,7 +370,8 @@ class singleWorker(StoppableThread): payload += encodeVarint(config.getint( myAddress, 'payloadlengthextrabytes')) - signature = highlevelcrypto.sign(payload, privSigningKeyHex) + signature = highlevelcrypto.sign( + payload, privSigningKeyHex, self.digestAlg) payload += encodeVarint(len(signature)) payload += signature @@ -455,8 +458,7 @@ class singleWorker(StoppableThread): ).digest()).digest() payload += doubleHashOfAddressData[32:] # the tag signature = highlevelcrypto.sign( - payload + dataToEncrypt, privSigningKeyHex - ) + payload + dataToEncrypt, privSigningKeyHex, self.digestAlg) dataToEncrypt += encodeVarint(len(signature)) dataToEncrypt += signature @@ -641,7 +643,7 @@ class singleWorker(StoppableThread): dataToSign = payload + dataToEncrypt signature = highlevelcrypto.sign( - dataToSign, privSigningKeyHex) + dataToSign, privSigningKeyHex, self.digestAlg) dataToEncrypt += encodeVarint(len(signature)) dataToEncrypt += signature @@ -1223,7 +1225,8 @@ class singleWorker(StoppableThread): payload += fullAckPayload dataToSign = pack('>Q', embeddedTime) + '\x00\x00\x00\x02' + \ encodeVarint(1) + encodeVarint(toStreamNumber) + payload - signature = highlevelcrypto.sign(dataToSign, privSigningKeyHex) + signature = highlevelcrypto.sign( + dataToSign, privSigningKeyHex, self.digestAlg) payload += encodeVarint(len(signature)) payload += signature diff --git a/src/highlevelcrypto.py b/src/highlevelcrypto.py index ec43d3f8..1bdb1593 100644 --- a/src/highlevelcrypto.py +++ b/src/highlevelcrypto.py @@ -13,7 +13,6 @@ import pyelliptic from pyelliptic import OpenSSL from pyelliptic import arithmetic as a -from bmconfigparser import config __all__ = ['encrypt', 'makeCryptor', 'pointMult', 'privToPub', 'sign', 'verify'] @@ -64,43 +63,44 @@ def decryptFast(msg, cryptor): return cryptor.decrypt(msg) -def sign(msg, hexPrivkey): +def _choose_digest_alg(name): + """ + Choose openssl digest constant by name raises ValueError if not appropriate + """ + if name not in ("sha1", "sha256"): + raise ValueError("Unknown digest algorithm %s" % name) + return ( + # SHA1, this will eventually be deprecated + OpenSSL.digest_ecdsa_sha1 if name == "sha1" else OpenSSL.EVP_sha256) + + +def sign(msg, hexPrivkey, digestAlg="sha256"): """ Signs with hex private key using SHA1 or SHA256 depending on - "digestalg" setting + *digestAlg* keyword. """ - digestAlg = config.safeGet( - 'bitmessagesettings', 'digestalg', 'sha256') - if digestAlg == "sha1": - # SHA1, this will eventually be deprecated - return makeCryptor(hexPrivkey).sign( - msg, digest_alg=OpenSSL.digest_ecdsa_sha1) - elif digestAlg == "sha256": - # SHA256. Eventually this will become the default - return makeCryptor(hexPrivkey).sign(msg, digest_alg=OpenSSL.EVP_sha256) - else: - raise ValueError("Unknown digest algorithm %s" % digestAlg) + return makeCryptor(hexPrivkey).sign( + msg, digest_alg=_choose_digest_alg(digestAlg)) -def verify(msg, sig, hexPubkey): +def verify(msg, sig, hexPubkey, digestAlg=None): """Verifies with hex public key using SHA1 or SHA256""" # As mentioned above, we must upgrade gracefully to use SHA256. So # let us check the signature using both SHA1 and SHA256 and if one # of them passes then we will be satisfied. Eventually this can # be simplified and we'll only check with SHA256. - try: + if digestAlg is None: # old SHA1 algorithm. - sigVerifyPassed = makePubCryptor(hexPubkey).verify( - sig, msg, digest_alg=OpenSSL.digest_ecdsa_sha1) - except: - sigVerifyPassed = False - if sigVerifyPassed: - # The signature check passed using SHA1 - return True - # The signature check using SHA1 failed. Let us try it with SHA256. + sigVerifyPassed = verify(msg, sig, hexPubkey, "sha1") + if sigVerifyPassed: + # The signature check passed using SHA1 + return True + # The signature check using SHA1 failed. Let us try it with SHA256. + return verify(msg, sig, hexPubkey, "sha256") + try: return makePubCryptor(hexPubkey).verify( - sig, msg, digest_alg=OpenSSL.EVP_sha256) + sig, msg, digest_alg=_choose_digest_alg(digestAlg)) except: return False diff --git a/src/tests/samples.py b/src/tests/samples.py index 93e5ed61..e33c5f50 100644 --- a/src/tests/samples.py +++ b/src/tests/samples.py @@ -63,3 +63,13 @@ sample_object_expires = 1712271487 # .. do pow and obj.to_bytes() sample_object_data = unhexlify( '00000000001be7fc00000000660f307f0000002a010248454c4c4f') + +sample_msg = unhexlify( + '0592a10584ffabf96539f3d780d776828c67da1ab5b169e9e8aed838aaecc9ed36d49ff' + '1423c55f019e050c66c6324f53588be88894fef4dcffdb74b98e2b200') +sample_sig = unhexlify( + '304402202302475351db6b822de15d922e29397541f10d8a19780ba2ca4a920b1035f075' + '02205e5bba40d5f07a24c23a89ba5f01a3828371dfbb685dd5375fa1c29095fd232b') +sample_sig_sha1 = unhexlify( + '30460221008ad234687d1bdc259932e28ea6ee091b88b0900d8134902aa8c2fd7f016b96e' + 'd022100dafb94e28322c2fa88878f9dcbf0c2d33270466ab3bbffaec3dca0a2d1ef9354') diff --git a/src/tests/test_crypto.py b/src/tests/test_crypto.py index e68e7ee5..b3f2484e 100644 --- a/src/tests/test_crypto.py +++ b/src/tests/test_crypto.py @@ -17,8 +17,9 @@ except ImportError: RIPEMD160 = None from .samples import ( - sample_pubsigningkey, sample_pubencryptionkey, - sample_privsigningkey, sample_privencryptionkey, sample_ripe + sample_msg, sample_pubsigningkey, sample_pubencryptionkey, + sample_privsigningkey, sample_privencryptionkey, sample_ripe, + sample_sig, sample_sig_sha1 ) @@ -65,6 +66,28 @@ class TestCrypto(RIPEMD160TestCase, unittest.TestCase): class TestHighlevelcrypto(unittest.TestCase): """Test highlevelcrypto public functions""" + def test_signatures(self): + """Verify sample signatures and newly generated ones""" + pubkey_hex = hexlify(sample_pubsigningkey) + # pregenerated signatures + self.assertTrue(highlevelcrypto.verify( + sample_msg, sample_sig, pubkey_hex, "sha256")) + self.assertFalse(highlevelcrypto.verify( + sample_msg, sample_sig, pubkey_hex, "sha1")) + self.assertTrue(highlevelcrypto.verify( + sample_msg, sample_sig_sha1, pubkey_hex, "sha1")) + self.assertTrue(highlevelcrypto.verify( + sample_msg, sample_sig_sha1, pubkey_hex)) + # new signatures + sig256 = highlevelcrypto.sign(sample_msg, sample_privsigningkey) + sig1 = highlevelcrypto.sign(sample_msg, sample_privsigningkey, "sha1") + self.assertTrue( + highlevelcrypto.verify(sample_msg, sig256, pubkey_hex)) + self.assertTrue( + highlevelcrypto.verify(sample_msg, sig256, pubkey_hex, "sha256")) + self.assertTrue( + highlevelcrypto.verify(sample_msg, sig1, pubkey_hex)) + def test_privtopub(self): """Generate public keys and check the result""" self.assertEqual(