Refactor using of crypto functions #1796
|
@ -2,11 +2,16 @@
|
||||||
Operations with addresses
|
Operations with addresses
|
||||||
"""
|
"""
|
||||||
# pylint: disable=inconsistent-return-statements
|
# pylint: disable=inconsistent-return-statements
|
||||||
import hashlib
|
|
||||||
import logging
|
import logging
|
||||||
from binascii import hexlify, unhexlify
|
from binascii import hexlify, unhexlify
|
||||||
from struct import pack, unpack
|
from struct import pack, unpack
|
||||||
|
|
||||||
|
try:
|
||||||
|
from highlevelcrypto import double_sha512
|
||||||
|
except ImportError:
|
||||||
|
from .highlevelcrypto import double_sha512
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger('default')
|
logger = logging.getLogger('default')
|
||||||
|
|
||||||
|
@ -134,15 +139,6 @@ def decodeVarint(data):
|
||||||
return (encodedValue, 9)
|
return (encodedValue, 9)
|
||||||
|
|
||||||
|
|
||||||
def calculateInventoryHash(data):
|
|
||||||
"""Calculate inventory hash from object data"""
|
|
||||||
sha = hashlib.new('sha512')
|
|
||||||
sha2 = hashlib.new('sha512')
|
|
||||||
sha.update(data)
|
|
||||||
sha2.update(sha.digest())
|
|
||||||
return sha2.digest()[0:32]
|
|
||||||
|
|
||||||
|
|
||||||
def encodeAddress(version, stream, ripe):
|
def encodeAddress(version, stream, ripe):
|
||||||
"""Convert ripe to address"""
|
"""Convert ripe to address"""
|
||||||
if version >= 2 and version < 4:
|
if version >= 2 and version < 4:
|
||||||
|
@ -166,12 +162,7 @@ def encodeAddress(version, stream, ripe):
|
||||||
storedBinaryData = encodeVarint(version) + encodeVarint(stream) + ripe
|
storedBinaryData = encodeVarint(version) + encodeVarint(stream) + ripe
|
||||||
|
|
||||||
# Generate the checksum
|
# Generate the checksum
|
||||||
sha = hashlib.new('sha512')
|
checksum = double_sha512(storedBinaryData)[0:4]
|
||||||
sha.update(storedBinaryData)
|
|
||||||
currentHash = sha.digest()
|
|
||||||
sha = hashlib.new('sha512')
|
|
||||||
sha.update(currentHash)
|
|
||||||
checksum = sha.digest()[0:4]
|
|
||||||
|
|
||||||
# FIXME: encodeBase58 should take binary data, to reduce conversions
|
# FIXME: encodeBase58 should take binary data, to reduce conversions
|
||||||
# encodeBase58(storedBinaryData + checksum)
|
# encodeBase58(storedBinaryData + checksum)
|
||||||
|
@ -207,13 +198,7 @@ def decodeAddress(address):
|
||||||
data = unhexlify(hexdata)
|
data = unhexlify(hexdata)
|
||||||
checksum = data[-4:]
|
checksum = data[-4:]
|
||||||
|
|
||||||
sha = hashlib.new('sha512')
|
if checksum != double_sha512(data[:-4])[0:4]:
|
||||||
sha.update(data[:-4])
|
|
||||||
currentHash = sha.digest()
|
|
||||||
sha = hashlib.new('sha512')
|
|
||||||
sha.update(currentHash)
|
|
||||||
|
|
||||||
if checksum != sha.digest()[0:4]:
|
|
||||||
status = 'checksumfailed'
|
status = 'checksumfailed'
|
||||||
return status, 0, 0, ''
|
return status, 0, 0, ''
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,8 @@ from binascii import hexlify, unhexlify
|
||||||
from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer
|
from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer
|
||||||
from struct import pack
|
from struct import pack
|
||||||
|
|
||||||
|
from six.moves import queue
|
||||||
|
|
||||||
import defaults
|
import defaults
|
||||||
import helper_inbox
|
import helper_inbox
|
||||||
import helper_sent
|
import helper_sent
|
||||||
|
@ -82,17 +84,17 @@ import shutdown
|
||||||
import state
|
import state
|
||||||
from addresses import (
|
from addresses import (
|
||||||
addBMIfNotPresent,
|
addBMIfNotPresent,
|
||||||
calculateInventoryHash,
|
|
||||||
decodeAddress,
|
decodeAddress,
|
||||||
decodeVarint,
|
decodeVarint,
|
||||||
varintDecodeError
|
varintDecodeError
|
||||||
)
|
)
|
||||||
from bmconfigparser import BMConfigParser
|
from bmconfigparser import BMConfigParser
|
||||||
from debug import logger
|
from debug import logger
|
||||||
from helper_sql import SqlBulkExecute, sqlExecute, sqlQuery, sqlStoredProcedure, sql_ready
|
from helper_sql import (
|
||||||
|
SqlBulkExecute, sqlExecute, sqlQuery, sql_ready, sqlStoredProcedure)
|
||||||
|
from highlevelcrypto import calculateInventoryHash
|
||||||
from inventory import Inventory
|
from inventory import Inventory
|
||||||
from network.threads import StoppableThread
|
from network.threads import StoppableThread
|
||||||
from six.moves import queue
|
|
||||||
from version import softwareVersion
|
from version import softwareVersion
|
||||||
|
|
||||||
try: # TODO: write tests for XML vulnerabilities
|
try: # TODO: write tests for XML vulnerabilities
|
||||||
|
|
|
@ -15,8 +15,6 @@ from addresses import decodeAddress, encodeAddress, encodeVarint
|
||||||
from bmconfigparser import BMConfigParser
|
from bmconfigparser import BMConfigParser
|
||||||
from fallback import RIPEMD160Hash
|
from fallback import RIPEMD160Hash
|
||||||
from network import StoppableThread
|
from network import StoppableThread
|
||||||
from pyelliptic import arithmetic
|
|
||||||
from pyelliptic.openssl import OpenSSL
|
|
||||||
from six.moves import configparser, queue
|
from six.moves import configparser, queue
|
||||||
|
|
||||||
|
|
||||||
|
@ -129,17 +127,13 @@ class addressGenerator(StoppableThread):
|
||||||
# the \x00 or \x00\x00 bytes thus making the address shorter.
|
# the \x00 or \x00\x00 bytes thus making the address shorter.
|
||||||
startTime = time.time()
|
startTime = time.time()
|
||||||
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix = 0
|
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix = 0
|
||||||
potentialPrivSigningKey = OpenSSL.rand(32)
|
privSigningKey, pubSigningKey = highlevelcrypto.random_keys()
|
||||||
potentialPubSigningKey = highlevelcrypto.pointMult(
|
|
||||||
potentialPrivSigningKey)
|
|
||||||
while True:
|
while True:
|
||||||
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix += 1
|
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix += 1
|
||||||
potentialPrivEncryptionKey = OpenSSL.rand(32)
|
potentialPrivEncryptionKey, potentialPubEncryptionKey = \
|
||||||
potentialPubEncryptionKey = highlevelcrypto.pointMult(
|
highlevelcrypto.random_keys()
|
||||||
potentialPrivEncryptionKey)
|
|
||||||
sha = hashlib.new('sha512')
|
sha = hashlib.new('sha512')
|
||||||
sha.update(
|
sha.update(pubSigningKey + potentialPubEncryptionKey)
|
||||||
potentialPubSigningKey + potentialPubEncryptionKey)
|
|
||||||
ripe = RIPEMD160Hash(sha.digest()).digest()
|
ripe = RIPEMD160Hash(sha.digest()).digest()
|
||||||
if (
|
if (
|
||||||
ripe[:numberOfNullBytesDemandedOnFrontOfRipeHash]
|
ripe[:numberOfNullBytesDemandedOnFrontOfRipeHash]
|
||||||
|
@ -163,20 +157,10 @@ class addressGenerator(StoppableThread):
|
||||||
address = encodeAddress(
|
address = encodeAddress(
|
||||||
addressVersionNumber, streamNumber, ripe)
|
addressVersionNumber, streamNumber, ripe)
|
||||||
|
|
||||||
# An excellent way for us to store our keys
|
privSigningKeyWIF = highlevelcrypto.encodeWalletImportFormat(
|
||||||
# is in Wallet Import Format. Let us convert now.
|
privSigningKey)
|
||||||
# https://en.bitcoin.it/wiki/Wallet_import_format
|
privEncryptionKeyWIF = highlevelcrypto.encodeWalletImportFormat(
|
||||||
privSigningKey = b'\x80' + potentialPrivSigningKey
|
potentialPrivEncryptionKey)
|
||||||
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)
|
|
||||||
|
|
||||||
BMConfigParser().add_section(address)
|
BMConfigParser().add_section(address)
|
||||||
BMConfigParser().set(address, 'label', label)
|
BMConfigParser().set(address, 'label', label)
|
||||||
|
@ -246,18 +230,15 @@ class addressGenerator(StoppableThread):
|
||||||
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix = 0
|
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix = 0
|
||||||
while True:
|
while True:
|
||||||
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix += 1
|
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix += 1
|
||||||
potentialPrivSigningKey = hashlib.sha512(
|
potentialPrivSigningKey, potentialPubSigningKey = \
|
||||||
deterministicPassphrase
|
highlevelcrypto.deterministic_keys(
|
||||||
+ encodeVarint(signingKeyNonce)
|
deterministicPassphrase,
|
||||||
).digest()[:32]
|
encodeVarint(signingKeyNonce))
|
||||||
potentialPrivEncryptionKey = hashlib.sha512(
|
potentialPrivEncryptionKey, potentialPubEncryptionKey = \
|
||||||
deterministicPassphrase
|
highlevelcrypto.deterministic_keys(
|
||||||
+ encodeVarint(encryptionKeyNonce)
|
deterministicPassphrase,
|
||||||
).digest()[:32]
|
encodeVarint(encryptionKeyNonce))
|
||||||
potentialPubSigningKey = highlevelcrypto.pointMult(
|
|
||||||
potentialPrivSigningKey)
|
|
||||||
potentialPubEncryptionKey = highlevelcrypto.pointMult(
|
|
||||||
potentialPrivEncryptionKey)
|
|
||||||
signingKeyNonce += 2
|
signingKeyNonce += 2
|
||||||
encryptionKeyNonce += 2
|
encryptionKeyNonce += 2
|
||||||
sha = hashlib.new('sha512')
|
sha = hashlib.new('sha512')
|
||||||
|
@ -300,21 +281,12 @@ class addressGenerator(StoppableThread):
|
||||||
saveAddressToDisk = False
|
saveAddressToDisk = False
|
||||||
|
|
||||||
if saveAddressToDisk and live:
|
if saveAddressToDisk and live:
|
||||||
# An excellent way for us to store our keys is
|
privSigningKeyWIF = \
|
||||||
# in Wallet Import Format. Let us convert now.
|
highlevelcrypto.encodeWalletImportFormat(
|
||||||
# https://en.bitcoin.it/wiki/Wallet_import_format
|
potentialPrivSigningKey)
|
||||||
privSigningKey = b'\x80' + potentialPrivSigningKey
|
privEncryptionKeyWIF = \
|
||||||
checksum = hashlib.sha256(hashlib.sha256(
|
highlevelcrypto.encodeWalletImportFormat(
|
||||||
privSigningKey).digest()).digest()[0:4]
|
potentialPrivEncryptionKey)
|
||||||
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)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
BMConfigParser().add_section(address)
|
BMConfigParser().add_section(address)
|
||||||
|
@ -367,10 +339,10 @@ class addressGenerator(StoppableThread):
|
||||||
highlevelcrypto.makeCryptor(
|
highlevelcrypto.makeCryptor(
|
||||||
hexlify(potentialPrivEncryptionKey))
|
hexlify(potentialPrivEncryptionKey))
|
||||||
shared.myAddressesByHash[ripe] = address
|
shared.myAddressesByHash[ripe] = address
|
||||||
tag = hashlib.sha512(hashlib.sha512(
|
tag = highlevelcrypto.double_sha512(
|
||||||
encodeVarint(addressVersionNumber)
|
encodeVarint(addressVersionNumber)
|
||||||
+ encodeVarint(streamNumber) + ripe
|
+ encodeVarint(streamNumber) + ripe
|
||||||
).digest()).digest()[32:]
|
)[32:]
|
||||||
shared.myAddressesByTag[tag] = address
|
shared.myAddressesByTag[tag] = address
|
||||||
if addressVersionNumber == 3:
|
if addressVersionNumber == 3:
|
||||||
# If this is a chan address,
|
# If this is a chan address,
|
||||||
|
|
|
@ -23,7 +23,7 @@ import queues
|
||||||
import shared
|
import shared
|
||||||
import state
|
import state
|
||||||
from addresses import (
|
from addresses import (
|
||||||
calculateInventoryHash, decodeAddress, decodeVarint,
|
decodeAddress, decodeVarint,
|
||||||
encodeAddress, encodeVarint, varintDecodeError
|
encodeAddress, encodeVarint, varintDecodeError
|
||||||
)
|
)
|
||||||
from bmconfigparser import BMConfigParser
|
from bmconfigparser import BMConfigParser
|
||||||
|
@ -450,7 +450,7 @@ class objectProcessor(threading.Thread):
|
||||||
streamNumberAsClaimedByMsg, streamNumberAsClaimedByMsgLength = \
|
streamNumberAsClaimedByMsg, streamNumberAsClaimedByMsgLength = \
|
||||||
decodeVarint(data[readPosition:readPosition + 9])
|
decodeVarint(data[readPosition:readPosition + 9])
|
||||||
readPosition += streamNumberAsClaimedByMsgLength
|
readPosition += streamNumberAsClaimedByMsgLength
|
||||||
inventoryHash = calculateInventoryHash(data)
|
inventoryHash = highlevelcrypto.calculateInventoryHash(data)
|
||||||
initialDecryptionSuccessful = False
|
initialDecryptionSuccessful = False
|
||||||
|
|
||||||
# This is not an acknowledgement bound for me. See if it is a message
|
# This is not an acknowledgement bound for me. See if it is a message
|
||||||
|
@ -580,8 +580,7 @@ class objectProcessor(threading.Thread):
|
||||||
helper_bitcoin.calculateTestnetAddressFromPubkey(pubSigningKey)
|
helper_bitcoin.calculateTestnetAddressFromPubkey(pubSigningKey)
|
||||||
)
|
)
|
||||||
# Used to detect and ignore duplicate messages in our inbox
|
# Used to detect and ignore duplicate messages in our inbox
|
||||||
sigHash = hashlib.sha512(
|
sigHash = highlevelcrypto.double_sha512(signature)[32:]
|
||||||
hashlib.sha512(signature).digest()).digest()[32:]
|
|
||||||
|
|
||||||
# calculate the fromRipe.
|
# calculate the fromRipe.
|
||||||
sha = hashlib.new('sha512')
|
sha = hashlib.new('sha512')
|
||||||
|
@ -751,7 +750,7 @@ class objectProcessor(threading.Thread):
|
||||||
state.numberOfBroadcastsProcessed += 1
|
state.numberOfBroadcastsProcessed += 1
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateNumberOfBroadcastsProcessed', 'no data'))
|
'updateNumberOfBroadcastsProcessed', 'no data'))
|
||||||
inventoryHash = calculateInventoryHash(data)
|
inventoryHash = highlevelcrypto.calculateInventoryHash(data)
|
||||||
readPosition = 20 # bypass the nonce, time, and object type
|
readPosition = 20 # bypass the nonce, time, and object type
|
||||||
broadcastVersion, broadcastVersionLength = decodeVarint(
|
broadcastVersion, broadcastVersionLength = decodeVarint(
|
||||||
data[readPosition:readPosition + 9])
|
data[readPosition:readPosition + 9])
|
||||||
|
@ -885,10 +884,10 @@ class objectProcessor(threading.Thread):
|
||||||
' itself. Ignoring message.'
|
' itself. Ignoring message.'
|
||||||
)
|
)
|
||||||
elif broadcastVersion == 5:
|
elif broadcastVersion == 5:
|
||||||
calculatedTag = hashlib.sha512(hashlib.sha512(
|
calculatedTag = highlevelcrypto.double_sha512(
|
||||||
encodeVarint(sendersAddressVersion)
|
encodeVarint(sendersAddressVersion)
|
||||||
+ encodeVarint(sendersStream) + calculatedRipe
|
+ encodeVarint(sendersStream) + calculatedRipe
|
||||||
).digest()).digest()[32:]
|
)[32:]
|
||||||
if calculatedTag != embeddedTag:
|
if calculatedTag != embeddedTag:
|
||||||
return logger.debug(
|
return logger.debug(
|
||||||
'The tag and encryption key used to encrypt this'
|
'The tag and encryption key used to encrypt this'
|
||||||
|
@ -918,8 +917,7 @@ class objectProcessor(threading.Thread):
|
||||||
return
|
return
|
||||||
logger.debug('ECDSA verify passed')
|
logger.debug('ECDSA verify passed')
|
||||||
# Used to detect and ignore duplicate messages in our inbox
|
# Used to detect and ignore duplicate messages in our inbox
|
||||||
sigHash = hashlib.sha512(
|
sigHash = highlevelcrypto.double_sha512(signature)[32:]
|
||||||
hashlib.sha512(signature).digest()).digest()[32:]
|
|
||||||
|
|
||||||
fromAddress = encodeAddress(
|
fromAddress = encodeAddress(
|
||||||
sendersAddressVersion, sendersStream, calculatedRipe)
|
sendersAddressVersion, sendersStream, calculatedRipe)
|
||||||
|
@ -993,10 +991,10 @@ class objectProcessor(threading.Thread):
|
||||||
# Let us create the tag from the address and see if we were waiting
|
# Let us create the tag from the address and see if we were waiting
|
||||||
# for it.
|
# for it.
|
||||||
elif addressVersion >= 4:
|
elif addressVersion >= 4:
|
||||||
tag = hashlib.sha512(hashlib.sha512(
|
tag = highlevelcrypto.double_sha512(
|
||||||
encodeVarint(addressVersion) + encodeVarint(streamNumber)
|
encodeVarint(addressVersion) + encodeVarint(streamNumber)
|
||||||
+ ripe
|
+ ripe
|
||||||
).digest()).digest()[32:]
|
)[32:]
|
||||||
if tag in state.neededPubkeys:
|
if tag in state.neededPubkeys:
|
||||||
del state.neededPubkeys[tag]
|
del state.neededPubkeys[tag]
|
||||||
self.sendMessages(address)
|
self.sendMessages(address)
|
||||||
|
|
|
@ -25,9 +25,7 @@ import queues
|
||||||
import shared
|
import shared
|
||||||
import state
|
import state
|
||||||
import tr
|
import tr
|
||||||
from addresses import (
|
from addresses import decodeAddress, decodeVarint, encodeVarint
|
||||||
calculateInventoryHash, decodeAddress, decodeVarint, encodeVarint
|
|
||||||
)
|
|
||||||
from bmconfigparser import BMConfigParser
|
from bmconfigparser import BMConfigParser
|
||||||
from helper_sql import sqlExecute, sqlQuery
|
from helper_sql import sqlExecute, sqlQuery
|
||||||
from inventory import Inventory
|
from inventory import Inventory
|
||||||
|
@ -50,6 +48,8 @@ class singleWorker(StoppableThread):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(singleWorker, self).__init__(name="singleWorker")
|
super(singleWorker, self).__init__(name="singleWorker")
|
||||||
|
self.digestAlg = BMConfigParser().safeGet(
|
||||||
|
'bitmessagesettings', 'digestalg', 'sha256')
|
||||||
proofofwork.init()
|
proofofwork.init()
|
||||||
|
|
||||||
def stopThread(self):
|
def stopThread(self):
|
||||||
|
@ -73,18 +73,16 @@ class singleWorker(StoppableThread):
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''SELECT DISTINCT toaddress FROM sent'''
|
'''SELECT DISTINCT toaddress FROM sent'''
|
||||||
''' WHERE (status='awaitingpubkey' AND folder='sent')''')
|
''' WHERE (status='awaitingpubkey' AND folder='sent')''')
|
||||||
for row in queryreturn:
|
for toAddress, in queryreturn:
|
||||||
toAddress, = row
|
toAddressVersionNumber, toStreamNumber, toRipe = \
|
||||||
# toStatus
|
decodeAddress(toAddress)[1:]
|
||||||
_, toAddressVersionNumber, toStreamNumber, toRipe = \
|
|
||||||
decodeAddress(toAddress)
|
|
||||||
if toAddressVersionNumber <= 3:
|
if toAddressVersionNumber <= 3:
|
||||||
state.neededPubkeys[toAddress] = 0
|
state.neededPubkeys[toAddress] = 0
|
||||||
elif toAddressVersionNumber >= 4:
|
elif toAddressVersionNumber >= 4:
|
||||||
doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(
|
doubleHashOfAddressData = highlevelcrypto.double_sha512(
|
||||||
encodeVarint(toAddressVersionNumber)
|
encodeVarint(toAddressVersionNumber)
|
||||||
+ encodeVarint(toStreamNumber) + toRipe
|
+ encodeVarint(toStreamNumber) + toRipe
|
||||||
).digest()).digest()
|
)
|
||||||
# Note that this is the first half of the sha512 hash.
|
# Note that this is the first half of the sha512 hash.
|
||||||
privEncryptionKey = doubleHashOfAddressData[:32]
|
privEncryptionKey = doubleHashOfAddressData[:32]
|
||||||
tag = doubleHashOfAddressData[32:]
|
tag = doubleHashOfAddressData[32:]
|
||||||
|
@ -195,15 +193,20 @@ class singleWorker(StoppableThread):
|
||||||
self.logger.info("Quitting...")
|
self.logger.info("Quitting...")
|
||||||
|
|
||||||
def _getKeysForAddress(self, address):
|
def _getKeysForAddress(self, address):
|
||||||
|
try:
|
||||||
privSigningKeyBase58 = BMConfigParser().get(
|
privSigningKeyBase58 = BMConfigParser().get(
|
||||||
address, 'privsigningkey')
|
address, 'privsigningkey')
|
||||||
privEncryptionKeyBase58 = BMConfigParser().get(
|
privEncryptionKeyBase58 = BMConfigParser().get(
|
||||||
address, 'privencryptionkey')
|
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(
|
privSigningKeyHex = hexlify(
|
||||||
privSigningKeyBase58))
|
highlevelcrypto.decodeWalletImportFormat(privSigningKeyBase58))
|
||||||
privEncryptionKeyHex = hexlify(shared.decodeWalletImportFormat(
|
privEncryptionKeyHex = hexlify(
|
||||||
privEncryptionKeyBase58))
|
highlevelcrypto.decodeWalletImportFormat(privEncryptionKeyBase58))
|
||||||
|
|
||||||
# The \x04 on the beginning of the public keys are not sent.
|
# The \x04 on the beginning of the public keys are not sent.
|
||||||
# This way there is only one acceptable way to encode
|
# This way there is only one acceptable way to encode
|
||||||
|
@ -254,9 +257,7 @@ class singleWorker(StoppableThread):
|
||||||
message once it is done with the POW"""
|
message once it is done with the POW"""
|
||||||
# Look up my stream number based on my address hash
|
# Look up my stream number based on my address hash
|
||||||
myAddress = shared.myAddressesByHash[adressHash]
|
myAddress = shared.myAddressesByHash[adressHash]
|
||||||
# status
|
addressVersionNumber, streamNumber = decodeAddress(myAddress)[1:3]
|
||||||
_, addressVersionNumber, streamNumber, adressHash = (
|
|
||||||
decodeAddress(myAddress))
|
|
||||||
|
|
||||||
# 28 days from now plus or minus five minutes
|
# 28 days from now plus or minus five minutes
|
||||||
TTL = int(28 * 24 * 60 * 60 + helper_random.randomrandrange(-300, 300))
|
TTL = int(28 * 24 * 60 * 60 + helper_random.randomrandrange(-300, 300))
|
||||||
|
@ -269,18 +270,15 @@ class singleWorker(StoppableThread):
|
||||||
payload += protocol.getBitfield(myAddress)
|
payload += protocol.getBitfield(myAddress)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# privSigningKeyHex, privEncryptionKeyHex
|
pubSigningKey, pubEncryptionKey = self._getKeysForAddress(
|
||||||
_, _, pubSigningKey, pubEncryptionKey = \
|
myAddress)[2:]
|
||||||
self._getKeysForAddress(myAddress)
|
except ValueError:
|
||||||
except (configparser.NoSectionError, configparser.NoOptionError) as err:
|
return
|
||||||
self.logger.warning("Section or Option did not found: %s", err)
|
except Exception:
|
||||||
except Exception as err:
|
return self.logger.error(
|
||||||
self.logger.error(
|
|
||||||
'Error within doPOWForMyV2Pubkey. Could not read'
|
'Error within doPOWForMyV2Pubkey. Could not read'
|
||||||
' the keys from the keys.dat file for a requested'
|
' the keys from the keys.dat file for a requested'
|
||||||
' address. %s\n', err
|
' address. %s\n', exc_info=True)
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
payload += pubSigningKey + pubEncryptionKey
|
payload += pubSigningKey + pubEncryptionKey
|
||||||
|
|
||||||
|
@ -288,7 +286,7 @@ class singleWorker(StoppableThread):
|
||||||
payload = self._doPOWDefaults(
|
payload = self._doPOWDefaults(
|
||||||
payload, TTL, log_prefix='(For pubkey message)')
|
payload, TTL, log_prefix='(For pubkey message)')
|
||||||
|
|
||||||
inventoryHash = calculateInventoryHash(payload)
|
inventoryHash = highlevelcrypto.calculateInventoryHash(payload)
|
||||||
objectType = 1
|
objectType = 1
|
||||||
Inventory()[inventoryHash] = (
|
Inventory()[inventoryHash] = (
|
||||||
objectType, streamNumber, payload, embeddedTime, '')
|
objectType, streamNumber, payload, embeddedTime, '')
|
||||||
|
@ -318,9 +316,8 @@ class singleWorker(StoppableThread):
|
||||||
try:
|
try:
|
||||||
myAddress = shared.myAddressesByHash[adressHash]
|
myAddress = shared.myAddressesByHash[adressHash]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
# The address has been deleted.
|
return self.logger.warning( # The address has been deleted.
|
||||||
self.logger.warning("Can't find %s in myAddressByHash", hexlify(adressHash))
|
"Can't find %s in myAddressByHash", hexlify(adressHash))
|
||||||
return
|
|
||||||
if BMConfigParser().safeGetBoolean(myAddress, 'chan'):
|
if BMConfigParser().safeGetBoolean(myAddress, 'chan'):
|
||||||
self.logger.info('This is a chan address. Not sending pubkey.')
|
self.logger.info('This is a chan address. Not sending pubkey.')
|
||||||
return
|
return
|
||||||
|
@ -351,15 +348,13 @@ class singleWorker(StoppableThread):
|
||||||
# , privEncryptionKeyHex
|
# , privEncryptionKeyHex
|
||||||
privSigningKeyHex, _, pubSigningKey, pubEncryptionKey = \
|
privSigningKeyHex, _, pubSigningKey, pubEncryptionKey = \
|
||||||
self._getKeysForAddress(myAddress)
|
self._getKeysForAddress(myAddress)
|
||||||
except (configparser.NoSectionError, configparser.NoOptionError) as err:
|
except ValueError:
|
||||||
self.logger.warning("Section or Option did not found: %s", err)
|
return
|
||||||
except Exception as err:
|
except Exception:
|
||||||
self.logger.error(
|
return self.logger.error(
|
||||||
'Error within sendOutOrStoreMyV3Pubkey. Could not read'
|
'Error within sendOutOrStoreMyV3Pubkey. Could not read'
|
||||||
' the keys from the keys.dat file for a requested'
|
' the keys from the keys.dat file for a requested'
|
||||||
' address. %s\n', err
|
' address. %s\n', exc_info=True)
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
payload += pubSigningKey + pubEncryptionKey
|
payload += pubSigningKey + pubEncryptionKey
|
||||||
|
|
||||||
|
@ -368,7 +363,8 @@ class singleWorker(StoppableThread):
|
||||||
payload += encodeVarint(BMConfigParser().getint(
|
payload += encodeVarint(BMConfigParser().getint(
|
||||||
myAddress, 'payloadlengthextrabytes'))
|
myAddress, 'payloadlengthextrabytes'))
|
||||||
|
|
||||||
signature = highlevelcrypto.sign(payload, privSigningKeyHex)
|
signature = highlevelcrypto.sign(
|
||||||
|
payload, privSigningKeyHex, self.digestAlg)
|
||||||
payload += encodeVarint(len(signature))
|
payload += encodeVarint(len(signature))
|
||||||
payload += signature
|
payload += signature
|
||||||
|
|
||||||
|
@ -376,7 +372,7 @@ class singleWorker(StoppableThread):
|
||||||
payload = self._doPOWDefaults(
|
payload = self._doPOWDefaults(
|
||||||
payload, TTL, log_prefix='(For pubkey message)')
|
payload, TTL, log_prefix='(For pubkey message)')
|
||||||
|
|
||||||
inventoryHash = calculateInventoryHash(payload)
|
inventoryHash = highlevelcrypto.calculateInventoryHash(payload)
|
||||||
objectType = 1
|
objectType = 1
|
||||||
Inventory()[inventoryHash] = (
|
Inventory()[inventoryHash] = (
|
||||||
objectType, streamNumber, payload, embeddedTime, '')
|
objectType, streamNumber, payload, embeddedTime, '')
|
||||||
|
@ -425,15 +421,13 @@ class singleWorker(StoppableThread):
|
||||||
# , privEncryptionKeyHex
|
# , privEncryptionKeyHex
|
||||||
privSigningKeyHex, _, pubSigningKey, pubEncryptionKey = \
|
privSigningKeyHex, _, pubSigningKey, pubEncryptionKey = \
|
||||||
self._getKeysForAddress(myAddress)
|
self._getKeysForAddress(myAddress)
|
||||||
except (configparser.NoSectionError, configparser.NoOptionError) as err:
|
except ValueError:
|
||||||
self.logger.warning("Section or Option did not found: %s", err)
|
return
|
||||||
except Exception as err:
|
except Exception:
|
||||||
self.logger.error(
|
return self.logger.error(
|
||||||
'Error within sendOutOrStoreMyV4Pubkey. Could not read'
|
'Error within sendOutOrStoreMyV4Pubkey. Could not read'
|
||||||
' the keys from the keys.dat file for a requested'
|
' the keys from the keys.dat file for a requested'
|
||||||
' address. %s\n', err
|
' address. %s\n', exc_info=True)
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
dataToEncrypt += pubSigningKey + pubEncryptionKey
|
dataToEncrypt += pubSigningKey + pubEncryptionKey
|
||||||
|
|
||||||
|
@ -449,14 +443,13 @@ class singleWorker(StoppableThread):
|
||||||
# unencrypted, the pubkey with part of the hash so that nodes
|
# unencrypted, the pubkey with part of the hash so that nodes
|
||||||
# know which pubkey object to try to decrypt
|
# know which pubkey object to try to decrypt
|
||||||
# when they want to send a message.
|
# when they want to send a message.
|
||||||
doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(
|
doubleHashOfAddressData = highlevelcrypto.double_sha512(
|
||||||
encodeVarint(addressVersionNumber)
|
encodeVarint(addressVersionNumber)
|
||||||
+ encodeVarint(streamNumber) + addressHash
|
+ encodeVarint(streamNumber) + addressHash
|
||||||
).digest()).digest()
|
)
|
||||||
payload += doubleHashOfAddressData[32:] # the tag
|
payload += doubleHashOfAddressData[32:] # the tag
|
||||||
signature = highlevelcrypto.sign(
|
signature = highlevelcrypto.sign(
|
||||||
payload + dataToEncrypt, privSigningKeyHex
|
payload + dataToEncrypt, privSigningKeyHex, self.digestAlg)
|
||||||
)
|
|
||||||
dataToEncrypt += encodeVarint(len(signature))
|
dataToEncrypt += encodeVarint(len(signature))
|
||||||
dataToEncrypt += signature
|
dataToEncrypt += signature
|
||||||
|
|
||||||
|
@ -469,7 +462,7 @@ class singleWorker(StoppableThread):
|
||||||
payload = self._doPOWDefaults(
|
payload = self._doPOWDefaults(
|
||||||
payload, TTL, log_prefix='(For pubkey message)')
|
payload, TTL, log_prefix='(For pubkey message)')
|
||||||
|
|
||||||
inventoryHash = calculateInventoryHash(payload)
|
inventoryHash = highlevelcrypto.calculateInventoryHash(payload)
|
||||||
objectType = 1
|
objectType = 1
|
||||||
Inventory()[inventoryHash] = (
|
Inventory()[inventoryHash] = (
|
||||||
objectType, streamNumber, payload, embeddedTime,
|
objectType, streamNumber, payload, embeddedTime,
|
||||||
|
@ -505,7 +498,7 @@ class singleWorker(StoppableThread):
|
||||||
objectType = protocol.OBJECT_ONIONPEER
|
objectType = protocol.OBJECT_ONIONPEER
|
||||||
# FIXME: ideally the objectPayload should be signed
|
# FIXME: ideally the objectPayload should be signed
|
||||||
objectPayload = encodeVarint(peer.port) + protocol.encodeHost(peer.host)
|
objectPayload = encodeVarint(peer.port) + protocol.encodeHost(peer.host)
|
||||||
tag = calculateInventoryHash(objectPayload)
|
tag = highlevelcrypto.calculateInventoryHash(objectPayload)
|
||||||
|
|
||||||
if Inventory().by_type_and_tag(objectType, tag):
|
if Inventory().by_type_and_tag(objectType, tag):
|
||||||
return # not expired
|
return # not expired
|
||||||
|
@ -519,7 +512,7 @@ class singleWorker(StoppableThread):
|
||||||
payload = self._doPOWDefaults(
|
payload = self._doPOWDefaults(
|
||||||
payload, TTL, log_prefix='(For onionpeer object)')
|
payload, TTL, log_prefix='(For onionpeer object)')
|
||||||
|
|
||||||
inventoryHash = calculateInventoryHash(payload)
|
inventoryHash = highlevelcrypto.calculateInventoryHash(payload)
|
||||||
Inventory()[inventoryHash] = (
|
Inventory()[inventoryHash] = (
|
||||||
objectType, streamNumber, buffer(payload),
|
objectType, streamNumber, buffer(payload),
|
||||||
embeddedTime, buffer(tag)
|
embeddedTime, buffer(tag)
|
||||||
|
@ -613,10 +606,10 @@ class singleWorker(StoppableThread):
|
||||||
|
|
||||||
payload += encodeVarint(streamNumber)
|
payload += encodeVarint(streamNumber)
|
||||||
if addressVersionNumber >= 4:
|
if addressVersionNumber >= 4:
|
||||||
doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(
|
doubleHashOfAddressData = highlevelcrypto.double_sha512(
|
||||||
encodeVarint(addressVersionNumber)
|
encodeVarint(addressVersionNumber)
|
||||||
+ encodeVarint(streamNumber) + ripe
|
+ encodeVarint(streamNumber) + ripe
|
||||||
).digest()).digest()
|
)
|
||||||
tag = doubleHashOfAddressData[32:]
|
tag = doubleHashOfAddressData[32:]
|
||||||
payload += tag
|
payload += tag
|
||||||
else:
|
else:
|
||||||
|
@ -641,7 +634,7 @@ class singleWorker(StoppableThread):
|
||||||
dataToSign = payload + dataToEncrypt
|
dataToSign = payload + dataToEncrypt
|
||||||
|
|
||||||
signature = highlevelcrypto.sign(
|
signature = highlevelcrypto.sign(
|
||||||
dataToSign, privSigningKeyHex)
|
dataToSign, privSigningKeyHex, self.digestAlg)
|
||||||
dataToEncrypt += encodeVarint(len(signature))
|
dataToEncrypt += encodeVarint(len(signature))
|
||||||
dataToEncrypt += signature
|
dataToEncrypt += signature
|
||||||
|
|
||||||
|
@ -686,7 +679,7 @@ class singleWorker(StoppableThread):
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
inventoryHash = calculateInventoryHash(payload)
|
inventoryHash = highlevelcrypto.calculateInventoryHash(payload)
|
||||||
objectType = 3
|
objectType = 3
|
||||||
Inventory()[inventoryHash] = (
|
Inventory()[inventoryHash] = (
|
||||||
objectType, streamNumber, payload, embeddedTime, tag)
|
objectType, streamNumber, payload, embeddedTime, tag)
|
||||||
|
@ -795,10 +788,10 @@ class singleWorker(StoppableThread):
|
||||||
if toAddressVersionNumber <= 3:
|
if toAddressVersionNumber <= 3:
|
||||||
toTag = ''
|
toTag = ''
|
||||||
else:
|
else:
|
||||||
toTag = hashlib.sha512(hashlib.sha512(
|
toTag = highlevelcrypto.double_sha512(
|
||||||
encodeVarint(toAddressVersionNumber)
|
encodeVarint(toAddressVersionNumber)
|
||||||
+ encodeVarint(toStreamNumber) + toRipe
|
+ encodeVarint(toStreamNumber) + toRipe
|
||||||
).digest()).digest()[32:]
|
)[32:]
|
||||||
if toaddress in state.neededPubkeys or \
|
if toaddress in state.neededPubkeys or \
|
||||||
toTag in state.neededPubkeys:
|
toTag in state.neededPubkeys:
|
||||||
# We already sent a request for the pubkey
|
# We already sent a request for the pubkey
|
||||||
|
@ -832,11 +825,11 @@ class singleWorker(StoppableThread):
|
||||||
# already contains the toAddress and cryptor
|
# already contains the toAddress and cryptor
|
||||||
# object associated with the tag for this toAddress.
|
# object associated with the tag for this toAddress.
|
||||||
if toAddressVersionNumber >= 4:
|
if toAddressVersionNumber >= 4:
|
||||||
doubleHashOfToAddressData = hashlib.sha512(
|
doubleHashOfToAddressData = \
|
||||||
hashlib.sha512(
|
highlevelcrypto.double_sha512(
|
||||||
encodeVarint(toAddressVersionNumber) + encodeVarint(toStreamNumber) + toRipe
|
encodeVarint(toAddressVersionNumber)
|
||||||
).digest()
|
+ encodeVarint(toStreamNumber) + toRipe
|
||||||
).digest()
|
)
|
||||||
# The first half of the sha512 hash.
|
# The first half of the sha512 hash.
|
||||||
privEncryptionKey = doubleHashOfToAddressData[:32]
|
privEncryptionKey = doubleHashOfToAddressData[:32]
|
||||||
# The second half of the sha512 hash.
|
# The second half of the sha512 hash.
|
||||||
|
@ -1116,7 +1109,8 @@ class singleWorker(StoppableThread):
|
||||||
' from the keys.dat file for our own address. %s\n',
|
' from the keys.dat file for our own address. %s\n',
|
||||||
err)
|
err)
|
||||||
continue
|
continue
|
||||||
privEncryptionKeyHex = hexlify(shared.decodeWalletImportFormat(
|
privEncryptionKeyHex = hexlify(
|
||||||
|
highlevelcrypto.decodeWalletImportFormat(
|
||||||
privEncryptionKeyBase58))
|
privEncryptionKeyBase58))
|
||||||
pubEncryptionKeyBase256 = unhexlify(highlevelcrypto.privToPub(
|
pubEncryptionKeyBase256 = unhexlify(highlevelcrypto.privToPub(
|
||||||
privEncryptionKeyHex))[1:]
|
privEncryptionKeyHex))[1:]
|
||||||
|
@ -1223,7 +1217,8 @@ class singleWorker(StoppableThread):
|
||||||
payload += fullAckPayload
|
payload += fullAckPayload
|
||||||
dataToSign = pack('>Q', embeddedTime) + '\x00\x00\x00\x02' + \
|
dataToSign = pack('>Q', embeddedTime) + '\x00\x00\x00\x02' + \
|
||||||
encodeVarint(1) + encodeVarint(toStreamNumber) + payload
|
encodeVarint(1) + encodeVarint(toStreamNumber) + payload
|
||||||
signature = highlevelcrypto.sign(dataToSign, privSigningKeyHex)
|
signature = highlevelcrypto.sign(
|
||||||
|
dataToSign, privSigningKeyHex, self.digestAlg)
|
||||||
payload += encodeVarint(len(signature))
|
payload += encodeVarint(len(signature))
|
||||||
payload += signature
|
payload += signature
|
||||||
|
|
||||||
|
@ -1301,7 +1296,7 @@ class singleWorker(StoppableThread):
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
inventoryHash = calculateInventoryHash(encryptedPayload)
|
inventoryHash = highlevelcrypto.calculateInventoryHash(encryptedPayload)
|
||||||
objectType = 2
|
objectType = 2
|
||||||
Inventory()[inventoryHash] = (
|
Inventory()[inventoryHash] = (
|
||||||
objectType, toStreamNumber, encryptedPayload, embeddedTime, '')
|
objectType, toStreamNumber, encryptedPayload, embeddedTime, '')
|
||||||
|
@ -1351,8 +1346,7 @@ class singleWorker(StoppableThread):
|
||||||
# the message in our own inbox.
|
# the message in our own inbox.
|
||||||
if BMConfigParser().has_section(toaddress):
|
if BMConfigParser().has_section(toaddress):
|
||||||
# Used to detect and ignore duplicate messages in our inbox
|
# Used to detect and ignore duplicate messages in our inbox
|
||||||
sigHash = hashlib.sha512(hashlib.sha512(
|
sigHash = highlevelcrypto.double_sha512(signature)[32:]
|
||||||
signature).digest()).digest()[32:]
|
|
||||||
t = (inventoryHash, toaddress, fromaddress, subject, int(
|
t = (inventoryHash, toaddress, fromaddress, subject, int(
|
||||||
time.time()), message, 'inbox', encoding, 0, sigHash)
|
time.time()), message, 'inbox', encoding, 0, sigHash)
|
||||||
helper_inbox.insert(t)
|
helper_inbox.insert(t)
|
||||||
|
@ -1407,16 +1401,13 @@ class singleWorker(StoppableThread):
|
||||||
# neededPubkeys dictionary. But if we are recovering
|
# neededPubkeys dictionary. But if we are recovering
|
||||||
# from a restart of the client then we have to put it in now.
|
# from a restart of the client then we have to put it in now.
|
||||||
|
|
||||||
# Note that this is the first half of the sha512 hash.
|
doubleHashOfAddressData = highlevelcrypto.double_sha512(
|
||||||
privEncryptionKey = hashlib.sha512(hashlib.sha512(
|
|
||||||
encodeVarint(addressVersionNumber)
|
encodeVarint(addressVersionNumber)
|
||||||
+ encodeVarint(streamNumber) + ripe
|
+ encodeVarint(streamNumber) + ripe
|
||||||
).digest()).digest()[:32]
|
)
|
||||||
|
privEncryptionKey = doubleHashOfAddressData[:32]
|
||||||
# Note that this is the second half of the sha512 hash.
|
# Note that this is the second half of the sha512 hash.
|
||||||
tag = hashlib.sha512(hashlib.sha512(
|
tag = doubleHashOfAddressData[32:]
|
||||||
encodeVarint(addressVersionNumber)
|
|
||||||
+ encodeVarint(streamNumber) + ripe
|
|
||||||
).digest()).digest()[32:]
|
|
||||||
if tag not in state.neededPubkeys:
|
if tag not in state.neededPubkeys:
|
||||||
# We'll need this for when we receive a pubkey reply:
|
# We'll need this for when we receive a pubkey reply:
|
||||||
# it will be encrypted and we'll need to decrypt it.
|
# it will be encrypted and we'll need to decrypt it.
|
||||||
|
@ -1459,7 +1450,7 @@ class singleWorker(StoppableThread):
|
||||||
|
|
||||||
payload = self._doPOWDefaults(payload, TTL)
|
payload = self._doPOWDefaults(payload, TTL)
|
||||||
|
|
||||||
inventoryHash = calculateInventoryHash(payload)
|
inventoryHash = highlevelcrypto.calculateInventoryHash(payload)
|
||||||
objectType = 1
|
objectType = 1
|
||||||
Inventory()[inventoryHash] = (
|
Inventory()[inventoryHash] = (
|
||||||
objectType, streamNumber, payload, embeddedTime, '')
|
objectType, streamNumber, payload, embeddedTime, '')
|
||||||
|
|
|
@ -25,10 +25,10 @@ def genAckPayload(streamNumber=1, stealthLevel=0):
|
||||||
if stealthLevel == 2: # Generate privacy-enhanced payload
|
if stealthLevel == 2: # Generate privacy-enhanced payload
|
||||||
# Generate a dummy privkey and derive the pubkey
|
# Generate a dummy privkey and derive the pubkey
|
||||||
dummyPubKeyHex = highlevelcrypto.privToPub(
|
dummyPubKeyHex = highlevelcrypto.privToPub(
|
||||||
hexlify(helper_random.randomBytes(32)))
|
hexlify(highlevelcrypto.randomBytes(32)))
|
||||||
# Generate a dummy message of random length
|
# Generate a dummy message of random length
|
||||||
# (the smallest possible standard-formatted message is 234 bytes)
|
# (the smallest possible standard-formatted message is 234 bytes)
|
||||||
dummyMessage = helper_random.randomBytes(
|
dummyMessage = highlevelcrypto.randomBytes(
|
||||||
helper_random.randomrandrange(234, 801))
|
helper_random.randomrandrange(234, 801))
|
||||||
# Encrypt the message using standard BM encryption (ECIES)
|
# Encrypt the message using standard BM encryption (ECIES)
|
||||||
ackdata = highlevelcrypto.encrypt(dummyMessage, dummyPubKeyHex)
|
ackdata = highlevelcrypto.encrypt(dummyMessage, dummyPubKeyHex)
|
||||||
|
@ -36,12 +36,12 @@ def genAckPayload(streamNumber=1, stealthLevel=0):
|
||||||
version = 1
|
version = 1
|
||||||
|
|
||||||
elif stealthLevel == 1: # Basic privacy payload (random getpubkey)
|
elif stealthLevel == 1: # Basic privacy payload (random getpubkey)
|
||||||
ackdata = helper_random.randomBytes(32)
|
ackdata = highlevelcrypto.randomBytes(32)
|
||||||
acktype = 0 # getpubkey
|
acktype = 0 # getpubkey
|
||||||
version = 4
|
version = 4
|
||||||
|
|
||||||
else: # Minimum viable payload (non stealth)
|
else: # Minimum viable payload (non stealth)
|
||||||
ackdata = helper_random.randomBytes(32)
|
ackdata = highlevelcrypto.randomBytes(32)
|
||||||
acktype = 2 # message
|
acktype = 2 # message
|
||||||
version = 1
|
version = 1
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
"""Convenience functions for random operations. Not suitable for security / cryptography operations."""
|
"""Convenience functions for random operations. Not suitable for security / cryptography operations."""
|
||||||
|
|
||||||
import os
|
|
||||||
import random
|
import random
|
||||||
|
|
||||||
try:
|
|
||||||
from pyelliptic.openssl import OpenSSL
|
|
||||||
except ImportError:
|
|
||||||
from .pyelliptic.openssl import OpenSSL
|
|
||||||
|
|
||||||
NoneType = type(None)
|
NoneType = type(None)
|
||||||
|
|
||||||
|
@ -16,14 +11,6 @@ def seed():
|
||||||
random.seed()
|
random.seed()
|
||||||
|
|
||||||
|
|
||||||
def randomBytes(n):
|
|
||||||
"""Method randomBytes."""
|
|
||||||
try:
|
|
||||||
return os.urandom(n)
|
|
||||||
except NotImplementedError:
|
|
||||||
return OpenSSL.rand(n)
|
|
||||||
|
|
||||||
|
|
||||||
def randomshuffle(population):
|
def randomshuffle(population):
|
||||||
"""Method randomShuffle.
|
"""Method randomShuffle.
|
||||||
|
|
||||||
|
|
|
@ -7,17 +7,85 @@ High level cryptographic functions based on `.pyelliptic` OpenSSL bindings.
|
||||||
`More discussion. <https://github.com/yann2192/pyelliptic/issues/32>`_
|
`More discussion. <https://github.com/yann2192/pyelliptic/issues/32>`_
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import hashlib
|
||||||
|
import os
|
||||||
from binascii import hexlify
|
from binascii import hexlify
|
||||||
|
|
||||||
import pyelliptic
|
import pyelliptic
|
||||||
from pyelliptic import OpenSSL
|
from pyelliptic import OpenSSL
|
||||||
from pyelliptic import arithmetic as a
|
from pyelliptic import arithmetic as a
|
||||||
|
|
||||||
from bmconfigparser import BMConfigParser
|
|
||||||
|
|
||||||
__all__ = ['encrypt', 'makeCryptor', 'pointMult', 'privToPub', 'sign', 'verify']
|
__all__ = ['encrypt', 'makeCryptor', 'pointMult', 'privToPub', 'sign', 'verify']
|
||||||
|
|
||||||
|
|
||||||
|
# Hashes
|
||||||
|
|
||||||
|
def double_sha512(data):
|
||||||
|
"""Binary double SHA512 digest"""
|
||||||
|
return hashlib.sha512(hashlib.sha512(data).digest()).digest()
|
||||||
|
|
||||||
|
|
||||||
|
def calculateInventoryHash(data):
|
||||||
|
"""Calculate inventory hash from object data"""
|
||||||
|
return double_sha512(data)[:32]
|
||||||
|
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
|
||||||
|
# Random
|
||||||
|
|
||||||
|
def randomBytes(n):
|
||||||
|
"""Get n random bytes"""
|
||||||
|
try:
|
||||||
|
return os.urandom(n)
|
||||||
|
except NotImplementedError:
|
||||||
|
return OpenSSL.rand(n)
|
||||||
|
|
||||||
|
|
||||||
|
# Keys
|
||||||
|
|
||||||
|
def random_keys():
|
||||||
|
"""Return a pair of keys, private and public"""
|
||||||
|
priv = randomBytes(32)
|
||||||
|
pub = pointMult(priv)
|
||||||
|
return priv, pub
|
||||||
|
|
||||||
|
|
||||||
|
def deterministic_keys(passphrase, nonce):
|
||||||
|
"""Generate keys from *passphrase* and *nonce* (encoded as varint)"""
|
||||||
|
priv = hashlib.sha512(passphrase + nonce).digest()[:32]
|
||||||
|
pub = pointMult(priv)
|
||||||
|
return priv, pub
|
||||||
|
|
||||||
|
|||||||
|
|
||||||
def makeCryptor(privkey):
|
def makeCryptor(privkey):
|
||||||
"""Return a private `.pyelliptic.ECC` instance"""
|
"""Return a private `.pyelliptic.ECC` instance"""
|
||||||
private_key = a.changebase(privkey, 16, 256, minlen=32)
|
private_key = a.changebase(privkey, 16, 256, minlen=32)
|
||||||
|
@ -67,22 +135,17 @@ def decryptFast(msg, cryptor):
|
||||||
return cryptor.decrypt(msg)
|
return cryptor.decrypt(msg)
|
||||||
|
|
||||||
|
|
||||||
def sign(msg, hexPrivkey):
|
def sign(msg, hexPrivkey, digestAlg="sha256"):
|
||||||
"""
|
"""
|
||||||
Signs with hex private key using SHA1 or SHA256 depending on
|
Signs with hex private key using SHA1 or SHA256 depending on
|
||||||
"digestalg" setting
|
*digestAlg* keyword.
|
||||||
"""
|
"""
|
||||||
digestAlg = BMConfigParser().safeGet(
|
if digestAlg not in ("sha1", "sha256"):
|
||||||
'bitmessagesettings', 'digestalg', 'sha256')
|
raise ValueError("Unknown digest algorithm %s" % digestAlg)
|
||||||
if digestAlg == "sha1":
|
|
||||||
# SHA1, this will eventually be deprecated
|
# SHA1, this will eventually be deprecated
|
||||||
return makeCryptor(hexPrivkey).sign(
|
return makeCryptor(hexPrivkey).sign(
|
||||||
msg, digest_alg=OpenSSL.digest_ecdsa_sha1)
|
msg, digest_alg=OpenSSL.digest_ecdsa_sha1
|
||||||
elif digestAlg == "sha256":
|
if digestAlg == "sha1" else OpenSSL.EVP_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)
|
|
||||||
|
|
||||||
|
|
||||||
def verify(msg, sig, hexPubkey):
|
def verify(msg, sig, hexPubkey):
|
||||||
|
|
|
@ -6,7 +6,7 @@ import time
|
||||||
|
|
||||||
import protocol
|
import protocol
|
||||||
import state
|
import state
|
||||||
from addresses import calculateInventoryHash
|
from highlevelcrypto import calculateInventoryHash
|
||||||
from inventory import Inventory
|
from inventory import Inventory
|
||||||
from network.dandelion import Dandelion
|
from network.dandelion import Dandelion
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ import knownnodes
|
||||||
import protocol
|
import protocol
|
||||||
import state
|
import state
|
||||||
from bmconfigparser import BMConfigParser
|
from bmconfigparser import BMConfigParser
|
||||||
from helper_random import randomBytes
|
from highlevelcrypto import randomBytes
|
||||||
from inventory import Inventory
|
from inventory import Inventory
|
||||||
from network.advanceddispatcher import AdvancedDispatcher
|
from network.advanceddispatcher import AdvancedDispatcher
|
||||||
from network.assemble import assemble_addr
|
from network.assemble import assemble_addr
|
||||||
|
|
|
@ -4,7 +4,6 @@ Proof of work calculation
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import ctypes
|
import ctypes
|
||||||
import hashlib
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
|
@ -12,6 +11,7 @@ import time
|
||||||
from struct import pack, unpack
|
from struct import pack, unpack
|
||||||
from subprocess import call
|
from subprocess import call
|
||||||
|
|
||||||
|
import highlevelcrypto
|
||||||
import openclpow
|
import openclpow
|
||||||
import paths
|
import paths
|
||||||
import queues
|
import queues
|
||||||
|
@ -87,13 +87,20 @@ def _set_idle():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def trial_value(nonce, initialHash):
|
||||||
|
"""Calculate PoW trial value"""
|
||||||
|
trialValue, = unpack(
|
||||||
|
'>Q', highlevelcrypto.double_sha512(
|
||||||
|
pack('>Q', nonce) + initialHash)[0:8])
|
||||||
|
return trialValue
|
||||||
|
|
||||||
|
|
||||||
def _pool_worker(nonce, initialHash, target, pool_size):
|
def _pool_worker(nonce, initialHash, target, pool_size):
|
||||||
_set_idle()
|
_set_idle()
|
||||||
trialValue = float('inf')
|
trialValue = float('inf')
|
||||||
while trialValue > target:
|
while trialValue > target:
|
||||||
nonce += pool_size
|
nonce += pool_size
|
||||||
trialValue, = unpack('>Q', hashlib.sha512(hashlib.sha512(
|
trialValue = trial_value(nonce, initialHash)
|
||||||
pack('>Q', nonce) + initialHash).digest()).digest()[0:8])
|
|
||||||
return [trialValue, nonce]
|
return [trialValue, nonce]
|
||||||
|
|
||||||
|
|
||||||
|
@ -103,10 +110,9 @@ def _doSafePoW(target, initialHash):
|
||||||
trialValue = float('inf')
|
trialValue = float('inf')
|
||||||
while trialValue > target and state.shutdown == 0:
|
while trialValue > target and state.shutdown == 0:
|
||||||
nonce += 1
|
nonce += 1
|
||||||
trialValue, = unpack('>Q', hashlib.sha512(hashlib.sha512(
|
trialValue = trial_value(nonce, initialHash)
|
||||||
pack('>Q', nonce) + initialHash).digest()).digest()[0:8])
|
|
||||||
if state.shutdown != 0:
|
if state.shutdown != 0:
|
||||||
raise StopIteration("Interrupted") # pylint: misplaced-bare-raise
|
raise StopIteration("Interrupted")
|
||||||
logger.debug("Safe PoW done")
|
logger.debug("Safe PoW done")
|
||||||
return [trialValue, nonce]
|
return [trialValue, nonce]
|
||||||
|
|
||||||
|
@ -163,7 +169,7 @@ def _doCPoW(target, initialHash):
|
||||||
logger.debug("C PoW start")
|
logger.debug("C PoW start")
|
||||||
nonce = bmpow(out_h, out_m)
|
nonce = bmpow(out_h, out_m)
|
||||||
|
|
||||||
trialValue, = unpack('>Q', hashlib.sha512(hashlib.sha512(pack('>Q', nonce) + initialHash).digest()).digest()[0:8])
|
trialValue = trial_value(nonce, initialHash)
|
||||||
if state.shutdown != 0:
|
if state.shutdown != 0:
|
||||||
raise StopIteration("Interrupted")
|
raise StopIteration("Interrupted")
|
||||||
logger.debug("C PoW done")
|
logger.debug("C PoW done")
|
||||||
|
@ -173,7 +179,7 @@ def _doCPoW(target, initialHash):
|
||||||
def _doGPUPoW(target, initialHash):
|
def _doGPUPoW(target, initialHash):
|
||||||
logger.debug("GPU PoW start")
|
logger.debug("GPU PoW start")
|
||||||
nonce = openclpow.do_opencl_pow(initialHash.encode("hex"), target)
|
nonce = openclpow.do_opencl_pow(initialHash.encode("hex"), target)
|
||||||
trialValue, = unpack('>Q', hashlib.sha512(hashlib.sha512(pack('>Q', nonce) + initialHash).digest()).digest()[0:8])
|
trialValue = trial_value(nonce, initialHash)
|
||||||
if trialValue > target:
|
if trialValue > target:
|
||||||
deviceNames = ", ".join(gpu.name for gpu in openclpow.enabledGpus)
|
deviceNames = ", ".join(gpu.name for gpu in openclpow.enabledGpus)
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
|
|
|
@ -269,12 +269,11 @@ def isProofOfWorkSufficient(
|
||||||
if payloadLengthExtraBytes < defaults.networkDefaultPayloadLengthExtraBytes:
|
if payloadLengthExtraBytes < defaults.networkDefaultPayloadLengthExtraBytes:
|
||||||
payloadLengthExtraBytes = defaults.networkDefaultPayloadLengthExtraBytes
|
payloadLengthExtraBytes = defaults.networkDefaultPayloadLengthExtraBytes
|
||||||
endOfLifeTime, = unpack('>Q', data[8:16])
|
endOfLifeTime, = unpack('>Q', data[8:16])
|
||||||
TTL = endOfLifeTime - (int(recvTime) if recvTime else int(time.time()))
|
TTL = endOfLifeTime - int(recvTime if recvTime else time.time())
|
||||||
if TTL < 300:
|
if TTL < 300:
|
||||||
TTL = 300
|
TTL = 300
|
||||||
POW, = unpack('>Q', hashlib.sha512(hashlib.sha512(
|
POW, = unpack('>Q', highlevelcrypto.double_sha512(
|
||||||
data[:8] + hashlib.sha512(data[8:]).digest()
|
data[:8] + hashlib.sha512(data[8:]).digest())[0:8])
|
||||||
).digest()).digest()[0:8])
|
|
||||||
return POW <= 2 ** 64 / (
|
return POW <= 2 ** 64 / (
|
||||||
nonceTrialsPerByte * (
|
nonceTrialsPerByte * (
|
||||||
len(data) + payloadLengthExtraBytes
|
len(data) + payloadLengthExtraBytes
|
||||||
|
|
|
@ -23,6 +23,12 @@ sample_privsigningkey = \
|
||||||
sample_privencryptionkey = \
|
sample_privencryptionkey = \
|
||||||
b'4b0b73a54e19b059dc274ab69df095fe699f43b17397bca26fdf40f4d7400a3a'
|
b'4b0b73a54e19b059dc274ab69df095fe699f43b17397bca26fdf40f4d7400a3a'
|
||||||
|
|
||||||
|
# [chan] bitmessage
|
||||||
|
sample_wif_privsigningkey = \
|
||||||
|
b'a2e8b841a531c1c558ee0680c396789c7a2ea3ac4795ae3f000caf9fe367d144'
|
||||||
|
sample_wif_privencryptionkey = \
|
||||||
|
b'114ec0e2dca24a826a0eed064b0405b0ac148abc3b1d52729697f4d7b873fdc6'
|
||||||
|
|
||||||
sample_factor = \
|
sample_factor = \
|
||||||
66858749573256452658262553961707680376751171096153613379801854825275240965733
|
66858749573256452658262553961707680376751171096153613379801854825275240965733
|
||||||
# G * sample_factor
|
# G * sample_factor
|
||||||
|
@ -40,6 +46,38 @@ class TestArithmetic(unittest.TestCase):
|
||||||
sample_point,
|
sample_point,
|
||||||
arithmetic.base10_multiply(arithmetic.G, sample_factor))
|
arithmetic.base10_multiply(arithmetic.G, sample_factor))
|
||||||
|
|
||||||
|
def test_base58(self):
|
||||||
|
"""Test encoding/decoding base58 using arithmetic functions"""
|
||||||
|
self.assertEqual(
|
||||||
|
arithmetic.decode(arithmetic.changebase(
|
||||||
|
b'2cWzSnwjJ7yRP3nLEWUV5LisTZyREWSzUK', 58, 256), 256),
|
||||||
|
25152821841976547050350277460563089811513157529113201589004)
|
||||||
|
self.assertEqual(
|
||||||
|
arithmetic.decode(arithmetic.changebase(
|
||||||
|
b'2DBPTgeSawWYZceFD69AbDT5q4iUWtj1ZN', 58, 256), 256),
|
||||||
|
18875720106589866286514488037355423395410802084648916523381)
|
||||||
|
self.assertEqual(
|
||||||
|
arithmetic.changebase(arithmetic.encode(
|
||||||
|
25152821841976547050350277460563089811513157529113201589004,
|
||||||
|
256), 256, 58), b'2cWzSnwjJ7yRP3nLEWUV5LisTZyREWSzUK')
|
||||||
|
self.assertEqual(
|
||||||
|
arithmetic.changebase(arithmetic.encode(
|
||||||
|
18875720106589866286514488037355423395410802084648916523381,
|
||||||
|
256), 256, 58), b'2DBPTgeSawWYZceFD69AbDT5q4iUWtj1ZN')
|
||||||
|
|
||||||
|
def test_wif(self):
|
||||||
|
"""Decode WIFs of [chan] bitmessage and check the keys"""
|
||||||
|
self.assertEqual(
|
||||||
|
sample_wif_privsigningkey,
|
||||||
|
arithmetic.changebase(arithmetic.changebase(
|
||||||
|
b'5K42shDERM5g7Kbi3JT5vsAWpXMqRhWZpX835M2pdSoqQQpJMYm', 58, 256
|
||||||
|
)[1:-4], 256, 16))
|
||||||
|
self.assertEqual(
|
||||||
|
sample_wif_privencryptionkey,
|
||||||
|
arithmetic.changebase(arithmetic.changebase(
|
||||||
|
b'5HwugVWm31gnxtoYcvcK7oywH2ezYTh6Y4tzRxsndAeMi6NHqpA', 58, 256
|
||||||
|
)[1:-4], 256, 16))
|
||||||
|
|
||||||
def test_decode(self):
|
def test_decode(self):
|
||||||
"""Decode sample privsigningkey from hex to int and compare to factor"""
|
"""Decode sample privsigningkey from hex to int and compare to factor"""
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
|
|
|
@ -4,9 +4,10 @@ Test if OpenSSL is working correctly
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
from pyelliptic.ecc import ECC
|
||||||
from pyelliptic.openssl import OpenSSL
|
from pyelliptic.openssl import OpenSSL
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from pybitmessage.pyelliptic import OpenSSL
|
from pybitmessage.pyelliptic import ECC, OpenSSL
|
||||||
|
|
||||||
try:
|
try:
|
||||||
OpenSSL.BN_bn2binpad
|
OpenSSL.BN_bn2binpad
|
||||||
|
@ -55,3 +56,10 @@ class TestOpenSSL(unittest.TestCase):
|
||||||
if b.raw != c.raw.rjust(OpenSSL.BN_num_bytes(n), b'\x00'):
|
if b.raw != c.raw.rjust(OpenSSL.BN_num_bytes(n), b'\x00'):
|
||||||
bad += 1
|
bad += 1
|
||||||
self.assertEqual(bad, 0)
|
self.assertEqual(bad, 0)
|
||||||
|
|
||||||
|
def test_random_keys(self):
|
||||||
|
"""A dummy test for random keys in ECC object"""
|
||||||
|
eccobj = ECC(curve='secp256k1')
|
||||||
|
self.assertEqual(len(eccobj.privkey), 32)
|
||||||
|
pubkey = eccobj.get_pubkey()
|
||||||
|
self.assertEqual(pubkey[:4], b'\x02\xca\x00\x20')
|
||||||
|
|
|
@ -23,8 +23,6 @@ from bmconfigparser import BMConfigParser
|
||||||
from debug import logger
|
from debug import logger
|
||||||
from helper_sql import sqlQuery
|
from helper_sql import sqlQuery
|
||||||
|
|
||||||
from pyelliptic import arithmetic
|
|
||||||
|
|
||||||
|
|
||||||
myECCryptorObjects = {}
|
myECCryptorObjects = {}
|
||||||
MyECSubscriptionCryptorObjects = {}
|
MyECSubscriptionCryptorObjects = {}
|
||||||
|
@ -76,35 +74,6 @@ def isAddressInMyAddressBookSubscriptionsListOrWhitelist(address):
|
||||||
return False
|
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():
|
def reloadMyAddressHashes():
|
||||||
"""Reload keys for user's addresses from the config file"""
|
"""Reload keys for user's addresses from the config file"""
|
||||||
logger.debug('reloading keys from keys.dat file')
|
logger.debug('reloading keys from keys.dat file')
|
||||||
|
@ -118,29 +87,39 @@ def reloadMyAddressHashes():
|
||||||
hasEnabledKeys = False
|
hasEnabledKeys = False
|
||||||
for addressInKeysFile in BMConfigParser().addresses():
|
for addressInKeysFile in BMConfigParser().addresses():
|
||||||
isEnabled = BMConfigParser().getboolean(addressInKeysFile, 'enabled')
|
isEnabled = BMConfigParser().getboolean(addressInKeysFile, 'enabled')
|
||||||
if isEnabled:
|
if not isEnabled:
|
||||||
|
continue
|
||||||
|
|
||||||
hasEnabledKeys = True
|
hasEnabledKeys = True
|
||||||
# status
|
|
||||||
addressVersionNumber, streamNumber, hashobj = decodeAddress(addressInKeysFile)[1:]
|
addressVersionNumber, streamNumber, hashobj = decodeAddress(
|
||||||
if addressVersionNumber in (2, 3, 4):
|
addressInKeysFile)[1:]
|
||||||
# Returns a simple 32 bytes of information encoded
|
if addressVersionNumber not in (2, 3, 4):
|
||||||
# in 64 Hex characters, or null if there was an error.
|
logger.error(
|
||||||
privEncryptionKey = hexlify(decodeWalletImportFormat(
|
'Error in reloadMyAddressHashes: Can\'t handle'
|
||||||
BMConfigParser().get(addressInKeysFile, 'privencryptionkey')))
|
' 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(
|
||||||
|
BMConfigParser().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
|
# It is 32 bytes encoded as 64 hex characters
|
||||||
if len(privEncryptionKey) == 64:
|
if len(privEncryptionKey) == 64:
|
||||||
myECCryptorObjects[hashobj] = \
|
myECCryptorObjects[hashobj] = \
|
||||||
highlevelcrypto.makeCryptor(privEncryptionKey)
|
highlevelcrypto.makeCryptor(privEncryptionKey)
|
||||||
myAddressesByHash[hashobj] = addressInKeysFile
|
myAddressesByHash[hashobj] = addressInKeysFile
|
||||||
tag = hashlib.sha512(hashlib.sha512(
|
tag = highlevelcrypto.double_sha512(
|
||||||
encodeVarint(addressVersionNumber)
|
encodeVarint(addressVersionNumber)
|
||||||
+ encodeVarint(streamNumber) + hashobj).digest()).digest()[32:]
|
+ encodeVarint(streamNumber) + hashobj)[32:]
|
||||||
myAddressesByTag[tag] = addressInKeysFile
|
myAddressesByTag[tag] = addressInKeysFile
|
||||||
else:
|
|
||||||
logger.error(
|
|
||||||
'Error in reloadMyAddressHashes: Can\'t handle'
|
|
||||||
' address versions other than 2, 3, or 4.'
|
|
||||||
)
|
|
||||||
|
|
||||||
if not keyfileSecure:
|
if not keyfileSecure:
|
||||||
fixSensitiveFilePermissions(os.path.join(
|
fixSensitiveFilePermissions(os.path.join(
|
||||||
|
@ -174,10 +153,10 @@ def reloadBroadcastSendersForWhichImWatching():
|
||||||
MyECSubscriptionCryptorObjects[hashobj] = \
|
MyECSubscriptionCryptorObjects[hashobj] = \
|
||||||
highlevelcrypto.makeCryptor(hexlify(privEncryptionKey))
|
highlevelcrypto.makeCryptor(hexlify(privEncryptionKey))
|
||||||
else:
|
else:
|
||||||
doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(
|
doubleHashOfAddressData = highlevelcrypto.double_sha512(
|
||||||
encodeVarint(addressVersionNumber)
|
encodeVarint(addressVersionNumber)
|
||||||
+ encodeVarint(streamNumber) + hashobj
|
+ encodeVarint(streamNumber) + hashobj
|
||||||
).digest()).digest()
|
)
|
||||||
tag = doubleHashOfAddressData[32:]
|
tag = doubleHashOfAddressData[32:]
|
||||||
privEncryptionKey = doubleHashOfAddressData[:32]
|
privEncryptionKey = doubleHashOfAddressData[:32]
|
||||||
MyECSubscriptionCryptorObjects[tag] = \
|
MyECSubscriptionCryptorObjects[tag] = \
|
||||||
|
|
|
@ -2,6 +2,11 @@
|
||||||
|
|
||||||
from binascii import unhexlify
|
from binascii import unhexlify
|
||||||
|
|
||||||
|
# hello, page 1 of the Specification
|
||||||
|
sample_double_sha512 = unhexlify(
|
||||||
|
'0592a10584ffabf96539f3d780d776828c67da1ab5b169e9e8aed838aaecc9ed36d49ff14'
|
||||||
|
'23c55f019e050c66c6324f53588be88894fef4dcffdb74b98e2b200')
|
||||||
|
|
||||||
|
|
||||||
magic = 0xE9BEB4D9
|
magic = 0xE9BEB4D9
|
||||||
|
|
||||||
|
@ -28,17 +33,39 @@ sample_point = (
|
||||||
94730058721143827257669456336351159718085716196507891067256111928318063085006
|
94730058721143827257669456336351159718085716196507891067256111928318063085006
|
||||||
)
|
)
|
||||||
|
|
||||||
sample_seed = 'TIGER, tiger, burning bright. In the forests of the night'
|
sample_seed = b'TIGER, tiger, burning bright. In the forests of the night'
|
||||||
# Deterministic addresses with stream 1 and versions 3, 4
|
# RIPE hash on step 22 with signing key nonce 42
|
||||||
sample_deterministic_ripe = b'00cfb69416ae76f68a81c459de4e13460c7d17eb'
|
sample_deterministic_ripe = b'00cfb69416ae76f68a81c459de4e13460c7d17eb'
|
||||||
|
# Deterministic addresses with stream 1 and versions 3, 4
|
||||||
sample_deterministic_addr3 = 'BM-2DBPTgeSawWYZceFD69AbDT5q4iUWtj1ZN'
|
sample_deterministic_addr3 = 'BM-2DBPTgeSawWYZceFD69AbDT5q4iUWtj1ZN'
|
||||||
sample_deterministic_addr4 = 'BM-2cWzSnwjJ7yRP3nLEWUV5LisTZyREWSzUK'
|
sample_deterministic_addr4 = 'BM-2cWzSnwjJ7yRP3nLEWUV5LisTZyREWSzUK'
|
||||||
sample_daddr3_512 = 18875720106589866286514488037355423395410802084648916523381
|
sample_daddr3_512 = 18875720106589866286514488037355423395410802084648916523381
|
||||||
sample_daddr4_512 = 25152821841976547050350277460563089811513157529113201589004
|
sample_daddr4_512 = 25152821841976547050350277460563089811513157529113201589004
|
||||||
|
|
||||||
sample_statusbar_msg = "new status bar message"
|
sample_statusbar_msg = 'new status bar message'
|
||||||
sample_inbox_msg_ids = ['27e644765a3e4b2e973ee7ccf958ea20', '51fc5531-3989-4d69-bbb5-68d64b756f5b',
|
sample_inbox_msg_ids = [
|
||||||
|
'27e644765a3e4b2e973ee7ccf958ea20', '51fc5531-3989-4d69-bbb5-68d64b756f5b',
|
||||||
'2c975c515f8b414db5eea60ba57ba455', 'bc1f2d8a-681c-4cc0-9a12-6067c7e1ac24']
|
'2c975c515f8b414db5eea60ba57ba455', 'bc1f2d8a-681c-4cc0-9a12-6067c7e1ac24']
|
||||||
# second address in sample_test_subscription_address is for the announcement broadcast
|
# second address in sample_subscription_addresses
|
||||||
sample_test_subscription_address = ['BM-2cWQLCBGorT9pUGkYSuGGVr9LzE4mRnQaq', 'BM-GtovgYdgs7qXPkoYaRgrLFuFKz1SFpsw']
|
# is for the announcement broadcast
|
||||||
|
sample_subscription_addresses = [
|
||||||
|
'BM-2cWQLCBGorT9pUGkYSuGGVr9LzE4mRnQaq',
|
||||||
|
'BM-GtovgYdgs7qXPkoYaRgrLFuFKz1SFpsw']
|
||||||
sample_subscription_name = 'test sub'
|
sample_subscription_name = 'test sub'
|
||||||
|
|
||||||
|
sample_msg = unhexlify(
|
||||||
|
'0592a10584ffabf96539f3d780d776828c67da1ab5b169e9e8aed838aaecc9ed36d49ff'
|
||||||
|
'1423c55f019e050c66c6324f53588be88894fef4dcffdb74b98e2b200')
|
||||||
|
sample_sig = unhexlify(
|
||||||
|
'304402202302475351db6b822de15d922e29397541f10d8a19780ba2ca4a920b1035f075'
|
||||||
|
'02205e5bba40d5f07a24c23a89ba5f01a3828371dfbb685dd5375fa1c29095fd232b')
|
||||||
|
sample_sig_sha1 = unhexlify(
|
||||||
|
'304502203b50123af78b4e40f5f819ae5b8786f48826e56d0f3e65744708a493f5b65de1'
|
||||||
|
'0221009ddce2981ea143c0ac70404a535327e774adce8eebbae2d35104f1d326255f9a')
|
||||||
|
|
||||||
|
|
||||||
|
# [chan] bitmessage
|
||||||
|
sample_wif_privsigningkey = unhexlify(
|
||||||
|
b'a2e8b841a531c1c558ee0680c396789c7a2ea3ac4795ae3f000caf9fe367d144')
|
||||||
|
sample_wif_privencryptionkey = unhexlify(
|
||||||
|
b'114ec0e2dca24a826a0eed064b0405b0ac148abc3b1d52729697f4d7b873fdc6')
|
||||||
|
|
|
@ -2,12 +2,13 @@
|
||||||
import unittest
|
import unittest
|
||||||
from binascii import unhexlify
|
from binascii import unhexlify
|
||||||
|
|
||||||
from pybitmessage import addresses
|
from pybitmessage import addresses, highlevelcrypto
|
||||||
|
|
||||||
from .samples import (
|
from .samples import (
|
||||||
sample_address, sample_daddr3_512, sample_daddr4_512,
|
sample_address, sample_daddr3_512, sample_daddr4_512,
|
||||||
sample_deterministic_addr4, sample_deterministic_addr3,
|
sample_deterministic_addr4, sample_deterministic_addr3,
|
||||||
sample_deterministic_ripe, sample_ripe)
|
sample_deterministic_ripe, sample_ripe,
|
||||||
|
sample_wif_privsigningkey, sample_wif_privencryptionkey)
|
||||||
|
|
||||||
sample_addr3 = sample_deterministic_addr3.split('-')[1]
|
sample_addr3 = sample_deterministic_addr3.split('-')[1]
|
||||||
sample_addr4 = sample_deterministic_addr4.split('-')[1]
|
sample_addr4 = sample_deterministic_addr4.split('-')[1]
|
||||||
|
@ -59,3 +60,26 @@ class TestAddresses(unittest.TestCase):
|
||||||
sample_addr4, addresses.encodeBase58(sample_daddr4_512))
|
sample_addr4, addresses.encodeBase58(sample_daddr4_512))
|
||||||
these binary data should also be a variable in samples. these binary data should also be a variable in samples.
|
|||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sample_addr3, addresses.encodeBase58(sample_daddr3_512))
|
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(
|
||||||
|
b'5K42shDERM5g7Kbi3JT5vsAWpXMqRhWZpX835M2pdSoqQQpJMYm'))
|
||||||
|
self.assertEqual(
|
||||||
|
sample_wif_privencryptionkey,
|
||||||
|
highlevelcrypto.decodeWalletImportFormat(
|
||||||
|
b'5HwugVWm31gnxtoYcvcK7oywH2ezYTh6Y4tzRxsndAeMi6NHqpA'))
|
||||||
|
self.assertEqual(
|
||||||
|
b'5K42shDERM5g7Kbi3JT5vsAWpXMqRhWZpX835M2pdSoqQQpJMYm',
|
||||||
|
highlevelcrypto.encodeWalletImportFormat(
|
||||||
|
sample_wif_privsigningkey))
|
||||||
|
self.assertEqual(
|
||||||
|
b'5HwugVWm31gnxtoYcvcK7oywH2ezYTh6Y4tzRxsndAeMi6NHqpA',
|
||||||
|
highlevelcrypto.encodeWalletImportFormat(
|
||||||
|
sample_wif_privencryptionkey))
|
||||||
|
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
highlevelcrypto.decodeWalletImportFormat(
|
||||||
|
b'5HwugVWm31gnxtoYcvcK7oywH2ezYTh6Y4tzRxsndAeMi6NHq')
|
||||||
|
|
|
@ -12,8 +12,10 @@ from six.moves import xmlrpc_client # nosec
|
||||||
import psutil
|
import psutil
|
||||||
|
|
||||||
from .samples import (
|
from .samples import (
|
||||||
sample_seed, sample_deterministic_addr3, sample_deterministic_addr4, sample_statusbar_msg,
|
sample_seed, sample_deterministic_addr3, sample_deterministic_addr4,
|
||||||
sample_inbox_msg_ids, sample_test_subscription_address, sample_subscription_name)
|
sample_statusbar_msg, sample_inbox_msg_ids, sample_subscription_addresses,
|
||||||
|
sample_subscription_name
|
||||||
|
)
|
||||||
|
|
||||||
from .test_process import TestProcessProto
|
from .test_process import TestProcessProto
|
||||||
|
|
||||||
|
@ -263,9 +265,10 @@ class TestAPI(TestAPIProto):
|
||||||
|
|
||||||
def test_subscriptions(self):
|
def test_subscriptions(self):
|
||||||
"""Testing the API commands related to subscriptions"""
|
"""Testing the API commands related to subscriptions"""
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.api.addSubscription(sample_test_subscription_address[0], sample_subscription_name.encode('base64')),
|
self.api.addSubscription(
|
||||||
|
sample_subscription_addresses[0],
|
||||||
|
sample_subscription_name.encode('base64')),
|
||||||
'Added subscription.'
|
'Added subscription.'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -273,18 +276,19 @@ class TestAPI(TestAPIProto):
|
||||||
# check_address
|
# check_address
|
||||||
for sub in json.loads(self.api.listSubscriptions())['subscriptions']:
|
for sub in json.loads(self.api.listSubscriptions())['subscriptions']:
|
||||||
# special address, added when sqlThread starts
|
# special address, added when sqlThread starts
|
||||||
if sub['address'] == sample_test_subscription_address[0]:
|
if sub['address'] == sample_subscription_addresses[0]:
|
||||||
added_subscription = sub
|
added_subscription = sub
|
||||||
break
|
break
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
base64.decodestring(added_subscription['label']) if added_subscription['label'] else None,
|
base64.decodestring(added_subscription['label'])
|
||||||
|
if added_subscription['label'] else None,
|
||||||
sample_subscription_name)
|
sample_subscription_name)
|
||||||
self.assertTrue(added_subscription['enabled'])
|
self.assertTrue(added_subscription['enabled'])
|
||||||
|
|
||||||
for s in json.loads(self.api.listSubscriptions())['subscriptions']:
|
for s in json.loads(self.api.listSubscriptions())['subscriptions']:
|
||||||
# special address, added when sqlThread starts
|
# special address, added when sqlThread starts
|
||||||
if s['address'] == sample_test_subscription_address[1]:
|
if s['address'] == sample_subscription_addresses[1]:
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
base64.decodestring(s['label']),
|
base64.decodestring(s['label']),
|
||||||
'Bitmessage new releases/announcements')
|
'Bitmessage new releases/announcements')
|
||||||
|
@ -295,10 +299,10 @@ class TestAPI(TestAPIProto):
|
||||||
'Could not find Bitmessage new releases/announcements'
|
'Could not find Bitmessage new releases/announcements'
|
||||||
' in subscriptions')
|
' in subscriptions')
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.api.deleteSubscription(sample_test_subscription_address[0]),
|
self.api.deleteSubscription(sample_subscription_addresses[0]),
|
||||||
'Deleted subscription if it existed.')
|
'Deleted subscription if it existed.')
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.api.deleteSubscription(sample_test_subscription_address[1]),
|
self.api.deleteSubscription(sample_subscription_addresses[1]),
|
||||||
'Deleted subscription if it existed.')
|
'Deleted subscription if it existed.')
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
json.loads(self.api.listSubscriptions())['subscriptions'], [])
|
json.loads(self.api.listSubscriptions())['subscriptions'], [])
|
||||||
|
|
|
@ -16,8 +16,10 @@ except ImportError:
|
||||||
RIPEMD = None
|
RIPEMD = None
|
||||||
|
|
||||||
from .samples import (
|
from .samples import (
|
||||||
sample_pubsigningkey, sample_pubencryptionkey,
|
sample_deterministic_ripe, sample_double_sha512,
|
||||||
sample_privsigningkey, sample_privencryptionkey, sample_ripe
|
sample_msg, sample_pubsigningkey, sample_pubencryptionkey,
|
||||||
|
sample_privsigningkey, sample_privencryptionkey, sample_ripe,
|
||||||
|
sample_seed, sample_sig, sample_sig_sha1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -62,6 +64,56 @@ class TestCrypto(RIPEMD160TestCase, unittest.TestCase):
|
||||||
class TestHighlevelcrypto(unittest.TestCase):
|
class TestHighlevelcrypto(unittest.TestCase):
|
||||||
"""Test highlevelcrypto public functions"""
|
"""Test highlevelcrypto public functions"""
|
||||||
|
|
||||||
|
# def test_sign(self):
|
||||||
|
# """Check the signature of the sample_msg created with sample key"""
|
||||||
|
# self.assertEqual(
|
||||||
|
# highlevelcrypto.sign(sample_msg, sample_privsigningkey), sample_sig)
|
||||||
|
|
||||||
|
def test_double_sha512(self):
|
||||||
|
"""Reproduce the example on page 1 of the Specification"""
|
||||||
|
self.assertEqual(
|
||||||
|
highlevelcrypto.double_sha512(b'hello'), sample_double_sha512)
|
||||||
|
|
||||||
|
def test_randomBytes(self):
|
||||||
|
"""Dummy checks for random bytes"""
|
||||||
|
for n in (8, 32, 64):
|
||||||
|
data = highlevelcrypto.randomBytes(n)
|
||||||
|
self.assertEqual(len(data), n)
|
||||||
|
self.assertNotEqual(len(set(data)), 1)
|
||||||
|
self.assertNotEqual(data, highlevelcrypto.randomBytes(n))
|
||||||
|
|
||||||
|
def test_random_keys(self):
|
||||||
|
"""Dummy checks for random keys"""
|
||||||
|
priv, pub = highlevelcrypto.random_keys()
|
||||||
|
self.assertEqual(len(priv), 32)
|
||||||
ideally ideally `b'hello'` should also be a variable in samples
It's from here: https://pybitmessage-test.readthedocs.io/en/doc/protocol.html#hashes
|
|||||||
|
self.assertEqual(highlevelcrypto.pointMult(priv), pub)
|
||||||
|
|
||||||
|
def test_deterministic_keys(self):
|
||||||
|
"""Generate deterministic keys, make ripe and compare it to sample"""
|
||||||
|
# encodeVarint(42) = b'*'
|
||||||
|
sigkey = highlevelcrypto.deterministic_keys(sample_seed, b'*')[1]
|
||||||
|
enkey = highlevelcrypto.deterministic_keys(sample_seed, b'+')[1]
|
||||||
|
self.assertEqual(
|
||||||
|
sample_deterministic_ripe,
|
||||||
|
hexlify(TestHashlib._hashdigest(
|
||||||
|
hashlib.sha512(sigkey + enkey).digest())))
|
||||||
|
|
||||||
|
def test_verify(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))
|
||||||
|
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, sig1, pubkey_hex))
|
||||||
|
|
||||||
def test_privtopub(self):
|
def test_privtopub(self):
|
||||||
"""Generate public keys and check the result"""
|
"""Generate public keys and check the result"""
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
"""
|
"""
|
||||||
Tests for openclpow module
|
Tests for openclpow module
|
||||||
"""
|
"""
|
||||||
import hashlib
|
|
||||||
import unittest
|
import unittest
|
||||||
from struct import pack, unpack
|
|
||||||
from pybitmessage import openclpow
|
from pybitmessage import openclpow, proofofwork
|
||||||
|
|
||||||
|
|
||||||
class TestOpenClPow(unittest.TestCase):
|
class TestOpenClPow(unittest.TestCase):
|
||||||
|
@ -25,7 +25,5 @@ class TestOpenClPow(unittest.TestCase):
|
||||||
"b93f3ffeba0ef2fd08a8dc2f87b68ae5a0dc819ab57f22ad2c4c9c8618a43b3"
|
"b93f3ffeba0ef2fd08a8dc2f87b68ae5a0dc819ab57f22ad2c4c9c8618a43b3"
|
||||||
).decode("hex")
|
).decode("hex")
|
||||||
nonce = openclpow.do_opencl_pow(initialHash.encode("hex"), target_)
|
nonce = openclpow.do_opencl_pow(initialHash.encode("hex"), target_)
|
||||||
trialValue, = unpack(
|
self.assertLess(
|
||||||
'>Q', hashlib.sha512(hashlib.sha512(
|
nonce - proofofwork.trial_value(nonce, initialHash), target_)
|
||||||
pack('>Q', nonce) + initialHash).digest()).digest()[0:8])
|
|
||||||
self.assertLess((nonce - trialValue), target_)
|
|
||||||
|
|
Reference in New Issue
Block a user
I'm not sure if these functions should return the pair or only the private key.