From 3adadd398f6307901e388cad9602984c57fc29cc Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Wed, 30 Jan 2019 11:14:42 +0200 Subject: [PATCH] Removed from shared the functions duplicating protocol: decryptAndCheckPubkeyPayload, isBitSetWithinBitfield --- src/class_objectProcessor.py | 2 +- src/class_singleWorker.py | 4 +- src/protocol.py | 108 ++++++++++++++----------- src/shared.py | 151 +---------------------------------- 4 files changed, 67 insertions(+), 198 deletions(-) diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index d2bc9574..edfcec05 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -400,7 +400,7 @@ class objectProcessor(threading.Thread): # Let us try to decrypt the pubkey toAddress, _ = state.neededPubkeys[tag] - if shared.decryptAndCheckPubkeyPayload(data, toAddress) == \ + if protocol.decryptAndCheckPubkeyPayload(data, toAddress) == \ 'successful': # At this point we know that we have been waiting on this # pubkey. This function will command the workerThread diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 575a909e..4e3be929 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -758,7 +758,7 @@ class singleWorker(threading.Thread, StoppableThread): for value in Inventory().by_type_and_tag(1, toTag): # if valid, this function also puts it # in the pubkeys table. - if shared.decryptAndCheckPubkeyPayload( + if protocol.decryptAndCheckPubkeyPayload( value.payload, toaddress ) == 'successful': needToRequestPubkey = False @@ -860,7 +860,7 @@ class singleWorker(threading.Thread, StoppableThread): # if receiver is a mobile device who expects that their # address RIPE is included unencrypted on the front of # the message.. - if shared.isBitSetWithinBitfield(behaviorBitfield, 30): + if protocol.isBitSetWithinBitfield(behaviorBitfield, 30): # if we are Not willing to include the receiver's # RIPE hash on the message.. if not shared.BMConfigParser().safeGetBoolean( diff --git a/src/protocol.py b/src/protocol.py index 6a62b522..a138e7ee 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -9,21 +9,21 @@ Low-level protocol-related functions. from __future__ import absolute_import import base64 -from binascii import hexlify import hashlib -import os import random import socket import ssl -from struct import pack, unpack, Struct import sys import time import traceback +from binascii import hexlify +from struct import pack, unpack, Struct import defaults import highlevelcrypto import state -from addresses import encodeVarint, decodeVarint, decodeAddress, varintDecodeError +from addresses import ( + encodeVarint, decodeVarint, decodeAddress, varintDecodeError) from bmconfigparser import BMConfigParser from debug import logger from helper_sql import sqlExecute @@ -321,33 +321,41 @@ def assembleErrorMessage(fatal=0, banTime=0, inventoryVector='', errorText=''): def decryptAndCheckPubkeyPayload(data, address): """ - Version 4 pubkeys are encrypted. This function is run when we already have the - address to which we want to try to send a message. The 'data' may come either - off of the wire or we might have had it already in our inventory when we tried - to send a msg to this particular address. + Version 4 pubkeys are encrypted. This function is run when we + already have the address to which we want to try to send a message. + The 'data' may come either off of the wire or we might have had it + already in our inventory when we tried to send a msg to this + particular address. """ - # pylint: disable=unused-variable try: - status, addressVersion, streamNumber, ripe = decodeAddress(address) + addressVersion, streamNumber, ripe = decodeAddress(address)[1:] readPosition = 20 # bypass the nonce, time, and object type - embeddedAddressVersion, varintLength = decodeVarint(data[readPosition:readPosition + 10]) + embeddedAddressVersion, varintLength = decodeVarint( + data[readPosition:readPosition + 10]) readPosition += varintLength - embeddedStreamNumber, varintLength = decodeVarint(data[readPosition:readPosition + 10]) + embeddedStreamNumber, varintLength = decodeVarint( + data[readPosition:readPosition + 10]) readPosition += varintLength - # We'll store the address version and stream number (and some more) in the pubkeys table. + # We'll store the address version and stream number + # (and some more) in the pubkeys table. storedData = data[20:readPosition] if addressVersion != embeddedAddressVersion: - logger.info('Pubkey decryption was UNsuccessful due to address version mismatch.') + logger.info( + 'Pubkey decryption was UNsuccessful' + ' due to address version mismatch.') return 'failed' if streamNumber != embeddedStreamNumber: - logger.info('Pubkey decryption was UNsuccessful due to stream number mismatch.') + logger.info( + 'Pubkey decryption was UNsuccessful' + ' due to stream number mismatch.') return 'failed' tag = data[readPosition:readPosition + 32] readPosition += 32 - # the time through the tag. More data is appended onto signedData below after the decryption. + # the time through the tag. More data is appended onto + # signedData below after the decryption. signedData = data[8:readPosition] encryptedData = data[readPosition:] @@ -355,13 +363,15 @@ def decryptAndCheckPubkeyPayload(data, address): toAddress, cryptorObject = state.neededPubkeys[tag] if toAddress != address: logger.critical( - 'decryptAndCheckPubkeyPayload failed due to toAddress mismatch.' - ' This is very peculiar. toAddress: %s, address %s', - toAddress, - address) - # the only way I can think that this could happen is if someone encodes their address data two different - # ways. That sort of address-malleability should have been caught by the UI or API and an error given to - # the user. + 'decryptAndCheckPubkeyPayload failed due to toAddress' + ' mismatch. This is very peculiar.' + ' toAddress: %s, address %s', + toAddress, address + ) + # the only way I can think that this could happen + # is if someone encodes their address data two different ways. + # That sort of address-malleability should have been caught + # by the UI or API and an error given to the user. return 'failed' try: decryptedData = cryptorObject.decrypt(encryptedData) @@ -372,17 +382,17 @@ def decryptAndCheckPubkeyPayload(data, address): return 'failed' readPosition = 0 - bitfieldBehaviors = decryptedData[readPosition:readPosition + 4] + # bitfieldBehaviors = decryptedData[readPosition:readPosition + 4] readPosition += 4 publicSigningKey = '\x04' + decryptedData[readPosition:readPosition + 64] readPosition += 64 publicEncryptionKey = '\x04' + decryptedData[readPosition:readPosition + 64] readPosition += 64 - specifiedNonceTrialsPerByte, specifiedNonceTrialsPerByteLength = decodeVarint( - decryptedData[readPosition:readPosition + 10]) + specifiedNonceTrialsPerByteLength = decodeVarint( + decryptedData[readPosition:readPosition + 10])[1] readPosition += specifiedNonceTrialsPerByteLength - specifiedPayloadLengthExtraBytes, specifiedPayloadLengthExtraBytesLength = decodeVarint( - decryptedData[readPosition:readPosition + 10]) + specifiedPayloadLengthExtraBytesLength = decodeVarint( + decryptedData[readPosition:readPosition + 10])[1] readPosition += specifiedPayloadLengthExtraBytesLength storedData += decryptedData[:readPosition] signedData += decryptedData[:readPosition] @@ -391,12 +401,15 @@ def decryptAndCheckPubkeyPayload(data, address): readPosition += signatureLengthLength signature = decryptedData[readPosition:readPosition + signatureLength] - if highlevelcrypto.verify(signedData, signature, hexlify(publicSigningKey)): - logger.info('ECDSA verify passed (within decryptAndCheckPubkeyPayload)') - else: - logger.info('ECDSA verify failed (within decryptAndCheckPubkeyPayload)') + if not highlevelcrypto.verify( + signedData, signature, hexlify(publicSigningKey)): + logger.info( + 'ECDSA verify failed (within decryptAndCheckPubkeyPayload)') return 'failed' + logger.info( + 'ECDSA verify passed (within decryptAndCheckPubkeyPayload)') + sha = hashlib.new('sha512') sha.update(publicSigningKey + publicEncryptionKey) ripeHasher = hashlib.new('ripemd160') @@ -404,34 +417,37 @@ def decryptAndCheckPubkeyPayload(data, address): embeddedRipe = ripeHasher.digest() if embeddedRipe != ripe: - # Although this pubkey object had the tag were were looking for and was - # encrypted with the correct encryption key, it doesn't contain the - # correct pubkeys. Someone is either being malicious or using buggy software. - logger.info('Pubkey decryption was UNsuccessful due to RIPE mismatch.') + # Although this pubkey object had the tag were were looking for + # and was encrypted with the correct encryption key, + # it doesn't contain the correct pubkeys. Someone is + # either being malicious or using buggy software. + logger.info( + 'Pubkey decryption was UNsuccessful due to RIPE mismatch.') return 'failed' # Everything checked out. Insert it into the pubkeys table. logger.info( - os.linesep.join([ - 'within decryptAndCheckPubkeyPayload,' - ' addressVersion: %s, streamNumber: %s' % addressVersion, streamNumber, - 'ripe %s' % hexlify(ripe), - 'publicSigningKey in hex: %s' % hexlify(publicSigningKey), - 'publicEncryptionKey in hex: %s' % hexlify(publicEncryptionKey), - ]) + 'within decryptAndCheckPubkeyPayload, ' + 'addressVersion: %s, streamNumber: %s\nripe %s\n' + 'publicSigningKey in hex: %s\npublicEncryptionKey in hex: %s', + addressVersion, streamNumber, hexlify(ripe), + hexlify(publicSigningKey), hexlify(publicEncryptionKey) ) t = (address, addressVersion, storedData, int(time.time()), 'yes') sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', *t) return 'successful' except varintDecodeError: - logger.info('Pubkey decryption was UNsuccessful due to a malformed varint.') + logger.info( + 'Pubkey decryption was UNsuccessful due to a malformed varint.') return 'failed' except Exception: logger.critical( - 'Pubkey decryption was UNsuccessful because of an unhandled exception! This is definitely a bug! \n%s', - traceback.format_exc()) + 'Pubkey decryption was UNsuccessful because of' + ' an unhandled exception! This is definitely a bug! \n%s', + traceback.format_exc() + ) return 'failed' diff --git a/src/shared.py b/src/shared.py index 6a2980d9..9a1c08d1 100644 --- a/src/shared.py +++ b/src/shared.py @@ -6,10 +6,8 @@ import sys import stat import time import threading -import traceback import hashlib import subprocess -from struct import unpack from binascii import hexlify from pyelliptic import arithmetic @@ -18,10 +16,8 @@ import state import highlevelcrypto from bmconfigparser import BMConfigParser from debug import logger -from addresses import ( - decodeAddress, encodeVarint, decodeVarint, varintDecodeError -) -from helper_sql import sqlQuery, sqlExecute +from addresses import decodeAddress, encodeVarint +from helper_sql import sqlQuery verbose = 1 @@ -281,149 +277,6 @@ def fixSensitiveFilePermissions(filename, hasEnabledKeys): raise -def isBitSetWithinBitfield(fourByteString, n): - # Uses MSB 0 bit numbering across 4 bytes of data - n = 31 - n - x, = unpack('>L', fourByteString) - return x & 2**n != 0 - - -def decryptAndCheckPubkeyPayload(data, address): - """ - Version 4 pubkeys are encrypted. This function is run when we - already have the address to which we want to try to send a message. - The 'data' may come either off of the wire or we might have had it - already in our inventory when we tried to send a msg to this - particular address. - """ - try: - # status - _, addressVersion, streamNumber, ripe = decodeAddress(address) - - readPosition = 20 # bypass the nonce, time, and object type - embeddedAddressVersion, varintLength = \ - decodeVarint(data[readPosition:readPosition + 10]) - readPosition += varintLength - embeddedStreamNumber, varintLength = \ - decodeVarint(data[readPosition:readPosition + 10]) - readPosition += varintLength - # We'll store the address version and stream number - # (and some more) in the pubkeys table. - storedData = data[20:readPosition] - - if addressVersion != embeddedAddressVersion: - logger.info( - 'Pubkey decryption was UNsuccessful' - ' due to address version mismatch.') - return 'failed' - if streamNumber != embeddedStreamNumber: - logger.info( - 'Pubkey decryption was UNsuccessful' - ' due to stream number mismatch.') - return 'failed' - - tag = data[readPosition:readPosition + 32] - readPosition += 32 - # the time through the tag. More data is appended onto - # signedData below after the decryption. - signedData = data[8:readPosition] - encryptedData = data[readPosition:] - - # Let us try to decrypt the pubkey - toAddress, cryptorObject = state.neededPubkeys[tag] - if toAddress != address: - logger.critical( - 'decryptAndCheckPubkeyPayload failed due to toAddress' - ' mismatch. This is very peculiar.' - ' toAddress: %s, address %s', - toAddress, address - ) - # the only way I can think that this could happen - # is if someone encodes their address data two different ways. - # That sort of address-malleability should have been caught - # by the UI or API and an error given to the user. - return 'failed' - try: - decryptedData = cryptorObject.decrypt(encryptedData) - except: - # Someone must have encrypted some data with a different key - # but tagged it with a tag for which we are watching. - logger.info('Pubkey decryption was unsuccessful.') - return 'failed' - - readPosition = 0 - # bitfieldBehaviors = decryptedData[readPosition:readPosition + 4] - readPosition += 4 - publicSigningKey = \ - '\x04' + decryptedData[readPosition:readPosition + 64] - readPosition += 64 - publicEncryptionKey = \ - '\x04' + decryptedData[readPosition:readPosition + 64] - readPosition += 64 - specifiedNonceTrialsPerByte, specifiedNonceTrialsPerByteLength = \ - decodeVarint(decryptedData[readPosition:readPosition + 10]) - readPosition += specifiedNonceTrialsPerByteLength - specifiedPayloadLengthExtraBytes, \ - specifiedPayloadLengthExtraBytesLength = \ - decodeVarint(decryptedData[readPosition:readPosition + 10]) - readPosition += specifiedPayloadLengthExtraBytesLength - storedData += decryptedData[:readPosition] - signedData += decryptedData[:readPosition] - signatureLength, signatureLengthLength = \ - decodeVarint(decryptedData[readPosition:readPosition + 10]) - readPosition += signatureLengthLength - signature = decryptedData[readPosition:readPosition + signatureLength] - - if not highlevelcrypto.verify( - signedData, signature, hexlify(publicSigningKey)): - logger.info( - 'ECDSA verify failed (within decryptAndCheckPubkeyPayload)') - return 'failed' - - logger.info( - 'ECDSA verify passed (within decryptAndCheckPubkeyPayload)') - - sha = hashlib.new('sha512') - sha.update(publicSigningKey + publicEncryptionKey) - ripeHasher = hashlib.new('ripemd160') - ripeHasher.update(sha.digest()) - embeddedRipe = ripeHasher.digest() - - if embeddedRipe != ripe: - # Although this pubkey object had the tag were were looking for - # and was encrypted with the correct encryption key, - # it doesn't contain the correct pubkeys. Someone is - # either being malicious or using buggy software. - logger.info( - 'Pubkey decryption was UNsuccessful due to RIPE mismatch.') - return 'failed' - - # Everything checked out. Insert it into the pubkeys table. - - logger.info( - 'within decryptAndCheckPubkeyPayload, ' - 'addressVersion: %s, streamNumber: %s\nripe %s\n' - 'publicSigningKey in hex: %s\npublicEncryptionKey in hex: %s', - addressVersion, streamNumber, hexlify(ripe), - hexlify(publicSigningKey), hexlify(publicEncryptionKey) - ) - - t = (address, addressVersion, storedData, int(time.time()), 'yes') - sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', *t) - return 'successful' - except varintDecodeError: - logger.info( - 'Pubkey decryption was UNsuccessful due to a malformed varint.') - return 'failed' - except Exception: - logger.critical( - 'Pubkey decryption was UNsuccessful because of' - ' an unhandled exception! This is definitely a bug! \n%s' % - traceback.format_exc() - ) - return 'failed' - - def openKeysFile(): if 'linux' in sys.platform: subprocess.call(["xdg-open", state.appdata + 'keys.dat'])