Test WIF decoding and encoding in highlevelcrypto #2208
|
@ -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)
|
||||
|
|
|
@ -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 = \
|
||||
|
|
|
@ -7,6 +7,7 @@ High level cryptographic functions based on `.pyelliptic` OpenSSL bindings.
|
|||
`More discussion. <https://github.com/yann2192/pyelliptic/issues/32>`_
|
||||
"""
|
||||
|
||||
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'):
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -73,3 +73,13 @@ sample_sig = unhexlify(
|
|||
sample_sig_sha1 = unhexlify(
|
||||
'30460221008ad234687d1bdc259932e28ea6ee091b88b0900d8134902aa8c2fd7f016b96e'
|
||||
'd022100dafb94e28322c2fa88878f9dcbf0c2d33270466ab3bbffaec3dca0a2d1ef9354')
|
||||
|
||||
# [chan] bitmessage
|
||||
sample_wif_privsigningkey = unhexlify(
|
||||
b'a2e8b841a531c1c558ee0680c396789c7a2ea3ac4795ae3f000caf9fe367d144')
|
||||
sample_wif_privencryptionkey = unhexlify(
|
||||
b'114ec0e2dca24a826a0eed064b0405b0ac148abc3b1d52729697f4d7b873fdc6')
|
||||
sample_privsigningkey_wif = \
|
||||
b'5K42shDERM5g7Kbi3JT5vsAWpXMqRhWZpX835M2pdSoqQQpJMYm'
|
||||
sample_privencryptionkey_wif = \
|
||||
b'5HwugVWm31gnxtoYcvcK7oywH2ezYTh6Y4tzRxsndAeMi6NHqpA'
|
||||
|
|
|
@ -2,12 +2,14 @@
|
|||
import unittest
|
||||
from binascii import unhexlify
|
||||
|
||||
from pybitmessage import addresses
|
||||
from pybitmessage import addresses, highlevelcrypto
|
||||
|
||||
from .samples import (
|
||||
sample_address, sample_daddr3_512, sample_daddr4_512,
|
||||
sample_deterministic_addr4, sample_deterministic_addr3,
|
||||
sample_deterministic_ripe, sample_ripe)
|
||||
sample_deterministic_ripe, sample_ripe,
|
||||
sample_privsigningkey_wif, sample_privencryptionkey_wif,
|
||||
sample_wif_privsigningkey, sample_wif_privencryptionkey)
|
||||
|
||||
sample_addr3 = sample_deterministic_addr3.split('-')[1]
|
||||
sample_addr4 = sample_deterministic_addr4.split('-')[1]
|
||||
|
@ -59,3 +61,26 @@ class TestAddresses(unittest.TestCase):
|
|||
sample_addr4, addresses.encodeBase58(sample_daddr4_512))
|
||||
self.assertEqual(
|
||||
sample_addr3, addresses.encodeBase58(sample_daddr3_512))
|
||||
|
||||
def test_wif(self):
|
||||
"""Decode WIFs of [chan] bitmessage and check the keys"""
|
||||
self.assertEqual(
|
||||
sample_wif_privsigningkey,
|
||||
highlevelcrypto.decodeWalletImportFormat(
|
||||
sample_privsigningkey_wif))
|
||||
self.assertEqual(
|
||||
sample_wif_privencryptionkey,
|
||||
highlevelcrypto.decodeWalletImportFormat(
|
||||
sample_privencryptionkey_wif))
|
||||
self.assertEqual(
|
||||
sample_privsigningkey_wif,
|
||||
highlevelcrypto.encodeWalletImportFormat(
|
||||
sample_wif_privsigningkey))
|
||||
self.assertEqual(
|
||||
sample_privencryptionkey_wif,
|
||||
highlevelcrypto.encodeWalletImportFormat(
|
||||
sample_wif_privencryptionkey))
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
highlevelcrypto.decodeWalletImportFormat(
|
||||
sample_privencryptionkey_wif[:-2])
|
||||
|
|
Reference in New Issue
Block a user