diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index 06a0521a..d42469c3 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -16,7 +16,6 @@ from addresses import decodeAddress, encodeAddress, encodeVarint from bmconfigparser import config from fallback import RIPEMD160Hash from network import StoppableThread -from pyelliptic import arithmetic from pyelliptic.openssl import OpenSSL from tr import _translate @@ -164,20 +163,10 @@ class addressGenerator(StoppableThread): address = encodeAddress( addressVersionNumber, streamNumber, ripe) - # An excellent way for us to store our keys - # is in Wallet Import Format. Let us convert now. - # https://en.bitcoin.it/wiki/Wallet_import_format - privSigningKey = b'\x80' + potentialPrivSigningKey - checksum = hashlib.sha256(hashlib.sha256( - privSigningKey).digest()).digest()[0:4] - privSigningKeyWIF = arithmetic.changebase( - privSigningKey + checksum, 256, 58) - - privEncryptionKey = b'\x80' + potentialPrivEncryptionKey - checksum = hashlib.sha256(hashlib.sha256( - privEncryptionKey).digest()).digest()[0:4] - privEncryptionKeyWIF = arithmetic.changebase( - privEncryptionKey + checksum, 256, 58) + privSigningKeyWIF = highlevelcrypto.encodeWalletImportFormat( + potentialPrivSigningKey) + privEncryptionKeyWIF = highlevelcrypto.encodeWalletImportFormat( + potentialPrivEncryptionKey) config.add_section(address) config.set(address, 'label', label) @@ -303,21 +292,12 @@ class addressGenerator(StoppableThread): saveAddressToDisk = False if saveAddressToDisk and live: - # An excellent way for us to store our keys is - # in Wallet Import Format. Let us convert now. - # https://en.bitcoin.it/wiki/Wallet_import_format - privSigningKey = b'\x80' + potentialPrivSigningKey - checksum = hashlib.sha256(hashlib.sha256( - privSigningKey).digest()).digest()[0:4] - privSigningKeyWIF = arithmetic.changebase( - privSigningKey + checksum, 256, 58) - - privEncryptionKey = b'\x80' + \ - potentialPrivEncryptionKey - checksum = hashlib.sha256(hashlib.sha256( - privEncryptionKey).digest()).digest()[0:4] - privEncryptionKeyWIF = arithmetic.changebase( - privEncryptionKey + checksum, 256, 58) + privSigningKeyWIF = \ + highlevelcrypto.encodeWalletImportFormat( + potentialPrivSigningKey) + privEncryptionKeyWIF = \ + highlevelcrypto.encodeWalletImportFormat( + potentialPrivEncryptionKey) try: config.add_section(address) diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 60cfd9d7..d9ee69e7 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -197,15 +197,18 @@ class singleWorker(StoppableThread): self.logger.info("Quitting...") def _getKeysForAddress(self, address): - privSigningKeyBase58 = config.get( - address, 'privsigningkey') - privEncryptionKeyBase58 = config.get( - address, 'privencryptionkey') + try: + privSigningKeyBase58 = config.get(address, 'privsigningkey') + privEncryptionKeyBase58 = config.get(address, 'privencryptionkey') + except (configparser.NoSectionError, configparser.NoOptionError): + self.logger.error( + 'Could not read or decode privkey for address %s', address) + raise ValueError - privSigningKeyHex = hexlify(shared.decodeWalletImportFormat( - privSigningKeyBase58)) - privEncryptionKeyHex = hexlify(shared.decodeWalletImportFormat( - privEncryptionKeyBase58)) + privSigningKeyHex = hexlify( + highlevelcrypto.decodeWalletImportFormat(privSigningKeyBase58)) + privEncryptionKeyHex = hexlify( + highlevelcrypto.decodeWalletImportFormat(privEncryptionKeyBase58)) # The \x04 on the beginning of the public keys are not sent. # This way there is only one acceptable way to encode @@ -256,9 +259,7 @@ class singleWorker(StoppableThread): message once it is done with the POW""" # Look up my stream number based on my address hash myAddress = shared.myAddressesByHash[adressHash] - # status - _, addressVersionNumber, streamNumber, adressHash = ( - decodeAddress(myAddress)) + addressVersionNumber, streamNumber = decodeAddress(myAddress)[1:3] # 28 days from now plus or minus five minutes TTL = int(28 * 24 * 60 * 60 + helper_random.randomrandrange(-300, 300)) @@ -271,17 +272,15 @@ class singleWorker(StoppableThread): payload += protocol.getBitfield(myAddress) try: - # privSigningKeyHex, privEncryptionKeyHex - _, _, pubSigningKey, pubEncryptionKey = \ - self._getKeysForAddress(myAddress) - except (configparser.NoSectionError, configparser.NoOptionError) as err: - self.logger.warning("Section or Option did not found: %s", err) - except Exception as err: + pubSigningKey, pubEncryptionKey = self._getKeysForAddress( + myAddress)[2:] + except ValueError: + return + except Exception: # pylint:disable=broad-exception-caught self.logger.error( 'Error within doPOWForMyV2Pubkey. Could not read' ' the keys from the keys.dat file for a requested' - ' address. %s\n', err - ) + ' address. %s\n', exc_info=True) return payload += pubSigningKey + pubEncryptionKey @@ -320,8 +319,8 @@ class singleWorker(StoppableThread): try: myAddress = shared.myAddressesByHash[adressHash] except KeyError: - # The address has been deleted. - self.logger.warning("Can't find %s in myAddressByHash", hexlify(adressHash)) + self.logger.warning( # The address has been deleted. + "Can't find %s in myAddressByHash", hexlify(adressHash)) return if config.safeGetBoolean(myAddress, 'chan'): self.logger.info('This is a chan address. Not sending pubkey.') @@ -353,14 +352,13 @@ class singleWorker(StoppableThread): # , privEncryptionKeyHex privSigningKeyHex, _, pubSigningKey, pubEncryptionKey = \ self._getKeysForAddress(myAddress) - except (configparser.NoSectionError, configparser.NoOptionError) as err: - self.logger.warning("Section or Option did not found: %s", err) - except Exception as err: + except ValueError: + return + except Exception: # pylint:disable=broad-exception-caught self.logger.error( 'Error within sendOutOrStoreMyV3Pubkey. Could not read' ' the keys from the keys.dat file for a requested' - ' address. %s\n', err - ) + ' address. %s\n', exc_info=True) return payload += pubSigningKey + pubEncryptionKey @@ -428,14 +426,13 @@ class singleWorker(StoppableThread): # , privEncryptionKeyHex privSigningKeyHex, _, pubSigningKey, pubEncryptionKey = \ self._getKeysForAddress(myAddress) - except (configparser.NoSectionError, configparser.NoOptionError) as err: - self.logger.warning("Section or Option did not found: %s", err) - except Exception as err: + except ValueError: + return + except Exception: # pylint:disable=broad-exception-caught self.logger.error( 'Error within sendOutOrStoreMyV4Pubkey. Could not read' ' the keys from the keys.dat file for a requested' - ' address. %s\n', err - ) + ' address. %s\n', exc_info=True) return dataToEncrypt += pubSigningKey + pubEncryptionKey @@ -1118,8 +1115,9 @@ class singleWorker(StoppableThread): ' from the keys.dat file for our own address. %s\n', err) continue - privEncryptionKeyHex = hexlify(shared.decodeWalletImportFormat( - privEncryptionKeyBase58)) + privEncryptionKeyHex = hexlify( + highlevelcrypto.decodeWalletImportFormat( + privEncryptionKeyBase58)) pubEncryptionKeyBase256 = unhexlify(highlevelcrypto.privToPub( privEncryptionKeyHex))[1:] requiredAverageProofOfWorkNonceTrialsPerByte = \ diff --git a/src/highlevelcrypto.py b/src/highlevelcrypto.py index 1bdb1593..a52ac77f 100644 --- a/src/highlevelcrypto.py +++ b/src/highlevelcrypto.py @@ -7,6 +7,7 @@ High level cryptographic functions based on `.pyelliptic` OpenSSL bindings. `More discussion. `_ """ +import hashlib from binascii import hexlify import pyelliptic @@ -14,7 +15,38 @@ from pyelliptic import OpenSSL from pyelliptic import arithmetic as a -__all__ = ['encrypt', 'makeCryptor', 'pointMult', 'privToPub', 'sign', 'verify'] +__all__ = [ + 'decodeWalletImportFormat', 'encodeWalletImportFormat', + 'encrypt', 'makeCryptor', 'pointMult', 'privToPub', 'sign', 'verify'] + + +# WIF (uses arithmetic ): +def decodeWalletImportFormat(WIFstring): + """ + Convert private key from base58 that's used in the config file to + 8-bit binary string. + """ + fullString = a.changebase(WIFstring, 58, 256) + privkey = fullString[:-4] + if fullString[-4:] != \ + hashlib.sha256(hashlib.sha256(privkey).digest()).digest()[:4]: + raise ValueError('Checksum failed') + elif privkey[0:1] == b'\x80': # checksum passed + return privkey[1:] + + raise ValueError('No hex 80 prefix') + + +# An excellent way for us to store our keys +# is in Wallet Import Format. Let us convert now. +# https://en.bitcoin.it/wiki/Wallet_import_format +def encodeWalletImportFormat(privKey): + """ + Convert private key from binary 8-bit string into base58check WIF string. + """ + privKey = b'\x80' + privKey + checksum = hashlib.sha256(hashlib.sha256(privKey).digest()).digest()[0:4] + return a.changebase(privKey + checksum, 256, 58) def makeCryptor(privkey, curve='secp256k1'): diff --git a/src/shared.py b/src/shared.py index cb7968f6..114bd916 100644 --- a/src/shared.py +++ b/src/shared.py @@ -23,8 +23,6 @@ from bmconfigparser import config from debug import logger from helper_sql import sqlQuery -from pyelliptic import arithmetic - myECCryptorObjects = {} MyECSubscriptionCryptorObjects = {} @@ -76,35 +74,6 @@ def isAddressInMyAddressBookSubscriptionsListOrWhitelist(address): return False -def decodeWalletImportFormat(WIFstring): - # pylint: disable=inconsistent-return-statements - """ - Convert private key from base58 that's used in the config file to - 8-bit binary string - """ - fullString = arithmetic.changebase(WIFstring, 58, 256) - privkey = fullString[:-4] - if fullString[-4:] != \ - hashlib.sha256(hashlib.sha256(privkey).digest()).digest()[:4]: - logger.critical( - 'Major problem! When trying to decode one of your' - ' private keys, the checksum failed. Here are the first' - ' 6 characters of the PRIVATE key: %s', - str(WIFstring)[:6] - ) - os._exit(0) # pylint: disable=protected-access - # return "" - elif privkey[0] == '\x80': # checksum passed - return privkey[1:] - - logger.critical( - 'Major problem! When trying to decode one of your private keys,' - ' the checksum passed but the key doesn\'t begin with hex 80.' - ' Here is the PRIVATE key: %s', WIFstring - ) - os._exit(0) # pylint: disable=protected-access - - def reloadMyAddressHashes(): """Reload keys for user's addresses from the config file""" logger.debug('reloading keys from keys.dat file') @@ -118,29 +87,39 @@ def reloadMyAddressHashes(): hasEnabledKeys = False for addressInKeysFile in config.addresses(): isEnabled = config.getboolean(addressInKeysFile, 'enabled') - if isEnabled: - hasEnabledKeys = True - # status - addressVersionNumber, streamNumber, hashobj = decodeAddress(addressInKeysFile)[1:] - if addressVersionNumber in (2, 3, 4): - # Returns a simple 32 bytes of information encoded - # in 64 Hex characters, or null if there was an error. - privEncryptionKey = hexlify(decodeWalletImportFormat( - config.get(addressInKeysFile, 'privencryptionkey'))) - # It is 32 bytes encoded as 64 hex characters - if len(privEncryptionKey) == 64: - myECCryptorObjects[hashobj] = \ - highlevelcrypto.makeCryptor(privEncryptionKey) - myAddressesByHash[hashobj] = addressInKeysFile - tag = hashlib.sha512(hashlib.sha512( - encodeVarint(addressVersionNumber) - + encodeVarint(streamNumber) + hashobj).digest()).digest()[32:] - myAddressesByTag[tag] = addressInKeysFile - else: - logger.error( - 'Error in reloadMyAddressHashes: Can\'t handle' - ' address versions other than 2, 3, or 4.' - ) + if not isEnabled: + continue + + hasEnabledKeys = True + + addressVersionNumber, streamNumber, hashobj = decodeAddress( + addressInKeysFile)[1:] + if addressVersionNumber not in (2, 3, 4): + logger.error( + 'Error in reloadMyAddressHashes: Can\'t handle' + ' address versions other than 2, 3, or 4.') + continue + + # Returns a simple 32 bytes of information encoded in 64 Hex characters + try: + privEncryptionKey = hexlify( + highlevelcrypto.decodeWalletImportFormat( + config.get(addressInKeysFile, 'privencryptionkey') + )) + except ValueError: + logger.error( + 'Error in reloadMyAddressHashes: failed to decode' + ' one of the private keys for address %s', addressInKeysFile) + continue + # It is 32 bytes encoded as 64 hex characters + if len(privEncryptionKey) == 64: + myECCryptorObjects[hashobj] = \ + highlevelcrypto.makeCryptor(privEncryptionKey) + myAddressesByHash[hashobj] = addressInKeysFile + tag = hashlib.sha512(hashlib.sha512( + encodeVarint(addressVersionNumber) + + encodeVarint(streamNumber) + hashobj).digest()).digest()[32:] + myAddressesByTag[tag] = addressInKeysFile if not keyfileSecure: fixSensitiveFilePermissions(os.path.join(