Removed from shared the functions duplicating protocol:
decryptAndCheckPubkeyPayload, isBitSetWithinBitfield
This commit is contained in:
parent
5b5ec2b63d
commit
3adadd398f
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
108
src/protocol.py
108
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'
|
||||
|
||||
|
||||
|
|
151
src/shared.py
151
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'])
|
||||
|
|
Reference in New Issue
Block a user