Removed obsolete Protocol v2 code
This commit is contained in:
parent
b02a5d3109
commit
e898b40203
|
@ -184,13 +184,15 @@ class objectProcessor(threading.Thread):
|
||||||
readPosition += 4
|
readPosition += 4
|
||||||
publicSigningKey = data[readPosition:readPosition + 64]
|
publicSigningKey = data[readPosition:readPosition + 64]
|
||||||
# Is it possible for a public key to be invalid such that trying to
|
# Is it possible for a public key to be invalid such that trying to
|
||||||
# encrypt or sign with it will cause an error? If it is, we should
|
# encrypt or sign with it will cause an error? If it is, it would
|
||||||
# probably test these keys here.
|
# be easiest to test them here.
|
||||||
readPosition += 64
|
readPosition += 64
|
||||||
publicEncryptionKey = data[readPosition:readPosition + 64]
|
publicEncryptionKey = data[readPosition:readPosition + 64]
|
||||||
if len(publicEncryptionKey) < 64:
|
if len(publicEncryptionKey) < 64:
|
||||||
logger.debug('publicEncryptionKey length less than 64. Sanity check failed.')
|
logger.debug('publicEncryptionKey length less than 64. Sanity check failed.')
|
||||||
return
|
return
|
||||||
|
readPosition += 64
|
||||||
|
dataToStore = data[20:readPosition] # The data we'll store in the pubkeys table.
|
||||||
sha = hashlib.new('sha512')
|
sha = hashlib.new('sha512')
|
||||||
sha.update(
|
sha.update(
|
||||||
'\x04' + publicSigningKey + '\x04' + publicEncryptionKey)
|
'\x04' + publicSigningKey + '\x04' + publicEncryptionKey)
|
||||||
|
@ -213,17 +215,6 @@ class objectProcessor(threading.Thread):
|
||||||
queryreturn = sqlQuery(
|
queryreturn = sqlQuery(
|
||||||
'''SELECT usedpersonally FROM pubkeys WHERE hash=? AND addressversion=? AND usedpersonally='yes' ''', ripe, addressVersion)
|
'''SELECT usedpersonally FROM pubkeys WHERE hash=? AND addressversion=? AND usedpersonally='yes' ''', ripe, addressVersion)
|
||||||
|
|
||||||
"""
|
|
||||||
With the changes in protocol v3, we have to be careful to store pubkey data
|
|
||||||
in the database the same way we did before to maintain backwards compatibility
|
|
||||||
with what is in people's databases already. This means that for v2 keys, we
|
|
||||||
must store the nonce, the time, and then everything else starting with the
|
|
||||||
address version.
|
|
||||||
"""
|
|
||||||
dataToStore = '\x00' * 8 # fake nonce
|
|
||||||
dataToStore += data[8:16] # the time
|
|
||||||
dataToStore += data[20:] # everything else
|
|
||||||
|
|
||||||
if queryreturn != []: # if this pubkey is already in our database and if we have used it personally:
|
if queryreturn != []: # if this pubkey is already in our database and if we have used it personally:
|
||||||
logger.info('We HAVE used this pubkey personally. Updating time.')
|
logger.info('We HAVE used this pubkey personally. Updating time.')
|
||||||
t = (ripe, addressVersion, dataToStore, int(time.time()), 'yes')
|
t = (ripe, addressVersion, dataToStore, int(time.time()), 'yes')
|
||||||
|
@ -249,36 +240,16 @@ class objectProcessor(threading.Thread):
|
||||||
data[readPosition:readPosition + 10])
|
data[readPosition:readPosition + 10])
|
||||||
readPosition += specifiedPayloadLengthExtraBytesLength
|
readPosition += specifiedPayloadLengthExtraBytesLength
|
||||||
endOfSignedDataPosition = readPosition
|
endOfSignedDataPosition = readPosition
|
||||||
|
dataToStore = data[20:readPosition] # The data we'll store in the pubkeys table.
|
||||||
signatureLength, signatureLengthLength = decodeVarint(
|
signatureLength, signatureLengthLength = decodeVarint(
|
||||||
data[readPosition:readPosition + 10])
|
data[readPosition:readPosition + 10])
|
||||||
readPosition += signatureLengthLength
|
readPosition += signatureLengthLength
|
||||||
signature = data[readPosition:readPosition + signatureLength]
|
signature = data[readPosition:readPosition + signatureLength]
|
||||||
"""
|
if highlevelcrypto.verify(data[8:endOfSignedDataPosition], signature, publicSigningKey.encode('hex')):
|
||||||
With the changes in protocol v3, to maintain backwards compatibility, signatures will be sent
|
logger.debug('ECDSA verify passed (within processpubkey)')
|
||||||
the 'old' way during an upgrade period and then a 'new' simpler way after that. We will therefore
|
|
||||||
check the sig both ways.
|
|
||||||
Old way:
|
|
||||||
signedData = timePubkeyWasSigned(4 bytes) + addressVersion through extra_bytes
|
|
||||||
New way:
|
|
||||||
signedData = all of the payload data, from the time down through the extra_bytes
|
|
||||||
|
|
||||||
The timePubkeyWasSigned will be calculated by subtracting 28 days form the embedded expiresTime.
|
|
||||||
"""
|
|
||||||
expiresTime, = unpack('>Q', data[8:16])
|
|
||||||
TTL = 28 * 24 * 60 * 60
|
|
||||||
signedData = pack('>I', (expiresTime - TTL)) # the time that the pubkey was signed. 4 bytes.
|
|
||||||
signedData += data[20:endOfSignedDataPosition] # the address version down through the payloadLengthExtraBytes
|
|
||||||
|
|
||||||
if highlevelcrypto.verify(signedData, signature, publicSigningKey.encode('hex')):
|
|
||||||
logger.info('ECDSA verify passed (within processpubkey, old method)')
|
|
||||||
else:
|
else:
|
||||||
logger.warning('ECDSA verify failed (within processpubkey, old method)')
|
logger.warning('ECDSA verify failed (within processpubkey)')
|
||||||
# let us try the newer signature method
|
return
|
||||||
if highlevelcrypto.verify(data[8:endOfSignedDataPosition], signature, publicSigningKey.encode('hex')):
|
|
||||||
logger.info('ECDSA verify passed (within processpubkey, new method)')
|
|
||||||
else:
|
|
||||||
logger.warning('ECDSA verify failed (within processpubkey, new method)')
|
|
||||||
return
|
|
||||||
|
|
||||||
sha = hashlib.new('sha512')
|
sha = hashlib.new('sha512')
|
||||||
sha.update(publicSigningKey + publicEncryptionKey)
|
sha.update(publicSigningKey + publicEncryptionKey)
|
||||||
|
@ -299,17 +270,6 @@ class objectProcessor(threading.Thread):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
With the changes in protocol v3, we have to be careful to store pubkey data
|
|
||||||
in the database the same way we did before to maintain backwards compatibility
|
|
||||||
with what is in people's databases already. This means that for v3 keys, we
|
|
||||||
must store the nonce, the time, and then everything else starting with the
|
|
||||||
address version.
|
|
||||||
"""
|
|
||||||
dataToStore = '\x00' * 8 # fake nonce
|
|
||||||
dataToStore += data[8:16] # the time
|
|
||||||
dataToStore += data[20:] # everything else
|
|
||||||
|
|
||||||
queryreturn = sqlQuery('''SELECT usedpersonally FROM pubkeys WHERE hash=? AND addressversion=? AND usedpersonally='yes' ''', ripe, addressVersion)
|
queryreturn = sqlQuery('''SELECT usedpersonally FROM pubkeys WHERE hash=? AND addressversion=? AND usedpersonally='yes' ''', ripe, addressVersion)
|
||||||
if queryreturn != []: # if this pubkey is already in our database and if we have used it personally:
|
if queryreturn != []: # if this pubkey is already in our database and if we have used it personally:
|
||||||
logger.info('We HAVE used this pubkey personally. Updating time.')
|
logger.info('We HAVE used this pubkey personally. Updating time.')
|
||||||
|
@ -350,14 +310,11 @@ class objectProcessor(threading.Thread):
|
||||||
shared.UISignalQueue.put((
|
shared.UISignalQueue.put((
|
||||||
'updateNumberOfMessagesProcessed', 'no data'))
|
'updateNumberOfMessagesProcessed', 'no data'))
|
||||||
readPosition = 20 # bypass the nonce, time, and object type
|
readPosition = 20 # bypass the nonce, time, and object type
|
||||||
|
msgVersion, msgVersionLength = decodeVarint(data[readPosition:readPosition + 9])
|
||||||
"""
|
if msgVersion != 1:
|
||||||
In protocol v2, the next byte(s) was the streamNumber. But starting after
|
logger.info('Cannot understand message versions other than one. Ignoring message.')
|
||||||
the protocol v3 upgrade period, the next byte(s) will be a msg version
|
return
|
||||||
number followed by the streamNumber.
|
readPosition += msgVersionLength
|
||||||
"""
|
|
||||||
#msgVersionOutsideEncryption, msgVersionOutsideEncryptionLength = decodeVarint(data[readPosition:readPosition + 9])
|
|
||||||
#readPosition += msgVersionOutsideEncryptionLength
|
|
||||||
|
|
||||||
streamNumberAsClaimedByMsg, streamNumberAsClaimedByMsgLength = decodeVarint(
|
streamNumberAsClaimedByMsg, streamNumberAsClaimedByMsgLength = decodeVarint(
|
||||||
data[readPosition:readPosition + 9])
|
data[readPosition:readPosition + 9])
|
||||||
|
@ -379,34 +336,16 @@ class objectProcessor(threading.Thread):
|
||||||
# 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
|
||||||
# bound for me by trying to decrypt it with my private keys.
|
# bound for me by trying to decrypt it with my private keys.
|
||||||
|
|
||||||
# This can be simplified quite a bit after 1416175200: # Sun, 16 Nov 2014 22:00:00 GMT
|
|
||||||
for key, cryptorObject in shared.myECCryptorObjects.items():
|
for key, cryptorObject in shared.myECCryptorObjects.items():
|
||||||
try:
|
try:
|
||||||
decryptedData = cryptorObject.decrypt(data[readPosition:])
|
decryptedData = cryptorObject.decrypt(data[readPosition:])
|
||||||
toRipe = key # This is the RIPE hash of my pubkeys. We need this below to compare to the destination_ripe included in the encrypted data.
|
toRipe = key # This is the RIPE hash of my pubkeys. We need this below to compare to the destination_ripe included in the encrypted data.
|
||||||
initialDecryptionSuccessful = True
|
initialDecryptionSuccessful = True
|
||||||
logger.info('EC decryption successful using key associated with ripe hash: %s. msg did NOT specify version.' % key.encode('hex'))
|
logger.info('EC decryption successful using key associated with ripe hash: %s.' % key.encode('hex'))
|
||||||
|
#msgObjectContainedVersion = False
|
||||||
# We didn't bypass a msg version above as it is commented out.
|
|
||||||
# But the decryption was successful. Which means that there
|
|
||||||
# wasn't a msg version byte include in this msg.
|
|
||||||
msgObjectContainedVersion = False
|
|
||||||
break
|
break
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
# What if a client sent us a msg with
|
pass
|
||||||
# a msg version included? We didn't bypass it above. So
|
|
||||||
# let's try to decrypt the msg assuming that it is present.
|
|
||||||
try:
|
|
||||||
decryptedData = cryptorObject.decrypt(data[readPosition+1:]) # notice that we offset by 1 byte compared to the attempt above.
|
|
||||||
toRipe = key # This is the RIPE hash of my pubkeys. We need this below to compare to the destination_ripe included in the encrypted data.
|
|
||||||
initialDecryptionSuccessful = True
|
|
||||||
logger.info('EC decryption successful using key associated with ripe hash: %s. msg DID specifiy version.' % key.encode('hex'))
|
|
||||||
|
|
||||||
# There IS a msg version byte include in this msg.
|
|
||||||
msgObjectContainedVersion = True
|
|
||||||
break
|
|
||||||
except Exception as err:
|
|
||||||
pass
|
|
||||||
if not initialDecryptionSuccessful:
|
if not initialDecryptionSuccessful:
|
||||||
# This is not a message bound for me.
|
# This is not a message bound for me.
|
||||||
logger.info('Length of time program spent failing to decrypt this message: %s seconds.' % (time.time() - messageProcessingStartTime,))
|
logger.info('Length of time program spent failing to decrypt this message: %s seconds.' % (time.time() - messageProcessingStartTime,))
|
||||||
|
@ -416,15 +355,6 @@ class objectProcessor(threading.Thread):
|
||||||
toAddress = shared.myAddressesByHash[
|
toAddress = shared.myAddressesByHash[
|
||||||
toRipe] # Look up my address based on the RIPE hash.
|
toRipe] # Look up my address based on the RIPE hash.
|
||||||
readPosition = 0
|
readPosition = 0
|
||||||
if not msgObjectContainedVersion: # by which I mean "if the msg object didn't have the msg version outside of the encryption". This confusingness will be removed after the protocol v3 upgrade period.
|
|
||||||
messageVersionWithinEncryption, messageVersionWithinEncryptionLength = decodeVarint(
|
|
||||||
decryptedData[readPosition:readPosition + 10])
|
|
||||||
readPosition += messageVersionWithinEncryptionLength
|
|
||||||
if messageVersionWithinEncryption != 1:
|
|
||||||
logger.info('Cannot understand message versions other than one. Ignoring message.')
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
messageVersionWithinEncryptionLength = 0 # This variable can disappear after the protocol v3 upgrade period is complete.
|
|
||||||
sendersAddressVersionNumber, sendersAddressVersionNumberLength = decodeVarint(
|
sendersAddressVersionNumber, sendersAddressVersionNumberLength = decodeVarint(
|
||||||
decryptedData[readPosition:readPosition + 10])
|
decryptedData[readPosition:readPosition + 10])
|
||||||
readPosition += sendersAddressVersionNumberLength
|
readPosition += sendersAddressVersionNumberLength
|
||||||
|
@ -489,12 +419,7 @@ class objectProcessor(threading.Thread):
|
||||||
readPosition += signatureLengthLength
|
readPosition += signatureLengthLength
|
||||||
signature = decryptedData[
|
signature = decryptedData[
|
||||||
readPosition:readPosition + signatureLength]
|
readPosition:readPosition + signatureLength]
|
||||||
if not msgObjectContainedVersion:
|
signedData = data[8:20] + encodeVarint(1) + encodeVarint(streamNumberAsClaimedByMsg) + decryptedData[:positionOfBottomOfAckData]
|
||||||
# protocol v2. This can be removed after the end of the protocol v3 upgrade period.
|
|
||||||
signedData = decryptedData[:positionOfBottomOfAckData]
|
|
||||||
else:
|
|
||||||
# protocol v3
|
|
||||||
signedData = data[8:20] + encodeVarint(1) + encodeVarint(streamNumberAsClaimedByMsg) + decryptedData[:positionOfBottomOfAckData]
|
|
||||||
|
|
||||||
if not highlevelcrypto.verify(signedData, signature, pubSigningKey.encode('hex')):
|
if not highlevelcrypto.verify(signedData, signature, pubSigningKey.encode('hex')):
|
||||||
logger.debug('ECDSA verify failed')
|
logger.debug('ECDSA verify failed')
|
||||||
|
@ -511,32 +436,25 @@ class objectProcessor(threading.Thread):
|
||||||
ripe.update(sha.digest())
|
ripe.update(sha.digest())
|
||||||
fromAddress = encodeAddress(
|
fromAddress = encodeAddress(
|
||||||
sendersAddressVersionNumber, sendersStreamNumber, ripe.digest())
|
sendersAddressVersionNumber, sendersStreamNumber, ripe.digest())
|
||||||
|
|
||||||
# Let's store the public key in case we want to reply to this
|
# Let's store the public key in case we want to reply to this
|
||||||
# person.
|
# person.
|
||||||
|
sqlExecute(
|
||||||
|
'''INSERT INTO pubkeys VALUES (?,?,?,?,?)''',
|
||||||
|
ripe.digest(),
|
||||||
|
sendersAddressVersionNumber,
|
||||||
|
decryptedData[:endOfThePublicKeyPosition],
|
||||||
|
int(time.time()),
|
||||||
|
'yes')
|
||||||
|
|
||||||
|
# Check to see whether we happen to be awaiting this
|
||||||
|
# pubkey in order to send a message. If we are, it will do the POW
|
||||||
|
# and send it.
|
||||||
if sendersAddressVersionNumber <= 3:
|
if sendersAddressVersionNumber <= 3:
|
||||||
sqlExecute(
|
|
||||||
'''INSERT INTO pubkeys VALUES (?,?,?,?,?)''',
|
|
||||||
ripe.digest(),
|
|
||||||
sendersAddressVersionNumber,
|
|
||||||
'\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF' + '\xFF\xFF\xFF\xFF' + decryptedData[messageVersionWithinEncryptionLength:endOfThePublicKeyPosition],
|
|
||||||
int(time.time()),
|
|
||||||
'yes')
|
|
||||||
# This will check to see whether we happen to be awaiting this
|
|
||||||
# pubkey in order to send a message. If we are, it will do the POW
|
|
||||||
# and send it.
|
|
||||||
self.possibleNewPubkey(ripe=ripe.digest())
|
self.possibleNewPubkey(ripe=ripe.digest())
|
||||||
elif sendersAddressVersionNumber >= 4:
|
elif sendersAddressVersionNumber >= 4:
|
||||||
sqlExecute(
|
|
||||||
'''INSERT INTO pubkeys VALUES (?,?,?,?,?)''',
|
|
||||||
ripe.digest(),
|
|
||||||
sendersAddressVersionNumber,
|
|
||||||
'\x00\x00\x00\x00\x00\x00\x00\x01' + decryptedData[messageVersionWithinEncryptionLength:endOfThePublicKeyPosition],
|
|
||||||
int(time.time()),
|
|
||||||
'yes')
|
|
||||||
# This will check to see whether we happen to be awaiting this
|
|
||||||
# pubkey in order to send a message. If we are, it will do the POW
|
|
||||||
# and send it.
|
|
||||||
self.possibleNewPubkey(address = fromAddress)
|
self.possibleNewPubkey(address = fromAddress)
|
||||||
|
|
||||||
# If this message is bound for one of my version 3 addresses (or
|
# If this message is bound for one of my version 3 addresses (or
|
||||||
# higher), then we must check to make sure it meets our demanded
|
# higher), then we must check to make sure it meets our demanded
|
||||||
# proof of work requirement. If this is bound for one of my chan
|
# proof of work requirement. If this is bound for one of my chan
|
||||||
|
@ -665,22 +583,19 @@ class objectProcessor(threading.Thread):
|
||||||
broadcastVersion, broadcastVersionLength = decodeVarint(
|
broadcastVersion, broadcastVersionLength = decodeVarint(
|
||||||
data[readPosition:readPosition + 9])
|
data[readPosition:readPosition + 9])
|
||||||
readPosition += broadcastVersionLength
|
readPosition += broadcastVersionLength
|
||||||
if broadcastVersion < 1 or broadcastVersion > 5:
|
if broadcastVersion < 4 or broadcastVersion > 5:
|
||||||
logger.info('Cannot decode incoming broadcast versions higher than 5. Assuming the sender isn\'t being silly, you should upgrade Bitmessage because this message shall be ignored.')
|
logger.info('Cannot decode incoming broadcast versions less than 4 or higher than 5. Assuming the sender isn\'t being silly, you should upgrade Bitmessage because this message shall be ignored.')
|
||||||
return
|
return
|
||||||
if broadcastVersion == 1:
|
cleartextStreamNumber, cleartextStreamNumberLength = decodeVarint(
|
||||||
logger.info('Version 1 broadcasts are no longer supported. Not processing it at all.')
|
data[readPosition:readPosition + 10])
|
||||||
if broadcastVersion in [2,4]:
|
readPosition += cleartextStreamNumberLength
|
||||||
|
if broadcastVersion == 4:
|
||||||
"""
|
"""
|
||||||
v2 (and later v4) broadcasts are encrypted the same way the msgs were encrypted. To see if we are interested in a
|
v4 broadcasts are encrypted the same way the msgs are encrypted. To see if we are interested in a
|
||||||
v2 broadcast, we try to decrypt it. This was replaced with v3 (and later v5) broadcasts which include a tag which
|
v4 broadcast, we try to decrypt it. This was replaced with v5 broadcasts which include a tag which
|
||||||
we check instead, just like we do with v4 pubkeys.
|
we check instead, just like we do with v4 pubkeys.
|
||||||
v2 and v3 broadcasts should be completely obsolete after the protocol v3 upgrade period and some code can be simplified.
|
|
||||||
"""
|
"""
|
||||||
cleartextStreamNumber, cleartextStreamNumberLength = decodeVarint(
|
signedData = data[8:readPosition]
|
||||||
data[readPosition:readPosition + 10])
|
|
||||||
readPosition += cleartextStreamNumberLength
|
|
||||||
signedData = data[8:readPosition] # This doesn't end up being used if the broadcastVersion is 2
|
|
||||||
initialDecryptionSuccessful = False
|
initialDecryptionSuccessful = False
|
||||||
for key, cryptorObject in shared.MyECSubscriptionCryptorObjects.items():
|
for key, cryptorObject in shared.MyECSubscriptionCryptorObjects.items():
|
||||||
try:
|
try:
|
||||||
|
@ -694,145 +609,9 @@ class objectProcessor(threading.Thread):
|
||||||
# print 'cryptorObject.decrypt Exception:', err
|
# print 'cryptorObject.decrypt Exception:', err
|
||||||
if not initialDecryptionSuccessful:
|
if not initialDecryptionSuccessful:
|
||||||
# This is not a broadcast I am interested in.
|
# This is not a broadcast I am interested in.
|
||||||
logger.debug('Length of time program spent failing to decrypt this v2 broadcast: %s seconds.' % (time.time() - messageProcessingStartTime,))
|
logger.debug('Length of time program spent failing to decrypt this v4 broadcast: %s seconds.' % (time.time() - messageProcessingStartTime,))
|
||||||
return
|
return
|
||||||
# At this point this is a broadcast I have decrypted and thus am
|
elif broadcastVersion == 5:
|
||||||
# interested in.
|
|
||||||
readPosition = 0
|
|
||||||
if broadcastVersion == 2:
|
|
||||||
signedBroadcastVersion, signedBroadcastVersionLength = decodeVarint(
|
|
||||||
decryptedData[:10])
|
|
||||||
readPosition += signedBroadcastVersionLength
|
|
||||||
|
|
||||||
beginningOfPubkeyPosition = readPosition # used when we add the pubkey to our pubkey table. This variable can be disposed of after the protocol v3 upgrade period because it will necessarily be at the beginning of the decryptedData; ie it will definitely equal 0
|
|
||||||
sendersAddressVersion, sendersAddressVersionLength = decodeVarint(
|
|
||||||
decryptedData[readPosition:readPosition + 9])
|
|
||||||
if sendersAddressVersion < 2 or sendersAddressVersion > 3:
|
|
||||||
logger.info('Cannot decode senderAddressVersion other than 2 or 3. Assuming the sender isn\'t being silly, you should upgrade Bitmessage because this message shall be ignored.')
|
|
||||||
return
|
|
||||||
readPosition += sendersAddressVersionLength
|
|
||||||
sendersStream, sendersStreamLength = decodeVarint(
|
|
||||||
decryptedData[readPosition:readPosition + 9])
|
|
||||||
if sendersStream != cleartextStreamNumber:
|
|
||||||
logger.info('The stream number outside of the encryption on which the POW was completed doesn\'t match the stream number inside the encryption. Ignoring broadcast.')
|
|
||||||
return
|
|
||||||
readPosition += sendersStreamLength
|
|
||||||
behaviorBitfield = decryptedData[readPosition:readPosition + 4]
|
|
||||||
readPosition += 4
|
|
||||||
sendersPubSigningKey = '\x04' + \
|
|
||||||
decryptedData[readPosition:readPosition + 64]
|
|
||||||
readPosition += 64
|
|
||||||
sendersPubEncryptionKey = '\x04' + \
|
|
||||||
decryptedData[readPosition:readPosition + 64]
|
|
||||||
readPosition += 64
|
|
||||||
if sendersAddressVersion >= 3:
|
|
||||||
requiredAverageProofOfWorkNonceTrialsPerByte, varintLength = decodeVarint(
|
|
||||||
decryptedData[readPosition:readPosition + 10])
|
|
||||||
readPosition += varintLength
|
|
||||||
logger.debug('sender\'s requiredAverageProofOfWorkNonceTrialsPerByte is %s' % requiredAverageProofOfWorkNonceTrialsPerByte)
|
|
||||||
requiredPayloadLengthExtraBytes, varintLength = decodeVarint(
|
|
||||||
decryptedData[readPosition:readPosition + 10])
|
|
||||||
readPosition += varintLength
|
|
||||||
logger.debug('sender\'s requiredPayloadLengthExtraBytes is %s' % requiredPayloadLengthExtraBytes)
|
|
||||||
endOfPubkeyPosition = readPosition
|
|
||||||
|
|
||||||
sha = hashlib.new('sha512')
|
|
||||||
sha.update(sendersPubSigningKey + sendersPubEncryptionKey)
|
|
||||||
ripe = hashlib.new('ripemd160')
|
|
||||||
ripe.update(sha.digest())
|
|
||||||
|
|
||||||
if toRipe != ripe.digest():
|
|
||||||
logger.info('The encryption key used to encrypt this message doesn\'t match the keys inbedded in the message itself. Ignoring message.')
|
|
||||||
return
|
|
||||||
messageEncodingType, messageEncodingTypeLength = decodeVarint(
|
|
||||||
decryptedData[readPosition:readPosition + 9])
|
|
||||||
if messageEncodingType == 0:
|
|
||||||
return
|
|
||||||
readPosition += messageEncodingTypeLength
|
|
||||||
messageLength, messageLengthLength = decodeVarint(
|
|
||||||
decryptedData[readPosition:readPosition + 9])
|
|
||||||
readPosition += messageLengthLength
|
|
||||||
message = decryptedData[readPosition:readPosition + messageLength]
|
|
||||||
readPosition += messageLength
|
|
||||||
readPositionAtBottomOfMessage = readPosition
|
|
||||||
signatureLength, signatureLengthLength = decodeVarint(
|
|
||||||
decryptedData[readPosition:readPosition + 9])
|
|
||||||
readPosition += signatureLengthLength
|
|
||||||
signature = decryptedData[
|
|
||||||
readPosition:readPosition + signatureLength]
|
|
||||||
if broadcastVersion == 2: # this can be removed after the protocol v3 upgrade period
|
|
||||||
signedData = decryptedData[:readPositionAtBottomOfMessage]
|
|
||||||
else:
|
|
||||||
signedData += decryptedData[:readPositionAtBottomOfMessage]
|
|
||||||
if not highlevelcrypto.verify(signedData, signature, sendersPubSigningKey.encode('hex')):
|
|
||||||
logger.debug('ECDSA verify failed')
|
|
||||||
return
|
|
||||||
logger.debug('ECDSA verify passed')
|
|
||||||
# verify passed
|
|
||||||
|
|
||||||
# Let's store the public key in case we want to reply to this
|
|
||||||
# person.
|
|
||||||
sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''',
|
|
||||||
ripe.digest(),
|
|
||||||
sendersAddressVersion,
|
|
||||||
'\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF' + '\xFF\xFF\xFF\xFF' + decryptedData[beginningOfPubkeyPosition:endOfPubkeyPosition],
|
|
||||||
int(time.time()),
|
|
||||||
'yes')
|
|
||||||
# shared.workerQueue.put(('newpubkey',(sendersAddressVersion,sendersStream,ripe.digest())))
|
|
||||||
# This will check to see whether we happen to be awaiting this
|
|
||||||
# pubkey in order to send a message. If we are, it will do the POW
|
|
||||||
# and send it.
|
|
||||||
self.possibleNewPubkey(ripe=ripe.digest())
|
|
||||||
|
|
||||||
fromAddress = encodeAddress(
|
|
||||||
sendersAddressVersion, sendersStream, ripe.digest())
|
|
||||||
with shared.printLock:
|
|
||||||
print 'fromAddress:', fromAddress
|
|
||||||
|
|
||||||
if messageEncodingType == 2:
|
|
||||||
subject, body = self.decodeType2Message(message)
|
|
||||||
logger.info('Broadcast subject (first 100 characters): %s' % repr(subject)[:100])
|
|
||||||
elif messageEncodingType == 1:
|
|
||||||
body = message
|
|
||||||
subject = ''
|
|
||||||
elif messageEncodingType == 0:
|
|
||||||
logger.info('messageEncodingType == 0. Doing nothing with the message.')
|
|
||||||
else:
|
|
||||||
body = 'Unknown encoding type.\n\n' + repr(message)
|
|
||||||
subject = ''
|
|
||||||
|
|
||||||
toAddress = '[Broadcast subscribers]'
|
|
||||||
if messageEncodingType != 0:
|
|
||||||
if helper_inbox.isMessageAlreadyInInbox(toAddress, fromAddress, subject, body, messageEncodingType):
|
|
||||||
logger.info('This broadcast is already in our inbox. Ignoring it.')
|
|
||||||
else:
|
|
||||||
t = (inventoryHash, toAddress, fromAddress, subject, int(
|
|
||||||
time.time()), body, 'inbox', messageEncodingType, 0)
|
|
||||||
helper_inbox.insert(t)
|
|
||||||
|
|
||||||
shared.UISignalQueue.put(('displayNewInboxMessage', (
|
|
||||||
inventoryHash, toAddress, fromAddress, subject, body)))
|
|
||||||
|
|
||||||
# If we are behaving as an API then we might need to run an
|
|
||||||
# outside command to let some program know that a new message
|
|
||||||
# has arrived.
|
|
||||||
if shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'):
|
|
||||||
try:
|
|
||||||
apiNotifyPath = shared.config.get(
|
|
||||||
'bitmessagesettings', 'apinotifypath')
|
|
||||||
except:
|
|
||||||
apiNotifyPath = ''
|
|
||||||
if apiNotifyPath != '':
|
|
||||||
call([apiNotifyPath, "newBroadcast"])
|
|
||||||
|
|
||||||
# Display timing data
|
|
||||||
logger.info('Time spent processing this interesting broadcast: %s' % (time.time() - messageProcessingStartTime,))
|
|
||||||
|
|
||||||
if broadcastVersion in [3,5]:
|
|
||||||
# broadcast version 3 should be completely obsolete after the end of the protocol v3 upgrade period
|
|
||||||
cleartextStreamNumber, cleartextStreamNumberLength = decodeVarint(
|
|
||||||
data[readPosition:readPosition + 10])
|
|
||||||
readPosition += cleartextStreamNumberLength
|
|
||||||
embeddedTag = data[readPosition:readPosition+32]
|
embeddedTag = data[readPosition:readPosition+32]
|
||||||
readPosition += 32
|
readPosition += 32
|
||||||
if embeddedTag not in shared.MyECSubscriptionCryptorObjects:
|
if embeddedTag not in shared.MyECSubscriptionCryptorObjects:
|
||||||
|
@ -847,153 +626,161 @@ class objectProcessor(threading.Thread):
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.debug('Broadcast version %s decryption Unsuccessful.' % broadcastVersion)
|
logger.debug('Broadcast version %s decryption Unsuccessful.' % broadcastVersion)
|
||||||
return
|
return
|
||||||
|
# At this point this is a broadcast I have decrypted and am
|
||||||
# broadcast version 3 includes the broadcast version at the beginning
|
# interested in.
|
||||||
# of the decryptedData. Broadcast version 5 doesn't.
|
readPosition = 0
|
||||||
readPosition = 0
|
sendersAddressVersion, sendersAddressVersionLength = decodeVarint(
|
||||||
if broadcastVersion == 3: # This section can be removed after the protocol v3 upgrade period
|
decryptedData[readPosition:readPosition + 9])
|
||||||
signedBroadcastVersion, signedBroadcastVersionLength = decodeVarint(
|
if broadcastVersion == 4:
|
||||||
decryptedData[:10])
|
if sendersAddressVersion < 2 or sendersAddressVersion > 3:
|
||||||
readPosition += signedBroadcastVersionLength
|
logger.warning('Cannot decode senderAddressVersion other than 2 or 3. Assuming the sender isn\'t being silly, you should upgrade Bitmessage because this message shall be ignored.')
|
||||||
|
return
|
||||||
beginningOfPubkeyPosition = readPosition # used when we add the pubkey to our pubkey table
|
elif broadcastVersion == 5:
|
||||||
sendersAddressVersion, sendersAddressVersionLength = decodeVarint(
|
|
||||||
decryptedData[readPosition:readPosition + 9])
|
|
||||||
if sendersAddressVersion < 4:
|
if sendersAddressVersion < 4:
|
||||||
logger.info('Cannot decode senderAddressVersion less than 4 for broadcast version number 3 or 4. Assuming the sender isn\'t being silly, you should upgrade Bitmessage because this message shall be ignored.')
|
logger.info('Cannot decode senderAddressVersion less than 4 for broadcast version number 5. Assuming the sender isn\'t being silly, you should upgrade Bitmessage because this message shall be ignored.')
|
||||||
return
|
return
|
||||||
readPosition += sendersAddressVersionLength
|
readPosition += sendersAddressVersionLength
|
||||||
sendersStream, sendersStreamLength = decodeVarint(
|
sendersStream, sendersStreamLength = decodeVarint(
|
||||||
decryptedData[readPosition:readPosition + 9])
|
decryptedData[readPosition:readPosition + 9])
|
||||||
if sendersStream != cleartextStreamNumber:
|
if sendersStream != cleartextStreamNumber:
|
||||||
logger.info('The stream number outside of the encryption on which the POW was completed doesn\'t match the stream number inside the encryption. Ignoring broadcast.')
|
logger.info('The stream number outside of the encryption on which the POW was completed doesn\'t match the stream number inside the encryption. Ignoring broadcast.')
|
||||||
|
return
|
||||||
|
readPosition += sendersStreamLength
|
||||||
|
behaviorBitfield = decryptedData[readPosition:readPosition + 4]
|
||||||
|
readPosition += 4
|
||||||
|
sendersPubSigningKey = '\x04' + \
|
||||||
|
decryptedData[readPosition:readPosition + 64]
|
||||||
|
readPosition += 64
|
||||||
|
sendersPubEncryptionKey = '\x04' + \
|
||||||
|
decryptedData[readPosition:readPosition + 64]
|
||||||
|
readPosition += 64
|
||||||
|
if sendersAddressVersion >= 3:
|
||||||
|
requiredAverageProofOfWorkNonceTrialsPerByte, varintLength = decodeVarint(
|
||||||
|
decryptedData[readPosition:readPosition + 10])
|
||||||
|
readPosition += varintLength
|
||||||
|
logger.debug('sender\'s requiredAverageProofOfWorkNonceTrialsPerByte is %s' % requiredAverageProofOfWorkNonceTrialsPerByte)
|
||||||
|
requiredPayloadLengthExtraBytes, varintLength = decodeVarint(
|
||||||
|
decryptedData[readPosition:readPosition + 10])
|
||||||
|
readPosition += varintLength
|
||||||
|
logger.debug('sender\'s requiredPayloadLengthExtraBytes is %s' % requiredPayloadLengthExtraBytes)
|
||||||
|
endOfPubkeyPosition = readPosition
|
||||||
|
|
||||||
|
sha = hashlib.new('sha512')
|
||||||
|
sha.update(sendersPubSigningKey + sendersPubEncryptionKey)
|
||||||
|
ripeHasher = hashlib.new('ripemd160')
|
||||||
|
ripeHasher.update(sha.digest())
|
||||||
|
calculatedRipe = ripeHasher.digest()
|
||||||
|
|
||||||
|
if broadcastVersion == 4:
|
||||||
|
if toRipe != calculatedRipe:
|
||||||
|
logger.info('The encryption key used to encrypt this message doesn\'t match the keys inbedded in the message itself. Ignoring message.')
|
||||||
return
|
return
|
||||||
readPosition += sendersStreamLength
|
elif broadcastVersion == 5:
|
||||||
behaviorBitfield = decryptedData[readPosition:readPosition + 4]
|
|
||||||
readPosition += 4
|
|
||||||
sendersPubSigningKey = '\x04' + \
|
|
||||||
decryptedData[readPosition:readPosition + 64]
|
|
||||||
readPosition += 64
|
|
||||||
sendersPubEncryptionKey = '\x04' + \
|
|
||||||
decryptedData[readPosition:readPosition + 64]
|
|
||||||
readPosition += 64
|
|
||||||
if sendersAddressVersion >= 3:
|
|
||||||
requiredAverageProofOfWorkNonceTrialsPerByte, varintLength = decodeVarint(
|
|
||||||
decryptedData[readPosition:readPosition + 10])
|
|
||||||
readPosition += varintLength
|
|
||||||
logger.debug('sender\'s requiredAverageProofOfWorkNonceTrialsPerByte is %s' % requiredAverageProofOfWorkNonceTrialsPerByte)
|
|
||||||
requiredPayloadLengthExtraBytes, varintLength = decodeVarint(
|
|
||||||
decryptedData[readPosition:readPosition + 10])
|
|
||||||
readPosition += varintLength
|
|
||||||
logger.debug('sender\'s requiredPayloadLengthExtraBytes is %s' % requiredPayloadLengthExtraBytes)
|
|
||||||
endOfPubkeyPosition = readPosition
|
|
||||||
|
|
||||||
sha = hashlib.new('sha512')
|
|
||||||
sha.update(sendersPubSigningKey + sendersPubEncryptionKey)
|
|
||||||
ripeHasher = hashlib.new('ripemd160')
|
|
||||||
ripeHasher.update(sha.digest())
|
|
||||||
calculatedRipe = ripeHasher.digest()
|
|
||||||
|
|
||||||
calculatedTag = hashlib.sha512(hashlib.sha512(encodeVarint(
|
calculatedTag = hashlib.sha512(hashlib.sha512(encodeVarint(
|
||||||
sendersAddressVersion) + encodeVarint(sendersStream) + calculatedRipe).digest()).digest()[32:]
|
sendersAddressVersion) + encodeVarint(sendersStream) + calculatedRipe).digest()).digest()[32:]
|
||||||
if calculatedTag != embeddedTag:
|
if calculatedTag != embeddedTag:
|
||||||
logger.debug('The tag and encryption key used to encrypt this message doesn\'t match the keys inbedded in the message itself. Ignoring message.')
|
logger.debug('The tag and encryption key used to encrypt this message doesn\'t match the keys inbedded in the message itself. Ignoring message.')
|
||||||
return
|
return
|
||||||
messageEncodingType, messageEncodingTypeLength = decodeVarint(
|
messageEncodingType, messageEncodingTypeLength = decodeVarint(
|
||||||
decryptedData[readPosition:readPosition + 9])
|
decryptedData[readPosition:readPosition + 9])
|
||||||
if messageEncodingType == 0:
|
if messageEncodingType == 0:
|
||||||
return
|
return
|
||||||
readPosition += messageEncodingTypeLength
|
readPosition += messageEncodingTypeLength
|
||||||
messageLength, messageLengthLength = decodeVarint(
|
messageLength, messageLengthLength = decodeVarint(
|
||||||
decryptedData[readPosition:readPosition + 9])
|
decryptedData[readPosition:readPosition + 9])
|
||||||
readPosition += messageLengthLength
|
readPosition += messageLengthLength
|
||||||
message = decryptedData[readPosition:readPosition + messageLength]
|
message = decryptedData[readPosition:readPosition + messageLength]
|
||||||
readPosition += messageLength
|
readPosition += messageLength
|
||||||
readPositionAtBottomOfMessage = readPosition
|
readPositionAtBottomOfMessage = readPosition
|
||||||
signatureLength, signatureLengthLength = decodeVarint(
|
signatureLength, signatureLengthLength = decodeVarint(
|
||||||
decryptedData[readPosition:readPosition + 9])
|
decryptedData[readPosition:readPosition + 9])
|
||||||
readPosition += signatureLengthLength
|
readPosition += signatureLengthLength
|
||||||
signature = decryptedData[
|
signature = decryptedData[
|
||||||
readPosition:readPosition + signatureLength]
|
readPosition:readPosition + signatureLength]
|
||||||
if broadcastVersion == 3: # broadcastVersion 3 should be completely unused after the end of the protocol v3 upgrade period
|
signedData += decryptedData[:readPositionAtBottomOfMessage]
|
||||||
signedData = decryptedData[:readPositionAtBottomOfMessage]
|
if not highlevelcrypto.verify(signedData, signature, sendersPubSigningKey.encode('hex')):
|
||||||
elif broadcastVersion == 5:
|
logger.debug('ECDSA verify failed')
|
||||||
signedData += decryptedData[:readPositionAtBottomOfMessage]
|
return
|
||||||
if not highlevelcrypto.verify(signedData, signature, sendersPubSigningKey.encode('hex')):
|
logger.debug('ECDSA verify passed')
|
||||||
logger.debug('ECDSA verify failed')
|
|
||||||
return
|
|
||||||
logger.debug('ECDSA verify passed')
|
|
||||||
# verify passed
|
|
||||||
|
|
||||||
fromAddress = encodeAddress(
|
fromAddress = encodeAddress(
|
||||||
sendersAddressVersion, sendersStream, calculatedRipe)
|
sendersAddressVersion, sendersStream, calculatedRipe)
|
||||||
logger.info('fromAddress: %s' % fromAddress)
|
logger.info('fromAddress: %s' % fromAddress)
|
||||||
|
|
||||||
# Let's store the public key in case we want to reply to this person.
|
# Let's store the public key in case we want to reply to this person.
|
||||||
sqlExecute(
|
sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''',
|
||||||
'''INSERT INTO pubkeys VALUES (?,?,?,?,?)''',
|
calculatedRipe,
|
||||||
calculatedRipe,
|
sendersAddressVersion,
|
||||||
sendersAddressVersion,
|
decryptedData[:endOfPubkeyPosition],
|
||||||
'\x00\x00\x00\x00\x00\x00\x00\x01' + decryptedData[beginningOfPubkeyPosition:endOfPubkeyPosition],
|
int(time.time()),
|
||||||
int(time.time()),
|
'yes')
|
||||||
'yes')
|
|
||||||
# This will check to see whether we happen to be awaiting this
|
|
||||||
# pubkey in order to send a message. If we are, it will do the
|
|
||||||
# POW and send it.
|
|
||||||
self.possibleNewPubkey(address = fromAddress)
|
|
||||||
|
|
||||||
if messageEncodingType == 2:
|
# Check to see whether we happen to be awaiting this
|
||||||
subject, body = self.decodeType2Message(message)
|
# pubkey in order to send a message. If we are, it will do the POW
|
||||||
logger.info('Broadcast subject (first 100 characters): %s' % repr(subject)[:100])
|
# and send it.
|
||||||
elif messageEncodingType == 1:
|
if broadcastVersion == 4:
|
||||||
body = message
|
self.possibleNewPubkey(ripe=calculatedRipe)
|
||||||
subject = ''
|
elif broadcastVersion == 5:
|
||||||
elif messageEncodingType == 0:
|
self.possibleNewPubkey(address=fromAddress)
|
||||||
logger.info('messageEncodingType == 0. Doing nothing with the message.')
|
|
||||||
|
fromAddress = encodeAddress(
|
||||||
|
sendersAddressVersion, sendersStream, calculatedRipe)
|
||||||
|
with shared.printLock:
|
||||||
|
print 'fromAddress:', fromAddress
|
||||||
|
|
||||||
|
if messageEncodingType == 2:
|
||||||
|
subject, body = self.decodeType2Message(message)
|
||||||
|
logger.info('Broadcast subject (first 100 characters): %s' % repr(subject)[:100])
|
||||||
|
elif messageEncodingType == 1:
|
||||||
|
body = message
|
||||||
|
subject = ''
|
||||||
|
elif messageEncodingType == 0:
|
||||||
|
logger.info('messageEncodingType == 0. Doing nothing with the message.')
|
||||||
|
else:
|
||||||
|
body = 'Unknown encoding type.\n\n' + repr(message)
|
||||||
|
subject = ''
|
||||||
|
|
||||||
|
toAddress = '[Broadcast subscribers]'
|
||||||
|
if messageEncodingType != 0:
|
||||||
|
if helper_inbox.isMessageAlreadyInInbox(toAddress, fromAddress, subject, body, messageEncodingType):
|
||||||
|
logger.info('This broadcast is already in our inbox. Ignoring it.')
|
||||||
else:
|
else:
|
||||||
body = 'Unknown encoding type.\n\n' + repr(message)
|
t = (inventoryHash, toAddress, fromAddress, subject, int(
|
||||||
subject = ''
|
time.time()), body, 'inbox', messageEncodingType, 0)
|
||||||
|
helper_inbox.insert(t)
|
||||||
|
|
||||||
toAddress = '[Broadcast subscribers]'
|
shared.UISignalQueue.put(('displayNewInboxMessage', (
|
||||||
if messageEncodingType != 0:
|
inventoryHash, toAddress, fromAddress, subject, body)))
|
||||||
if helper_inbox.isMessageAlreadyInInbox(toAddress, fromAddress, subject, body, messageEncodingType):
|
|
||||||
logger.info('This broadcast is already in our inbox. Ignoring it.')
|
# If we are behaving as an API then we might need to run an
|
||||||
else:
|
# outside command to let some program know that a new message
|
||||||
t = (inventoryHash, toAddress, fromAddress, subject, int(
|
# has arrived.
|
||||||
time.time()), body, 'inbox', messageEncodingType, 0)
|
if shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'):
|
||||||
helper_inbox.insert(t)
|
try:
|
||||||
|
apiNotifyPath = shared.config.get(
|
||||||
shared.UISignalQueue.put(('displayNewInboxMessage', (
|
'bitmessagesettings', 'apinotifypath')
|
||||||
inventoryHash, toAddress, fromAddress, subject, body)))
|
except:
|
||||||
|
apiNotifyPath = ''
|
||||||
# If we are behaving as an API then we might need to run an
|
if apiNotifyPath != '':
|
||||||
# outside command to let some program know that a new message
|
call([apiNotifyPath, "newBroadcast"])
|
||||||
# has arrived.
|
|
||||||
if shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'):
|
# Display timing data
|
||||||
try:
|
logger.info('Time spent processing this interesting broadcast: %s' % (time.time() - messageProcessingStartTime,))
|
||||||
apiNotifyPath = shared.config.get(
|
|
||||||
'bitmessagesettings', 'apinotifypath')
|
|
||||||
except:
|
|
||||||
apiNotifyPath = ''
|
|
||||||
if apiNotifyPath != '':
|
|
||||||
call([apiNotifyPath, "newBroadcast"])
|
|
||||||
|
|
||||||
# Display timing data
|
|
||||||
logger.debug('Time spent processing this interesting broadcast: %s' % (time.time() - messageProcessingStartTime,))
|
|
||||||
|
|
||||||
# We have inserted a pubkey into our pubkey table which we received from a
|
# We have inserted a pubkey into our pubkey table which we received from a
|
||||||
# pubkey, msg, or broadcast message. It might be one that we have been
|
# pubkey, msg, or broadcast message. It might be one that we have been
|
||||||
# waiting for. Let's check.
|
# waiting for. Let's check.
|
||||||
def possibleNewPubkey(self, ripe=None, address=None):
|
def possibleNewPubkey(self, ripe=None, address=None):
|
||||||
|
"""
|
||||||
|
We have put a new pubkey in our pubkeys table. Let's see if we have been
|
||||||
|
awaiting it.
|
||||||
|
"""
|
||||||
# For address versions <= 3, we wait on a key with the correct ripe hash
|
# For address versions <= 3, we wait on a key with the correct ripe hash
|
||||||
if ripe != None:
|
if ripe != None:
|
||||||
if ripe in shared.neededPubkeys:
|
if ripe in shared.neededPubkeys:
|
||||||
logger.info('We have been awaiting the arrival of this pubkey.')
|
|
||||||
del shared.neededPubkeys[ripe]
|
del shared.neededPubkeys[ripe]
|
||||||
sqlExecute(
|
self.sendMessages(ripe)
|
||||||
'''UPDATE sent SET status='doingmsgpow' WHERE toripe=? AND (status='awaitingpubkey' or status='doingpubkeypow') and folder='sent' ''',
|
|
||||||
ripe)
|
|
||||||
shared.workerQueue.put(('sendmessage', ''))
|
|
||||||
else:
|
else:
|
||||||
logger.debug('We don\'t need this pub key. We didn\'t ask for it. Pubkey hash: %s' % ripe.encode('hex'))
|
logger.debug('We don\'t need this pub key. We didn\'t ask for it. Pubkey hash: %s' % ripe.encode('hex'))
|
||||||
# For address versions >= 4, we wait on a pubkey with the correct tag.
|
# For address versions >= 4, we wait on a pubkey with the correct tag.
|
||||||
|
@ -1004,12 +791,20 @@ class objectProcessor(threading.Thread):
|
||||||
tag = hashlib.sha512(hashlib.sha512(encodeVarint(
|
tag = hashlib.sha512(hashlib.sha512(encodeVarint(
|
||||||
addressVersion) + encodeVarint(streamNumber) + ripe).digest()).digest()[32:]
|
addressVersion) + encodeVarint(streamNumber) + ripe).digest()).digest()[32:]
|
||||||
if tag in shared.neededPubkeys:
|
if tag in shared.neededPubkeys:
|
||||||
logger.info('We have been awaiting the arrival of this pubkey.')
|
|
||||||
del shared.neededPubkeys[tag]
|
del shared.neededPubkeys[tag]
|
||||||
sqlExecute(
|
self.sendMessages(ripe)
|
||||||
'''UPDATE sent SET status='doingmsgpow' WHERE toripe=? AND (status='awaitingpubkey' or status='doingpubkeypow') and folder='sent' ''',
|
|
||||||
ripe)
|
def sendMessages(self, ripe):
|
||||||
shared.workerQueue.put(('sendmessage', ''))
|
"""
|
||||||
|
This function is called by the possibleNewPubkey function when
|
||||||
|
that function sees that we now have the necessary pubkey
|
||||||
|
to send one or more messages.
|
||||||
|
"""
|
||||||
|
logger.info('We have been awaiting the arrival of this pubkey.')
|
||||||
|
sqlExecute(
|
||||||
|
'''UPDATE sent SET status='doingmsgpow' WHERE toripe=? AND (status='awaitingpubkey' or status='doingpubkeypow') and folder='sent' ''',
|
||||||
|
ripe)
|
||||||
|
shared.workerQueue.put(('sendmessage', ''))
|
||||||
|
|
||||||
def ackDataHasAVaildHeader(self, ackData):
|
def ackDataHasAVaildHeader(self, ackData):
|
||||||
if len(ackData) < shared.Header.size:
|
if len(ackData) < shared.Header.size:
|
||||||
|
@ -1040,22 +835,6 @@ class objectProcessor(threading.Thread):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def decodeType2Message(self, message):
|
|
||||||
bodyPositionIndex = string.find(message, '\nBody:')
|
|
||||||
if bodyPositionIndex > 1:
|
|
||||||
subject = message[8:bodyPositionIndex]
|
|
||||||
# Only save and show the first 500 characters of the subject.
|
|
||||||
# Any more is probably an attack.
|
|
||||||
subject = subject[:500]
|
|
||||||
body = message[bodyPositionIndex + 6:]
|
|
||||||
else:
|
|
||||||
subject = ''
|
|
||||||
body = message
|
|
||||||
# Throw away any extra lines (headers) after the subject.
|
|
||||||
if subject:
|
|
||||||
subject = subject.splitlines()[0]
|
|
||||||
return subject, body
|
|
||||||
|
|
||||||
def addMailingListNameToSubject(self, subject, mailingListName):
|
def addMailingListNameToSubject(self, subject, mailingListName):
|
||||||
subject = subject.strip()
|
subject = subject.strip()
|
||||||
if subject[:3] == 'Re:' or subject[:3] == 'RE:':
|
if subject[:3] == 'Re:' or subject[:3] == 'RE:':
|
||||||
|
|
|
@ -219,12 +219,7 @@ class singleWorker(threading.Thread):
|
||||||
payload += encodeVarint(shared.config.getint(
|
payload += encodeVarint(shared.config.getint(
|
||||||
myAddress, 'payloadlengthextrabytes'))
|
myAddress, 'payloadlengthextrabytes'))
|
||||||
|
|
||||||
if int(time.time()) < 1416175200: # Sun, 16 Nov 2014 22:00:00 GMT
|
signature = highlevelcrypto.sign(payload, privSigningKeyHex)
|
||||||
signedData = pack('>I', signedTimeForProtocolV2) + payload[12:]
|
|
||||||
else:
|
|
||||||
signedData = payload
|
|
||||||
|
|
||||||
signature = highlevelcrypto.sign(signedData, privSigningKeyHex)
|
|
||||||
payload += encodeVarint(len(signature))
|
payload += encodeVarint(len(signature))
|
||||||
payload += signature
|
payload += signature
|
||||||
|
|
||||||
|
@ -309,8 +304,6 @@ class singleWorker(threading.Thread):
|
||||||
dataToEncrypt += encodeVarint(shared.config.getint(
|
dataToEncrypt += encodeVarint(shared.config.getint(
|
||||||
myAddress, 'payloadlengthextrabytes'))
|
myAddress, 'payloadlengthextrabytes'))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# When we encrypt, we'll use a hash of the data
|
# When we encrypt, we'll use a hash of the data
|
||||||
# contained in an address as a decryption key. This way in order to
|
# contained in an address as a decryption key. This way in order to
|
||||||
# read the public keys in a pubkey message, a node must know the address
|
# read the public keys in a pubkey message, a node must know the address
|
||||||
|
@ -320,23 +313,7 @@ class singleWorker(threading.Thread):
|
||||||
doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(encodeVarint(
|
doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(encodeVarint(
|
||||||
addressVersionNumber) + encodeVarint(streamNumber) + hash).digest()).digest()
|
addressVersionNumber) + encodeVarint(streamNumber) + hash).digest()).digest()
|
||||||
payload += doubleHashOfAddressData[32:] # the tag
|
payload += doubleHashOfAddressData[32:] # the tag
|
||||||
|
signature = highlevelcrypto.sign(payload + dataToEncrypt, privSigningKeyHex)
|
||||||
"""
|
|
||||||
According to the protocol specification, the expiresTime along with the pubkey information is
|
|
||||||
signed. But to be backwards compatible during the upgrade period, we shall sign not the
|
|
||||||
expiresTime but rather the current time. There must be precisely a 28 day difference
|
|
||||||
between the two. After the upgrade period we'll switch to signing the whole payload from
|
|
||||||
above appended with dataToEncrypt.
|
|
||||||
"""
|
|
||||||
if int(time.time()) < 1416175200: # Sun, 16 Nov 2014 22:00:00 GMT
|
|
||||||
dataToSign = pack('>Q', (embeddedTime - TTL))
|
|
||||||
dataToSign += encodeVarint(addressVersionNumber) # Address version number
|
|
||||||
dataToSign += encodeVarint(streamNumber)
|
|
||||||
dataToSign += dataToEncrypt
|
|
||||||
else:
|
|
||||||
dataToSign = payload + dataToEncrypt
|
|
||||||
|
|
||||||
signature = highlevelcrypto.sign(dataToSign, privSigningKeyHex)
|
|
||||||
dataToEncrypt += encodeVarint(len(signature))
|
dataToEncrypt += encodeVarint(len(signature))
|
||||||
dataToEncrypt += signature
|
dataToEncrypt += signature
|
||||||
|
|
||||||
|
@ -411,17 +388,11 @@ class singleWorker(threading.Thread):
|
||||||
embeddedTime = int(time.time() + TTL)
|
embeddedTime = int(time.time() + TTL)
|
||||||
payload = pack('>Q', embeddedTime)
|
payload = pack('>Q', embeddedTime)
|
||||||
payload += '\x00\x00\x00\x03' # object type: broadcast
|
payload += '\x00\x00\x00\x03' # object type: broadcast
|
||||||
|
|
||||||
if int(time.time()) < 1416175200: # Before Sun, 16 Nov 2014 22:00:00 GMT
|
if addressVersionNumber <= 3:
|
||||||
if addressVersionNumber <= 3:
|
payload += encodeVarint(4) # broadcast version
|
||||||
payload += encodeVarint(2) # broadcast version
|
else:
|
||||||
else:
|
payload += encodeVarint(5) # broadcast version
|
||||||
payload += encodeVarint(3) # broadcast version
|
|
||||||
else: # After Sun, 16 Nov 2014 22:00:00 GMT
|
|
||||||
if addressVersionNumber <= 3:
|
|
||||||
payload += encodeVarint(4) # broadcast version
|
|
||||||
else:
|
|
||||||
payload += encodeVarint(5) # broadcast version
|
|
||||||
|
|
||||||
payload += encodeVarint(streamNumber)
|
payload += encodeVarint(streamNumber)
|
||||||
if addressVersionNumber >= 4:
|
if addressVersionNumber >= 4:
|
||||||
|
@ -432,14 +403,7 @@ class singleWorker(threading.Thread):
|
||||||
else:
|
else:
|
||||||
tag = ''
|
tag = ''
|
||||||
|
|
||||||
dataToEncrypt = ""
|
dataToEncrypt = encodeVarint(addressVersionNumber)
|
||||||
# the broadcast version is not included here after the end of the protocol v3 upgrade period
|
|
||||||
if int(time.time()) < 1416175200: # Sun, 16 Nov 2014 22:00:00 GMT
|
|
||||||
if addressVersionNumber <= 3:
|
|
||||||
dataToEncrypt += encodeVarint(2) # broadcast version
|
|
||||||
else:
|
|
||||||
dataToEncrypt += encodeVarint(3) # broadcast version
|
|
||||||
dataToEncrypt += encodeVarint(addressVersionNumber)
|
|
||||||
dataToEncrypt += encodeVarint(streamNumber)
|
dataToEncrypt += encodeVarint(streamNumber)
|
||||||
dataToEncrypt += '\x00\x00\x00\x01' # behavior bitfield
|
dataToEncrypt += '\x00\x00\x00\x01' # behavior bitfield
|
||||||
dataToEncrypt += pubSigningKey[1:]
|
dataToEncrypt += pubSigningKey[1:]
|
||||||
|
@ -450,10 +414,7 @@ class singleWorker(threading.Thread):
|
||||||
dataToEncrypt += '\x02' # message encoding type
|
dataToEncrypt += '\x02' # message encoding type
|
||||||
dataToEncrypt += encodeVarint(len('Subject:' + subject + '\n' + 'Body:' + body)) #Type 2 is simple UTF-8 message encoding per the documentation on the wiki.
|
dataToEncrypt += encodeVarint(len('Subject:' + subject + '\n' + 'Body:' + body)) #Type 2 is simple UTF-8 message encoding per the documentation on the wiki.
|
||||||
dataToEncrypt += 'Subject:' + subject + '\n' + 'Body:' + body
|
dataToEncrypt += 'Subject:' + subject + '\n' + 'Body:' + body
|
||||||
if int(time.time()) < 1416175200: # Sun, 16 Nov 2014 22:00:00 GMT
|
dataToSign = payload + dataToEncrypt
|
||||||
dataToSign = dataToEncrypt
|
|
||||||
else:
|
|
||||||
dataToSign = payload + dataToEncrypt
|
|
||||||
|
|
||||||
signature = highlevelcrypto.sign(
|
signature = highlevelcrypto.sign(
|
||||||
dataToSign, privSigningKeyHex)
|
dataToSign, privSigningKeyHex)
|
||||||
|
@ -646,25 +607,16 @@ class singleWorker(threading.Thread):
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
pubkeyPayload, = row
|
pubkeyPayload, = row
|
||||||
|
|
||||||
# The pubkey message is stored the way we originally received it
|
# The pubkey message is stored with the following items all appended:
|
||||||
# under protocol version 2
|
# -address version
|
||||||
# which means that we need to read beyond things like the nonce and
|
# -stream number
|
||||||
# time to get to the actual public keys.
|
# -behavior bitfield
|
||||||
if toAddressVersionNumber <= 3:
|
# -pub signing key
|
||||||
readPosition = 8 # to bypass the nonce
|
# -pub encryption key
|
||||||
elif toAddressVersionNumber >= 4:
|
# -nonce trials per byte (if address version is >= 3)
|
||||||
readPosition = 0 # the nonce is not included here so we don't need to skip over it.
|
# -length extra bytes (if address version is >= 3)
|
||||||
pubkeyEmbeddedTime, = unpack(
|
|
||||||
'>I', pubkeyPayload[readPosition:readPosition + 4])
|
readPosition = 1 # to bypass the address version whose length is definitely 1
|
||||||
# This section is used for the transition from 32 bit time to 64
|
|
||||||
# bit time in the protocol.
|
|
||||||
if pubkeyEmbeddedTime == 0:
|
|
||||||
pubkeyEmbeddedTime, = unpack(
|
|
||||||
'>Q', pubkeyPayload[readPosition:readPosition + 8])
|
|
||||||
readPosition += 8
|
|
||||||
else:
|
|
||||||
readPosition += 4
|
|
||||||
readPosition += 1 # to bypass the address version whose length is definitely 1
|
|
||||||
streamNumber, streamNumberLength = decodeVarint(
|
streamNumber, streamNumberLength = decodeVarint(
|
||||||
pubkeyPayload[readPosition:readPosition + 10])
|
pubkeyPayload[readPosition:readPosition + 10])
|
||||||
readPosition += streamNumberLength
|
readPosition += streamNumberLength
|
||||||
|
@ -679,9 +631,7 @@ class singleWorker(threading.Thread):
|
||||||
# if the human changes their setting and then sends another message or restarts their client, this one will send at that time.
|
# if the human changes their setting and then sends another message or restarts their client, this one will send at that time.
|
||||||
continue
|
continue
|
||||||
readPosition += 4 # to bypass the bitfield of behaviors
|
readPosition += 4 # to bypass the bitfield of behaviors
|
||||||
# pubSigningKeyBase256 =
|
# pubSigningKeyBase256 = pubkeyPayload[readPosition:readPosition+64] # We don't use this key for anything here.
|
||||||
# pubkeyPayload[readPosition:readPosition+64] #We don't use this
|
|
||||||
# key for anything here.
|
|
||||||
readPosition += 64
|
readPosition += 64
|
||||||
pubEncryptionKeyBase256 = pubkeyPayload[
|
pubEncryptionKeyBase256 = pubkeyPayload[
|
||||||
readPosition:readPosition + 64]
|
readPosition:readPosition + 64]
|
||||||
|
@ -740,91 +690,38 @@ class singleWorker(threading.Thread):
|
||||||
shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (
|
shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (
|
||||||
ackdata, tr.translateText("MainWindow", "Doing work necessary to send message."))))
|
ackdata, tr.translateText("MainWindow", "Doing work necessary to send message."))))
|
||||||
|
|
||||||
if fromAddressVersionNumber == 2:
|
# Now we can start to assemble our message.
|
||||||
payload = ""
|
payload = encodeVarint(fromAddressVersionNumber)
|
||||||
if int(time.time()) < 1416175200: # Sun, 16 Nov 2014 22:00:00 GMT
|
payload += encodeVarint(fromStreamNumber)
|
||||||
payload += '\x01' # Message version.
|
payload += '\x00\x00\x00\x01' # Bitfield of features and behaviors that can be expected from me. (See https://bitmessage.org/wiki/Protocol_specification#Pubkey_bitfield_features )
|
||||||
payload += encodeVarint(fromAddressVersionNumber)
|
|
||||||
payload += encodeVarint(fromStreamNumber)
|
|
||||||
payload += '\x00\x00\x00\x01' # Bitfield of features and behaviors that can be expected from me. (See https://bitmessage.org/wiki/Protocol_specification#Pubkey_bitfield_features )
|
|
||||||
|
|
||||||
# We need to convert our private keys to public keys in order
|
# We need to convert our private keys to public keys in order
|
||||||
# to include them.
|
# to include them.
|
||||||
try:
|
try:
|
||||||
privSigningKeyBase58 = shared.config.get(
|
privSigningKeyBase58 = shared.config.get(
|
||||||
fromaddress, 'privsigningkey')
|
fromaddress, 'privsigningkey')
|
||||||
privEncryptionKeyBase58 = shared.config.get(
|
privEncryptionKeyBase58 = shared.config.get(
|
||||||
fromaddress, 'privencryptionkey')
|
fromaddress, 'privencryptionkey')
|
||||||
except:
|
except:
|
||||||
shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (
|
shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (
|
||||||
ackdata, tr.translateText("MainWindow", "Error! Could not find sender address (your address) in the keys.dat file."))))
|
ackdata, tr.translateText("MainWindow", "Error! Could not find sender address (your address) in the keys.dat file."))))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
privSigningKeyHex = shared.decodeWalletImportFormat(
|
privSigningKeyHex = shared.decodeWalletImportFormat(
|
||||||
privSigningKeyBase58).encode('hex')
|
privSigningKeyBase58).encode('hex')
|
||||||
privEncryptionKeyHex = shared.decodeWalletImportFormat(
|
privEncryptionKeyHex = shared.decodeWalletImportFormat(
|
||||||
privEncryptionKeyBase58).encode('hex')
|
privEncryptionKeyBase58).encode('hex')
|
||||||
|
|
||||||
pubSigningKey = highlevelcrypto.privToPub(
|
pubSigningKey = highlevelcrypto.privToPub(
|
||||||
privSigningKeyHex).decode('hex')
|
privSigningKeyHex).decode('hex')
|
||||||
pubEncryptionKey = highlevelcrypto.privToPub(
|
pubEncryptionKey = highlevelcrypto.privToPub(
|
||||||
privEncryptionKeyHex).decode('hex')
|
privEncryptionKeyHex).decode('hex')
|
||||||
|
|
||||||
payload += pubSigningKey[
|
payload += pubSigningKey[
|
||||||
1:] # The \x04 on the beginning of the public keys are not sent. This way there is only one acceptable way to encode and send a public key.
|
1:] # The \x04 on the beginning of the public keys are not sent. This way there is only one acceptable way to encode and send a public key.
|
||||||
payload += pubEncryptionKey[1:]
|
payload += pubEncryptionKey[1:]
|
||||||
|
|
||||||
payload += toRipe # This hash will be checked by the receiver of the message to verify that toRipe belongs to them. This prevents a Surreptitious Forwarding Attack.
|
|
||||||
payload += '\x02' # Type 2 is simple UTF-8 message encoding as specified on the Protocol Specification on the Bitmessage Wiki.
|
|
||||||
messageToTransmit = 'Subject:' + \
|
|
||||||
subject + '\n' + 'Body:' + message
|
|
||||||
payload += encodeVarint(len(messageToTransmit))
|
|
||||||
payload += messageToTransmit
|
|
||||||
fullAckPayload = self.generateFullAckMessage(
|
|
||||||
ackdata, toStreamNumber) # The fullAckPayload is a normal msg protocol message with the proof of work already completed that the receiver of this message can easily send out.
|
|
||||||
payload += encodeVarint(len(fullAckPayload))
|
|
||||||
payload += fullAckPayload
|
|
||||||
if int(time.time()) < 1416175200: # Sun, 16 Nov 2014 22:00:00 GMT
|
|
||||||
dataToSign = payload
|
|
||||||
else:
|
|
||||||
dataToSign = pack('>Q', embeddedTime) + '\x00\x00\x00\x02' + encodeVarint(1) + encodeVarint(toStreamNumber) + payload
|
|
||||||
signature = highlevelcrypto.sign(dataToSign, privSigningKeyHex)
|
|
||||||
payload += encodeVarint(len(signature))
|
|
||||||
payload += signature
|
|
||||||
|
|
||||||
if fromAddressVersionNumber >= 3:
|
if fromAddressVersionNumber >= 3:
|
||||||
payload = ""
|
|
||||||
if int(time.time()) < 1416175200: # Sun, 16 Nov 2014 22:00:00 GMT
|
|
||||||
payload += '\x01' # Message version.
|
|
||||||
payload += encodeVarint(fromAddressVersionNumber)
|
|
||||||
payload += encodeVarint(fromStreamNumber)
|
|
||||||
payload += '\x00\x00\x00\x01' # Bitfield of features and behaviors that can be expected from me. (See https://bitmessage.org/wiki/Protocol_specification#Pubkey_bitfield_features )
|
|
||||||
|
|
||||||
# We need to convert our private keys to public keys in order
|
|
||||||
# to include them.
|
|
||||||
try:
|
|
||||||
privSigningKeyBase58 = shared.config.get(
|
|
||||||
fromaddress, 'privsigningkey')
|
|
||||||
privEncryptionKeyBase58 = shared.config.get(
|
|
||||||
fromaddress, 'privencryptionkey')
|
|
||||||
except:
|
|
||||||
shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (
|
|
||||||
ackdata, tr.translateText("MainWindow", "Error! Could not find sender address (your address) in the keys.dat file."))))
|
|
||||||
continue
|
|
||||||
|
|
||||||
privSigningKeyHex = shared.decodeWalletImportFormat(
|
|
||||||
privSigningKeyBase58).encode('hex')
|
|
||||||
privEncryptionKeyHex = shared.decodeWalletImportFormat(
|
|
||||||
privEncryptionKeyBase58).encode('hex')
|
|
||||||
|
|
||||||
pubSigningKey = highlevelcrypto.privToPub(
|
|
||||||
privSigningKeyHex).decode('hex')
|
|
||||||
pubEncryptionKey = highlevelcrypto.privToPub(
|
|
||||||
privEncryptionKeyHex).decode('hex')
|
|
||||||
|
|
||||||
payload += pubSigningKey[
|
|
||||||
1:] # The \x04 on the beginning of the public keys are not sent. This way there is only one acceptable way to encode and send a public key.
|
|
||||||
payload += pubEncryptionKey[1:]
|
|
||||||
# If the receiver of our message is in our address book,
|
# If the receiver of our message is in our address book,
|
||||||
# subscriptions list, or whitelist then we will allow them to
|
# subscriptions list, or whitelist then we will allow them to
|
||||||
# do the network-minimum proof of work. Let us check to see if
|
# do the network-minimum proof of work. Let us check to see if
|
||||||
|
@ -840,34 +737,30 @@ class singleWorker(threading.Thread):
|
||||||
payload += encodeVarint(shared.config.getint(
|
payload += encodeVarint(shared.config.getint(
|
||||||
fromaddress, 'payloadlengthextrabytes'))
|
fromaddress, 'payloadlengthextrabytes'))
|
||||||
|
|
||||||
payload += toRipe # This hash will be checked by the receiver of the message to verify that toRipe belongs to them. This prevents a Surreptitious Forwarding Attack.
|
payload += toRipe # This hash will be checked by the receiver of the message to verify that toRipe belongs to them. This prevents a Surreptitious Forwarding Attack.
|
||||||
payload += '\x02' # Type 2 is simple UTF-8 message encoding as specified on the Protocol Specification on the Bitmessage Wiki.
|
payload += '\x02' # Type 2 is simple UTF-8 message encoding as specified on the Protocol Specification on the Bitmessage Wiki.
|
||||||
messageToTransmit = 'Subject:' + \
|
messageToTransmit = 'Subject:' + \
|
||||||
subject + '\n' + 'Body:' + message
|
subject + '\n' + 'Body:' + message
|
||||||
payload += encodeVarint(len(messageToTransmit))
|
payload += encodeVarint(len(messageToTransmit))
|
||||||
payload += messageToTransmit
|
payload += messageToTransmit
|
||||||
if shared.config.has_section(toaddress):
|
if shared.config.has_section(toaddress):
|
||||||
with shared.printLock:
|
with shared.printLock:
|
||||||
print 'Not bothering to include ackdata because we are sending to ourselves or a chan.'
|
print 'Not bothering to include ackdata because we are sending to ourselves or a chan.'
|
||||||
fullAckPayload = ''
|
fullAckPayload = ''
|
||||||
elif not shared.isBitSetWithinBitfield(behaviorBitfield,31):
|
elif not shared.isBitSetWithinBitfield(behaviorBitfield,31):
|
||||||
with shared.printLock:
|
with shared.printLock:
|
||||||
print 'Not bothering to include ackdata because the receiver said that they won\'t relay it anyway.'
|
print 'Not bothering to include ackdata because the receiver said that they won\'t relay it anyway.'
|
||||||
fullAckPayload = ''
|
fullAckPayload = ''
|
||||||
else:
|
else:
|
||||||
fullAckPayload = self.generateFullAckMessage(
|
fullAckPayload = self.generateFullAckMessage(
|
||||||
ackdata, toStreamNumber) # The fullAckPayload is a normal msg protocol message with the proof of work already completed that the receiver of this message can easily send out.
|
ackdata, toStreamNumber) # The fullAckPayload is a normal msg protocol message with the proof of work already completed that the receiver of this message can easily send out.
|
||||||
payload += encodeVarint(len(fullAckPayload))
|
payload += encodeVarint(len(fullAckPayload))
|
||||||
payload += fullAckPayload
|
payload += fullAckPayload
|
||||||
if int(time.time()) < 1416175200: # Sun, 16 Nov 2014 22:00:00 GMT
|
dataToSign = pack('>Q', embeddedTime) + '\x00\x00\x00\x02' + encodeVarint(1) + encodeVarint(toStreamNumber) + payload
|
||||||
dataToSign = payload
|
signature = highlevelcrypto.sign(dataToSign, privSigningKeyHex)
|
||||||
else:
|
payload += encodeVarint(len(signature))
|
||||||
dataToSign = pack('>Q', embeddedTime) + '\x00\x00\x00\x02' + encodeVarint(1) + encodeVarint(toStreamNumber) + payload
|
payload += signature
|
||||||
signature = highlevelcrypto.sign(dataToSign, privSigningKeyHex)
|
|
||||||
payload += encodeVarint(len(signature))
|
|
||||||
payload += signature
|
|
||||||
|
|
||||||
print 'using pubEncryptionKey:', pubEncryptionKeyBase256.encode('hex')
|
|
||||||
# We have assembled the data that will be encrypted.
|
# We have assembled the data that will be encrypted.
|
||||||
try:
|
try:
|
||||||
encrypted = highlevelcrypto.encrypt(payload,"04"+pubEncryptionKeyBase256.encode('hex'))
|
encrypted = highlevelcrypto.encrypt(payload,"04"+pubEncryptionKeyBase256.encode('hex'))
|
||||||
|
@ -878,8 +771,7 @@ class singleWorker(threading.Thread):
|
||||||
|
|
||||||
encryptedPayload = pack('>Q', embeddedTime)
|
encryptedPayload = pack('>Q', embeddedTime)
|
||||||
encryptedPayload += '\x00\x00\x00\x02' # object type: msg
|
encryptedPayload += '\x00\x00\x00\x02' # object type: msg
|
||||||
if int(time.time()) >= 1416175200: # Sun, 16 Nov 2014 22:00:00 GMT
|
encryptedPayload += encodeVarint(1) # msg version
|
||||||
encryptedPayload += encodeVarint(1) # msg version
|
|
||||||
encryptedPayload += encodeVarint(toStreamNumber) + encrypted
|
encryptedPayload += encodeVarint(toStreamNumber) + encrypted
|
||||||
target = 2 ** 64 / (requiredAverageProofOfWorkNonceTrialsPerByte*(len(encryptedPayload) + 8 + requiredPayloadLengthExtraBytes + ((TTL*(len(encryptedPayload)+8+requiredPayloadLengthExtraBytes))/(2 ** 16))))
|
target = 2 ** 64 / (requiredAverageProofOfWorkNonceTrialsPerByte*(len(encryptedPayload) + 8 + requiredPayloadLengthExtraBytes + ((TTL*(len(encryptedPayload)+8+requiredPayloadLengthExtraBytes))/(2 ** 16))))
|
||||||
with shared.printLock:
|
with shared.printLock:
|
||||||
|
@ -1019,8 +911,7 @@ class singleWorker(threading.Thread):
|
||||||
embeddedTime = int(time.time() + TTL)
|
embeddedTime = int(time.time() + TTL)
|
||||||
payload = pack('>Q', (embeddedTime))
|
payload = pack('>Q', (embeddedTime))
|
||||||
payload += '\x00\x00\x00\x02' # object type: msg
|
payload += '\x00\x00\x00\x02' # object type: msg
|
||||||
if int(time.time()) >= 1416175200: # Sun, 16 Nov 2014 22:00:00 GMT
|
payload += encodeVarint(1) # msg version
|
||||||
payload += encodeVarint(1) # msg version
|
|
||||||
payload += encodeVarint(toStreamNumber) + ackdata
|
payload += encodeVarint(toStreamNumber) + ackdata
|
||||||
|
|
||||||
target = 2 ** 64 / (shared.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + shared.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+shared.networkDefaultPayloadLengthExtraBytes))/(2 ** 16))))
|
target = 2 ** 64 / (shared.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + shared.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+shared.networkDefaultPayloadLengthExtraBytes))/(2 ** 16))))
|
||||||
|
|
|
@ -346,6 +346,28 @@ class sqlThread(threading.Thread):
|
||||||
shared.config.set('bitmessagesettings', 'settingsversion', '10')
|
shared.config.set('bitmessagesettings', 'settingsversion', '10')
|
||||||
with open(shared.appdata + 'keys.dat', 'wb') as configfile:
|
with open(shared.appdata + 'keys.dat', 'wb') as configfile:
|
||||||
shared.config.write(configfile)
|
shared.config.write(configfile)
|
||||||
|
|
||||||
|
|
||||||
|
# The format of data stored in the pubkeys table has changed. Let's
|
||||||
|
# clear it, and the pubkeys from inventory, so that they'll be re-downloaded.
|
||||||
|
item = '''SELECT value FROM settings WHERE key='version';'''
|
||||||
|
parameters = ''
|
||||||
|
self.cur.execute(item, parameters)
|
||||||
|
currentVersion = int(self.cur.fetchall()[0][0])
|
||||||
|
if currentVersion == 7:
|
||||||
|
logger.debug('In messages.dat database, clearing pubkeys table because the data format has been updated.')
|
||||||
|
self.cur.execute(
|
||||||
|
'''delete from inventory where objecttype = 1;''')
|
||||||
|
self.cur.execute(
|
||||||
|
'''delete from pubkeys;''')
|
||||||
|
# Any sending messages for which we *thought* that we had the pubkey must
|
||||||
|
# be rechecked.
|
||||||
|
self.cur.execute(
|
||||||
|
'''UPDATE sent SET status='msgqueued' WHERE status='doingmsgpow' or status='badkey';''')
|
||||||
|
query = '''update settings set value=? WHERE key='version';'''
|
||||||
|
parameters = (8,)
|
||||||
|
self.cur.execute(query, parameters)
|
||||||
|
logger.debug('Finished clearing currently held pubkeys.')
|
||||||
|
|
||||||
|
|
||||||
# Are you hoping to add a new option to the keys.dat file of existing
|
# Are you hoping to add a new option to the keys.dat file of existing
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
from hashlib import sha512
|
from hashlib import sha512
|
||||||
from pyelliptic.openssl import OpenSSL
|
from pyelliptic.openssl import OpenSSL
|
||||||
from pyelliptic.cipher import Cipher
|
from pyelliptic.cipher import Cipher
|
||||||
from pyelliptic.hash import hmac_sha256
|
from pyelliptic.hash import hmac_sha256, equals
|
||||||
from struct import pack, unpack
|
from struct import pack, unpack
|
||||||
|
|
||||||
|
|
||||||
|
@ -436,16 +436,9 @@ class ECC:
|
||||||
pubkey = ephem.get_pubkey()
|
pubkey = ephem.get_pubkey()
|
||||||
iv = OpenSSL.rand(OpenSSL.get_cipher(ciphername).get_blocksize())
|
iv = OpenSSL.rand(OpenSSL.get_cipher(ciphername).get_blocksize())
|
||||||
ctx = Cipher(key_e, iv, 1, ciphername)
|
ctx = Cipher(key_e, iv, 1, ciphername)
|
||||||
import time
|
ciphertext = iv + pubkey + ctx.ciphering(data)
|
||||||
if int(time.time()) < 1416175200: # Sun, 16 Nov 2014 22:00:00 GMT
|
|
||||||
ciphertext = ctx.ciphering(data)
|
|
||||||
else:
|
|
||||||
ciphertext = iv + pubkey + ctx.ciphering(data) # Everyone should be using this line after the Bitmessage protocol v3 upgrade period
|
|
||||||
mac = hmac_sha256(key_m, ciphertext)
|
mac = hmac_sha256(key_m, ciphertext)
|
||||||
if int(time.time()) < 1416175200: # Sun, 16 Nov 2014 22:00:00 GMT
|
return ciphertext + mac
|
||||||
return iv + pubkey + ciphertext + mac
|
|
||||||
else:
|
|
||||||
return ciphertext + mac # Everyone should be using this line after the Bitmessage protocol v3 upgrade period
|
|
||||||
|
|
||||||
def decrypt(self, data, ciphername='aes-256-cbc'):
|
def decrypt(self, data, ciphername='aes-256-cbc'):
|
||||||
"""
|
"""
|
||||||
|
@ -461,14 +454,7 @@ class ECC:
|
||||||
mac = data[i:]
|
mac = data[i:]
|
||||||
key = sha512(self.raw_get_ecdh_key(pubkey_x, pubkey_y)).digest()
|
key = sha512(self.raw_get_ecdh_key(pubkey_x, pubkey_y)).digest()
|
||||||
key_e, key_m = key[:32], key[32:]
|
key_e, key_m = key[:32], key[32:]
|
||||||
"""
|
if not equals(hmac_sha256(key_m, data[:len(data) - 32]), mac):
|
||||||
pyelliptic was changed slightly so that the hmac covers the
|
raise RuntimeError("Fail to verify data")
|
||||||
iv and pubkey. So let's have an upgrade period where we support
|
|
||||||
both the old and the new hmac'ing algorithms.
|
|
||||||
https://github.com/yann2192/pyelliptic/issues/17
|
|
||||||
"""
|
|
||||||
if hmac_sha256(key_m, ciphertext) != mac:
|
|
||||||
if hmac_sha256(key_m, data[:len(data) - 32]) != mac:
|
|
||||||
raise RuntimeError("Fail to verify data")
|
|
||||||
ctx = Cipher(key_e, iv, 0, ciphername)
|
ctx = Cipher(key_e, iv, 0, ciphername)
|
||||||
return ctx.ciphering(ciphertext)
|
return ctx.ciphering(ciphertext)
|
||||||
|
|
|
@ -7,6 +7,32 @@
|
||||||
from pyelliptic.openssl import OpenSSL
|
from pyelliptic.openssl import OpenSSL
|
||||||
|
|
||||||
|
|
||||||
|
# For python3
|
||||||
|
def _equals_bytes(a, b):
|
||||||
|
if len(a) != len(b):
|
||||||
|
return False
|
||||||
|
result = 0
|
||||||
|
for x, y in zip(a, b):
|
||||||
|
result |= x ^ y
|
||||||
|
return result == 0
|
||||||
|
|
||||||
|
|
||||||
|
def _equals_str(a, b):
|
||||||
|
if len(a) != len(b):
|
||||||
|
return False
|
||||||
|
result = 0
|
||||||
|
for x, y in zip(a, b):
|
||||||
|
result |= ord(x) ^ ord(y)
|
||||||
|
return result == 0
|
||||||
|
|
||||||
|
|
||||||
|
def equals(a, b):
|
||||||
|
if isinstance(a, str):
|
||||||
|
return _equals_str(a, b)
|
||||||
|
else:
|
||||||
|
return _equals_bytes(a, b)
|
||||||
|
|
||||||
|
|
||||||
def hmac_sha256(k, m):
|
def hmac_sha256(k, m):
|
||||||
"""
|
"""
|
||||||
Compute the key and the message with HMAC SHA5256
|
Compute the key and the message with HMAC SHA5256
|
||||||
|
|
|
@ -472,20 +472,10 @@ def isBitSetWithinBitfield(fourByteString, n):
|
||||||
|
|
||||||
def decryptAndCheckPubkeyPayload(data, address):
|
def decryptAndCheckPubkeyPayload(data, address):
|
||||||
"""
|
"""
|
||||||
With the changes in protocol v3, to maintain backwards compatibility, signatures will be sent
|
Version 4 pubkeys are encrypted. This function is run when we already have the
|
||||||
the 'old' way during an upgrade period and then a 'new' simpler way after that. We will therefore
|
address to which we want to try to send a message. The 'data' may come either
|
||||||
check the sig both ways.
|
off of the wire or we might have had it already in our inventory when we tried
|
||||||
Old way:
|
to send a msg to this particular address.
|
||||||
signedData = timePubkeyWasSigned(8 bytes) + addressVersion + streamNumber + the decrypted data down through the payloadLengthExtraBytes
|
|
||||||
New way:
|
|
||||||
signedData = all of the payload data from the time to the tag + the decrypted data down through the payloadLengthExtraBytes
|
|
||||||
|
|
||||||
The timePubkeyWasSigned will be calculated by subtracting 28 days form the embedded expiresTime.
|
|
||||||
"""
|
|
||||||
|
|
||||||
"""
|
|
||||||
The time, address version, and stream number are not encrypted so let's
|
|
||||||
keep that data here for now.
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
status, addressVersion, streamNumber, ripe = decodeAddress(address)
|
status, addressVersion, streamNumber, ripe = decodeAddress(address)
|
||||||
|
@ -495,6 +485,7 @@ def decryptAndCheckPubkeyPayload(data, address):
|
||||||
readPosition += varintLength
|
readPosition += varintLength
|
||||||
embeddedStreamNumber, varintLength = decodeVarint(data[readPosition:readPosition + 10])
|
embeddedStreamNumber, varintLength = decodeVarint(data[readPosition:readPosition + 10])
|
||||||
readPosition += varintLength
|
readPosition += varintLength
|
||||||
|
storedData = data[20:readPosition] # We'll store the address version and stream number (and some more) in the pubkeys table.
|
||||||
|
|
||||||
if addressVersion != embeddedAddressVersion:
|
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.')
|
||||||
|
@ -503,16 +494,9 @@ def decryptAndCheckPubkeyPayload(data, address):
|
||||||
logger.info('Pubkey decryption was UNsuccessful due to stream number mismatch.')
|
logger.info('Pubkey decryption was UNsuccessful due to stream number mismatch.')
|
||||||
return 'failed'
|
return 'failed'
|
||||||
|
|
||||||
expiresTime, = unpack('>Q', data[8:16])
|
|
||||||
TTL = 28 * 24 * 60 * 60
|
|
||||||
signedDataOldMethod = pack('>Q', (expiresTime - TTL)) # the time that the pubkey was signed. 8 bytes.
|
|
||||||
signedDataOldMethod += data[20:readPosition] # the address version and stream number
|
|
||||||
|
|
||||||
tag = data[readPosition:readPosition + 32]
|
tag = data[readPosition:readPosition + 32]
|
||||||
readPosition += 32
|
readPosition += 32
|
||||||
|
signedData = data[8:readPosition] # the time through the tag. More data is appended onto signedData below after the decryption.
|
||||||
signedDataNewMethod = data[8:readPosition] # the time through the tag
|
|
||||||
|
|
||||||
encryptedData = data[readPosition:]
|
encryptedData = data[readPosition:]
|
||||||
|
|
||||||
# Let us try to decrypt the pubkey
|
# Let us try to decrypt the pubkey
|
||||||
|
@ -520,7 +504,7 @@ def decryptAndCheckPubkeyPayload(data, address):
|
||||||
if toAddress != address:
|
if toAddress != address:
|
||||||
logger.critical('decryptAndCheckPubkeyPayload failed due to toAddress mismatch. This is very peculiar. toAddress: %s, address %s' % (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.
|
# 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 prevented earlier.
|
# That sort of address-malleability should have been caught by the UI or API and an error given to the user.
|
||||||
return 'failed'
|
return 'failed'
|
||||||
try:
|
try:
|
||||||
decryptedData = cryptorObject.decrypt(encryptedData)
|
decryptedData = cryptorObject.decrypt(encryptedData)
|
||||||
|
@ -543,23 +527,18 @@ def decryptAndCheckPubkeyPayload(data, address):
|
||||||
specifiedPayloadLengthExtraBytes, specifiedPayloadLengthExtraBytesLength = decodeVarint(
|
specifiedPayloadLengthExtraBytes, specifiedPayloadLengthExtraBytesLength = decodeVarint(
|
||||||
decryptedData[readPosition:readPosition + 10])
|
decryptedData[readPosition:readPosition + 10])
|
||||||
readPosition += specifiedPayloadLengthExtraBytesLength
|
readPosition += specifiedPayloadLengthExtraBytesLength
|
||||||
signedDataOldMethod += decryptedData[:readPosition]
|
storedData += decryptedData[:readPosition]
|
||||||
signedDataNewMethod += decryptedData[:readPosition]
|
signedData += decryptedData[:readPosition]
|
||||||
signatureLength, signatureLengthLength = decodeVarint(
|
signatureLength, signatureLengthLength = decodeVarint(
|
||||||
decryptedData[readPosition:readPosition + 10])
|
decryptedData[readPosition:readPosition + 10])
|
||||||
readPosition += signatureLengthLength
|
readPosition += signatureLengthLength
|
||||||
signature = decryptedData[readPosition:readPosition + signatureLength]
|
signature = decryptedData[readPosition:readPosition + signatureLength]
|
||||||
|
|
||||||
if highlevelcrypto.verify(signedDataOldMethod, signature, publicSigningKey.encode('hex')):
|
if highlevelcrypto.verify(signedData, signature, publicSigningKey.encode('hex')):
|
||||||
logger.info('ECDSA verify passed (within decryptAndCheckPubkeyPayload, old method)')
|
logger.info('ECDSA verify passed (within decryptAndCheckPubkeyPayload)')
|
||||||
else:
|
else:
|
||||||
logger.info('ECDSA verify failed (within decryptAndCheckPubkeyPayload, old method)')
|
logger.info('ECDSA verify failed (within decryptAndCheckPubkeyPayload)')
|
||||||
# Try the protocol v3 signing method
|
return 'failed'
|
||||||
if highlevelcrypto.verify(signedDataNewMethod, signature, publicSigningKey.encode('hex')):
|
|
||||||
logger.info('ECDSA verify passed (within decryptAndCheckPubkeyPayload, new method)')
|
|
||||||
else:
|
|
||||||
logger.info('ECDSA verify failed (within decryptAndCheckPubkeyPayload, new method)')
|
|
||||||
return 'failed'
|
|
||||||
|
|
||||||
sha = hashlib.new('sha512')
|
sha = hashlib.new('sha512')
|
||||||
sha.update(publicSigningKey + publicEncryptionKey)
|
sha.update(publicSigningKey + publicEncryptionKey)
|
||||||
|
@ -570,7 +549,7 @@ def decryptAndCheckPubkeyPayload(data, address):
|
||||||
if embeddedRipe != ripe:
|
if embeddedRipe != ripe:
|
||||||
# Although this pubkey object had the tag were were looking for and was
|
# Although this pubkey object had the tag were were looking for and was
|
||||||
# encrypted with the correct encryption key, it doesn't contain the
|
# encrypted with the correct encryption key, it doesn't contain the
|
||||||
# correct keys. Someone is either being malicious or using buggy software.
|
# correct pubkeys. Someone is either being malicious or using buggy software.
|
||||||
logger.info('Pubkey decryption was UNsuccessful due to RIPE mismatch.')
|
logger.info('Pubkey decryption was UNsuccessful due to RIPE mismatch.')
|
||||||
return 'failed'
|
return 'failed'
|
||||||
|
|
||||||
|
@ -587,7 +566,7 @@ def decryptAndCheckPubkeyPayload(data, address):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
t = (ripe, addressVersion, signedDataOldMethod, int(time.time()), 'yes')
|
t = (ripe, addressVersion, storedData, int(time.time()), 'yes')
|
||||||
sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', *t)
|
sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', *t)
|
||||||
return 'successful'
|
return 'successful'
|
||||||
except varintDecodeError as e:
|
except varintDecodeError as e:
|
||||||
|
|
Reference in New Issue
Block a user