Exemplo n.º 1
0
def checkAndShareObjectWithPeers(data):
    """
    This function is called after either receiving an object
    off of the wire or after receiving one as ackdata.
    Returns the length of time that we should reserve to process
    this message if we are receiving it off of the wire.
    """
    if len(data) > 2**18:
        logger.info(
            'The payload length of this object is too large (%i bytes).'
            ' Ignoring it.', len(data))
        return 0
    # Let us check to make sure that the proof of work is sufficient.
    if not protocol.isProofOfWorkSufficient(data):
        logger.info('Proof of work is insufficient.')
        return 0

    endOfLifeTime, = unpack('>Q', data[8:16])
    # The TTL may not be larger than 28 days + 3 hours of wiggle room
    if endOfLifeTime - int(time.time()) > 28 * 24 * 60 * 60 + 10800:
        logger.info(
            'This object\'s End of Life time is too far in the future.'
            ' Ignoring it. Time is %s', endOfLifeTime)
        return 0
    # The EOL time was more than an hour ago. That's too much.
    if endOfLifeTime - int(time.time()) < -3600:
        logger.info(
            'This object\'s End of Life time was more than an hour ago.'
            ' Ignoring the object. Time is %s' % endOfLifeTime)
        return 0
    intObjectType, = unpack('>I', data[16:20])
    try:
        if intObjectType == 0:
            _checkAndShareGetpubkeyWithPeers(data)
            return 0.1
        elif intObjectType == 1:
            _checkAndSharePubkeyWithPeers(data)
            return 0.1
        elif intObjectType == 2:
            _checkAndShareMsgWithPeers(data)
            return 0.6
        elif intObjectType == 3:
            _checkAndShareBroadcastWithPeers(data)
            return 0.6
        else:
            _checkAndShareUndefinedObjectWithPeers(data)
            return 0.6
    except varintDecodeError as e:
        logger.debug('There was a problem with a varint while checking'
                     ' to see whether it was appropriate to share an object'
                     ' with peers. Some details: %s' % e)
    except Exception:
        logger.critical(
            'There was a problem while checking to see whether it was'
            ' appropriate to share an object with peers. This is'
            ' definitely a bug! \n%s' % traceback.format_exc())
    return 0
Exemplo n.º 2
0
def checkAndShareObjectWithPeers(data):
    """
    This function is called after either receiving an object off of the wire
    or after receiving one as ackdata. 
    Returns the length of time that we should reserve to process this message
    if we are receiving it off of the wire.
    """
    if len(data) > 2 ** 18:
        logger.info('The payload length of this object is too large (%s bytes). Ignoring it.' % len(data))
        return 0
    # Let us check to make sure that the proof of work is sufficient.
    if not protocol.isProofOfWorkSufficient(data):
        logger.info('Proof of work is insufficient.')
        return 0
    
    endOfLifeTime, = unpack('>Q', data[8:16])
    if endOfLifeTime - int(time.time()) > 28 * 24 * 60 * 60 + 10800: # The TTL may not be larger than 28 days + 3 hours of wiggle room
        logger.info('This object\'s End of Life time is too far in the future. Ignoring it. Time is %s' % endOfLifeTime)
        return 0
    if endOfLifeTime - int(time.time()) < - 3600: # The EOL time was more than an hour ago. That's too much.
        logger.info('This object\'s End of Life time was more than an hour ago. Ignoring the object. Time is %s' % endOfLifeTime)
        return 0
    intObjectType, = unpack('>I', data[16:20])
    try:
        if intObjectType == 0:
            _checkAndShareGetpubkeyWithPeers(data)
            return 0.1
        elif intObjectType == 1:
            _checkAndSharePubkeyWithPeers(data)
            return 0.1
        elif intObjectType == 2:
            _checkAndShareMsgWithPeers(data)
            return 0.6
        elif intObjectType == 3:
            _checkAndShareBroadcastWithPeers(data)
            return 0.6
        else:
            _checkAndShareUndefinedObjectWithPeers(data)
            return 0.6
    except varintDecodeError as e:
        logger.debug("There was a problem with a varint while checking to see whether it was appropriate to share an object with peers. Some details: %s" % e)
    except Exception as e:
        logger.critical('There was a problem while checking to see whether it was appropriate to share an object with peers. This is definitely a bug! \n%s' % traceback.format_exc())
    return 0
Exemplo n.º 3
0
 def checkProofOfWorkSufficient(self):
     # Let us check to make sure that the proof of work is sufficient.
     if not protocol.isProofOfWorkSufficient(self.data):
         logger.info('Proof of work is insufficient.')
         raise BMObjectInsufficientPOWError()
Exemplo n.º 4
0
 def checkProofOfWorkSufficient(self):
     """Perform a proof of work check for sufficiency."""
     # Let us check to make sure that the proof of work is sufficient.
     if not protocol.isProofOfWorkSufficient(self.data):
         logger.info('Proof of work is insufficient.')
         raise BMObjectInsufficientPOWError()
    def processmsg(self, data):
        messageProcessingStartTime = time.time()
        shared.numberOfMessagesProcessed += 1
        queues.UISignalQueue.put(
            ('updateNumberOfMessagesProcessed', 'no data'))
        readPosition = 20  # bypass the nonce, time, and object type
        msgVersion, msgVersionLength = decodeVarint(
            data[readPosition:readPosition + 9])
        if msgVersion != 1:
            logger.info(
                'Cannot understand message versions other than one. Ignoring message.'
            )
            return
        readPosition += msgVersionLength

        streamNumberAsClaimedByMsg, streamNumberAsClaimedByMsgLength = decodeVarint(
            data[readPosition:readPosition + 9])
        readPosition += streamNumberAsClaimedByMsgLength
        inventoryHash = calculateInventoryHash(data)
        initialDecryptionSuccessful = False

        # 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.

        for key, cryptorObject in sorted(shared.myECCryptorObjects.items(),
                                         key=lambda x: random.random()):
            try:
                if initialDecryptionSuccessful:  # continue decryption attempts to avoid timing attacks
                    cryptorObject.decrypt(data[readPosition:])
                else:
                    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.
                    initialDecryptionSuccessful = True
                    logger.info(
                        'EC decryption successful using key associated with ripe hash: %s.'
                        % hexlify(key))
            except Exception as err:
                pass
        if not initialDecryptionSuccessful:
            # 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, ))
            return

        # This is a message bound for me.
        toAddress = shared.myAddressesByHash[
            toRipe]  # Look up my address based on the RIPE hash.
        readPosition = 0
        sendersAddressVersionNumber, sendersAddressVersionNumberLength = decodeVarint(
            decryptedData[readPosition:readPosition + 10])
        readPosition += sendersAddressVersionNumberLength
        if sendersAddressVersionNumber == 0:
            logger.info(
                'Cannot understand sendersAddressVersionNumber = 0. Ignoring message.'
            )
            return
        if sendersAddressVersionNumber > 4:
            logger.info(
                'Sender\'s address version number %s not yet supported. Ignoring message.'
                % sendersAddressVersionNumber)
            return
        if len(decryptedData) < 170:
            logger.info(
                'Length of the unencrypted data is unreasonably short. Sanity check failed. Ignoring message.'
            )
            return
        sendersStreamNumber, sendersStreamNumberLength = decodeVarint(
            decryptedData[readPosition:readPosition + 10])
        if sendersStreamNumber == 0:
            logger.info('sender\'s stream number is 0. Ignoring message.')
            return
        readPosition += sendersStreamNumberLength
        behaviorBitfield = decryptedData[readPosition:readPosition + 4]
        readPosition += 4
        pubSigningKey = '\x04' + decryptedData[readPosition:readPosition + 64]
        readPosition += 64
        pubEncryptionKey = '\x04' + decryptedData[readPosition:readPosition +
                                                  64]
        readPosition += 64
        if sendersAddressVersionNumber >= 3:
            requiredAverageProofOfWorkNonceTrialsPerByte, varintLength = decodeVarint(
                decryptedData[readPosition:readPosition + 10])
            readPosition += varintLength
            logger.info(
                'sender\'s requiredAverageProofOfWorkNonceTrialsPerByte is %s'
                % requiredAverageProofOfWorkNonceTrialsPerByte)
            requiredPayloadLengthExtraBytes, varintLength = decodeVarint(
                decryptedData[readPosition:readPosition + 10])
            readPosition += varintLength
            logger.info('sender\'s requiredPayloadLengthExtraBytes is %s' %
                        requiredPayloadLengthExtraBytes)
        endOfThePublicKeyPosition = readPosition  # needed for when we store the pubkey in our database of pubkeys for later use.
        if toRipe != decryptedData[readPosition:readPosition + 20]:
            logger.info(
                'The original sender of this message did not send it to you. Someone is attempting a Surreptitious Forwarding Attack.\n\
                See: http://world.std.com/~dtd/sign_encrypt/sign_encrypt7.html \n\
                your toRipe: %s\n\
                embedded destination toRipe: %s' %
                (hexlify(toRipe),
                 hexlify(decryptedData[readPosition:readPosition + 20])))
            return
        readPosition += 20
        messageEncodingType, messageEncodingTypeLength = decodeVarint(
            decryptedData[readPosition:readPosition + 10])
        readPosition += messageEncodingTypeLength
        messageLength, messageLengthLength = decodeVarint(
            decryptedData[readPosition:readPosition + 10])
        readPosition += messageLengthLength
        message = decryptedData[readPosition:readPosition + messageLength]
        # print 'First 150 characters of message:', repr(message[:150])
        readPosition += messageLength
        ackLength, ackLengthLength = decodeVarint(
            decryptedData[readPosition:readPosition + 10])
        readPosition += ackLengthLength
        ackData = decryptedData[readPosition:readPosition + ackLength]
        readPosition += ackLength
        positionOfBottomOfAckData = readPosition  # needed to mark the end of what is covered by the signature
        signatureLength, signatureLengthLength = decodeVarint(
            decryptedData[readPosition:readPosition + 10])
        readPosition += signatureLengthLength
        signature = decryptedData[readPosition:readPosition + signatureLength]
        signedData = data[8:20] + encodeVarint(
            1) + encodeVarint(streamNumberAsClaimedByMsg
                              ) + decryptedData[:positionOfBottomOfAckData]

        if not highlevelcrypto.verify(signedData, signature,
                                      hexlify(pubSigningKey)):
            logger.debug('ECDSA verify failed')
            return
        logger.debug('ECDSA verify passed')
        logger.debug(
            'As a matter of intellectual curiosity, here is the Bitcoin address associated with the keys owned by the other person: %s  ..and here is the testnet address: %s. The other person must take their private signing key from Bitmessage and import it into Bitcoin (or a service like Blockchain.info) for it to be of any use. Do not use this unless you know what you are doing.'
            %
            (helper_bitcoin.calculateBitcoinAddressFromPubkey(pubSigningKey),
             helper_bitcoin.calculateTestnetAddressFromPubkey(pubSigningKey)))
        sigHash = hashlib.sha512(hashlib.sha512(signature).digest()).digest()[
            32:]  # Used to detect and ignore duplicate messages in our inbox

        # calculate the fromRipe.
        sha = hashlib.new('sha512')
        sha.update(pubSigningKey + pubEncryptionKey)
        ripe = hashlib.new('ripemd160')
        ripe.update(sha.digest())
        fromAddress = encodeAddress(sendersAddressVersionNumber,
                                    sendersStreamNumber, ripe.digest())

        # Let's store the public key in case we want to reply to this
        # person.
        sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', fromAddress,
                   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.
        self.possibleNewPubkey(fromAddress)

        # 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
        # proof of work requirement. If this is bound for one of my chan
        # addresses then we skip this check; the minimum network POW is
        # fine.
        if decodeAddress(toAddress)[1] >= 3 and not BMConfigParser(
        ).safeGetBoolean(
                toAddress, 'chan'
        ):  # If the toAddress version number is 3 or higher and not one of my chan addresses:
            if not shared.isAddressInMyAddressBookSubscriptionsListOrWhitelist(
                    fromAddress):  # If I'm not friendly with this person:
                requiredNonceTrialsPerByte = BMConfigParser().getint(
                    toAddress, 'noncetrialsperbyte')
                requiredPayloadLengthExtraBytes = BMConfigParser().getint(
                    toAddress, 'payloadlengthextrabytes')
                if not protocol.isProofOfWorkSufficient(
                        data, requiredNonceTrialsPerByte,
                        requiredPayloadLengthExtraBytes):
                    logger.info(
                        'Proof of work in msg is insufficient only because it does not meet our higher requirement.'
                    )
                    return
        blockMessage = False  # Gets set to True if the user shouldn't see the message according to black or white lists.
        if BMConfigParser().get(
                'bitmessagesettings',
                'blackwhitelist') == 'black':  # If we are using a blacklist
            queryreturn = sqlQuery(
                '''SELECT label FROM blacklist where address=? and enabled='1' ''',
                fromAddress)
            if queryreturn != []:
                logger.info('Message ignored because address is in blacklist.')

                blockMessage = True
        else:  # We're using a whitelist
            queryreturn = sqlQuery(
                '''SELECT label FROM whitelist where address=? and enabled='1' ''',
                fromAddress)
            if queryreturn == []:
                logger.info(
                    'Message ignored because address not in whitelist.')
                blockMessage = True

        toLabel = BMConfigParser().get(toAddress, 'label')
        if toLabel == '':
            toLabel = toAddress

        try:
            decodedMessage = helper_msgcoding.MsgDecode(
                messageEncodingType, message)
        except helper_msgcoding.MsgDecodeException:
            return
        subject = decodedMessage.subject
        body = decodedMessage.body

        # Let us make sure that we haven't already received this message
        if helper_inbox.isMessageAlreadyInInbox(sigHash):
            logger.info('This msg is already in our inbox. Ignoring it.')
            blockMessage = True
        if not blockMessage:
            if messageEncodingType != 0:
                t = (inventoryHash, toAddress, fromAddress, subject,
                     int(time.time()), body, 'inbox', messageEncodingType, 0,
                     sigHash)
                helper_inbox.insert(t)

                queues.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 BMConfigParser().safeGetBoolean('bitmessagesettings',
                                               'apienabled'):
                try:
                    apiNotifyPath = BMConfigParser().get(
                        'bitmessagesettings', 'apinotifypath')
                except:
                    apiNotifyPath = ''
                if apiNotifyPath != '':
                    call([apiNotifyPath, "newMessage"])

            # Let us now check and see whether our receiving address is
            # behaving as a mailing list
            if BMConfigParser().safeGetBoolean(
                    toAddress, 'mailinglist') and messageEncodingType != 0:
                try:
                    mailingListName = BMConfigParser().get(
                        toAddress, 'mailinglistname')
                except:
                    mailingListName = ''
                # Let us send out this message as a broadcast
                subject = self.addMailingListNameToSubject(
                    subject, mailingListName)
                # Let us now send this message out as a broadcast
                message = time.strftime(
                    "%a, %Y-%m-%d %H:%M:%S UTC", time.gmtime()
                ) + '   Message ostensibly from ' + fromAddress + ':\n\n' + body
                fromAddress = toAddress  # The fromAddress for the broadcast that we are about to send is the toAddress (my address) for the msg message we are currently processing.
                # We don't actually need the ackdata for acknowledgement since this is a broadcast message but we can use it to update the user interface when the POW is done generating.
                streamNumber = decodeAddress(fromAddress)[2]

                ackdata = genAckPayload(streamNumber, 0)
                toAddress = '[Broadcast subscribers]'
                ripe = ''

                # We really should have a discussion about how to
                # set the TTL for mailing list broadcasts. This is obviously
                # hard-coded.
                TTL = 2 * 7 * 24 * 60 * 60  # 2 weeks
                t = (
                    '',
                    toAddress,
                    ripe,
                    fromAddress,
                    subject,
                    message,
                    ackdata,
                    int(time.time()),  # sentTime (this doesn't change)
                    int(time.time()),  # lastActionTime
                    0,
                    'broadcastqueued',
                    0,
                    'sent',
                    messageEncodingType,
                    TTL)
                helper_sent.insert(t)

                queues.UISignalQueue.put(
                    ('displayNewSentMessage',
                     (toAddress, '[Broadcast subscribers]', fromAddress,
                      subject, message, ackdata)))
                queues.workerQueue.put(('sendbroadcast', ''))

        # Don't send ACK if invalid, blacklisted senders, invisible messages, disabled or chan
        if self.ackDataHasAValidHeader(ackData) and \
            not blockMessage and \
            messageEncodingType != 0 and \
            not BMConfigParser().safeGetBoolean(toAddress, 'dontsendack') and \
            not BMConfigParser().safeGetBoolean(toAddress, 'chan'):
            shared.checkAndShareObjectWithPeers(ackData[24:])

        # Display timing data
        timeRequiredToAttemptToDecryptMessage = time.time(
        ) - messageProcessingStartTime
        shared.successfullyDecryptMessageTimings.append(
            timeRequiredToAttemptToDecryptMessage)
        sum = 0
        for item in shared.successfullyDecryptMessageTimings:
            sum += item
        logger.debug('Time to decrypt this message successfully: %s\n\
                     Average time for all message decryption successes since startup: %s.'
                     % (timeRequiredToAttemptToDecryptMessage,
                        sum / len(shared.successfullyDecryptMessageTimings)))
    def processmsg(self, data):
        messageProcessingStartTime = time.time()
        shared.numberOfMessagesProcessed += 1
        queues.UISignalQueue.put((
            'updateNumberOfMessagesProcessed', 'no data'))
        readPosition = 20 # bypass the nonce, time, and object type
        msgVersion, msgVersionLength = decodeVarint(data[readPosition:readPosition + 9])
        if msgVersion != 1:
            logger.info('Cannot understand message versions other than one. Ignoring message.') 
            return
        readPosition += msgVersionLength
        
        streamNumberAsClaimedByMsg, streamNumberAsClaimedByMsgLength = decodeVarint(
            data[readPosition:readPosition + 9])
        readPosition += streamNumberAsClaimedByMsgLength
        inventoryHash = calculateInventoryHash(data)
        initialDecryptionSuccessful = False

        # 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.
        
        for key, cryptorObject in sorted(shared.myECCryptorObjects.items(), key=lambda x: random.random()):
            try:
                if initialDecryptionSuccessful: # continue decryption attempts to avoid timing attacks
                    cryptorObject.decrypt(data[readPosition:])
                else:
                    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.
                    initialDecryptionSuccessful = True
                    logger.info('EC decryption successful using key associated with ripe hash: %s.' % hexlify(key))
            except Exception as err:
                pass
        if not initialDecryptionSuccessful:
            # 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,)) 
            return

        # This is a message bound for me.
        toAddress = shared.myAddressesByHash[
            toRipe]  # Look up my address based on the RIPE hash.
        readPosition = 0
        sendersAddressVersionNumber, sendersAddressVersionNumberLength = decodeVarint(
            decryptedData[readPosition:readPosition + 10])
        readPosition += sendersAddressVersionNumberLength
        if sendersAddressVersionNumber == 0:
            logger.info('Cannot understand sendersAddressVersionNumber = 0. Ignoring message.') 
            return
        if sendersAddressVersionNumber > 4:
            logger.info('Sender\'s address version number %s not yet supported. Ignoring message.' % sendersAddressVersionNumber)  
            return
        if len(decryptedData) < 170:
            logger.info('Length of the unencrypted data is unreasonably short. Sanity check failed. Ignoring message.')
            return
        sendersStreamNumber, sendersStreamNumberLength = decodeVarint(
            decryptedData[readPosition:readPosition + 10])
        if sendersStreamNumber == 0:
            logger.info('sender\'s stream number is 0. Ignoring message.')
            return
        readPosition += sendersStreamNumberLength
        behaviorBitfield = decryptedData[readPosition:readPosition + 4]
        readPosition += 4
        pubSigningKey = '\x04' + decryptedData[
            readPosition:readPosition + 64]
        readPosition += 64
        pubEncryptionKey = '\x04' + decryptedData[
            readPosition:readPosition + 64]
        readPosition += 64
        if sendersAddressVersionNumber >= 3:
            requiredAverageProofOfWorkNonceTrialsPerByte, varintLength = decodeVarint(
                decryptedData[readPosition:readPosition + 10])
            readPosition += varintLength
            logger.info('sender\'s requiredAverageProofOfWorkNonceTrialsPerByte is %s' % requiredAverageProofOfWorkNonceTrialsPerByte)
            requiredPayloadLengthExtraBytes, varintLength = decodeVarint(
                decryptedData[readPosition:readPosition + 10])
            readPosition += varintLength
            logger.info('sender\'s requiredPayloadLengthExtraBytes is %s' % requiredPayloadLengthExtraBytes)
        endOfThePublicKeyPosition = readPosition  # needed for when we store the pubkey in our database of pubkeys for later use.
        if toRipe != decryptedData[readPosition:readPosition + 20]:
            logger.info('The original sender of this message did not send it to you. Someone is attempting a Surreptitious Forwarding Attack.\n\
                See: http://world.std.com/~dtd/sign_encrypt/sign_encrypt7.html \n\
                your toRipe: %s\n\
                embedded destination toRipe: %s' % (hexlify(toRipe), hexlify(decryptedData[readPosition:readPosition + 20]))
                       )
            return
        readPosition += 20
        messageEncodingType, messageEncodingTypeLength = decodeVarint(
            decryptedData[readPosition:readPosition + 10])
        readPosition += messageEncodingTypeLength
        messageLength, messageLengthLength = decodeVarint(
            decryptedData[readPosition:readPosition + 10])
        readPosition += messageLengthLength
        message = decryptedData[readPosition:readPosition + messageLength]
        # print 'First 150 characters of message:', repr(message[:150])
        readPosition += messageLength
        ackLength, ackLengthLength = decodeVarint(
            decryptedData[readPosition:readPosition + 10])
        readPosition += ackLengthLength
        ackData = decryptedData[readPosition:readPosition + ackLength]
        readPosition += ackLength
        positionOfBottomOfAckData = readPosition  # needed to mark the end of what is covered by the signature
        signatureLength, signatureLengthLength = decodeVarint(
            decryptedData[readPosition:readPosition + 10])
        readPosition += signatureLengthLength
        signature = decryptedData[
            readPosition:readPosition + signatureLength]
        signedData = data[8:20] + encodeVarint(1) + encodeVarint(streamNumberAsClaimedByMsg) + decryptedData[:positionOfBottomOfAckData]
        
        if not highlevelcrypto.verify(signedData, signature, hexlify(pubSigningKey)):
            logger.debug('ECDSA verify failed')
            return
        logger.debug('ECDSA verify passed')
        logger.debug('As a matter of intellectual curiosity, here is the Bitcoin address associated with the keys owned by the other person: %s  ..and here is the testnet address: %s. The other person must take their private signing key from Bitmessage and import it into Bitcoin (or a service like Blockchain.info) for it to be of any use. Do not use this unless you know what you are doing.' %
                     (helper_bitcoin.calculateBitcoinAddressFromPubkey(pubSigningKey), helper_bitcoin.calculateTestnetAddressFromPubkey(pubSigningKey))
                     )
        sigHash = hashlib.sha512(hashlib.sha512(signature).digest()).digest()[32:] # Used to detect and ignore duplicate messages in our inbox

        # calculate the fromRipe.
        sha = hashlib.new('sha512')
        sha.update(pubSigningKey + pubEncryptionKey)
        ripe = hashlib.new('ripemd160')
        ripe.update(sha.digest())
        fromAddress = encodeAddress(
            sendersAddressVersionNumber, sendersStreamNumber, ripe.digest())
        
        # Let's store the public key in case we want to reply to this
        # person.
        sqlExecute(
            '''INSERT INTO pubkeys VALUES (?,?,?,?,?)''',
            fromAddress,
            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.
        self.possibleNewPubkey(fromAddress)
        
        # 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
        # proof of work requirement. If this is bound for one of my chan
        # addresses then we skip this check; the minimum network POW is
        # fine.
        if decodeAddress(toAddress)[1] >= 3 and not BMConfigParser().safeGetBoolean(toAddress, 'chan'):  # If the toAddress version number is 3 or higher and not one of my chan addresses:
            if not shared.isAddressInMyAddressBookSubscriptionsListOrWhitelist(fromAddress):  # If I'm not friendly with this person:
                requiredNonceTrialsPerByte = BMConfigParser().getint(
                    toAddress, 'noncetrialsperbyte')
                requiredPayloadLengthExtraBytes = BMConfigParser().getint(
                    toAddress, 'payloadlengthextrabytes')
                if not protocol.isProofOfWorkSufficient(data, requiredNonceTrialsPerByte, requiredPayloadLengthExtraBytes):
                    logger.info('Proof of work in msg is insufficient only because it does not meet our higher requirement.')
                    return
        blockMessage = False  # Gets set to True if the user shouldn't see the message according to black or white lists.
        if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black':  # If we are using a blacklist
            queryreturn = sqlQuery(
                '''SELECT label FROM blacklist where address=? and enabled='1' ''',
                fromAddress)
            if queryreturn != []:
                logger.info('Message ignored because address is in blacklist.')

                blockMessage = True
        else:  # We're using a whitelist
            queryreturn = sqlQuery(
                '''SELECT label FROM whitelist where address=? and enabled='1' ''',
                fromAddress)
            if queryreturn == []:
                logger.info('Message ignored because address not in whitelist.')
                blockMessage = True

        toLabel = BMConfigParser().get(toAddress, 'label')
        if toLabel == '':
            toLabel = toAddress

        try:
            decodedMessage = helper_msgcoding.MsgDecode(messageEncodingType, message)
        except helper_msgcoding.MsgDecodeException:
            return
        subject = decodedMessage.subject
        body = decodedMessage.body

        # Let us make sure that we haven't already received this message
        if helper_inbox.isMessageAlreadyInInbox(sigHash):
            logger.info('This msg is already in our inbox. Ignoring it.')
            blockMessage = True
        if not blockMessage:
            if messageEncodingType != 0:
                t = (inventoryHash, toAddress, fromAddress, subject, int(
                    time.time()), body, 'inbox', messageEncodingType, 0, sigHash)
                helper_inbox.insert(t)

                queues.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 BMConfigParser().safeGetBoolean('bitmessagesettings', 'apienabled'):
                try:
                    apiNotifyPath = BMConfigParser().get(
                        'bitmessagesettings', 'apinotifypath')
                except:
                    apiNotifyPath = ''
                if apiNotifyPath != '':
                    call([apiNotifyPath, "newMessage"])

            # Let us now check and see whether our receiving address is
            # behaving as a mailing list
            if BMConfigParser().safeGetBoolean(toAddress, 'mailinglist') and messageEncodingType != 0:
                try:
                    mailingListName = BMConfigParser().get(
                        toAddress, 'mailinglistname')
                except:
                    mailingListName = ''
                # Let us send out this message as a broadcast
                subject = self.addMailingListNameToSubject(
                    subject, mailingListName)
                # Let us now send this message out as a broadcast
                message = time.strftime("%a, %Y-%m-%d %H:%M:%S UTC", time.gmtime(
                )) + '   Message ostensibly from ' + fromAddress + ':\n\n' + body
                fromAddress = toAddress  # The fromAddress for the broadcast that we are about to send is the toAddress (my address) for the msg message we are currently processing.
                # We don't actually need the ackdata for acknowledgement since this is a broadcast message but we can use it to update the user interface when the POW is done generating.
                streamNumber = decodeAddress(fromAddress)[2]

                ackdata = genAckPayload(streamNumber, 0)
                toAddress = '[Broadcast subscribers]'
                ripe = ''

                # We really should have a discussion about how to
                # set the TTL for mailing list broadcasts. This is obviously
                # hard-coded. 
                TTL = 2*7*24*60*60 # 2 weeks
                t = ('', 
                     toAddress, 
                     ripe, 
                     fromAddress, 
                     subject, 
                     message, 
                     ackdata, 
                     int(time.time()), # sentTime (this doesn't change)
                     int(time.time()), # lastActionTime
                     0, 
                     'broadcastqueued', 
                     0, 
                     'sent', 
                     messageEncodingType, 
                     TTL)
                helper_sent.insert(t)

                queues.UISignalQueue.put(('displayNewSentMessage', (
                    toAddress, '[Broadcast subscribers]', fromAddress, subject, message, ackdata)))
                queues.workerQueue.put(('sendbroadcast', ''))

        # Don't send ACK if invalid, blacklisted senders, invisible messages, disabled or chan
        if self.ackDataHasAValidHeader(ackData) and \
            not blockMessage and \
            messageEncodingType != 0 and \
            not BMConfigParser().safeGetBoolean(toAddress, 'dontsendack') and \
            not BMConfigParser().safeGetBoolean(toAddress, 'chan'):
            shared.checkAndShareObjectWithPeers(ackData[24:])

        # Display timing data
        timeRequiredToAttemptToDecryptMessage = time.time(
        ) - messageProcessingStartTime
        shared.successfullyDecryptMessageTimings.append(
            timeRequiredToAttemptToDecryptMessage)
        sum = 0
        for item in shared.successfullyDecryptMessageTimings:
            sum += item
        logger.debug('Time to decrypt this message successfully: %s\n\
                     Average time for all message decryption successes since startup: %s.' %
                     (timeRequiredToAttemptToDecryptMessage, sum / len(shared.successfullyDecryptMessageTimings)) 
                     )