From 3a04e351cc04f4d6b64ce2289676e70f378d70f6 Mon Sep 17 00:00:00 2001 From: Lee Miller Date: Tue, 31 May 2022 00:57:55 +0300 Subject: [PATCH] Move RIPEMD160 hash to highlevelcrypto and export to_ripe() (closes: #1796) --- src/class_addressGenerator.py | 14 +++++--------- src/class_objectProcessor.py | 35 +++++++++++++---------------------- src/highlevelcrypto.py | 13 ++++++++++++- src/protocol.py | 13 +++++-------- src/tests/samples.py | 1 + src/tests/test_crypto.py | 26 +++++++++++++++++++------- 6 files changed, 55 insertions(+), 47 deletions(-) diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index 929ac364..33da1371 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -1,7 +1,7 @@ """ A thread for creating addresses """ -import hashlib + import time from binascii import hexlify @@ -14,7 +14,6 @@ import shared import state from addresses import decodeAddress, encodeAddress, encodeVarint from bmconfigparser import config -from fallback import RIPEMD160Hash from network import StoppableThread from tr import _translate @@ -133,9 +132,8 @@ class addressGenerator(StoppableThread): numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix += 1 potentialPrivEncryptionKey, potentialPubEncryptionKey = \ highlevelcrypto.random_keys() - sha = hashlib.new('sha512') - sha.update(pubSigningKey + potentialPubEncryptionKey) - ripe = RIPEMD160Hash(sha.digest()).digest() + ripe = highlevelcrypto.to_ripe( + pubSigningKey, potentialPubEncryptionKey) if ( ripe[:numberOfNullBytesDemandedOnFrontOfRipeHash] == b'\x00' * numberOfNullBytesDemandedOnFrontOfRipeHash @@ -244,10 +242,8 @@ class addressGenerator(StoppableThread): signingKeyNonce += 2 encryptionKeyNonce += 2 - sha = hashlib.new('sha512') - sha.update( - potentialPubSigningKey + potentialPubEncryptionKey) - ripe = RIPEMD160Hash(sha.digest()).digest() + ripe = highlevelcrypto.to_ripe( + potentialPubSigningKey, potentialPubEncryptionKey) if ( ripe[:numberOfNullBytesDemandedOnFrontOfRipeHash] == b'\x00' * numberOfNullBytesDemandedOnFrontOfRipeHash diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index 50c23e2c..469ccbfa 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -28,7 +28,6 @@ from addresses import ( encodeAddress, encodeVarint, varintDecodeError ) from bmconfigparser import config -from fallback import RIPEMD160Hash from helper_sql import ( sql_ready, sql_timeout, SqlBulkExecute, sqlExecute, sqlQuery) from network import knownnodes @@ -300,23 +299,20 @@ class objectProcessor(threading.Thread): '(within processpubkey) payloadLength less than 146.' ' Sanity check failed.') readPosition += 4 - publicSigningKey = data[readPosition:readPosition + 64] + pubSigningKey = '\x04' + data[readPosition:readPosition + 64] # Is it possible for a public key to be invalid such that trying to # encrypt or sign with it will cause an error? If it is, it would # be easiest to test them here. readPosition += 64 - publicEncryptionKey = data[readPosition:readPosition + 64] - if len(publicEncryptionKey) < 64: + pubEncryptionKey = '\x04' + data[readPosition:readPosition + 64] + if len(pubEncryptionKey) < 65: return logger.debug( 'publicEncryptionKey length less than 64. Sanity check' ' failed.') readPosition += 64 # The data we'll store in the pubkeys table. dataToStore = data[20:readPosition] - sha = hashlib.new('sha512') - sha.update( - '\x04' + publicSigningKey + '\x04' + publicEncryptionKey) - ripe = RIPEMD160Hash(sha.digest()).digest() + ripe = highlevelcrypto.to_ripe(pubSigningKey, pubEncryptionKey) if logger.isEnabledFor(logging.DEBUG): logger.debug( @@ -324,7 +320,7 @@ class objectProcessor(threading.Thread): '\nripe %s\npublicSigningKey in hex: %s' '\npublicEncryptionKey in hex: %s', addressVersion, streamNumber, hexlify(ripe), - hexlify(publicSigningKey), hexlify(publicEncryptionKey) + hexlify(pubSigningKey), hexlify(pubEncryptionKey) ) address = encodeAddress(addressVersion, streamNumber, ripe) @@ -354,9 +350,9 @@ class objectProcessor(threading.Thread): ' Sanity check failed.') return readPosition += 4 - publicSigningKey = '\x04' + data[readPosition:readPosition + 64] + pubSigningKey = '\x04' + data[readPosition:readPosition + 64] readPosition += 64 - publicEncryptionKey = '\x04' + data[readPosition:readPosition + 64] + pubEncryptionKey = '\x04' + data[readPosition:readPosition + 64] readPosition += 64 specifiedNonceTrialsPerByteLength = decodeVarint( data[readPosition:readPosition + 10])[1] @@ -373,15 +369,13 @@ class objectProcessor(threading.Thread): signature = data[readPosition:readPosition + signatureLength] if highlevelcrypto.verify( data[8:endOfSignedDataPosition], - signature, hexlify(publicSigningKey)): + signature, hexlify(pubSigningKey)): logger.debug('ECDSA verify passed (within processpubkey)') else: logger.warning('ECDSA verify failed (within processpubkey)') return - sha = hashlib.new('sha512') - sha.update(publicSigningKey + publicEncryptionKey) - ripe = RIPEMD160Hash(sha.digest()).digest() + ripe = highlevelcrypto.to_ripe(pubSigningKey, pubEncryptionKey) if logger.isEnabledFor(logging.DEBUG): logger.debug( @@ -389,7 +383,7 @@ class objectProcessor(threading.Thread): '\nripe %s\npublicSigningKey in hex: %s' '\npublicEncryptionKey in hex: %s', addressVersion, streamNumber, hexlify(ripe), - hexlify(publicSigningKey), hexlify(publicEncryptionKey) + hexlify(pubSigningKey), hexlify(pubEncryptionKey) ) address = encodeAddress(addressVersion, streamNumber, ripe) @@ -588,9 +582,7 @@ class objectProcessor(threading.Thread): sigHash = highlevelcrypto.double_sha512(signature)[32:] # calculate the fromRipe. - sha = hashlib.new('sha512') - sha.update(pubSigningKey + pubEncryptionKey) - ripe = RIPEMD160Hash(sha.digest()).digest() + ripe = highlevelcrypto.to_ripe(pubSigningKey, pubEncryptionKey) fromAddress = encodeAddress( sendersAddressVersionNumber, sendersStreamNumber, ripe) @@ -883,9 +875,8 @@ class objectProcessor(threading.Thread): requiredPayloadLengthExtraBytes) endOfPubkeyPosition = readPosition - sha = hashlib.new('sha512') - sha.update(sendersPubSigningKey + sendersPubEncryptionKey) - calculatedRipe = RIPEMD160Hash(sha.digest()).digest() + calculatedRipe = highlevelcrypto.to_ripe( + sendersPubSigningKey, sendersPubEncryptionKey) if broadcastVersion == 4: if toRipe != calculatedRipe: diff --git a/src/highlevelcrypto.py b/src/highlevelcrypto.py index d7af85de..d59a721d 100644 --- a/src/highlevelcrypto.py +++ b/src/highlevelcrypto.py @@ -15,12 +15,13 @@ import pyelliptic from pyelliptic import OpenSSL from pyelliptic import arithmetic as a +from fallback import RIPEMD160Hash __all__ = [ 'decodeWalletImportFormat', 'deterministic_keys', 'double_sha512', 'calculateInventoryHash', 'encodeWalletImportFormat', 'encrypt', 'makeCryptor', 'pointMult', 'privToPub', 'randomBytes', - 'random_keys', 'sign', 'verify'] + 'random_keys', 'sign', 'to_ripe', 'verify'] # WIF (uses arithmetic ): @@ -64,6 +65,16 @@ def randomBytes(n): # Hashes +def _bm160(data): + """RIPEME160(SHA512(data)) -> bytes""" + return RIPEMD160Hash(hashlib.sha512(data).digest()).digest() + + +def to_ripe(signing_key, encryption_key): + """Convert two public keys to a ripe hash""" + return _bm160(signing_key + encryption_key) + + def double_sha512(data): """Binary double SHA512 digest""" return hashlib.sha512(hashlib.sha512(data).digest()).digest() diff --git a/src/protocol.py b/src/protocol.py index d1a5f865..7f9830e5 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -20,7 +20,6 @@ from addresses import ( encodeVarint, decodeVarint, decodeAddress, varintDecodeError) from bmconfigparser import config from debug import logger -from fallback import RIPEMD160Hash from helper_sql import sqlExecute from network.node import Peer from version import softwareVersion @@ -512,9 +511,9 @@ def decryptAndCheckPubkeyPayload(data, address): readPosition = 0 # bitfieldBehaviors = decryptedData[readPosition:readPosition + 4] readPosition += 4 - publicSigningKey = '\x04' + decryptedData[readPosition:readPosition + 64] + pubSigningKey = '\x04' + decryptedData[readPosition:readPosition + 64] readPosition += 64 - publicEncryptionKey = '\x04' + decryptedData[readPosition:readPosition + 64] + pubEncryptionKey = '\x04' + decryptedData[readPosition:readPosition + 64] readPosition += 64 specifiedNonceTrialsPerByteLength = decodeVarint( decryptedData[readPosition:readPosition + 10])[1] @@ -530,7 +529,7 @@ def decryptAndCheckPubkeyPayload(data, address): signature = decryptedData[readPosition:readPosition + signatureLength] if not highlevelcrypto.verify( - signedData, signature, hexlify(publicSigningKey)): + signedData, signature, hexlify(pubSigningKey)): logger.info( 'ECDSA verify failed (within decryptAndCheckPubkeyPayload)') return 'failed' @@ -538,9 +537,7 @@ def decryptAndCheckPubkeyPayload(data, address): logger.info( 'ECDSA verify passed (within decryptAndCheckPubkeyPayload)') - sha = hashlib.new('sha512') - sha.update(publicSigningKey + publicEncryptionKey) - embeddedRipe = RIPEMD160Hash(sha.digest()).digest() + embeddedRipe = highlevelcrypto.to_ripe(pubSigningKey, pubEncryptionKey) if embeddedRipe != ripe: # Although this pubkey object had the tag were were looking for @@ -558,7 +555,7 @@ def decryptAndCheckPubkeyPayload(data, address): 'addressVersion: %s, streamNumber: %s\nripe %s\n' 'publicSigningKey in hex: %s\npublicEncryptionKey in hex: %s', addressVersion, streamNumber, hexlify(ripe), - hexlify(publicSigningKey), hexlify(publicEncryptionKey) + hexlify(pubSigningKey), hexlify(pubEncryptionKey) ) t = (address, addressVersion, storedData, int(time.time()), 'yes') diff --git a/src/tests/samples.py b/src/tests/samples.py index 9f6c9d5b..dd862318 100644 --- a/src/tests/samples.py +++ b/src/tests/samples.py @@ -8,6 +8,7 @@ sample_double_sha512 = unhexlify( '0592a10584ffabf96539f3d780d776828c67da1ab5b169e9e8aed838aaecc9ed36d49ff14' '23c55f019e050c66c6324f53588be88894fef4dcffdb74b98e2b200') +sample_bm160 = unhexlify('79a324faeebcbf9849f310545ed531556882487e') # 500 identical peers: # 1626611891, 1, 1, 127.0.0.1, 8444 diff --git a/src/tests/test_crypto.py b/src/tests/test_crypto.py index e518d7fd..6dbb2f31 100644 --- a/src/tests/test_crypto.py +++ b/src/tests/test_crypto.py @@ -8,7 +8,7 @@ import unittest from abc import ABCMeta, abstractmethod from binascii import hexlify -from pybitmessage import highlevelcrypto, fallback +from pybitmessage import highlevelcrypto try: @@ -17,10 +17,10 @@ except ImportError: RIPEMD160 = None from .samples import ( - sample_deterministic_ripe, sample_double_sha512, sample_hash_data, - sample_msg, sample_pubsigningkey, sample_pubencryptionkey, - sample_privsigningkey, sample_privencryptionkey, sample_ripe, - sample_seed, sample_sig, sample_sig_sha1 + sample_bm160, sample_deterministic_ripe, sample_double_sha512, + sample_hash_data, sample_msg, sample_pubsigningkey, + sample_pubencryptionkey, sample_privsigningkey, sample_privencryptionkey, + sample_ripe, sample_seed, sample_sig, sample_sig_sha1 ) @@ -73,6 +73,19 @@ class TestHighlevelcrypto(unittest.TestCase): highlevelcrypto.double_sha512(sample_hash_data), sample_double_sha512) + def test_bm160(self): + """Formally check highlevelcrypto._bm160()""" + # pylint: disable=protected-access + self.assertEqual( + highlevelcrypto._bm160(sample_hash_data), sample_bm160) + + def test_to_ripe(self): + """Formally check highlevelcrypto.to_ripe()""" + self.assertEqual( + hexlify(highlevelcrypto.to_ripe( + sample_pubsigningkey, sample_pubencryptionkey)), + sample_ripe) + def test_randomBytes(self): """Dummy checks for random bytes""" for n in (8, 32, 64): @@ -94,8 +107,7 @@ class TestHighlevelcrypto(unittest.TestCase): enkey = highlevelcrypto.deterministic_keys(sample_seed, b'+')[1] self.assertEqual( sample_deterministic_ripe, - hexlify(fallback.RIPEMD160Hash( - hashlib.sha512(sigkey + enkey).digest()).digest())) + hexlify(highlevelcrypto.to_ripe(sigkey, enkey))) def test_signatures(self): """Verify sample signatures and newly generated ones"""