PyBitmessage/src/class_singleWorker.py

1459 lines
65 KiB
Python
Raw Normal View History

"""
src/class_singleWorker.py
=========================
"""
# pylint: disable=protected-access,too-many-branches,too-many-statements,no-self-use,too-many-lines,too-many-locals
2015-01-21 17:38:25 +00:00
from __future__ import division
2017-09-21 15:24:51 +00:00
import hashlib
import time
from binascii import hexlify, unhexlify
2017-09-21 15:24:51 +00:00
from struct import pack
2018-05-02 15:29:55 +00:00
from subprocess import call # nosec
2017-09-21 15:24:51 +00:00
import defaults
import helper_inbox
import helper_msgcoding
import helper_random
import highlevelcrypto
import l10n
import proofofwork
import protocol
import queues
2017-09-21 15:24:51 +00:00
import shared
import state
import tr
from addresses import calculateInventoryHash, decodeAddress, decodeVarint, encodeVarint
2017-09-21 15:24:51 +00:00
from bmconfigparser import BMConfigParser
from debug import logger
from helper_sql import sqlExecute, sqlQuery
2017-09-21 15:24:51 +00:00
from helper_threading import StoppableThread
from inventory import Inventory
def sizeof_fmt(num, suffix='h/s'):
"""Format hashes per seconds nicely (SI prefix)"""
2017-09-21 15:24:51 +00:00
for unit in ['', 'k', 'M', 'G', 'T', 'P', 'E', 'Z']:
if abs(num) < 1000.0:
return "%3.1f%s%s" % (num, unit, suffix)
num /= 1024.0
return "%.1f%s%s" % (num, 'Yi', suffix)
2017-09-21 15:24:51 +00:00
class singleWorker(StoppableThread):
"""Thread for performing PoW"""
def __init__(self):
super(singleWorker, self).__init__(name="singleWorker")
proofofwork.init()
def stopThread(self):
"""Signal through the queue that the thread should be stopped"""
try:
queues.workerQueue.put(("stopThread", "data"))
except:
pass
super(singleWorker, self).stopThread()
def run(self):
# pylint: disable=attribute-defined-outside-init
while not state.sqlReady and state.shutdown == 0:
self.stop.wait(2)
if state.shutdown > 0:
return
2017-09-21 15:24:51 +00:00
2015-03-09 06:35:32 +00:00
# Initialize the neededPubkeys dictionary.
2013-08-29 11:27:30 +00:00
queryreturn = sqlQuery(
2017-09-21 15:24:51 +00:00
'''SELECT DISTINCT toaddress FROM sent'''
''' WHERE (status='awaitingpubkey' AND folder='sent')''')
for row in queryreturn:
2014-08-27 07:14:32 +00:00
toAddress, = row
2018-03-22 11:23:36 +00:00
# toStatus
_, toAddressVersionNumber, toStreamNumber, toRipe = \
2017-09-21 15:24:51 +00:00
decodeAddress(toAddress)
if toAddressVersionNumber <= 3:
state.neededPubkeys[toAddress] = 0
elif toAddressVersionNumber >= 4:
2017-09-21 15:24:51 +00:00
doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(
encodeVarint(toAddressVersionNumber) +
encodeVarint(toStreamNumber) + toRipe
).digest()).digest()
# Note that this is the first half of the sha512 hash.
privEncryptionKey = doubleHashOfAddressData[:32]
2013-09-15 01:06:26 +00:00
tag = doubleHashOfAddressData[32:]
2017-09-21 15:24:51 +00:00
# We'll need this for when we receive a pubkey reply:
# it will be encrypted and we'll need to decrypt it.
state.neededPubkeys[tag] = (
toAddress,
highlevelcrypto.makeCryptor(
hexlify(privEncryptionKey))
)
2014-08-27 07:14:32 +00:00
# Initialize the shared.ackdataForWhichImWatching data structure
2013-08-29 11:27:30 +00:00
queryreturn = sqlQuery(
'''SELECT ackdata FROM sent WHERE status = 'msgsent' ''')
for row in queryreturn:
ackdata, = row
logger.info('Watching for ackdata %s', hexlify(ackdata))
shared.ackdataForWhichImWatching[ackdata] = 0
2017-09-30 09:19:44 +00:00
# Fix legacy (headerless) watched ackdata to include header
for oldack in shared.ackdataForWhichImWatching:
if len(oldack) == 32:
2017-09-30 09:19:44 +00:00
# attach legacy header, always constant (msg/1/1)
newack = '\x00\x00\x00\x02\x01\x01' + oldack
shared.ackdataForWhichImWatching[newack] = 0
2017-09-21 15:24:51 +00:00
sqlExecute(
'UPDATE sent SET ackdata=? WHERE ackdata=?',
newack, oldack
)
2017-09-30 09:19:44 +00:00
del shared.ackdataForWhichImWatching[oldack]
2017-09-21 15:24:51 +00:00
# give some time for the GUI to start
# before we start on existing POW tasks.
self.stop.wait(10)
2015-03-09 06:35:32 +00:00
2019-05-10 06:03:29 +00:00
if state.shutdown:
return
# just in case there are any pending tasks for msg
# messages that have yet to be sent.
queues.workerQueue.put(('sendmessage', ''))
# just in case there are any tasks for Broadcasts
# that have yet to be sent.
queues.workerQueue.put(('sendbroadcast', ''))
# send onionpeer object
queues.workerQueue.put(('sendOnionPeerObj', ''))
while state.shutdown == 0:
self.busy = 0
command, data = queues.workerQueue.get()
self.busy = 1
if command == 'sendmessage':
try:
self.sendMsg()
except:
pass
elif command == 'sendbroadcast':
try:
self.sendBroadcast()
except:
pass
elif command == 'doPOWForMyV2Pubkey':
try:
self.doPOWForMyV2Pubkey(data)
except:
pass
2013-07-22 05:10:22 +00:00
elif command == 'sendOutOrStoreMyV3Pubkey':
try:
self.sendOutOrStoreMyV3Pubkey(data)
except:
pass
elif command == 'sendOutOrStoreMyV4Pubkey':
try:
self.sendOutOrStoreMyV4Pubkey(data)
except:
pass
elif command == 'sendOnionPeerObj':
try:
self.sendOnionPeerObj(data)
except:
pass
elif command == 'resetPoW':
try:
proofofwork.resetPoW()
except:
pass
elif command == 'stopThread':
self.busy = 0
return
else:
2017-09-21 15:24:51 +00:00
logger.error(
'Probable programming error: The command sent'
' to the workerThread is weird. It is: %s\n',
command
)
queues.workerQueue.task_done()
logger.info("Quitting...")
def _getKeysForAddress(self, address):
privSigningKeyBase58 = BMConfigParser().get(
address, 'privsigningkey')
privEncryptionKeyBase58 = BMConfigParser().get(
address, 'privencryptionkey')
privSigningKeyHex = hexlify(shared.decodeWalletImportFormat(
privSigningKeyBase58))
privEncryptionKeyHex = hexlify(shared.decodeWalletImportFormat(
privEncryptionKeyBase58))
# 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.
pubSigningKey = unhexlify(highlevelcrypto.privToPub(
privSigningKeyHex))[1:]
pubEncryptionKey = unhexlify(highlevelcrypto.privToPub(
privEncryptionKeyHex))[1:]
return privSigningKeyHex, privEncryptionKeyHex, \
pubSigningKey, pubEncryptionKey
def _doPOWDefaults(self, payload, TTL,
log_prefix='',
log_time=False):
target = 2 ** 64 / (
defaults.networkDefaultProofOfWorkNonceTrialsPerByte * (
len(payload) + 8 +
defaults.networkDefaultPayloadLengthExtraBytes + ((
TTL * (
len(payload) + 8 +
defaults.networkDefaultPayloadLengthExtraBytes
)) / (2 ** 16))
))
initialHash = hashlib.sha512(payload).digest()
logger.info(
'%s Doing proof of work... TTL set to %s', log_prefix, TTL)
if log_time:
start_time = time.time()
trialValue, nonce = proofofwork.run(target, initialHash)
logger.info(
'%s Found proof of work %s Nonce: %s',
log_prefix, trialValue, nonce
)
try:
delta = time.time() - start_time
logger.info(
'PoW took %.1f seconds, speed %s.',
delta, sizeof_fmt(nonce / delta)
)
except: # NameError
pass
payload = pack('>Q', nonce) + payload
# inventoryHash = calculateInventoryHash(payload)
return payload
2018-05-02 15:29:55 +00:00
def doPOWForMyV2Pubkey(self, adressHash):
""" This function also broadcasts out the pubkey message once it is done with the POW"""
# Look up my stream number based on my address hash
2018-05-02 15:29:55 +00:00
myAddress = shared.myAddressesByHash[adressHash]
2018-03-22 11:23:36 +00:00
# status
2018-05-02 15:29:55 +00:00
_, addressVersionNumber, streamNumber, adressHash = decodeAddress(myAddress)
2017-09-21 15:24:51 +00:00
# 28 days from now plus or minus five minutes
TTL = int(28 * 24 * 60 * 60 + helper_random.randomrandrange(-300, 300))
2014-11-13 21:32:31 +00:00
embeddedTime = int(time.time() + TTL)
2014-08-27 07:14:32 +00:00
payload = pack('>Q', (embeddedTime))
2017-09-21 15:24:51 +00:00
payload += '\x00\x00\x00\x01' # object type: pubkey
payload += encodeVarint(addressVersionNumber) # Address version number
payload += encodeVarint(streamNumber)
2017-09-21 15:24:51 +00:00
# bitfield of features supported by me (see the wiki).
payload += protocol.getBitfield(myAddress)
try:
# privSigningKeyHex, privEncryptionKeyHex
_, _, pubSigningKey, pubEncryptionKey = \
self._getKeysForAddress(myAddress)
except Exception as err:
2017-09-21 15:24:51 +00:00
logger.error(
'Error within doPOWForMyV2Pubkey. Could not read'
' the keys from the keys.dat file for a requested'
' address. %s\n', err
2017-09-21 15:24:51 +00:00
)
return
payload += pubSigningKey + pubEncryptionKey
# Do the POW for this pubkey message
payload = self._doPOWDefaults(
payload, TTL, log_prefix='(For pubkey message)')
inventoryHash = calculateInventoryHash(payload)
2014-08-27 07:14:32 +00:00
objectType = 1
Inventory()[inventoryHash] = (
2017-09-21 15:24:51 +00:00
objectType, streamNumber, payload, embeddedTime, '')
2017-09-21 15:24:51 +00:00
logger.info('broadcasting inv with hash: %s', hexlify(inventoryHash))
queues.invQueue.put((streamNumber, inventoryHash))
queues.UISignalQueue.put(('updateStatusBar', ''))
2013-11-07 04:38:19 +00:00
try:
BMConfigParser().set(
2013-11-07 04:38:19 +00:00
myAddress, 'lastpubkeysendtime', str(int(time.time())))
BMConfigParser().save()
2013-11-07 04:38:19 +00:00
except:
2017-09-21 15:24:51 +00:00
# The user deleted the address out of the keys.dat file
# before this finished.
2013-11-07 04:38:19 +00:00
pass
2018-05-02 15:29:55 +00:00
def sendOutOrStoreMyV3Pubkey(self, adressHash):
"""
If this isn't a chan address, this function assembles the pubkey data, does the necessary POW and sends it out.
If it *is* a chan then it assembles the pubkey and stores is in the pubkey table so that we can send messages
to "ourselves".
"""
2013-11-07 04:38:19 +00:00
try:
2018-05-02 15:29:55 +00:00
myAddress = shared.myAddressesByHash[adressHash]
2013-11-07 04:38:19 +00:00
except:
2017-09-21 15:24:51 +00:00
# The address has been deleted.
2013-11-07 04:38:19 +00:00
return
if BMConfigParser().safeGetBoolean(myAddress, 'chan'):
logger.info('This is a chan address. Not sending pubkey.')
2013-09-29 23:24:27 +00:00
return
2018-05-02 15:29:55 +00:00
_, addressVersionNumber, streamNumber, adressHash = decodeAddress(
myAddress)
# 28 days from now plus or minus five minutes
2017-09-21 15:24:51 +00:00
TTL = int(28 * 24 * 60 * 60 + helper_random.randomrandrange(-300, 300))
2014-11-13 21:32:31 +00:00
embeddedTime = int(time.time() + TTL)
2018-05-02 15:29:55 +00:00
2017-09-21 15:24:51 +00:00
# signedTimeForProtocolV2 = embeddedTime - TTL
2018-05-02 15:29:55 +00:00
# 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 with the
# expiresTime time.
2014-08-27 07:14:32 +00:00
payload = pack('>Q', (embeddedTime))
2017-09-21 15:24:51 +00:00
payload += '\x00\x00\x00\x01' # object type: pubkey
payload += encodeVarint(addressVersionNumber) # Address version number
payload += encodeVarint(streamNumber)
2017-09-21 15:24:51 +00:00
# bitfield of features supported by me (see the wiki).
payload += protocol.getBitfield(myAddress)
try:
2018-03-22 11:23:36 +00:00
# , privEncryptionKeyHex
privSigningKeyHex, _, pubSigningKey, pubEncryptionKey = \
self._getKeysForAddress(myAddress)
except Exception as err:
2017-09-21 15:24:51 +00:00
logger.error(
'Error within sendOutOrStoreMyV3Pubkey. Could not read'
' the keys from the keys.dat file for a requested'
' address. %s\n', err
2017-09-21 15:24:51 +00:00
)
return
payload += pubSigningKey + pubEncryptionKey
payload += encodeVarint(BMConfigParser().getint(
myAddress, 'noncetrialsperbyte'))
payload += encodeVarint(BMConfigParser().getint(
myAddress, 'payloadlengthextrabytes'))
2017-09-21 15:24:51 +00:00
2014-12-25 08:57:34 +00:00
signature = highlevelcrypto.sign(payload, privSigningKeyHex)
payload += encodeVarint(len(signature))
payload += signature
2013-09-29 23:24:27 +00:00
# Do the POW for this pubkey message
payload = self._doPOWDefaults(
payload, TTL, log_prefix='(For pubkey message)')
2013-09-29 23:24:27 +00:00
inventoryHash = calculateInventoryHash(payload)
2014-08-27 07:14:32 +00:00
objectType = 1
Inventory()[inventoryHash] = (
2017-09-21 15:24:51 +00:00
objectType, streamNumber, payload, embeddedTime, '')
logger.info('broadcasting inv with hash: %s', hexlify(inventoryHash))
queues.invQueue.put((streamNumber, inventoryHash))
queues.UISignalQueue.put(('updateStatusBar', ''))
2013-11-07 04:38:19 +00:00
try:
BMConfigParser().set(
2013-11-07 04:38:19 +00:00
myAddress, 'lastpubkeysendtime', str(int(time.time())))
BMConfigParser().save()
2013-11-07 04:38:19 +00:00
except:
# The user deleted the address out of the keys.dat file
# before this finished.
2013-11-07 04:38:19 +00:00
pass
def sendOutOrStoreMyV4Pubkey(self, myAddress):
"""
It doesn't send directly anymore. It put is to a queue for another thread to send at an appropriate time,
whereas in the past it directly appended it to the outgoing buffer, I think. Same with all the other methods in
this class.
"""
if not BMConfigParser().has_section(myAddress):
2017-09-21 15:24:51 +00:00
# The address has been deleted.
2013-11-07 04:38:19 +00:00
return
if shared.BMConfigParser().safeGetBoolean(myAddress, 'chan'):
logger.info('This is a chan address. Not sending pubkey.')
2013-09-29 23:24:27 +00:00
return
2018-05-02 15:29:55 +00:00
_, addressVersionNumber, streamNumber, addressHash = decodeAddress(
myAddress)
2017-09-21 15:24:51 +00:00
# 28 days from now plus or minus five minutes
2017-09-21 15:24:51 +00:00
TTL = int(28 * 24 * 60 * 60 + helper_random.randomrandrange(-300, 300))
2014-11-13 21:32:31 +00:00
embeddedTime = int(time.time() + TTL)
payload = pack('>Q', (embeddedTime))
2017-09-21 15:24:51 +00:00
payload += '\x00\x00\x00\x01' # object type: pubkey
payload += encodeVarint(addressVersionNumber) # Address version number
payload += encodeVarint(streamNumber)
dataToEncrypt = protocol.getBitfield(myAddress)
try:
2018-03-22 11:48:07 +00:00
# , privEncryptionKeyHex
privSigningKeyHex, _, pubSigningKey, pubEncryptionKey = \
self._getKeysForAddress(myAddress)
except Exception as err:
2017-09-21 15:24:51 +00:00
logger.error(
'Error within sendOutOrStoreMyV4Pubkey. Could not read'
' the keys from the keys.dat file for a requested'
' address. %s\n', err
2017-09-21 15:24:51 +00:00
)
return
dataToEncrypt += pubSigningKey + pubEncryptionKey
dataToEncrypt += encodeVarint(BMConfigParser().getint(
myAddress, 'noncetrialsperbyte'))
dataToEncrypt += encodeVarint(BMConfigParser().getint(
myAddress, 'payloadlengthextrabytes'))
2017-09-21 15:24:51 +00:00
2014-08-27 07:14:32 +00:00
# When we encrypt, we'll use a hash of the data
2017-09-21 15:24:51 +00:00
# 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 first. We'll also tag,
# unencrypted, the pubkey with part of the hash so that nodes
# know which pubkey object to try to decrypt
# when they want to send a message.
doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(
encodeVarint(addressVersionNumber) +
2018-05-02 15:29:55 +00:00
encodeVarint(streamNumber) + addressHash
2017-09-21 15:24:51 +00:00
).digest()).digest()
payload += doubleHashOfAddressData[32:] # the tag
signature = highlevelcrypto.sign(
payload + dataToEncrypt, privSigningKeyHex
)
2014-08-27 07:14:32 +00:00
dataToEncrypt += encodeVarint(len(signature))
dataToEncrypt += signature
2017-09-21 15:24:51 +00:00
2013-09-29 23:24:27 +00:00
privEncryptionKey = doubleHashOfAddressData[:32]
pubEncryptionKey = highlevelcrypto.pointMult(privEncryptionKey)
2013-09-29 23:24:27 +00:00
payload += highlevelcrypto.encrypt(
2016-03-23 22:26:57 +00:00
dataToEncrypt, hexlify(pubEncryptionKey))
2013-09-18 04:04:01 +00:00
2013-09-29 23:24:27 +00:00
# Do the POW for this pubkey message
payload = self._doPOWDefaults(
payload, TTL, log_prefix='(For pubkey message)')
2013-09-29 23:24:27 +00:00
inventoryHash = calculateInventoryHash(payload)
2014-08-27 07:14:32 +00:00
objectType = 1
Inventory()[inventoryHash] = (
2017-09-21 15:24:51 +00:00
objectType, streamNumber, payload, embeddedTime,
doubleHashOfAddressData[32:]
)
logger.info('broadcasting inv with hash: %s', hexlify(inventoryHash))
2013-09-18 04:04:01 +00:00
queues.invQueue.put((streamNumber, inventoryHash))
queues.UISignalQueue.put(('updateStatusBar', ''))
try:
BMConfigParser().set(
myAddress, 'lastpubkeysendtime', str(int(time.time())))
BMConfigParser().save()
except Exception as err:
2017-09-21 15:24:51 +00:00
logger.error(
'Error: Couldn\'t add the lastpubkeysendtime'
' to the keys.dat file. Error message: %s', err
2017-09-21 15:24:51 +00:00
)
def sendOnionPeerObj(self, peer=None):
2019-05-06 10:05:21 +00:00
"""Send onionpeer object representing peer"""
if not peer: # find own onionhostname
for peer in state.ownAddresses:
if peer.host.endswith('.onion'):
break
else:
return
TTL = int(7 * 24 * 60 * 60 + helper_random.randomrandrange(-300, 300))
embeddedTime = int(time.time() + TTL)
streamNumber = 1 # Don't know yet what should be here
objectType = protocol.OBJECT_ONIONPEER
# FIXME: ideally the objectPayload should be signed
objectPayload = encodeVarint(peer.port) + protocol.encodeHost(peer.host)
tag = calculateInventoryHash(objectPayload)
if Inventory().by_type_and_tag(objectType, tag):
return # not expired
2019-06-06 06:21:59 +00:00
payload = pack('>Q', embeddedTime)
payload += pack('>I', objectType)
payload += encodeVarint(2 if len(peer.host) == 22 else 3)
payload += encodeVarint(streamNumber)
payload += objectPayload
payload = self._doPOWDefaults(
payload, TTL, log_prefix='(For onionpeer object)')
inventoryHash = calculateInventoryHash(payload)
Inventory()[inventoryHash] = (
objectType, streamNumber, buffer(payload),
embeddedTime, buffer(tag)
)
logger.info(
'sending inv (within sendOnionPeerObj function) for object: %s',
hexlify(inventoryHash))
queues.invQueue.put((streamNumber, inventoryHash))
def sendBroadcast(self):
"""Send a broadcast-type object (assemble the object, perform PoW and put it to the inv announcement queue)"""
# Reset just in case
sqlExecute(
2017-09-21 15:24:51 +00:00
'''UPDATE sent SET status='broadcastqueued' '''
2018-05-02 15:29:55 +00:00
2017-09-21 15:24:51 +00:00
'''WHERE status = 'doingbroadcastpow' ''')
2013-08-29 11:27:30 +00:00
queryreturn = sqlQuery(
2017-09-21 15:24:51 +00:00
'''SELECT fromaddress, subject, message, '''
''' ackdata, ttl, encodingtype FROM sent '''
''' WHERE status=? and folder='sent' ''', 'broadcastqueued')
for row in queryreturn:
fromaddress, subject, body, ackdata, TTL, encoding = row
2018-03-22 11:23:36 +00:00
# status
_, addressVersionNumber, streamNumber, ripe = \
2017-09-21 15:24:51 +00:00
decodeAddress(fromaddress)
if addressVersionNumber <= 1:
2017-09-21 15:24:51 +00:00
logger.error(
'Error: In the singleWorker thread, the '
' sendBroadcast function doesn\'t understand'
' the address version.\n')
return
# We need to convert our private keys to public keys in order
# to include them.
try:
2018-03-22 11:48:07 +00:00
# , privEncryptionKeyHex
privSigningKeyHex, _, pubSigningKey, pubEncryptionKey = \
self._getKeysForAddress(fromaddress)
except:
2017-09-21 15:24:51 +00:00
queues.UISignalQueue.put((
'updateSentItemStatusByAckdata', (
ackdata,
tr._translate(
"MainWindow",
"Error! Could not find sender address"
" (your address) in the keys.dat file."))
))
continue
sqlExecute(
2017-09-21 15:24:51 +00:00
'''UPDATE sent SET status='doingbroadcastpow' '''
''' WHERE ackdata=? AND status='broadcastqueued' ''',
ackdata)
2017-09-21 15:24:51 +00:00
# At this time these pubkeys are 65 bytes long
# because they include the encoding byte which we won't
# be sending in the broadcast message.
# pubSigningKey = \
# highlevelcrypto.privToPub(privSigningKeyHex).decode('hex')
2015-03-09 06:35:32 +00:00
if TTL > 28 * 24 * 60 * 60:
TTL = 28 * 24 * 60 * 60
2017-09-21 15:24:51 +00:00
if TTL < 60 * 60:
TTL = 60 * 60
# add some randomness to the TTL
2017-09-21 15:24:51 +00:00
TTL = int(TTL + helper_random.randomrandrange(-300, 300))
2014-11-13 21:32:31 +00:00
embeddedTime = int(time.time() + TTL)
2014-08-27 07:14:32 +00:00
payload = pack('>Q', embeddedTime)
2017-09-21 15:24:51 +00:00
payload += '\x00\x00\x00\x03' # object type: broadcast
2014-12-25 08:57:34 +00:00
if addressVersionNumber <= 3:
payload += encodeVarint(4) # broadcast version
else:
payload += encodeVarint(5) # broadcast version
2017-09-21 15:24:51 +00:00
payload += encodeVarint(streamNumber)
2013-09-15 01:06:26 +00:00
if addressVersionNumber >= 4:
2017-09-21 15:24:51 +00:00
doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(
encodeVarint(addressVersionNumber) +
encodeVarint(streamNumber) + ripe
).digest()).digest()
tag = doubleHashOfAddressData[32:]
payload += tag
else:
tag = ''
2014-12-25 08:57:34 +00:00
dataToEncrypt = encodeVarint(addressVersionNumber)
dataToEncrypt += encodeVarint(streamNumber)
2017-09-21 15:24:51 +00:00
# behavior bitfield
dataToEncrypt += protocol.getBitfield(fromaddress)
dataToEncrypt += pubSigningKey + pubEncryptionKey
if addressVersionNumber >= 3:
2017-09-21 15:24:51 +00:00
dataToEncrypt += encodeVarint(BMConfigParser().getint(
fromaddress, 'noncetrialsperbyte'))
dataToEncrypt += encodeVarint(BMConfigParser().getint(
fromaddress, 'payloadlengthextrabytes'))
# message encoding type
dataToEncrypt += encodeVarint(encoding)
encodedMessage = helper_msgcoding.MsgEncode(
{"subject": subject, "body": body}, encoding)
dataToEncrypt += encodeVarint(encodedMessage.length)
dataToEncrypt += encodedMessage.data
2014-12-25 08:57:34 +00:00
dataToSign = payload + dataToEncrypt
2017-09-21 15:24:51 +00:00
signature = highlevelcrypto.sign(
2014-08-27 07:14:32 +00:00
dataToSign, privSigningKeyHex)
dataToEncrypt += encodeVarint(len(signature))
dataToEncrypt += signature
2017-09-21 15:24:51 +00:00
# Encrypt the broadcast with the information
# contained in the broadcaster's address.
# Anyone who knows the address can generate
# the private encryption key to decrypt the broadcast.
# This provides virtually no privacy; its purpose is to keep
# questionable and illegal content from flowing through the
# Internet connections and being stored on the disk of 3rd parties.
2013-09-15 01:06:26 +00:00
if addressVersionNumber <= 3:
2017-09-21 15:24:51 +00:00
privEncryptionKey = hashlib.sha512(
encodeVarint(addressVersionNumber) +
encodeVarint(streamNumber) + ripe
).digest()[:32]
2013-09-15 01:06:26 +00:00
else:
privEncryptionKey = doubleHashOfAddressData[:32]
pubEncryptionKey = highlevelcrypto.pointMult(privEncryptionKey)
payload += highlevelcrypto.encrypt(
2016-03-23 22:26:57 +00:00
dataToEncrypt, hexlify(pubEncryptionKey))
2017-09-21 15:24:51 +00:00