From ecf78801bf9f145237638ebb5000fc46da6f8b6f Mon Sep 17 00:00:00 2001 From: bmng-dev Date: Wed, 21 May 2014 09:59:08 +0000 Subject: [PATCH 01/11] Move pointMult function to highlevelcrypto Copy pointMult function from class_addressGenerator.py to highlevelcrypto.py --- src/highlevelcrypto.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/highlevelcrypto.py b/src/highlevelcrypto.py index 22f44ed3..26143d59 100644 --- a/src/highlevelcrypto.py +++ b/src/highlevelcrypto.py @@ -1,5 +1,5 @@ import pyelliptic -from pyelliptic import arithmetic as a +from pyelliptic import arithmetic as a, OpenSSL def makeCryptor(privkey): privkey_bin = '\x02\xca\x00 '+a.changebase(privkey,16,256,minlen=32) pubkey = a.changebase(a.privtopub(privkey),16,256,minlen=65)[1:] @@ -31,3 +31,23 @@ def sign(msg,hexPrivkey): # Verifies with hex public key def verify(msg,sig,hexPubkey): return makePubCryptor(hexPubkey).verify(sig,msg) + +# Does an EC point multiplication; turns a private key into a public key. +def pointMult(secret): + k = OpenSSL.EC_KEY_new_by_curve_name(OpenSSL.get_curve('secp256k1')) + priv_key = OpenSSL.BN_bin2bn(secret, 32, None) + group = OpenSSL.EC_KEY_get0_group(k) + pub_key = OpenSSL.EC_POINT_new(group) + + OpenSSL.EC_POINT_mul(group, pub_key, priv_key, None, None, None) + OpenSSL.EC_KEY_set_private_key(k, priv_key) + OpenSSL.EC_KEY_set_public_key(k, pub_key) + + size = OpenSSL.i2o_ECPublicKey(k, None) + mb = OpenSSL.create_string_buffer(size) + OpenSSL.i2o_ECPublicKey(k, OpenSSL.byref(OpenSSL.pointer(mb))) + + OpenSSL.EC_POINT_free(pub_key) + OpenSSL.BN_free(priv_key) + OpenSSL.EC_KEY_free(k) + return mb.raw From 19deff7c75a88ca5363de640afedf86d1e4d2a58 Mon Sep 17 00:00:00 2001 From: bmng-dev Date: Wed, 21 May 2014 10:06:20 +0000 Subject: [PATCH 02/11] Move pointMult to highlevelcrypto Remove pointMult from class_addressGenerator Update pointMult calls to highlevelcrypto.pointMult --- src/class_addressGenerator.py | 37 ++++------------------------------- 1 file changed, 4 insertions(+), 33 deletions(-) diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index c6e99a4b..2e215606 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -79,11 +79,11 @@ class addressGenerator(threading.Thread): startTime = time.time() numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix = 0 potentialPrivSigningKey = OpenSSL.rand(32) - potentialPubSigningKey = pointMult(potentialPrivSigningKey) + potentialPubSigningKey = highlevelcrypto.pointMult(potentialPrivSigningKey) while True: numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix += 1 potentialPrivEncryptionKey = OpenSSL.rand(32) - potentialPubEncryptionKey = pointMult( + potentialPubEncryptionKey = highlevelcrypto.pointMult( potentialPrivEncryptionKey) # print 'potentialPubSigningKey', potentialPubSigningKey.encode('hex') # print 'potentialPubEncryptionKey', @@ -175,9 +175,9 @@ class addressGenerator(threading.Thread): deterministicPassphrase + encodeVarint(signingKeyNonce)).digest()[:32] potentialPrivEncryptionKey = hashlib.sha512( deterministicPassphrase + encodeVarint(encryptionKeyNonce)).digest()[:32] - potentialPubSigningKey = pointMult( + potentialPubSigningKey = highlevelcrypto.pointMult( potentialPrivSigningKey) - potentialPubEncryptionKey = pointMult( + potentialPubEncryptionKey = highlevelcrypto.pointMult( potentialPrivEncryptionKey) # print 'potentialPubSigningKey', potentialPubSigningKey.encode('hex') # print 'potentialPubEncryptionKey', @@ -280,32 +280,3 @@ class addressGenerator(threading.Thread): raise Exception( "Error in the addressGenerator thread. Thread was given a command it could not understand: " + command) - -# Does an EC point multiplication; turns a private key into a public key. -def pointMult(secret): - # ctx = OpenSSL.BN_CTX_new() #This value proved to cause Seg Faults on - # Linux. It turns out that it really didn't speed up EC_POINT_mul anyway. - k = OpenSSL.EC_KEY_new_by_curve_name(OpenSSL.get_curve('secp256k1')) - priv_key = OpenSSL.BN_bin2bn(secret, 32, 0) - group = OpenSSL.EC_KEY_get0_group(k) - pub_key = OpenSSL.EC_POINT_new(group) - - OpenSSL.EC_POINT_mul(group, pub_key, priv_key, None, None, None) - OpenSSL.EC_KEY_set_private_key(k, priv_key) - OpenSSL.EC_KEY_set_public_key(k, pub_key) - # print 'priv_key',priv_key - # print 'pub_key',pub_key - - size = OpenSSL.i2o_ECPublicKey(k, 0) - mb = ctypes.create_string_buffer(size) - OpenSSL.i2o_ECPublicKey(k, ctypes.byref(ctypes.pointer(mb))) - # print 'mb.raw', mb.raw.encode('hex'), 'length:', len(mb.raw) - # print 'mb.raw', mb.raw, 'length:', len(mb.raw) - - OpenSSL.EC_POINT_free(pub_key) - # OpenSSL.BN_CTX_free(ctx) - OpenSSL.BN_free(priv_key) - OpenSSL.EC_KEY_free(k) - return mb.raw - - From b1261a6c0e6247d4109026cf5f367caca30f4651 Mon Sep 17 00:00:00 2001 From: bmng-dev Date: Wed, 21 May 2014 10:15:07 +0000 Subject: [PATCH 03/11] Move pointMult to highlevelcrypto Update pointMult calls to highlevelcrypto.pointMult --- src/class_singleWorker.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 4b43c22f..18fdf9f3 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -8,7 +8,6 @@ from addresses import * import highlevelcrypto import proofofwork import sys -from class_addressGenerator import pointMult import tr from debug import logger from helper_sql import * @@ -304,7 +303,7 @@ class singleWorker(threading.Thread): addressVersionNumber) + encodeVarint(streamNumber) + hash).digest()).digest() payload += doubleHashOfAddressData[32:] # the tag privEncryptionKey = doubleHashOfAddressData[:32] - pubEncryptionKey = pointMult(privEncryptionKey) + pubEncryptionKey = highlevelcrypto.pointMult(privEncryptionKey) payload += highlevelcrypto.encrypt( dataToEncrypt, pubEncryptionKey.encode('hex')) @@ -415,7 +414,7 @@ class singleWorker(threading.Thread): else: privEncryptionKey = doubleHashOfAddressData[:32] - pubEncryptionKey = pointMult(privEncryptionKey) + pubEncryptionKey = highlevelcrypto.pointMult(privEncryptionKey) payload += highlevelcrypto.encrypt( dataToEncrypt, pubEncryptionKey.encode('hex')) From 9b40838f25c6a64f289b1bd07db9e0326486c8ec Mon Sep 17 00:00:00 2001 From: bmng-dev Date: Wed, 21 May 2014 11:08:15 +0000 Subject: [PATCH 04/11] Use pointMult instead of arithmetic.privtopub pointMult is faster than the pure python arithmetic.privtopub Additionally in makeCryptor the call to a.privtopub could have just simply be changed to call the local privToPub but then privkey would have been dehexified twice (once in makeCryptor, then again in privToPub) and privToPub would have hexified its result only for makeCryptor to immediately dehexify it. This sort of unnecessary hexifying/dehexifying seems to occur throughout PyBitmessage. --- src/highlevelcrypto.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/highlevelcrypto.py b/src/highlevelcrypto.py index 26143d59..28439c8d 100644 --- a/src/highlevelcrypto.py +++ b/src/highlevelcrypto.py @@ -1,9 +1,10 @@ import pyelliptic from pyelliptic import arithmetic as a, OpenSSL def makeCryptor(privkey): - privkey_bin = '\x02\xca\x00 '+a.changebase(privkey,16,256,minlen=32) - pubkey = a.changebase(a.privtopub(privkey),16,256,minlen=65)[1:] - pubkey_bin = '\x02\xca\x00 '+pubkey[:32]+'\x00 '+pubkey[32:] + private_key = a.changebase(privkey, 16, 256, minlen=32) + public_key = pointMult(private_key) + privkey_bin = '\x02\xca\x00\x20' + private_key + pubkey_bin = '\x02\xca\x00\x20' + public_key[1:-32] + '\x00\x20' + pubkey[-32:] cryptor = pyelliptic.ECC(curve='secp256k1',privkey=privkey_bin,pubkey=pubkey_bin) return cryptor def hexToPubkey(pubkey): @@ -15,7 +16,9 @@ def makePubCryptor(pubkey): return pyelliptic.ECC(curve='secp256k1',pubkey=pubkey_bin) # Converts hex private key into hex public key def privToPub(privkey): - return a.privtopub(privkey) + private_key = a.changebase(privkey, 16, 256, minlen=32) + public_key = pointMult(private_key) + return public_key.encode('hex') # Encrypts message with hex public key def encrypt(msg,hexPubkey): return pyelliptic.ECC(curve='secp256k1').encrypt(msg,hexToPubkey(hexPubkey)) From 947f7655abd96b8f45f4752efb4fc4091757d3a2 Mon Sep 17 00:00:00 2001 From: bmng-dev Date: Thu, 22 May 2014 12:30:51 +0000 Subject: [PATCH 05/11] Refactor generation of packet headers Added global variable Header - a compiled Struct to pack/unpack headers so as to avoid repeatedly compiling the same format string Add a new method CreatePacket to simply and efficiently construct a packet that is ready to be sent Modify assembleVersionMessage to use CreatePacket --- src/shared.py | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/shared.py b/src/shared.py index 96b9a7ce..d4df5da1 100644 --- a/src/shared.py +++ b/src/shared.py @@ -21,6 +21,7 @@ import stat import threading import time from os import path, environ +from struct import Struct # Project imports. from addresses import * @@ -104,6 +105,23 @@ frozen = getattr(sys,'frozen', None) # security. trustedPeer = None +#Compiled struct for packing/unpacking headers +#New code should use CreatePacket instead of Header.pack +Header = Struct('!L12sL4s') + +#Create a packet +def CreatePacket(command, payload=''): + payload_length = len(payload) + if payload_length == 0: + checksum = '\xCF\x83\xE1\x35' + else: + checksum = hashlib.sha512(payload).digest()[0:4] + + b = bytearray(Header.size + payload_length) + Header.pack_into(b, 0, 0xE9BEB4D9, command, payload_length, checksum) + b[Header.size:] = payload + return bytes(b) + def isInSqlInventory(hash): queryreturn = sqlQuery('''select hash from inventory where hash=?''', hash) return queryreturn != [] @@ -141,11 +159,7 @@ def assembleVersionMessage(remoteHost, remotePort, myStreamNumber): 1) # The number of streams about which I care. PyBitmessage currently only supports 1 per connection. payload += encodeVarint(myStreamNumber) - datatosend = '\xe9\xbe\xb4\xd9' # magic bits, slighly different from Bitcoin's magic bits. - datatosend = datatosend + 'version\x00\x00\x00\x00\x00' # version command - datatosend = datatosend + pack('>L', len(payload)) # payload length - datatosend = datatosend + hashlib.sha512(payload).digest()[0:4] - return datatosend + payload + return CreatePacket('version', payload) def lookupAppdataFolder(): APPNAME = "PyBitmessage" From ccfbe8da4777889e8a3c93865adb78ced8de0b8e Mon Sep 17 00:00:00 2001 From: bmng-dev Date: Thu, 22 May 2014 13:08:30 +0000 Subject: [PATCH 06/11] Refactor handling of packet headers Refactored ackDataHasAVaildHeader: -shared.Header is used as necessary -avoided slicing wherever possible -remove trailing null characters when comparing command strings -don't calculate the checksum of a large payload --- src/class_objectProcessor.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index 20ef31ff..717db9c6 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -1149,25 +1149,28 @@ class objectProcessor(threading.Thread): shared.workerQueue.put(('sendmessage', '')) def ackDataHasAVaildHeader(self, ackData): - if len(ackData) < 24: + if len(ackData) < shared.Header.size: logger.info('The length of ackData is unreasonably short. Not sending ackData.') return False - if ackData[0:4] != '\xe9\xbe\xb4\xd9': + + magic,command,payload_length,checksum = shared.Header.unpack(ackData[:shared.Header.size]) + if magic != 0xE9BEB4D9: logger.info('Ackdata magic bytes were wrong. Not sending ackData.') return False - ackDataPayloadLength, = unpack('>L', ackData[16:20]) - if len(ackData) - 24 != ackDataPayloadLength: + payload = ackData[shared.Header.size:] + if len(payload) != payload_length: logger.info('ackData payload length doesn\'t match the payload length specified in the header. Not sending ackdata.') return False - if ackData[20:24] != hashlib.sha512(ackData[24:]).digest()[0:4]: # test the checksum in the message. + if payload_length > 180000000: # If the size of the message is greater than 180MB, ignore it. + return False + if checksum != hashlib.sha512(payload).digest()[0:4]: # test the checksum in the message. logger.info('ackdata checksum wrong. Not sending ackdata.') return False - if ackDataPayloadLength > 180000000: # If the size of the message is greater than 180MB, ignore it. - return False - if (ackData[4:16] != 'getpubkey\x00\x00\x00' and - ackData[4:16] != 'pubkey\x00\x00\x00\x00\x00\x00' and - ackData[4:16] != 'msg\x00\x00\x00\x00\x00\x00\x00\x00\x00' and - ackData[4:16] != 'broadcast\x00\x00\x00'): + command = command.rstrip('\x00') + if (command != 'getpubkey' and + command != 'pubkey' and + command != 'msg' and + command != 'broadcast'): return False return True @@ -1210,4 +1213,4 @@ class objectProcessor(threading.Thread): # Throw away any extra lines (headers) after the subject. if subject: subject = subject.splitlines()[0] - return subject, body \ No newline at end of file + return subject, body From 0f9625aac79c985f2b684883d8cc506c71b8f66d Mon Sep 17 00:00:00 2001 From: bmng-dev Date: Thu, 22 May 2014 15:57:48 +0000 Subject: [PATCH 07/11] Refactor packet header extraction and generation Demote payloadLength from class instance variable to processData local variable as no other function was using it Improve processData: -Utilise shared.Header -Use a memoryview to reduce memory overhead -Clean up variables before a recursive call -Strip null bytes from command Refactor sendData Various functions: -Use shared.CreatePacket to generate packets Fix typo in _checkIPv4Address --- src/class_receiveDataThread.py | 150 +++++++++++++++------------------ 1 file changed, 66 insertions(+), 84 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index e78a7ae2..a9ef4313 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -47,7 +47,6 @@ class receiveDataThread(threading.Thread): self.sock = sock self.peer = shared.Peer(HOST, port) self.streamNumber = streamNumber - self.payloadLength = 0 # This is the protocol payload length thus it doesn't include the 24 byte message header self.objectsThatWeHaveYetToGetFromThisPeer = {} self.selfInitiatedConnections = selfInitiatedConnections self.sendDataThreadQueue = sendDataThreadQueue # used to send commands and data to the sendDataThread @@ -113,28 +112,39 @@ class receiveDataThread(threading.Thread): # with shared.printLock: # print 'self.data is currently ', repr(self.data) # - if len(self.data) < 24: # if so little of the data has arrived that we can't even read the checksum then wait for more data. + if len(self.data) < shared.Header.size: # if so little of the data has arrived that we can't even read the checksum then wait for more data. return - if self.data[0:4] != '\xe9\xbe\xb4\xd9': + #Use a memoryview so we don't copy data unnecessarily + view = memoryview(self.data) + magic,command,payloadLength,checksum = shared.Header.unpack(view[:shared.Header.size]) + view = view[shared.Header.size:] + if magic != 0xE9BEB4D9: #if shared.verbose >= 1: # with shared.printLock: # print 'The magic bytes were not correct. First 40 bytes of data: ' + repr(self.data[0:40]) self.data = "" return - self.payloadLength, = unpack('>L', self.data[16:20]) - if self.payloadLength > 20000000: - logger.info('The incoming message, which we have not yet download, is too large. Ignoring it. (unfortunately there is no way to tell the other node to stop sending it except to disconnect.) Message size: %s' % self.payloadLength) - self.data = self.data[self.payloadLength + 24:] + if payloadLength > 20000000: + logger.info('The incoming message, which we have not yet download, is too large. Ignoring it. (unfortunately there is no way to tell the other node to stop sending it except to disconnect.) Message size: %s' % payloadLength) + self.data = view[payloadLength:].tobytes() + del view,magic,command,payloadLength,checksum #we don't need these anymore and better to clean them now before the recursive call rather than after self.processData() return - if len(self.data) < self.payloadLength + 24: # check if the whole message has arrived yet. + if len(view) < payloadLength: # check if the whole message has arrived yet. return - if self.data[20:24] != hashlib.sha512(self.data[24:self.payloadLength + 24]).digest()[0:4]: # test the checksum in the message. If it is correct... + payload = view[:payloadLength] + if checksum != hashlib.sha512(payload).digest()[0:4]: # test the checksum in the message. If it is correct... print 'Checksum incorrect. Clearing this message.' - self.data = self.data[self.payloadLength + 24:] + self.data = view[payloadLength:].tobytes() + del view,magic,command,payloadLength,checksum,payload #again better to clean up before the recursive call self.processData() return + + #We can now revert back to bytestrings and take this message out + payload = payload.tobytes() + self.data = view[payloadLength:].tobytes() + del view,magic,payloadLength,checksum # The time we've last seen this node is obviously right now since we # just received valid data from it. So update the knownNodes list so # that other peers can be made aware of its existance. @@ -143,37 +153,39 @@ class receiveDataThread(threading.Thread): shared.knownNodes[self.streamNumber][self.peer] = int(time.time()) shared.knownNodesLock.release() - remoteCommand = self.data[4:16] + #Strip the nulls + command = command.rstrip('\x00') with shared.printLock: - print 'remoteCommand', repr(remoteCommand.replace('\x00', '')), ' from', self.peer + print 'remoteCommand', repr(command), ' from', self.peer + + #TODO: Use a dispatcher here + if not self.connectionIsOrWasFullyEstablished: + if command == 'version': + self.recversion(payload) + elif command == 'verack': + self.recverack() + else: + if command == 'addr': + self.recaddr(payload) + elif command == 'getpubkey': + shared.checkAndSharegetpubkeyWithPeers(payload) + elif command == 'pubkey': + self.recpubkey(payload) + elif command == 'inv': + self.recinv(payload) + elif command == 'getdata': + self.recgetdata(payload) + elif command == 'msg': + self.recmsg(payload) + elif command == 'broadcast': + self.recbroadcast(payload) + elif command == 'ping': + self.sendpong(payload) + #elif command == 'pong': + # pass + #elif command == 'alert': + # pass - if remoteCommand == 'version\x00\x00\x00\x00\x00' and not self.connectionIsOrWasFullyEstablished: - self.recversion(self.data[24:self.payloadLength + 24]) - elif remoteCommand == 'verack\x00\x00\x00\x00\x00\x00' and not self.connectionIsOrWasFullyEstablished: - self.recverack() - elif remoteCommand == 'addr\x00\x00\x00\x00\x00\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: - self.recaddr(self.data[24:self.payloadLength + 24]) - elif remoteCommand == 'getpubkey\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: - shared.checkAndSharegetpubkeyWithPeers(self.data[24:self.payloadLength + 24]) - elif remoteCommand == 'pubkey\x00\x00\x00\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: - self.recpubkey(self.data[24:self.payloadLength + 24]) - elif remoteCommand == 'inv\x00\x00\x00\x00\x00\x00\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: - self.recinv(self.data[24:self.payloadLength + 24]) - elif remoteCommand == 'getdata\x00\x00\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: - self.recgetdata(self.data[24:self.payloadLength + 24]) - elif remoteCommand == 'msg\x00\x00\x00\x00\x00\x00\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: - self.recmsg(self.data[24:self.payloadLength + 24]) - elif remoteCommand == 'broadcast\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: - self.recbroadcast(self.data[24:self.payloadLength + 24]) - elif remoteCommand == 'ping\x00\x00\x00\x00\x00\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: - self.sendpong() - elif remoteCommand == 'pong\x00\x00\x00\x00\x00\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: - pass - elif remoteCommand == 'alert\x00\x00\x00\x00\x00\x00\x00' and self.connectionIsOrWasFullyEstablished: - pass - - self.data = self.data[ - self.payloadLength + 24:] # take this message out and then process the next message if self.data == '': while len(self.objectsThatWeHaveYetToGetFromThisPeer) > 0: shared.numberOfInventoryLookupsPerformed += 1 @@ -226,7 +238,7 @@ class receiveDataThread(threading.Thread): def sendpong(self): print 'Sending pong' - self.sendDataThreadQueue.put((0, 'sendRawData', '\xE9\xBE\xB4\xD9\x70\x6F\x6E\x67\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcf\x83\xe1\x35')) + self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('pong'))) def recverack(self): @@ -297,7 +309,7 @@ class receiveDataThread(threading.Thread): for hash, storedValue in bigInvList.items(): payload += hash numberOfObjectsInInvMessage += 1 - if numberOfObjectsInInvMessage >= 50000: # We can only send a max of 50000 items per inv message but we may have more objects to advertise. They must be split up into multiple inv messages. + if numberOfObjectsInInvMessage == 50000: # We can only send a max of 50000 items per inv message but we may have more objects to advertise. They must be split up into multiple inv messages. self.sendinvMessageToJustThisOnePeer( numberOfObjectsInInvMessage, payload) payload = '' @@ -311,13 +323,9 @@ class receiveDataThread(threading.Thread): # function for broadcasting invs to everyone in our stream. def sendinvMessageToJustThisOnePeer(self, numberOfObjects, payload): payload = encodeVarint(numberOfObjects) + payload - headerData = '\xe9\xbe\xb4\xd9' # magic bits, slighly different from Bitcoin's magic bits. - headerData += 'inv\x00\x00\x00\x00\x00\x00\x00\x00\x00' - headerData += pack('>L', len(payload)) - headerData += hashlib.sha512(payload).digest()[:4] with shared.printLock: print 'Sending huge inv message with', numberOfObjects, 'objects to just this one peer' - self.sendDataThreadQueue.put((0, 'sendRawData', headerData + payload)) + self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('inv', payload))) def _sleepForTimingAttackMitigation(self, sleepTime): # We don't need to do the timing attack mitigation if we are @@ -457,12 +465,7 @@ class receiveDataThread(threading.Thread): print 'sending getdata to retrieve object with hash:', hash.encode('hex') payload = '\x01' + hash - headerData = '\xe9\xbe\xb4\xd9' # magic bits, slighly different from Bitcoin's magic bits. - headerData += 'getdata\x00\x00\x00\x00\x00' - headerData += pack('>L', len( - payload)) # payload length. Note that we add an extra 8 for the nonce. - headerData += hashlib.sha512(payload).digest()[:4] - self.sendDataThreadQueue.put((0, 'sendRawData', headerData + payload)) + self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('getdata', payload))) # We have received a getdata request from our peer @@ -499,34 +502,17 @@ class receiveDataThread(threading.Thread): # Our peer has requested (in a getdata message) that we send an object. def sendData(self, objectType, payload): - headerData = '\xe9\xbe\xb4\xd9' # magic bits, slighly different from Bitcoin's magic bits. - if objectType == 'pubkey': - with shared.printLock: - print 'sending pubkey' - - headerData += 'pubkey\x00\x00\x00\x00\x00\x00' - elif objectType == 'getpubkey' or objectType == 'pubkeyrequest': - with shared.printLock: - print 'sending getpubkey' - - headerData += 'getpubkey\x00\x00\x00' - elif objectType == 'msg': - with shared.printLock: - print 'sending msg' - - headerData += 'msg\x00\x00\x00\x00\x00\x00\x00\x00\x00' - elif objectType == 'broadcast': - with shared.printLock: - print 'sending broadcast' - - headerData += 'broadcast\x00\x00\x00' - else: + # pubkeyrequest?? + if objectType == 'pubkeyrequest': + objectType = 'getpubkey' + elif objectType != 'pubkey' and objectType != 'getpubkey' and + objectType != 'msg' and objectType != 'broadcast': sys.stderr.write( 'Error: sendData has been asked to send a strange objectType: %s\n' % str(objectType)) return - headerData += pack('>L', len(payload)) # payload length. - headerData += hashlib.sha512(payload).digest()[:4] - self.sendDataThreadQueue.put((0, 'sendRawData', headerData + payload)) + with shared.printLock: + print 'sending', objectType + self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket(objectType, payload))) # Advertise this object to all of our peers @@ -545,7 +531,7 @@ class receiveDataThread(threading.Thread): if host[0] == '\x0A': print 'Ignoring IP address in private range:', hostFromAddrMessage return False - if host[0:2] == '\xC0A8': + if host[0:2] == '\xC0\xA8': print 'Ignoring IP address in private range:', hostFromAddrMessage return False return True @@ -745,11 +731,7 @@ class receiveDataThread(threading.Thread): payload += pack('>H', PORT) # remote port payload = encodeVarint(numberOfAddressesInAddrMessage) + payload - datatosend = '\xE9\xBE\xB4\xD9addr\x00\x00\x00\x00\x00\x00\x00\x00' - datatosend = datatosend + pack('>L', len(payload)) # payload length - datatosend = datatosend + hashlib.sha512(payload).digest()[0:4] - datatosend = datatosend + payload - self.sendDataThreadQueue.put((0, 'sendRawData', datatosend)) + self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('addr', payload))) # We have received a version message @@ -832,7 +814,7 @@ class receiveDataThread(threading.Thread): def sendverack(self): with shared.printLock: print 'Sending verack' - self.sendDataThreadQueue.put((0, 'sendRawData', '\xE9\xBE\xB4\xD9\x76\x65\x72\x61\x63\x6B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcf\x83\xe1\x35')) + self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('verack'))) self.verackSent = True if self.verackReceived: self.connectionFullyEstablished() From 1f750472236f88f62d930e69c741d1be3ea528ba Mon Sep 17 00:00:00 2001 From: bmng-dev Date: Thu, 22 May 2014 16:21:20 +0000 Subject: [PATCH 08/11] Refactor generation of packet headers --- src/class_sendDataThread.py | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index 5aabaeb5..3dfbf12c 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -108,13 +108,9 @@ class sendDataThread(threading.Thread): payload += pack('>H', port) payload = encodeVarint(numberOfAddressesInAddrMessage) + payload - datatosend = '\xE9\xBE\xB4\xD9addr\x00\x00\x00\x00\x00\x00\x00\x00' - datatosend = datatosend + pack('>L', len(payload)) # payload length - datatosend = datatosend + hashlib.sha512(payload).digest()[0:4] - datatosend = datatosend + payload - + packet = shared.CreatePacket('addr', payload) try: - self.sock.sendall(datatosend) + self.sock.sendall(packet) self.lastTimeISentData = int(time.time()) except: print 'sendaddr: self.sock.sendall failed' @@ -131,12 +127,9 @@ class sendDataThread(threading.Thread): payload += hash if payload != '': payload = encodeVarint(len(payload)/32) + payload - headerData = '\xe9\xbe\xb4\xd9' # magic bits, slighly different from Bitcoin's magic bits. - headerData += 'inv\x00\x00\x00\x00\x00\x00\x00\x00\x00' - headerData += pack('>L', len(payload)) - headerData += hashlib.sha512(payload).digest()[:4] + packet = shared.CreatePacket('inv', payload) try: - self.sock.sendall(headerData + payload) + self.sock.sendall(packet) self.lastTimeISentData = int(time.time()) except: print 'sendinv: self.sock.sendall failed' @@ -147,10 +140,9 @@ class sendDataThread(threading.Thread): # Send out a pong message to keep the connection alive. with shared.printLock: print 'Sending pong to', self.peer, 'to keep connection alive.' - + packet = shared.CreatePacket('pong') try: - self.sock.sendall( - '\xE9\xBE\xB4\xD9\x70\x6F\x6E\x67\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcf\x83\xe1\x35') + self.sock.sendall(packet) self.lastTimeISentData = int(time.time()) except: print 'send pong failed' From 97647f23a6e72f141c0c54c0a69194947abbbece Mon Sep 17 00:00:00 2001 From: bmng-dev Date: Thu, 22 May 2014 16:33:42 +0000 Subject: [PATCH 09/11] Refactor header generation Modify generateFullAckMessage to use shared.CreatePacket --- src/class_singleWorker.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 18fdf9f3..8af012c3 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -948,8 +948,4 @@ class singleWorker(threading.Thread): pass payload = pack('>Q', nonce) + payload - headerData = '\xe9\xbe\xb4\xd9' # magic bits, slighly different from Bitcoin's magic bits. - headerData += 'msg\x00\x00\x00\x00\x00\x00\x00\x00\x00' - headerData += pack('>L', len(payload)) - headerData += hashlib.sha512(payload).digest()[:4] - return headerData + payload + return shared.CreatePacket('msg', payload) From 1f9991bcd0c6b023c1068a752ad91a03a7eca77a Mon Sep 17 00:00:00 2001 From: bmng-dev Date: Sun, 8 Jun 2014 14:03:58 +0000 Subject: [PATCH 10/11] Fix syntax error --- src/class_receiveDataThread.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index a9ef4313..cac1c98c 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -505,8 +505,10 @@ class receiveDataThread(threading.Thread): # pubkeyrequest?? if objectType == 'pubkeyrequest': objectType = 'getpubkey' - elif objectType != 'pubkey' and objectType != 'getpubkey' and - objectType != 'msg' and objectType != 'broadcast': + elif (objectType != 'pubkey' and + objectType != 'getpubkey' and + objectType != 'msg' and + objectType != 'broadcast'): sys.stderr.write( 'Error: sendData has been asked to send a strange objectType: %s\n' % str(objectType)) return From be5ab22d16670d91abe15a1de6af63c8fdc1365c Mon Sep 17 00:00:00 2001 From: bmng-dev Date: Sun, 8 Jun 2014 14:07:28 +0000 Subject: [PATCH 11/11] Fix name error --- src/highlevelcrypto.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/highlevelcrypto.py b/src/highlevelcrypto.py index 28439c8d..90a32435 100644 --- a/src/highlevelcrypto.py +++ b/src/highlevelcrypto.py @@ -4,7 +4,7 @@ def makeCryptor(privkey): private_key = a.changebase(privkey, 16, 256, minlen=32) public_key = pointMult(private_key) privkey_bin = '\x02\xca\x00\x20' + private_key - pubkey_bin = '\x02\xca\x00\x20' + public_key[1:-32] + '\x00\x20' + pubkey[-32:] + pubkey_bin = '\x02\xca\x00\x20' + public_key[1:-32] + '\x00\x20' + public_key[-32:] cryptor = pyelliptic.ECC(curve='secp256k1',privkey=privkey_bin,pubkey=pubkey_bin) return cryptor def hexToPubkey(pubkey):