Most of the ECC upgrade completed

This commit is contained in:
Jonathan Warren 2013-01-18 17:38:09 -05:00
parent 59187e1937
commit 74dc0a9a8f
7 changed files with 790 additions and 263 deletions

View File

@ -100,7 +100,6 @@ def encodeAddress(version,stream,ripe):
ripe = ripe[2:] ripe = ripe[2:]
elif ripe[:1] == '\x00': elif ripe[:1] == '\x00':
ripe = ripe[1:] ripe = ripe[1:]
print 'within encodeAddress, length of ripe is:', len(ripe)
a = encodeVarint(version) + encodeVarint(stream) + ripe a = encodeVarint(version) + encodeVarint(stream) + ripe
sha = hashlib.new('sha512') sha = hashlib.new('sha512')
sha.update(a) sha.update(a)
@ -184,13 +183,10 @@ def decodeAddress(address):
return status,addressVersionNumber,streamNumber,data[-24:-4] return status,addressVersionNumber,streamNumber,data[-24:-4]
elif addressVersionNumber == 2: elif addressVersionNumber == 2:
if len(data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4]) == 19: if len(data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4]) == 19:
print 'within decode address, lenth I think is 19'
return status,addressVersionNumber,streamNumber,'\x00'+data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4] return status,addressVersionNumber,streamNumber,'\x00'+data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4]
elif len(data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4]) == 20: elif len(data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4]) == 20:
print 'within decode address, lenth I think is 20'
return status,addressVersionNumber,streamNumber,data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4] return status,addressVersionNumber,streamNumber,data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4]
elif len(data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4]) == 18: elif len(data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4]) == 18:
print 'within decode address, lenth I think is 18'
return status,addressVersionNumber,streamNumber,'\x00\x00'+data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4] return status,addressVersionNumber,streamNumber,'\x00\x00'+data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4]
def addBMIfNotPresent(address): def addBMIfNotPresent(address):

View File

@ -5,13 +5,14 @@
#Right now, PyBitmessage only support connecting to stream 1. It doesn't yet contain logic to expand into further streams. #Right now, PyBitmessage only support connecting to stream 1. It doesn't yet contain logic to expand into further streams.
softwareVersion = '0.1.6' softwareVersion = '0.2.0'
verbose = 2 verbose = 2
maximumAgeOfAnObjectThatIAmWillingToAccept = 216000 #Equals two days and 12 hours. maximumAgeOfAnObjectThatIAmWillingToAccept = 216000 #Equals two days and 12 hours.
lengthOfTimeToLeaveObjectsInInventory = 237600 #Equals two days and 18 hours. This should be longer than maximumAgeOfAnObjectThatIAmWillingToAccept so that we don't process messages twice. lengthOfTimeToLeaveObjectsInInventory = 237600 #Equals two days and 18 hours. This should be longer than maximumAgeOfAnObjectThatIAmWillingToAccept so that we don't process messages twice.
maximumAgeOfObjectsThatIAdvertiseToOthers = 216000 #Equals two days and 12 hours maximumAgeOfObjectsThatIAdvertiseToOthers = 216000 #Equals two days and 12 hours
maximumAgeOfNodesThatIAdvertiseToOthers = 10800 #Equals three hours maximumAgeOfNodesThatIAdvertiseToOthers = 10800 #Equals three hours
storeConfigFilesInSameDirectoryAsProgram = True
userVeryEasyProofOfWorkForTesting = True #If you set this to True while on the normal network, you won't be able to send or sometimes receive messages.
import sys import sys
try: try:
@ -69,7 +70,7 @@ class outgoingSynSender(QThread):
time.sleep(1) time.sleep(1)
resetTime = int(time.time()) #used below to clear out the alreadyAttemptedConnectionsList periodically so that we will retry connecting to hosts to which we have already tried to connect. resetTime = int(time.time()) #used below to clear out the alreadyAttemptedConnectionsList periodically so that we will retry connecting to hosts to which we have already tried to connect.
while True: while True:
time.sleep(999999)#I'm using this to prevent connections for testing. #time.sleep(999999)#I'm using this to prevent connections for testing.
if len(self.selfInitiatedConnectionList) < 8: #maximum number of outgoing connections = 8 if len(self.selfInitiatedConnectionList) < 8: #maximum number of outgoing connections = 8
random.seed() random.seed()
HOST, = random.sample(knownNodes[self.streamNumber], 1) HOST, = random.sample(knownNodes[self.streamNumber], 1)
@ -354,7 +355,7 @@ class receiveDataThread(QThread):
print 'Inventory (SQL on disk) already has object listed in inv message.' print 'Inventory (SQL on disk) already has object listed in inv message.'
del self.objectsThatWeHaveYetToGet[objectHash] del self.objectsThatWeHaveYetToGet[objectHash]
else: else:
print 'processData function making request for object:', repr(objectHash) print 'processData function making request for object:', objectHash.encode('hex')
self.sendgetdata(objectHash) self.sendgetdata(objectHash)
del self.objectsThatWeHaveYetToGet[objectHash] #It is possible that the remote node doesn't respond with the object. In that case, we'll very likely get it from someone else anyway. del self.objectsThatWeHaveYetToGet[objectHash] #It is possible that the remote node doesn't respond with the object. In that case, we'll very likely get it from someone else anyway.
break break
@ -537,7 +538,6 @@ class receiveDataThread(QThread):
message = self.data[readPosition:readPosition+messageLength] message = self.data[readPosition:readPosition+messageLength]
readPosition += messageLength readPosition += messageLength
signature = self.data[readPosition:readPosition+nLength] signature = self.data[readPosition:readPosition+nLength]
print 'signature', repr(signature)
sendersPubkey = rsa.PublicKey(convertStringToInt(nString),convertStringToInt(eString)) sendersPubkey = rsa.PublicKey(convertStringToInt(nString),convertStringToInt(eString))
#print 'senders Pubkey', sendersPubkey #print 'senders Pubkey', sendersPubkey
try: try:
@ -595,13 +595,14 @@ class receiveDataThread(QThread):
print 'The time in the msg message is too old. Ignoring it. Time:', embeddedTime print 'The time in the msg message is too old. Ignoring it. Time:', embeddedTime
return return
readPosition += 4 readPosition += 4
inventoryHash = calculateInventoryHash(self.data[24:self.payloadLength+24])
streamNumberAsClaimedByMsg, streamNumberAsClaimedByMsgLength = decodeVarint(self.data[readPosition:readPosition+9]) streamNumberAsClaimedByMsg, streamNumberAsClaimedByMsgLength = decodeVarint(self.data[readPosition:readPosition+9])
if streamNumberAsClaimedByMsg != self.streamNumber: if streamNumberAsClaimedByMsg != self.streamNumber:
print 'The stream number encoded in this msg (' + streamNumberAsClaimedByMsg + ') message does not match the stream number on which it was received. Ignoring it.' print 'The stream number encoded in this msg (' + streamNumberAsClaimedByMsg + ') message does not match the stream number on which it was received. Ignoring it.'
return return
readPosition += streamNumberAsClaimedByMsgLength readPosition += streamNumberAsClaimedByMsgLength
inventoryHash = calculateInventoryHash(self.data[24:self.payloadLength+24])
inventoryLock.acquire() inventoryLock.acquire()
if inventoryHash in inventory: if inventoryHash in inventory:
print 'We have already received this msg message. Ignoring.' print 'We have already received this msg message. Ignoring.'
@ -640,10 +641,206 @@ class receiveDataThread(QThread):
printLock.release() printLock.release()
#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. #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 myECAddressHashes.items():
try:
data = cryptorObject.decrypt(self.data[readPosition:self.payloadLength+24])
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
print 'EC decryption successful using key associated with ripe hash:', key.encode('hex')
break
except Exception, err:
pass
#print 'cryptorObject.decrypt Exception:', err
if initialDecryptionSuccessful:
#This is a message bound for me.
flushInventory() #so that we won't accidentially receive this message twice if the user restarts Bitmessage violently.
readPosition = 0
messageVersion, messageVersionLength = decodeVarint(data[readPosition:readPosition+10])
readPosition += messageVersionLength
if messageVersion != 1:
print 'Cannot understand message versions other than one. Ignoring message.'
return
sendersAddressVersionNumber, sendersAddressVersionNumberLength = decodeVarint(data[readPosition:readPosition+10])
readPosition += sendersAddressVersionNumberLength
if sendersAddressVersionNumber == 0:
print 'Cannot understand sendersAddressVersionNumber = 0. Ignoring message.'
return
if sendersAddressVersionNumber >= 3:
print 'Sender\'s address version number', sendersAddressVersionNumber, ' not yet supported. Ignoring message.'
return
if len(data) < 170:
print 'Length of the unencrypted data is unreasonably short. Sanity check failed. Ignoring message.'
return
sendersStreamNumber, sendersStreamNumberLength = decodeVarint(data[readPosition:readPosition+10])
readPosition += sendersStreamNumberLength
behaviorBitfield = data[readPosition:readPosition+4]
print 'behaviorBitfield',behaviorBitfield.encode('hex')
readPosition += 4
pubSigningKey = '\x04' + data[readPosition:readPosition+64]
readPosition += 64
pubEncryptionKey = '\x04' + data[readPosition:readPosition+64]
readPosition += 64
endOfThePublicKeyPosition = readPosition #needed for when we store the pubkey in our database of pubkeys for later use.
if toRipe != data[readPosition:readPosition+20]:
printLock.acquire()
print 'The original sender of this message did not send it to you. Someone is attempting a Surreptitious Forwarding Attack.'
print 'See: http://tools.ietf.org/html/draft-ietf-smime-sender-auth-00'
print 'your toRipe:', toRipe.encode('hex')
print 'embedded destination toRipe:', data[readPosition:readPosition+20].encode('hex')
printLock.release()
return
readPosition += 20
messageEncodingType, messageEncodingTypeLength = decodeVarint(data[readPosition:readPosition+10])
readPosition += messageEncodingTypeLength
print 'Message Encoding Type:', messageEncodingType
messageLength, messageLengthLength = decodeVarint(data[readPosition:readPosition+10])
print 'message length:', messageLength
readPosition += messageLengthLength
message = data[readPosition:readPosition+messageLength]
#print 'First 150 characters of message:', repr(message[:150])
readPosition += messageLength
ackLength, ackLengthLength = decodeVarint(data[readPosition:readPosition+10])
readPosition += ackLengthLength
ackData = data[readPosition:readPosition+ackLength]
readPosition += ackLength
positionOfBottomOfAckData = readPosition #needed to mark the end of what is covered by the signature
signatureLength, signatureLengthLength = decodeVarint(data[readPosition:readPosition+10])
readPosition += signatureLengthLength
signature = data[readPosition:readPosition+signatureLength]
try:
highlevelcrypto.verify(data[:positionOfBottomOfAckData],signature,pubSigningKey.encode('hex'))
print 'ECDSA verify passed'
except Exception, err:
print 'ECDSA verify failed', err
return
printLock.acquire()
print 'As a matter of intellectual curiosity, here is the Bitcoin address associated with the keys owned by the other person:', calculateBitcoinAddressFromPubkey(pubSigningKey)
print 'And here is the testnet address:',calculateTestnetAddressFromPubkey(pubSigningKey),'. Be aware that the other person must take their private signing key from Bitmessage and import it into Bitcoin for it to be of any use. Do not use this unless you know what you are doing. Using testnet is recommended as no warranty is offered.'
printLock.release()
#calculate the fromRipe.
sha = hashlib.new('sha512')
sha.update(pubSigningKey+pubEncryptionKey)
ripe = hashlib.new('ripemd160')
ripe.update(sha.digest())
#Let's store the public key in case we want to reply to this person.
#We don't have the correct nonce or time (which would let us send out a pubkey message) so we'll just fill it with 1's. We won't be able to send this pubkey to others (without doing the proof of work ourselves, which this program is programmed to not do.)
t = (ripe.digest(),False,'\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF'+'\xFF\xFF\xFF\xFF'+data[messageVersionLength:endOfThePublicKeyPosition],int(time.time())+2419200) #after one month we may remove this pub key from our database. (2419200 = a month)
sqlLock.acquire()
sqlSubmitQueue.put('''INSERT INTO pubkeys VALUES (?,?,?,?)''')
sqlSubmitQueue.put(t)
sqlReturnQueue.get()
sqlLock.release()
blockMessage = False #Gets set to True if the user shouldn't see the message according to black or white lists.
fromAddress = encodeAddress(sendersAddressVersionNumber,sendersStreamNumber,ripe.digest())
if config.get('bitmessagesettings', 'blackwhitelist') == 'black': #If we are using a blacklist
t = (fromAddress,)
sqlLock.acquire()
sqlSubmitQueue.put('''SELECT label, enabled FROM blacklist where address=?''')
sqlSubmitQueue.put(t)
queryreturn = sqlReturnQueue.get()
sqlLock.release()
for row in queryreturn:
label, enabled = row
if enabled:
print 'Message ignored because address is in blacklist.'
blockMessage = True
else: #We're using a whitelist
t = (fromAddress,)
sqlLock.acquire()
sqlSubmitQueue.put('''SELECT label, enabled FROM whitelist where address=?''')
sqlSubmitQueue.put(t)
queryreturn = sqlReturnQueue.get()
sqlLock.release()
if queryreturn == []:
print 'Message ignored because address not in whitelist.'
blockMessage = True
for row in queryreturn: #It could be in the whitelist but disabled. Let's check.
label, enabled = row
if not enabled:
print 'Message ignored because address in whitelist but not enabled.'
blockMessage = True
if not blockMessage:
print 'fromAddress:', fromAddress
print 'First 150 characters of message:', repr(message[:150])
#Look up the destination address (my address) based on the destination ripe hash.
#I realize that I could have a data structure devoted to this task, or maintain an indexed table
#in the sql database, but I would prefer to minimize the number of data structures this program
#uses. Searching linearly through the user's short list of addresses doesn't take very long anyway.
configSections = config.sections()
for addressInKeysFile in configSections:
if addressInKeysFile <> 'bitmessagesettings':
status,addressVersionNumber,streamNumber,hash = decodeAddress(addressInKeysFile)
if hash == key:
toAddress = addressInKeysFile
toLabel = config.get(addressInKeysFile, 'label')
if toLabel == '':
toLabel = addressInKeysFile
if messageEncodingType == 2:
bodyPositionIndex = string.find(message,'\nBody:')
if bodyPositionIndex > 1:
subject = message[8:bodyPositionIndex]
body = message[bodyPositionIndex+6:]
else:
subject = ''
body = message
elif messageEncodingType == 1:
body = message
subject = ''
elif messageEncodingType == 0:
print 'messageEncodingType == 0. Doing nothing with the message. They probably just sent it so that we would store their public key or send their ack data for them.'
else:
body = 'Unknown encoding type.\n\n' + repr(message)
subject = ''
print 'within recmsg, inventoryHash is', inventoryHash.encode('hex')
if messageEncodingType <> 0:
sqlLock.acquire()
t = (inventoryHash,toAddress,fromAddress,subject,int(time.time()),body,'inbox')
sqlSubmitQueue.put('''INSERT INTO inbox VALUES (?,?,?,?,?,?,?)''')
sqlSubmitQueue.put(t)
sqlReturnQueue.get()
sqlLock.release()
self.emit(SIGNAL("displayNewMessage(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"),inventoryHash,toAddress,fromAddress,subject,body)
#Now let's send the acknowledgement
#POW, = unpack('>Q',hashlib.sha512(hashlib.sha512(ackData[24:]).digest()).digest()[4:12])
#if POW <= 2**64 / ((len(ackData[24:])+payloadLengthExtraBytes) * averageProofOfWorkNonceTrialsPerByte):
#print 'The POW is strong enough that this ackdataPayload will be accepted by the Bitmessage network.'
#Currently PyBitmessage only supports sending a message with the acknowledgement in the form of a msg message. But future versions, and other clients, could send any object and this software will relay them. This can be used to relay identifying information, like your public key, through another Bitmessage host in case you believe that your Internet connection is being individually watched. You may pick a random address, hope its owner is online, and send a message with encoding type 0 so that they ignore the message but send your acknowledgement data over the network. If you send and receive many messages, it would also be clever to take someone else's acknowledgement data and use it for your own. Assuming that your message is delivered successfully, both will be acknowledged simultaneously (though if it is not delivered successfully, you will be in a pickle.)
#print 'self.data before:', repr(self.data)
#We'll need to make sure that our client will properly process the ackData; if the packet is malformed, we could clear out self.data and an attacker could use that behavior to determine that we were capable of decoding this message.
ackDataValidThusFar = True
if len(ackData) < 24:
print 'The length of ackData is unreasonably short. Not sending ackData.'
ackDataValidThusFar = False
if ackData[0:4] != '\xe9\xbe\xb4\xd9':
print 'Ackdata magic bytes were wrong. Not sending ackData.'
ackDataValidThusFar = False
if ackDataValidThusFar:
ackDataPayloadLength, = unpack('>L',ackData[16:20])
if len(ackData)-24 != ackDataPayloadLength:
print 'ackData payload length doesn\'t match the payload length specified in the header. Not sending ackdata.'
ackDataValidThusFar = False
if ackDataValidThusFar:
print 'ackData is valid. Will process it.'
#self.data = self.data[:self.payloadLength+24] + ackData + self.data[self.payloadLength+24:]
self.ackDataThatWeHaveYetToSend.append(ackData) #When we have processed all data, the processData function will pop the ackData out and process it as if it is a message received from our peer.
#print 'self.data after:', repr(self.data)
#This section is for my RSA keys (version 1 addresses). If we don't have any version 1 addresses, then it won't matter.
initialDecryptionSuccessful = False
infile = cStringIO.StringIO(self.data[readPosition:self.payloadLength+24]) infile = cStringIO.StringIO(self.data[readPosition:self.payloadLength+24])
outfile = cStringIO.StringIO() outfile = cStringIO.StringIO()
#print 'len(myAddressHashes.items()):', len(myAddressHashes.items()) #print 'len(myRSAAddressHashes.items()):', len(myRSAAddressHashes.items())
for key, value in myAddressHashes.items(): for key, value in myRSAAddressHashes.items():
try: try:
decrypt_bigfile(infile, outfile, value) decrypt_bigfile(infile, outfile, value)
#The initial decryption passed though there is a small chance that the message isn't actually for me. We'll need to check that the 20 zeros are present. #The initial decryption passed though there is a small chance that the message isn't actually for me. We'll need to check that the 20 zeros are present.
@ -686,7 +883,6 @@ class receiveDataThread(QThread):
readPosition += sendersELength readPosition += sendersELength
endOfThePublicKeyPosition = readPosition endOfThePublicKeyPosition = readPosition
messageEncodingType, messageEncodingTypeLength = decodeVarint(data[readPosition:readPosition+10]) messageEncodingType, messageEncodingTypeLength = decodeVarint(data[readPosition:readPosition+10])
readPosition += messageEncodingTypeLength readPosition += messageEncodingTypeLength
print 'Message Encoding Type:', messageEncodingType print 'Message Encoding Type:', messageEncodingType
@ -714,7 +910,7 @@ class receiveDataThread(QThread):
except Exception, err: except Exception, err:
print 'verify failed', err print 'verify failed', err
if verifyPassed: if verifyPassed:
#Let's calculate the fromAddress. #calculate the fromRipe.
sha = hashlib.new('sha512') sha = hashlib.new('sha512')
sha.update(sendersN+sendersE) sha.update(sendersN+sendersE)
ripe = hashlib.new('ripemd160') ripe = hashlib.new('ripemd160')
@ -868,6 +1064,8 @@ class receiveDataThread(QThread):
#We have received a pubkey #We have received a pubkey
def recpubkey(self): def recpubkey(self):
if self.payloadLength < 32: #sanity check
return
#We must check to make sure the proof of work is sufficient. #We must check to make sure the proof of work is sufficient.
if not self.isProofOfWorkSufficient(): if not self.isProofOfWorkSufficient():
print 'Proof of work in pubkey message insufficient.' print 'Proof of work in pubkey message insufficient.'
@ -884,54 +1082,105 @@ class receiveDataThread(QThread):
inventoryLock.release() inventoryLock.release()
return return
readPosition = 24 #for the message header
readPosition += 8 #for the nonce
#bitfieldBehaviors = self.data[readPosition:readPosition+4] The bitfieldBehaviors used to be here
embeddedTime = self.data[readPosition:readPosition+4]
readPosition += 4 #for the time
addressVersion, varintLength = decodeVarint(self.data[readPosition:readPosition+10])
readPosition += varintLength
streamNumber, varintLength = decodeVarint(self.data[readPosition:readPosition+10])
readPosition += varintLength
if self.streamNumber != streamNumber:
print 'stream number embedded in this pubkey doesn\'t match our stream number. Ignoring.'
return
objectType = 'pubkey' objectType = 'pubkey'
inventory[inventoryHash] = (objectType, self.streamNumber, self.data[24:self.payloadLength+24], int(time.time())) inventory[inventoryHash] = (objectType, self.streamNumber, self.data[24:self.payloadLength+24], int(time.time()))
inventoryLock.release() inventoryLock.release()
self.broadcastinv(inventoryHash) self.broadcastinv(inventoryHash)
self.emit(SIGNAL("incrementNumberOfPubkeysProcessed()")) self.emit(SIGNAL("incrementNumberOfPubkeysProcessed()"))
readPosition = 24 #for the message header if addressVersion == 0:
readPosition += 8 #for the nonce print 'Within recpubkey, addressVersion of zero doesn\'t make sense.'
bitfieldBehaviors = self.data[readPosition:readPosition+4]
readPosition += 4 #for the bitfield of behaviors and features
addressVersion, varintLength = decodeVarint(self.data[readPosition:readPosition+10])
if addressVersion >= 2:
print 'This version of Bitmessgae cannot handle version', addressVersion,'addresses.'
return return
readPosition += varintLength if addressVersion >= 3:
streamNumber, varintLength = decodeVarint(self.data[readPosition:readPosition+10]) printLock.acquire()
readPosition += varintLength print 'This version of Bitmessage cannot handle version', addressVersion,'addresses.'
#ripe = self.data[readPosition:readPosition+20] printLock.release()
#readPosition += 20 #for the ripe hash return
nLength, varintLength = decodeVarint(self.data[readPosition:readPosition+10]) if addressVersion == 2:
readPosition += varintLength print 'within recpubkey, the self.payloadLength is', self.payloadLength,'. It should be 146.'
nString = self.data[readPosition:readPosition+nLength] if self.payloadLength < 146: #sanity check. This is the minimum possible length.
readPosition += nLength print 'payloadLength less than 146. Sanity check failed.'
eLength, varintLength = decodeVarint(self.data[readPosition:readPosition+10]) return
readPosition += varintLength bitfieldBehaviors = self.data[readPosition:readPosition+4]
eString = self.data[readPosition:readPosition+eLength] readPosition += 4
readPosition += eLength publicSigningKey = self.data[readPosition:readPosition+64]
#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 probably test these keys here.
readPosition += 64
publicEncryptionKey = self.data[readPosition:readPosition+64]
if len(publicEncryptionKey) < 64:
print 'publicEncryptionKey length less than 64. Sanity check failed.'
return
sha = hashlib.new('sha512')
print 'recpubkey hashing this data to make the ripe:', repr('\x04'+publicSigningKey+'\x04'+publicEncryptionKey)
sha.update('\x04'+publicSigningKey+'\x04'+publicEncryptionKey)
ripeHasher = hashlib.new('ripemd160')
ripeHasher.update(sha.digest())
ripe = ripeHasher.digest()
sha = hashlib.new('sha512') printLock.acquire()
sha.update(nString+eString) print 'within recpubkey, addressVersion', addressVersion
ripeHasher = hashlib.new('ripemd160') print 'streamNumber', streamNumber
ripeHasher.update(sha.digest()) print 'ripe', ripe.encode('hex')
ripe = ripeHasher.digest() print 'publicSigningKey in hex:', publicSigningKey.encode('hex')
print 'publicEncryptionKey in hex:', publicEncryptionKey.encode('hex')
printLock.release()
print 'within recpubkey, addressVersion', addressVersion t = (ripe,True,self.data[24:24+self.payloadLength],int(time.time())+604800) #after one week we may remove this pub key from our database.
print 'streamNumber', streamNumber sqlLock.acquire()
print 'ripe', repr(ripe) sqlSubmitQueue.put('''INSERT INTO pubkeys VALUES (?,?,?,?)''')
print 'n=', convertStringToInt(nString) sqlSubmitQueue.put(t)
print 'e=', convertStringToInt(eString) sqlReturnQueue.get()
sqlLock.release()
printLock.acquire()
print 'added foreign pubkey into our database'
printLock.release()
workerQueue.put(('newpubkey',(addressVersion,streamNumber,ripe)))
t = (ripe,True,self.data[24:24+self.payloadLength],int(time.time())+604800) #after one week we may remove this pub key from our database. elif addressVersion == 1:
sqlLock.acquire() nLength, varintLength = decodeVarint(self.data[readPosition:readPosition+10])
sqlSubmitQueue.put('''INSERT INTO pubkeys VALUES (?,?,?,?)''') readPosition += varintLength
sqlSubmitQueue.put(t) nString = self.data[readPosition:readPosition+nLength]
sqlReturnQueue.get() readPosition += nLength
sqlLock.release() eLength, varintLength = decodeVarint(self.data[readPosition:readPosition+10])
print 'added foreign pubkey into our database' readPosition += varintLength
workerQueue.put(('newpubkey',(addressVersion,streamNumber,ripe))) eString = self.data[readPosition:readPosition+eLength]
readPosition += eLength
sha = hashlib.new('sha512')
sha.update(nString+eString)
ripeHasher = hashlib.new('ripemd160')
ripeHasher.update(sha.digest())
ripe = ripeHasher.digest()
print 'within recpubkey, addressVersion', addressVersion
print 'streamNumber', streamNumber
print 'ripe', repr(ripe)
print 'n=', convertStringToInt(nString)
print 'e=', convertStringToInt(eString)
t = (ripe,True,self.data[24:24+self.payloadLength],int(time.time())+604800) #after one week we may remove this pub key from our database.
sqlLock.acquire()
sqlSubmitQueue.put('''INSERT INTO pubkeys VALUES (?,?,?,?)''')
sqlSubmitQueue.put(t)
sqlReturnQueue.get()
sqlLock.release()
print 'added foreign pubkey into our database'
workerQueue.put(('newpubkey',(addressVersion,streamNumber,ripe)))
#We have received a getpubkey message #We have received a getpubkey message
def recgetpubkey(self): def recgetpubkey(self):
@ -970,12 +1219,88 @@ class receiveDataThread(QThread):
#This getpubkey request is valid so far. Forward to peers. #This getpubkey request is valid so far. Forward to peers.
broadcastToSendDataQueues((self.streamNumber,'send',self.data[:self.payloadLength+24])) broadcastToSendDataQueues((self.streamNumber,'send',self.data[:self.payloadLength+24]))
if addressVersionNumber == 0:
if addressVersionNumber > 1: print 'The addressVersionNumber of the pubkey request is zero. That doesn\'t make any sense. Ignoring it.'
print 'The addressVersionNumber of the pubkey is too high. Can\'t understand. Ignoring it.'
return return
if self.data[36+addressVersionLength+streamNumberLength:56+addressVersionLength+streamNumberLength] in myAddressHashes: elif addressVersionNumber > 2:
print 'Found getpubkey requested hash in my list of hashes.' print 'The addressVersionNumber of the pubkey request is too high. Can\'t understand. Ignoring it.'
return
print 'the hash requested in this getpubkey request is:', self.data[36+addressVersionLength+streamNumberLength:56+addressVersionLength+streamNumberLength].encode('hex')
if self.data[36+addressVersionLength+streamNumberLength:56+addressVersionLength+streamNumberLength] in myECAddressHashes: #if this address hash is one of mine
print 'Found getpubkey requested hash in my list of EC hashes.'
#check to see whether we have already calculated the nonce and transmitted this key before
sqlLock.acquire()#released at the bottom of this payload generation section
t = (self.data[36+addressVersionLength+streamNumberLength:56+addressVersionLength+streamNumberLength],) #this prevents SQL injection
sqlSubmitQueue.put('SELECT * FROM pubkeys WHERE hash=?')
sqlSubmitQueue.put(t)
queryreturn = sqlReturnQueue.get()
#print 'queryreturn', queryreturn
if queryreturn == []:
print 'pubkey request is for me but the pubkey is not in our database of pubkeys. Making it.'
payload = pack('>I',(int(time.time()))) #todo: fuzz this time
payload += encodeVarint(2) #Address version number
payload += encodeVarint(streamNumber)
payload += '\x00\x00\x00\x01' #bitfield of features supported by me (see the wiki).
privSigningKeyBase58 = config.get(encodeAddress(addressVersionNumber,streamNumber,self.data[36+addressVersionLength+streamNumberLength:56+addressVersionLength+streamNumberLength]), 'privsigningkey')
privEncryptionKeyBase58 = config.get(encodeAddress(addressVersionNumber,streamNumber,self.data[36+addressVersionLength+streamNumberLength:56+addressVersionLength+streamNumberLength]), 'privencryptionkey')
privSigningKeyHex = decodeWalletImportFormat(privSigningKeyBase58).encode('hex')
privEncryptionKeyHex = decodeWalletImportFormat(privEncryptionKeyBase58).encode('hex')
pubSigningKey = highlevelcrypto.privToPub(privSigningKeyHex).decode('hex')
pubEncryptionKey = highlevelcrypto.privToPub(privEncryptionKeyHex).decode('hex')
#print 'within recgetpubkey'
#print 'pubSigningKey in hex:', pubSigningKey.encode('hex')
#print 'pubEncryptionKey in hex:', pubEncryptionKey.encode('hex')
payload += pubSigningKey[1:]
payload += pubEncryptionKey[1:]
#Time to do the POW for this pubkey message
nonce = 0
trialValue = 99999999999999999999
target = 2**64 / ((len(payload)+payloadLengthExtraBytes+8) * averageProofOfWorkNonceTrialsPerByte)
print '(For pubkey message) Doing proof of work...'
initialHash = hashlib.sha512(payload).digest()
while trialValue > target:
nonce += 1
trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8])
#trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + payload).digest()).digest()[4:12])
print '(For pubkey message) Found proof of work', trialValue, 'Nonce:', nonce
payload = pack('>Q',nonce) + payload
t = (self.data[36+addressVersionLength+streamNumberLength:56+addressVersionLength+streamNumberLength],True,payload,int(time.time())+1209600) #after two weeks (1,209,600 seconds), we may remove our own pub key from our database. It will be regenerated and put back in the database if it is requested.
sqlSubmitQueue.put('''INSERT INTO pubkeys VALUES (?,?,?,?)''')
sqlSubmitQueue.put(t)
queryreturn = sqlReturnQueue.get()
#Now that we have the full pubkey message ready either from making it just now or making it earlier, we can send it out.
t = (self.data[36+addressVersionLength+streamNumberLength:56+addressVersionLength+streamNumberLength],) #this prevents SQL injection
sqlSubmitQueue.put('''SELECT * FROM pubkeys WHERE hash=? AND havecorrectnonce=1''')
sqlSubmitQueue.put(t)
queryreturn = sqlReturnQueue.get()
if queryreturn == []:
sys.stderr.write('Error: pubkey which we just put in our pubkey database suddenly is not there. Is the database malfunctioning?')
sqlLock.release()
return
for row in queryreturn:
hash, havecorrectnonce, payload, timeLastRequested = row
if timeLastRequested < int(time.time())+604800: #if the last time anyone asked about this hash was this week, extend the time.
t = (int(time.time())+604800,hash)
sqlSubmitQueue.put('''UPDATE pubkeys set time=? WHERE hash=?''')
sqlSubmitQueue.put(t)
queryreturn = sqlReturnQueue.get()
sqlLock.release()
inventoryHash = calculateInventoryHash(payload)
objectType = 'pubkey'
inventory[inventoryHash] = (objectType, self.streamNumber, payload, int(time.time()))
self.broadcastinv(inventoryHash)
elif self.data[36+addressVersionLength+streamNumberLength:56+addressVersionLength+streamNumberLength] in myRSAAddressHashes:
print 'Found getpubkey requested hash in my list of RSA hashes.'
#check to see whether we have already calculated the nonce and transmitted this key before #check to see whether we have already calculated the nonce and transmitted this key before
sqlLock.acquire()#released at the bottom of this payload generation section sqlLock.acquire()#released at the bottom of this payload generation section
t = (self.data[36+addressVersionLength+streamNumberLength:56+addressVersionLength+streamNumberLength],) #this prevents SQL injection t = (self.data[36+addressVersionLength+streamNumberLength:56+addressVersionLength+streamNumberLength],) #this prevents SQL injection
@ -1098,7 +1423,7 @@ class receiveDataThread(QThread):
try: try:
for i in range(value): for i in range(value):
hash = self.data[24+lengthOfVarint+(i*32):56+lengthOfVarint+(i*32)] hash = self.data[24+lengthOfVarint+(i*32):56+lengthOfVarint+(i*32)]
print 'getdata request for item:', repr(hash), 'length', len(hash) print 'getdata request for item:', hash.encode('hex'), 'length', len(hash)
#print 'inventory is', inventory #print 'inventory is', inventory
if hash in inventory: if hash in inventory:
objectType, streamNumber, payload, receivedTime = inventory[hash] objectType, streamNumber, payload, receivedTime = inventory[hash]
@ -1170,7 +1495,7 @@ class receiveDataThread(QThread):
headerData = headerData + pack('>L',len(payload)) headerData = headerData + pack('>L',len(payload))
headerData = headerData + hashlib.sha512(payload).digest()[:4] headerData = headerData + hashlib.sha512(payload).digest()[:4]
printLock.acquire() printLock.acquire()
print 'broadcasting inv with hash:', repr(hash) print 'broadcasting inv with hash:', hash.encode('hex')
printLock.release() printLock.release()
broadcastToSendDataQueues((self.streamNumber, 'send', headerData + payload)) broadcastToSendDataQueues((self.streamNumber, 'send', headerData + payload))
@ -1606,6 +1931,84 @@ def convertIntToString(n):
def convertStringToInt(s): def convertStringToInt(s):
return int(s.encode('hex'), 16) return int(s.encode('hex'), 16)
def decodeWalletImportFormat(WIFstring):
fullString = arithmetic.changebase(WIFstring,58,256)
privkey = fullString[:-4]
if fullString[-4:] != hashlib.sha256(hashlib.sha256(privkey).digest()).digest()[:4]:
sys.stderr.write('Major problem! When trying to decode one of your private keys, the checksum failed. Here is the PRIVATE key: %s\n' % str(WIFstring))
return ""
else:
#checksum passed
if privkey[0] == '\x80':
return privkey[1:]
else:
sys.stderr.write('Major problem! When trying to decode one of your private keys, the checksum passed but the key doesn\'t begin with hex 80. Here is the PRIVATE key: %s\n' % str(WIFstring))
return ""
def reloadMyAddressHashes():
printLock.acquire()
print 'reloading my address hashes'
printLock.release()
myRSAAddressHashes.clear()
#myPrivateKeys.clear()
configSections = config.sections()
for addressInKeysFile in configSections:
if addressInKeysFile <> 'bitmessagesettings':
isEnabled = config.getboolean(addressInKeysFile, 'enabled')
if isEnabled:
status,addressVersionNumber,streamNumber,hash = decodeAddress(addressInKeysFile)
if addressVersionNumber == 2:
privEncryptionKey = decodeWalletImportFormat(config.get(addressInKeysFile, 'privencryptionkey')).encode('hex') #returns a simple 32 bytes of information encoded in 64 Hex characters, or null if there was an error
if len(privEncryptionKey) == 64:#It is 32 bytes encoded as 64 hex characters
myECAddressHashes[hash] = highlevelcrypto.makeCryptor(privEncryptionKey)
elif addressVersionNumber == 1:
n = config.getint(addressInKeysFile, 'n')
e = config.getint(addressInKeysFile, 'e')
d = config.getint(addressInKeysFile, 'd')
p = config.getint(addressInKeysFile, 'p')
q = config.getint(addressInKeysFile, 'q')
myRSAAddressHashes[hash] = rsa.PrivateKey(n,e,d,p,q)
#This function expects that pubkey begin with \x04
def calculateBitcoinAddressFromPubkey(pubkey):
if len(pubkey)!= 65:
print 'Could not calculate Bitcoin address from pubkey because function was passed a pubkey that was', len(pubkey),'bytes long rather than 65.'
return "error"
ripe = hashlib.new('ripemd160')
sha = hashlib.new('sha256')
sha.update(pubkey)
ripe.update(sha.digest())
ripeWithProdnetPrefix = '\x00' + ripe.digest()
checksum = hashlib.sha256(hashlib.sha256(ripeWithProdnetPrefix).digest()).digest()[:4]
binaryBitcoinAddress = ripeWithProdnetPrefix + checksum
numberOfZeroBytesOnBinaryBitcoinAddress = 0
while binaryBitcoinAddress[0] == '\x00':
numberOfZeroBytesOnBinaryBitcoinAddress += 1
binaryBitcoinAddress = binaryBitcoinAddress[1:]
base58encoded = arithmetic.changebase(binaryBitcoinAddress,256,58)
return "1"*numberOfZeroBytesOnBinaryBitcoinAddress + base58encoded
def calculateTestnetAddressFromPubkey(pubkey):
if len(pubkey)!= 65:
print 'Could not calculate Bitcoin address from pubkey because function was passed a pubkey that was', len(pubkey),'bytes long rather than 65.'
return "error"
ripe = hashlib.new('ripemd160')
sha = hashlib.new('sha256')
sha.update(pubkey)
ripe.update(sha.digest())
ripeWithProdnetPrefix = '\x6F' + ripe.digest()
checksum = hashlib.sha256(hashlib.sha256(ripeWithProdnetPrefix).digest()).digest()[:4]
binaryBitcoinAddress = ripeWithProdnetPrefix + checksum
numberOfZeroBytesOnBinaryBitcoinAddress = 0
while binaryBitcoinAddress[0] == '\x00':
numberOfZeroBytesOnBinaryBitcoinAddress += 1
binaryBitcoinAddress = binaryBitcoinAddress[1:]
base58encoded = arithmetic.changebase(binaryBitcoinAddress,256,58)
return "1"*numberOfZeroBytesOnBinaryBitcoinAddress + base58encoded
#This thread exists because SQLITE3 is so un-threadsafe that we must submit queries to it and it puts results back in a different queue. They won't let us just use locks. #This thread exists because SQLITE3 is so un-threadsafe that we must submit queries to it and it puts results back in a different queue. They won't let us just use locks.
class sqlThread(QThread): class sqlThread(QThread):
def __init__(self, parent = None): def __init__(self, parent = None):
@ -1792,7 +2195,7 @@ class singleWorker(QThread):
#We'll need to request the pub key because we don't have it. #We'll need to request the pub key because we don't have it.
if not toRipe in neededPubkeys: if not toRipe in neededPubkeys:
neededPubkeys[toRipe] = 0 neededPubkeys[toRipe] = 0
print 'requesting pubkey:', repr(toRipe) print 'requesting pubkey:', toRipe.encode('hex')
self.requestPubKey(toAddressVersionNumber,toStreamNumber,toRipe) self.requestPubKey(toAddressVersionNumber,toStreamNumber,toRipe)
else: else:
print 'We have already requested this pubkey (the ripe hash is in neededPubkeys). We will re-request again soon.' print 'We have already requested this pubkey (the ripe hash is in neededPubkeys). We will re-request again soon.'
@ -1812,7 +2215,7 @@ class singleWorker(QThread):
del neededPubkeys[toRipe] del neededPubkeys[toRipe]
self.sendMsg(toRipe) self.sendMsg(toRipe)
else: else:
print 'We don\'t need this pub key. We didn\'t ask for it. Pubkey hash:', repr(toRipe) print 'We don\'t need this pub key. We didn\'t ask for it. Pubkey hash:', toRipe.encode('hex')
workerQueue.task_done() workerQueue.task_done()
@ -1855,11 +2258,11 @@ class singleWorker(QThread):
payload += eString payload += eString
payload += messageToTransmit payload += messageToTransmit
signature = rsa.sign(messageToTransmit,myPrivatekey,'SHA-512') signature = rsa.sign(messageToTransmit,myPrivatekey,'SHA-512')
print 'signature', repr(signature) #print 'signature', signature.encode('hex')
payload += signature payload += signature
print 'nString', repr(nString) #print 'nString', repr(nString)
print 'eString', repr(eString) #print 'eString', repr(eString)
nonce = 0 nonce = 0
trialValue = 99999999999999999999 trialValue = 99999999999999999999
@ -1909,74 +2312,134 @@ class singleWorker(QThread):
for row in queryreturn: for row in queryreturn:
toaddress, fromaddress, subject, message, ackdata = row toaddress, fromaddress, subject, message, ackdata = row
ackdataForWhichImWatching[ackdata] = 0 ackdataForWhichImWatching[ackdata] = 0
status,addressVersionNumber,toStreamNumber,hash = decodeAddress(toaddress) toStatus,toAddressVersionNumber,toStreamNumber,toHash = decodeAddress(toaddress)
#if hash == toRipe: fromStatus,fromAddressVersionNumber,fromStreamNumber,fromHash = decodeAddress(fromaddress)
self.emit(SIGNAL("updateSentItemStatusByAckdata(PyQt_PyObject,PyQt_PyObject)"),ackdata,'Doing work necessary to send the message.') self.emit(SIGNAL("updateSentItemStatusByAckdata(PyQt_PyObject,PyQt_PyObject)"),ackdata,'Doing work necessary to send the message.')
printLock.acquire() printLock.acquire()
print 'Found the necessary message that needs to be sent with this pubkey.' print 'Found the necessary message that needs to be sent with this pubkey.'
print 'First 150 characters of message:', message[:150] print 'First 150 characters of message:', message[:150]
printLock.release() printLock.release()
payload = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' #this run of nulls allows the true message receiver to identify his message
payload += '\x01' #Message version.
payload += '\x00\x00\x00\x01'
fromStatus,fromAddressVersionNumber,fromStreamNumber,fromHash = decodeAddress(fromaddress)
payload += encodeVarint(fromAddressVersionNumber)
payload += encodeVarint(fromStreamNumber)
sendersN = convertIntToString(config.getint(fromaddress, 'n')) if fromAddressVersionNumber == 2:
payload += encodeVarint(len(sendersN)) payload = '\x01' #Message version.
payload += sendersN payload += encodeVarint(fromAddressVersionNumber)
payload += encodeVarint(fromStreamNumber)
payload += '\x00\x00\x00\x01'
sendersE = convertIntToString(config.getint(fromaddress, 'e')) #We need to convert our private keys to public keys in order to include them.
payload += encodeVarint(len(sendersE)) privSigningKeyBase58 = config.get(fromaddress, 'privsigningkey')
payload += sendersE privEncryptionKeyBase58 = config.get(fromaddress, 'privencryptionkey')
payload += '\x02' #Type 2 is simple UTF-8 message encoding. privSigningKeyHex = decodeWalletImportFormat(privSigningKeyBase58).encode('hex')
messageToTransmit = 'Subject:' + subject + '\n' + 'Body:' + message privEncryptionKeyHex = decodeWalletImportFormat(privEncryptionKeyBase58).encode('hex')
payload += encodeVarint(len(messageToTransmit))
payload += messageToTransmit
#Later, if anyone impliments clients that don't send the ack_data, then we should probably check here to make sure that the receiver will make use of this ack_data and not attach it if not. pubSigningKey = highlevelcrypto.privToPub(privSigningKeyHex).decode('hex')
fullAckPayload = self.generateFullAckMessage(ackdata,toStreamNumber) pubEncryptionKey = highlevelcrypto.privToPub(privEncryptionKeyHex).decode('hex')
payload += encodeVarint(len(fullAckPayload))
payload += fullAckPayload
sendersPrivKey = rsa.PrivateKey(config.getint(fromaddress, 'n'),config.getint(fromaddress, 'e'),config.getint(fromaddress, 'd'),config.getint(fromaddress, 'p'),config.getint(fromaddress, 'q'))
payload += rsa.sign(payload,sendersPrivKey,'SHA-512') payload += pubSigningKey[1:]
payload += pubEncryptionKey[1:]
print 'attaching pubSigningKey, length:', len(pubSigningKey), 'should be 64.'
sqlLock.acquire() payload += toHash
sqlSubmitQueue.put('SELECT * FROM pubkeys WHERE hash=?') payload += '\x02' #Type 2 is simple UTF-8 message encoding.
sqlSubmitQueue.put((toRipe,)) messageToTransmit = 'Subject:' + subject + '\n' + 'Body:' + message
queryreturn = sqlReturnQueue.get() payload += encodeVarint(len(messageToTransmit))
sqlLock.release() payload += messageToTransmit
fullAckPayload = self.generateFullAckMessage(ackdata,toStreamNumber)
payload += encodeVarint(len(fullAckPayload))
payload += fullAckPayload
signature = highlevelcrypto.sign(payload,privSigningKeyHex)
payload += encodeVarint(len(signature))
payload += signature
for row in queryreturn: elif fromAddressVersionNumber == 1:
hash, havecorrectnonce, pubkeyPayload, timeLastRequested = row payload = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' #this run of nulls allows the true message receiver to identify his message
payload += '\x01' #Message version.
payload += '\x00\x00\x00\x01'
payload += encodeVarint(fromAddressVersionNumber)
payload += encodeVarint(fromStreamNumber)
readPosition = 8 #to bypass the nonce sendersN = convertIntToString(config.getint(fromaddress, 'n'))
bitfieldBehaviors = pubkeyPayload[8:12] payload += encodeVarint(len(sendersN))
readPosition += 4 #to bypass the bitfield of behaviors payload += sendersN
addressVersion, addressVersionLength = decodeVarint(pubkeyPayload[readPosition:readPosition+10])
readPosition += addressVersionLength
streamNumber, streamNumberLength = decodeVarint(pubkeyPayload[readPosition:readPosition+10])
readPosition += streamNumberLength
nLength, nLengthLength = decodeVarint(pubkeyPayload[readPosition:readPosition+10])
readPosition += nLengthLength
n = convertStringToInt(pubkeyPayload[readPosition:readPosition+nLength])
readPosition += nLength
eLength, eLengthLength = decodeVarint(pubkeyPayload[readPosition:readPosition+10])
readPosition += eLengthLength
e = convertStringToInt(pubkeyPayload[readPosition:readPosition+eLength])
receiversPubkey = rsa.PublicKey(n,e)
infile = cStringIO.StringIO(payload) sendersE = convertIntToString(config.getint(fromaddress, 'e'))
outfile = cStringIO.StringIO() payload += encodeVarint(len(sendersE))
#print 'Encrypting using public key:', receiversPubkey payload += sendersE
encrypt_bigfile(infile,outfile,receiversPubkey)
encrypted = outfile.getvalue() payload += '\x02' #Type 2 is simple UTF-8 message encoding.
infile.close() messageToTransmit = 'Subject:' + subject + '\n' + 'Body:' + message
outfile.close() payload += encodeVarint(len(messageToTransmit))
payload += messageToTransmit
#Later, if anyone impliments clients that don't send the ack_data, then we should probably check here to make sure that the receiver will make use of this ack_data and not attach it if not.
fullAckPayload = self.generateFullAckMessage(ackdata,toStreamNumber)
payload += encodeVarint(len(fullAckPayload))
payload += fullAckPayload
sendersPrivKey = rsa.PrivateKey(config.getint(fromaddress, 'n'),config.getint(fromaddress, 'e'),config.getint(fromaddress, 'd'),config.getint(fromaddress, 'p'),config.getint(fromaddress, 'q'))
payload += rsa.sign(payload,sendersPrivKey,'SHA-512')
#We have assembled the data that will be encrypted. Now let us fetch the recipient's public key out of our database and do the encryption.
if toAddressVersionNumber == 2:
sqlLock.acquire()
sqlSubmitQueue.put('SELECT * FROM pubkeys WHERE hash=?')
sqlSubmitQueue.put((toRipe,))
queryreturn = sqlReturnQueue.get()
sqlLock.release()
for row in queryreturn:
hash, havecorrectnonce, pubkeyPayload, timeLastRequested = row
readPosition = 8 #to bypass the nonce
readPosition += 4 #to bypass the embedded time
readPosition += 1 #to bypass the address version whose length is definitely 1
streamNumber, streamNumberLength = decodeVarint(pubkeyPayload[readPosition:readPosition+10])
readPosition += streamNumberLength
behaviorBitfield = pubkeyPayload[readPosition:readPosition+4]
readPosition += 4 #to bypass the bitfield of behaviors
#pubSigningKeyBase256 = pubkeyPayload[readPosition:readPosition+64] #We don't use this key for anything here.
readPosition += 64
pubEncryptionKeyBase256 = pubkeyPayload[readPosition:readPosition+64]
readPosition += 64
encrypted = highlevelcrypto.encrypt(payload,"04"+pubEncryptionKeyBase256.encode('hex'))
elif toAddressVersionNumber == 1:
sqlLock.acquire()
sqlSubmitQueue.put('SELECT * FROM pubkeys WHERE hash=?')
sqlSubmitQueue.put((toRipe,))
queryreturn = sqlReturnQueue.get()
sqlLock.release()
for row in queryreturn:
hash, havecorrectnonce, pubkeyPayload, timeLastRequested = row
readPosition = 8 #to bypass the nonce
behaviorBitfield = pubkeyPayload[8:12]
readPosition += 4 #to bypass the bitfield of behaviors
addressVersion, addressVersionLength = decodeVarint(pubkeyPayload[readPosition:readPosition+10])
readPosition += addressVersionLength
streamNumber, streamNumberLength = decodeVarint(pubkeyPayload[readPosition:readPosition+10])
readPosition += streamNumberLength
nLength, nLengthLength = decodeVarint(pubkeyPayload[readPosition:readPosition+10])
readPosition += nLengthLength
n = convertStringToInt(pubkeyPayload[readPosition:readPosition+nLength])
readPosition += nLength
eLength, eLengthLength = decodeVarint(pubkeyPayload[readPosition:readPosition+10])
readPosition += eLengthLength
e = convertStringToInt(pubkeyPayload[readPosition:readPosition+eLength])
receiversPubkey = rsa.PublicKey(n,e)
infile = cStringIO.StringIO(payload)
outfile = cStringIO.StringIO()
#print 'Encrypting using public key:', receiversPubkey
encrypt_bigfile(infile,outfile,receiversPubkey)
encrypted = outfile.getvalue()
infile.close()
outfile.close()
nonce = 0 nonce = 0
trialValue = 99999999999999999999 trialValue = 99999999999999999999
@ -2002,9 +2465,9 @@ class singleWorker(QThread):
print 'sending inv (within sendmsg function)' print 'sending inv (within sendmsg function)'
payload = '\x01' + inventoryHash payload = '\x01' + inventoryHash
headerData = '\xe9\xbe\xb4\xd9' #magic bits, slighly different from Bitcoin's magic bits. headerData = '\xe9\xbe\xb4\xd9' #magic bits, slighly different from Bitcoin's magic bits.
headerData = headerData + 'inv\x00\x00\x00\x00\x00\x00\x00\x00\x00' headerData += 'inv\x00\x00\x00\x00\x00\x00\x00\x00\x00'
headerData = headerData + pack('>L',len(payload)) #payload length. Note that we add an extra 8 for the nonce. headerData += pack('>L',len(payload)) #payload length. Note that we add an extra 8 for the nonce.
headerData = headerData + hashlib.sha512(payload).digest()[:4] headerData += hashlib.sha512(payload).digest()[:4]
broadcastToSendDataQueues((toStreamNumber, 'send', headerData + payload)) broadcastToSendDataQueues((toStreamNumber, 'send', headerData + payload))
#Update the status of the message in the 'sent' table to have a 'sent' status #Update the status of the message in the 'sent' table to have a 'sent' status
@ -2028,6 +2491,7 @@ class singleWorker(QThread):
payload += encodeVarint(addressVersionNumber) payload += encodeVarint(addressVersionNumber)
payload += encodeVarint(streamNumber) payload += encodeVarint(streamNumber)
payload += ripe payload += ripe
print 'making request for pubkey with ripe:', ripe.encode('hex')
nonce = 0 nonce = 0
trialValue = 99999999999999999999 trialValue = 99999999999999999999
#print 'trial value', trialValue #print 'trial value', trialValue
@ -2128,13 +2592,9 @@ class addressGenerator(QThread):
print 'ripe.digest', ripe.digest().encode('hex') print 'ripe.digest', ripe.digest().encode('hex')
if ripe.digest()[:2] == '\x00\x00': if ripe.digest()[:2] == '\x00\x00':
address = encodeAddress(2,self.streamNumber,ripe.digest()[2:]) address = encodeAddress(2,self.streamNumber,ripe.digest()[2:])
print 'address has 18 byte ripe:', address
elif ripe.digest()[:1] == '\x00': elif ripe.digest()[:1] == '\x00':
address = encodeAddress(2,self.streamNumber,ripe.digest()[1:]) address = encodeAddress(2,self.streamNumber,ripe.digest()[1:])
print 'address has 19 byte ripe:', address #self.emit(SIGNAL("updateStatusBar(PyQt_PyObject)"),'Finished generating address. Writing to keys.dat')
self.emit(SIGNAL("updateStatusBar(PyQt_PyObject)"),'Finished generating address. Writing to keys.dat')
status,addressVersionNumber,streamNumber,hash = decodeAddress(address)
print status,addressVersionNumber,streamNumber,hash.encode('hex')
#An excellent way for us to store our keys is in Wallet Import Format. Let us convert now. #An excellent way for us to store our keys is in Wallet Import Format. Let us convert now.
#https://en.bitcoin.it/wiki/Wallet_import_format #https://en.bitcoin.it/wiki/Wallet_import_format
@ -2160,11 +2620,73 @@ class addressGenerator(QThread):
self.emit(SIGNAL("updateStatusBar(PyQt_PyObject)"),'Done generating address') self.emit(SIGNAL("updateStatusBar(PyQt_PyObject)"),'Done generating address')
self.emit(SIGNAL("writeNewAddressToTable(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"),self.label,address,str(self.streamNumber)) self.emit(SIGNAL("writeNewAddressToTable(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"),self.label,address,str(self.streamNumber))
reloadMyAddressHashes()
else: #There is something in the deterministicPassphrase variable thus we are going to do this deterministically. else: #There is something in the deterministicPassphrase variable thus we are going to do this deterministically.
statusbar = 'Generating '+numberOfAddressesToMake + ' new addresses.' statusbar = 'Generating '+str(self.numberOfAddressesToMake) + ' new addresses.'
self.emit(SIGNAL("updateStatusBar(PyQt_PyObject)"),statusbar) self.emit(SIGNAL("updateStatusBar(PyQt_PyObject)"),statusbar)
signingKeyNonce = 0
encryptionKeyNonce = 1
for i in range(self.numberOfAddressesToMake):
#This next section is a little bit strange. We're going to generate keys over and over until we
#find one that starts with either \x00 or \x00\x00. Then when we pack them into a Bitmessage address,
#we won't store the \x00 or \x00\x00 bytes thus making the address shorter.
while True:
potentialPrivSigningKey = hashlib.sha512(self.deterministicPassphrase + encodeVarint(signingKeyNonce)).digest()[:32]
potentialPrivEncryptionKey = hashlib.sha512(self.deterministicPassphrase + encodeVarint(encryptionKeyNonce)).digest()[:32]
potentialPubSigningKey = self.pointMult(potentialPrivSigningKey)
potentialPubEncryptionKey = self.pointMult(potentialPrivEncryptionKey)
#print 'potentialPubSigningKey', potentialPubSigningKey.encode('hex')
#print 'potentialPubEncryptionKey', potentialPubEncryptionKey.encode('hex')
signingKeyNonce += 2
encryptionKeyNonce += 2
ripe = hashlib.new('ripemd160')
sha = hashlib.new('sha512')
sha.update(potentialPubSigningKey+potentialPubEncryptionKey)
ripe.update(sha.digest())
#print 'potential ripe.digest', ripe.digest().encode('hex')
if self.eighteenByteRipe:
if ripe.digest()[:2] == '\x00\x00':
break
else:
if ripe.digest()[:1] == '\x00':
break
print 'ripe.digest', ripe.digest().encode('hex')
if ripe.digest()[:2] == '\x00\x00':
address = encodeAddress(2,self.streamNumber,ripe.digest()[2:])
elif ripe.digest()[:1] == '\x00':
address = encodeAddress(2,self.streamNumber,ripe.digest()[1:])
#self.emit(SIGNAL("updateStatusBar(PyQt_PyObject)"),'Finished generating address. Writing to keys.dat')
#An excellent way for us to store our keys is in Wallet Import Format. Let us convert now.
#https://en.bitcoin.it/wiki/Wallet_import_format
privSigningKey = '\x80'+potentialPrivSigningKey
checksum = hashlib.sha256(hashlib.sha256(privSigningKey).digest()).digest()[0:4]
privSigningKeyWIF = arithmetic.changebase(privSigningKey + checksum,256,58)
print 'privSigningKeyWIF',privSigningKeyWIF
privEncryptionKey = '\x80'+potentialPrivEncryptionKey
checksum = hashlib.sha256(hashlib.sha256(privEncryptionKey).digest()).digest()[0:4]
privEncryptionKeyWIF = arithmetic.changebase(privEncryptionKey + checksum,256,58)
try:
config.add_section(address)
print 'self.label', self.label
config.set(address,'label',self.label)
config.set(address,'enabled','true')
config.set(address,'decoy','false')
config.set(address,'privSigningKey',privSigningKeyWIF)
config.set(address,'privEncryptionKey',privEncryptionKeyWIF)
with open(appdata + 'keys.dat', 'wb') as configfile:
config.write(configfile)
self.emit(SIGNAL("writeNewAddressToTable(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"),self.label,address,str(self.streamNumber))
except:
print address,'already exists. Not adding it again.'
self.emit(SIGNAL("updateStatusBar(PyQt_PyObject)"),'Done generating address')
reloadMyAddressHashes()
elif self.addressVersionNumber == 1: elif self.addressVersionNumber == 1:
statusbar = 'Generating new ' + str(config.getint('bitmessagesettings', 'bitstrength')) + ' bit RSA key. This takes a minute on average. If you want to generate multiple addresses now, you can; they will queue.' statusbar = 'Generating new ' + str(config.getint('bitmessagesettings', 'bitstrength')) + ' bit RSA key. This takes a minute on average. If you want to generate multiple addresses now, you can; they will queue.'
@ -2198,7 +2720,8 @@ class addressGenerator(QThread):
self.emit(SIGNAL("updateStatusBar(PyQt_PyObject)"),'Done generating address') self.emit(SIGNAL("updateStatusBar(PyQt_PyObject)"),'Done generating address')
self.emit(SIGNAL("writeNewAddressToTable(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"),self.label,address,str(self.streamNumber)) self.emit(SIGNAL("writeNewAddressToTable(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"),self.label,address,str(self.streamNumber))
reloadMyAddressHashes()
def pointMult(self,secret): def pointMult(self,secret):
#passphrase += 'a' #passphrase += 'a'
#secret = hashlib.sha256(passphrase.encode('utf8')).digest() #secret = hashlib.sha256(passphrase.encode('utf8')).digest()
@ -2360,9 +2883,23 @@ class NewAddressDialog(QtGui.QDialog):
class MyForm(QtGui.QMainWindow): class MyForm(QtGui.QMainWindow):
def __init__(self, parent=None): def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent) QtGui.QWidget.__init__(self, parent)
self.ui = Ui_MainWindow() #Jonathan changed this line self.ui = Ui_MainWindow()
self.ui.setupUi(self) #Jonathan left this line alone self.ui.setupUi(self)
#Ask the user if we may delete their old version 1 addresses if they have any.
configSections = config.sections()
for addressInKeysFile in configSections:
if addressInKeysFile <> 'bitmessagesettings':
status,addressVersionNumber,streamNumber,hash = decodeAddress(addressInKeysFile)
if addressVersionNumber == 1:
displayMsg = "One of your addresses, "+addressInKeysFile+", is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now?"
reply = QtGui.QMessageBox.question(self, 'Message',displayMsg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
if reply == QtGui.QMessageBox.Yes:
config.remove_section(addressInKeysFile)
with open(appdata + 'keys.dat', 'wb') as configfile:
config.write(configfile)
#Configure Bitmessage to start on startup (or remove the configuration) based on the setting in the keys.dat file
if 'win32' in sys.platform or 'win64' in sys.platform: if 'win32' in sys.platform or 'win64' in sys.platform:
#Auto-startup for Windows #Auto-startup for Windows
RUN_PATH = "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run" RUN_PATH = "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run"
@ -2497,7 +3034,7 @@ class MyForm(QtGui.QMainWindow):
self.sqlLookup = sqlThread() self.sqlLookup = sqlThread()
self.sqlLookup.start() self.sqlLookup.start()
self.reloadMyAddressHashes() reloadMyAddressHashes()
self.reloadBroadcastSendersForWhichImWatching() self.reloadBroadcastSendersForWhichImWatching()
@ -2873,7 +3410,7 @@ class MyForm(QtGui.QMainWindow):
for row in queryreturn: for row in queryreturn:
toLabel, = row toLabel, = row
self.ui.tableWidgetSent.item(i,0).setText(unicode(toLabel,'utf-8')) self.ui.tableWidgetSent.item(i,0).setText(unicode(toLabel,'utf-8'))
def click_pushButtonSend(self): def click_pushButtonSend(self):
self.statusBar().showMessage('') self.statusBar().showMessage('')
toAddresses = str(self.ui.lineEditTo.text()) toAddresses = str(self.ui.lineEditTo.text())
@ -2887,7 +3424,9 @@ class MyForm(QtGui.QMainWindow):
if toAddress <> '': if toAddress <> '':
status,addressVersionNumber,streamNumber,ripe = decodeAddress(toAddress) status,addressVersionNumber,streamNumber,ripe = decodeAddress(toAddress)
if status <> 'success': if status <> 'success':
print 'Status bar!', 'Error: Could not decode', toAddress, ':', status printLock.acquire()
print 'Status bar:', 'Error: Could not decode', toAddress, ':', status
printLock.release()
if status == 'missingbm': if status == 'missingbm':
self.statusBar().showMessage('Error: Bitmessage addresses start with BM- Please check ' + toAddress) self.statusBar().showMessage('Error: Bitmessage addresses start with BM- Please check ' + toAddress)
if status == 'checksumfailed': if status == 'checksumfailed':
@ -2897,7 +3436,6 @@ class MyForm(QtGui.QMainWindow):
if status == 'versiontoohigh': if status == 'versiontoohigh':
self.statusBar().showMessage('Error: The address version in '+ toAddress+ ' is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever.') self.statusBar().showMessage('Error: The address version in '+ toAddress+ ' is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever.')
elif fromAddress == '': elif fromAddress == '':
print 'Status bar!', 'Error: you must specify a From address.'
self.statusBar().showMessage('Error: You must specify a From address. If you don''t have one, go to the ''Your Identities'' tab.') self.statusBar().showMessage('Error: You must specify a From address. If you don''t have one, go to the ''Your Identities'' tab.')
else: else:
toAddress = addBMIfNotPresent(toAddress) toAddress = addBMIfNotPresent(toAddress)
@ -2965,7 +3503,6 @@ class MyForm(QtGui.QMainWindow):
self.statusBar().showMessage('Your \'To\' field is empty.') self.statusBar().showMessage('Your \'To\' field is empty.')
else: #User selected 'Broadcast' else: #User selected 'Broadcast'
if fromAddress == '': if fromAddress == '':
print 'Status bar!', 'Error: you must specify a From address.'
self.statusBar().showMessage('Error: You must specify a From address. If you don\'t have one, go to the \'Your Identities\' tab.') self.statusBar().showMessage('Error: You must specify a From address. If you don\'t have one, go to the \'Your Identities\' tab.')
else: else:
self.statusBar().showMessage('') self.statusBar().showMessage('')
@ -3537,7 +4074,7 @@ class MyForm(QtGui.QMainWindow):
self.ui.tableWidgetYourIdentities.item(currentRow,0).setTextColor(QtGui.QColor(0,0,0)) self.ui.tableWidgetYourIdentities.item(currentRow,0).setTextColor(QtGui.QColor(0,0,0))
self.ui.tableWidgetYourIdentities.item(currentRow,1).setTextColor(QtGui.QColor(0,0,0)) self.ui.tableWidgetYourIdentities.item(currentRow,1).setTextColor(QtGui.QColor(0,0,0))
self.ui.tableWidgetYourIdentities.item(currentRow,2).setTextColor(QtGui.QColor(0,0,0)) self.ui.tableWidgetYourIdentities.item(currentRow,2).setTextColor(QtGui.QColor(0,0,0))
self.reloadMyAddressHashes() reloadMyAddressHashes()
def on_action_YourIdentitiesDisable(self): def on_action_YourIdentitiesDisable(self):
currentRow = self.ui.tableWidgetYourIdentities.currentRow() currentRow = self.ui.tableWidgetYourIdentities.currentRow()
addressAtCurrentRow = self.ui.tableWidgetYourIdentities.item(currentRow,1).text() addressAtCurrentRow = self.ui.tableWidgetYourIdentities.item(currentRow,1).text()
@ -3547,7 +4084,7 @@ class MyForm(QtGui.QMainWindow):
self.ui.tableWidgetYourIdentities.item(currentRow,2).setTextColor(QtGui.QColor(128,128,128)) self.ui.tableWidgetYourIdentities.item(currentRow,2).setTextColor(QtGui.QColor(128,128,128))
with open(appdata + 'keys.dat', 'wb') as configfile: with open(appdata + 'keys.dat', 'wb') as configfile:
config.write(configfile) config.write(configfile)
self.reloadMyAddressHashes() reloadMyAddressHashes()
def on_action_YourIdentitiesClipboard(self): def on_action_YourIdentitiesClipboard(self):
currentRow = self.ui.tableWidgetYourIdentities.currentRow() currentRow = self.ui.tableWidgetYourIdentities.currentRow()
addressAtCurrentRow = self.ui.tableWidgetYourIdentities.item(currentRow,1).text() addressAtCurrentRow = self.ui.tableWidgetYourIdentities.item(currentRow,1).text()
@ -3619,28 +4156,12 @@ class MyForm(QtGui.QMainWindow):
newItem.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled ) newItem.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled )
self.ui.tableWidgetYourIdentities.setItem(0, 2, newItem) self.ui.tableWidgetYourIdentities.setItem(0, 2, newItem)
self.rerenderComboBoxSendFrom() self.rerenderComboBoxSendFrom()
self.reloadMyAddressHashes()
def updateStatusBar(self,data): def updateStatusBar(self,data):
print 'Status bar!', data print 'Status bar:', data
self.statusBar().showMessage(data) self.statusBar().showMessage(data)
def reloadMyAddressHashes(self):
print 'reloading my address hashes'
myAddressHashes.clear()
#myPrivateKeys.clear()
configSections = config.sections()
for addressInKeysFile in configSections:
if addressInKeysFile <> 'bitmessagesettings':
isEnabled = config.getboolean(addressInKeysFile, 'enabled')
if isEnabled:
status,addressVersionNumber,streamNumber,hash = decodeAddress(addressInKeysFile)
n = config.getint(addressInKeysFile, 'n')
e = config.getint(addressInKeysFile, 'e')
d = config.getint(addressInKeysFile, 'd')
p = config.getint(addressInKeysFile, 'p')
q = config.getint(addressInKeysFile, 'q')
myAddressHashes[hash] = rsa.PrivateKey(n,e,d,p,q)
def reloadBroadcastSendersForWhichImWatching(self): def reloadBroadcastSendersForWhichImWatching(self):
broadcastSendersForWhichImWatching.clear() broadcastSendersForWhichImWatching.clear()
@ -3661,7 +4182,8 @@ class myTableWidgetItem(QTableWidgetItem):
sendDataQueues = [] #each sendData thread puts its queue in this list. sendDataQueues = [] #each sendData thread puts its queue in this list.
myAddressHashes = {} myRSAAddressHashes = {}
myECAddressHashes = {}
#myPrivateKeys = {} #myPrivateKeys = {}
inventory = {} #of objects (like msg payloads and pubkey payloads) Does not include protocol headers (the first 24 bytes of each packet). inventory = {} #of objects (like msg payloads and pubkey payloads) Does not include protocol headers (the first 24 bytes of each packet).
workerQueue = Queue.Queue() workerQueue = Queue.Queue()
@ -3683,6 +4205,10 @@ neededPubkeys = {}
averageProofOfWorkNonceTrialsPerByte = 320 #The amount of work that should be performed (and demanded) per byte of the payload. Double this number to double the work. averageProofOfWorkNonceTrialsPerByte = 320 #The amount of work that should be performed (and demanded) per byte of the payload. Double this number to double the work.
payloadLengthExtraBytes = 14000 #To make sending short messages a little more difficult, this value is added to the payload length for use in calculating the proof of work target. payloadLengthExtraBytes = 14000 #To make sending short messages a little more difficult, this value is added to the payload length for use in calculating the proof of work target.
if userVeryEasyProofOfWorkForTesting:
averageProofOfWorkNonceTrialsPerByte = averageProofOfWorkNonceTrialsPerByte / 10
payloadLengthExtraBytes = payloadLengthExtraBytes / 10
if __name__ == "__main__": if __name__ == "__main__":
#sqlite_version = sqlite3.sqlite_version_info #sqlite_version = sqlite3.sqlite_version_info
# Check the Major version, the first element in the array # Check the Major version, the first element in the array
@ -3690,22 +4216,25 @@ if __name__ == "__main__":
print 'This program requires sqlite version 3 or higher because 2 and lower cannot store NULL values. I see version:', sqlite3.sqlite_version_info print 'This program requires sqlite version 3 or higher because 2 and lower cannot store NULL values. I see version:', sqlite3.sqlite_version_info
sys.exit() sys.exit()
APPNAME = "PyBitmessage" if not storeConfigFilesInSameDirectoryAsProgram:
from os import path, environ APPNAME = "PyBitmessage"
if sys.platform == 'darwin': from os import path, environ
if "HOME" in environ: if sys.platform == 'darwin':
appdata = path.join(os.environ["HOME"], "Library/Application support/", APPNAME) + '/' if "HOME" in environ:
appdata = path.join(os.environ["HOME"], "Library/Application support/", APPNAME) + '/'
else:
print 'Could not find home folder, please report this message and your OS X version to the BitMessage Github.'
sys.exit()
elif 'win32' in sys.platform or 'win64' in sys.platform:
appdata = path.join(environ['APPDATA'], APPNAME) + '\\'
else: else:
print 'Could not find home folder, please report this message and your OS X version to the BitMessage Github.' appdata = path.expanduser(path.join("~", "." + APPNAME + "/"))
sys.exit()
elif 'win32' in sys.platform or 'win64' in sys.platform: if not os.path.exists(appdata):
appdata = path.join(environ['APPDATA'], APPNAME) + '\\' os.makedirs(appdata)
else: else:
appdata = path.expanduser(path.join("~", "." + APPNAME + "/")) appdata = ""
if not os.path.exists(appdata):
os.makedirs(appdata)
config = ConfigParser.SafeConfigParser() config = ConfigParser.SafeConfigParser()
config.read(appdata + 'keys.dat') config.read(appdata + 'keys.dat')
@ -3772,7 +4301,7 @@ if __name__ == "__main__":
knownNodes[1][item[4][0]] = (8444,int(time.time())) knownNodes[1][item[4][0]] = (8444,int(time.time()))
except: except:
print 'bootstrap8444.bitmessage.org DNS bootstrapping failed.' print 'bootstrap8444.bitmessage.org DNS bootstrapping failed.'
app = QtGui.QApplication(sys.argv) app = QtGui.QApplication(sys.argv)
app.setStyleSheet("QStatusBar::item { border: 0px solid black }") app.setStyleSheet("QStatusBar::item { border: 0px solid black }")
myapp = MyForm() myapp = MyForm()

View File

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'newaddressdialog.ui' # Form implementation generated from reading ui file 'newaddressdialog.ui'
# #
# Created: Tue Jan 15 15:21:33 2013 # Created: Fri Jan 18 13:48:49 2013
# by: PyQt4 UI code generator 4.9.4 # by: PyQt4 UI code generator 4.9.4
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!
@ -55,42 +55,42 @@ class Ui_NewAddressDialog(object):
self.groupBoxDeterministic.setObjectName(_fromUtf8("groupBoxDeterministic")) self.groupBoxDeterministic.setObjectName(_fromUtf8("groupBoxDeterministic"))
self.gridLayout = QtGui.QGridLayout(self.groupBoxDeterministic) self.gridLayout = QtGui.QGridLayout(self.groupBoxDeterministic)
self.gridLayout.setObjectName(_fromUtf8("gridLayout")) self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
self.label_6 = QtGui.QLabel(self.groupBoxDeterministic)
self.label_6.setObjectName(_fromUtf8("label_6"))
self.gridLayout.addWidget(self.label_6, 0, 0, 1, 4)
self.lineEditPassphrase = QtGui.QLineEdit(self.groupBoxDeterministic)
self.lineEditPassphrase.setInputMethodHints(QtCore.Qt.ImhHiddenText|QtCore.Qt.ImhNoAutoUppercase|QtCore.Qt.ImhNoPredictiveText)
self.lineEditPassphrase.setEchoMode(QtGui.QLineEdit.Password)
self.lineEditPassphrase.setObjectName(_fromUtf8("lineEditPassphrase"))
self.gridLayout.addWidget(self.lineEditPassphrase, 1, 0, 1, 7)
self.label_7 = QtGui.QLabel(self.groupBoxDeterministic)
self.label_7.setObjectName(_fromUtf8("label_7"))
self.gridLayout.addWidget(self.label_7, 2, 0, 1, 4)
self.lineEditPassphraseAgain = QtGui.QLineEdit(self.groupBoxDeterministic)
self.lineEditPassphraseAgain.setEchoMode(QtGui.QLineEdit.Password)
self.lineEditPassphraseAgain.setObjectName(_fromUtf8("lineEditPassphraseAgain"))
self.gridLayout.addWidget(self.lineEditPassphraseAgain, 3, 0, 1, 7)
self.label_8 = QtGui.QLabel(self.groupBoxDeterministic)
self.label_8.setObjectName(_fromUtf8("label_8"))
self.gridLayout.addWidget(self.label_8, 4, 0, 1, 7)
self.label_9 = QtGui.QLabel(self.groupBoxDeterministic) self.label_9 = QtGui.QLabel(self.groupBoxDeterministic)
self.label_9.setObjectName(_fromUtf8("label_9")) self.label_9.setObjectName(_fromUtf8("label_9"))
self.gridLayout.addWidget(self.label_9, 5, 0, 1, 1) self.gridLayout.addWidget(self.label_9, 6, 0, 1, 1)
spacerItem = QtGui.QSpacerItem(73, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) self.label_8 = QtGui.QLabel(self.groupBoxDeterministic)
self.gridLayout.addItem(spacerItem, 5, 1, 1, 1) self.label_8.setObjectName(_fromUtf8("label_8"))
self.label_10 = QtGui.QLabel(self.groupBoxDeterministic) self.gridLayout.addWidget(self.label_8, 5, 0, 1, 3)
self.label_10.setObjectName(_fromUtf8("label_10"))
self.gridLayout.addWidget(self.label_10, 5, 3, 1, 1)
spacerItem1 = QtGui.QSpacerItem(42, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.gridLayout.addItem(spacerItem1, 5, 4, 1, 2)
self.label_11 = QtGui.QLabel(self.groupBoxDeterministic)
self.label_11.setObjectName(_fromUtf8("label_11"))
self.gridLayout.addWidget(self.label_11, 6, 0, 1, 5)
self.spinBoxNumberOfAddressesToMake = QtGui.QSpinBox(self.groupBoxDeterministic) self.spinBoxNumberOfAddressesToMake = QtGui.QSpinBox(self.groupBoxDeterministic)
self.spinBoxNumberOfAddressesToMake.setMinimum(1) self.spinBoxNumberOfAddressesToMake.setMinimum(1)
self.spinBoxNumberOfAddressesToMake.setProperty("value", 8) self.spinBoxNumberOfAddressesToMake.setProperty("value", 8)
self.spinBoxNumberOfAddressesToMake.setObjectName(_fromUtf8("spinBoxNumberOfAddressesToMake")) self.spinBoxNumberOfAddressesToMake.setObjectName(_fromUtf8("spinBoxNumberOfAddressesToMake"))
self.gridLayout.addWidget(self.spinBoxNumberOfAddressesToMake, 6, 5, 1, 2) self.gridLayout.addWidget(self.spinBoxNumberOfAddressesToMake, 4, 3, 1, 1)
self.label_6 = QtGui.QLabel(self.groupBoxDeterministic)
self.label_6.setObjectName(_fromUtf8("label_6"))
self.gridLayout.addWidget(self.label_6, 0, 0, 1, 1)
self.label_11 = QtGui.QLabel(self.groupBoxDeterministic)
self.label_11.setObjectName(_fromUtf8("label_11"))
self.gridLayout.addWidget(self.label_11, 4, 0, 1, 3)
spacerItem = QtGui.QSpacerItem(73, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.gridLayout.addItem(spacerItem, 6, 1, 1, 1)
self.label_10 = QtGui.QLabel(self.groupBoxDeterministic)
self.label_10.setObjectName(_fromUtf8("label_10"))
self.gridLayout.addWidget(self.label_10, 6, 2, 1, 1)
spacerItem1 = QtGui.QSpacerItem(42, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.gridLayout.addItem(spacerItem1, 6, 3, 1, 1)
self.label_7 = QtGui.QLabel(self.groupBoxDeterministic)
self.label_7.setObjectName(_fromUtf8("label_7"))
self.gridLayout.addWidget(self.label_7, 2, 0, 1, 1)
self.lineEditPassphraseAgain = QtGui.QLineEdit(self.groupBoxDeterministic)
self.lineEditPassphraseAgain.setEchoMode(QtGui.QLineEdit.Password)
self.lineEditPassphraseAgain.setObjectName(_fromUtf8("lineEditPassphraseAgain"))
self.gridLayout.addWidget(self.lineEditPassphraseAgain, 3, 0, 1, 4)
self.lineEditPassphrase = QtGui.QLineEdit(self.groupBoxDeterministic)
self.lineEditPassphrase.setInputMethodHints(QtCore.Qt.ImhHiddenText|QtCore.Qt.ImhNoAutoUppercase|QtCore.Qt.ImhNoPredictiveText)
self.lineEditPassphrase.setEchoMode(QtGui.QLineEdit.Password)
self.lineEditPassphrase.setObjectName(_fromUtf8("lineEditPassphrase"))
self.gridLayout.addWidget(self.lineEditPassphrase, 1, 0, 1, 4)
self.formLayout.setWidget(8, QtGui.QFormLayout.LabelRole, self.groupBoxDeterministic) self.formLayout.setWidget(8, QtGui.QFormLayout.LabelRole, self.groupBoxDeterministic)
self.groupBox = QtGui.QGroupBox(NewAddressDialog) self.groupBox = QtGui.QGroupBox(NewAddressDialog)
self.groupBox.setObjectName(_fromUtf8("groupBox")) self.groupBox.setObjectName(_fromUtf8("groupBox"))
@ -103,7 +103,7 @@ class Ui_NewAddressDialog(object):
self.newaddresslabel.setObjectName(_fromUtf8("newaddresslabel")) self.newaddresslabel.setObjectName(_fromUtf8("newaddresslabel"))
self.gridLayout_2.addWidget(self.newaddresslabel, 1, 0, 1, 2) self.gridLayout_2.addWidget(self.newaddresslabel, 1, 0, 1, 2)
self.radioButtonMostAvailable = QtGui.QRadioButton(self.groupBox) self.radioButtonMostAvailable = QtGui.QRadioButton(self.groupBox)
self.radioButtonMostAvailable.setChecked(False) self.radioButtonMostAvailable.setChecked(True)
self.radioButtonMostAvailable.setObjectName(_fromUtf8("radioButtonMostAvailable")) self.radioButtonMostAvailable.setObjectName(_fromUtf8("radioButtonMostAvailable"))
self.gridLayout_2.addWidget(self.radioButtonMostAvailable, 2, 0, 1, 2) self.gridLayout_2.addWidget(self.radioButtonMostAvailable, 2, 0, 1, 2)
self.label_3 = QtGui.QLabel(self.groupBox) self.label_3 = QtGui.QLabel(self.groupBox)
@ -155,12 +155,12 @@ class Ui_NewAddressDialog(object):
self.radioButtonDeterministicAddress.setText(QtGui.QApplication.translate("NewAddressDialog", "Use a passpharase to make addresses", None, QtGui.QApplication.UnicodeUTF8)) self.radioButtonDeterministicAddress.setText(QtGui.QApplication.translate("NewAddressDialog", "Use a passpharase to make addresses", None, QtGui.QApplication.UnicodeUTF8))
self.checkBoxEighteenByteRipe.setText(QtGui.QApplication.translate("NewAddressDialog", "Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter", None, QtGui.QApplication.UnicodeUTF8)) self.checkBoxEighteenByteRipe.setText(QtGui.QApplication.translate("NewAddressDialog", "Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter", None, QtGui.QApplication.UnicodeUTF8))
self.groupBoxDeterministic.setTitle(QtGui.QApplication.translate("NewAddressDialog", "Make deterministic addresses", None, QtGui.QApplication.UnicodeUTF8)) self.groupBoxDeterministic.setTitle(QtGui.QApplication.translate("NewAddressDialog", "Make deterministic addresses", None, QtGui.QApplication.UnicodeUTF8))
self.label_6.setText(QtGui.QApplication.translate("NewAddressDialog", "Passphrase", None, QtGui.QApplication.UnicodeUTF8))
self.label_7.setText(QtGui.QApplication.translate("NewAddressDialog", "Retype passphrase", None, QtGui.QApplication.UnicodeUTF8))
self.label_8.setText(QtGui.QApplication.translate("NewAddressDialog", "In addition to your passphrase, you must remember these numbers:", None, QtGui.QApplication.UnicodeUTF8))
self.label_9.setText(QtGui.QApplication.translate("NewAddressDialog", "Address version number: 2", None, QtGui.QApplication.UnicodeUTF8)) self.label_9.setText(QtGui.QApplication.translate("NewAddressDialog", "Address version number: 2", None, QtGui.QApplication.UnicodeUTF8))
self.label_10.setText(QtGui.QApplication.translate("NewAddressDialog", "Stream number: 1", None, QtGui.QApplication.UnicodeUTF8)) self.label_8.setText(QtGui.QApplication.translate("NewAddressDialog", "In addition to your passphrase, you must remember these numbers:", None, QtGui.QApplication.UnicodeUTF8))
self.label_6.setText(QtGui.QApplication.translate("NewAddressDialog", "Passphrase", None, QtGui.QApplication.UnicodeUTF8))
self.label_11.setText(QtGui.QApplication.translate("NewAddressDialog", "Number of addresses to make based on your passphrase:", None, QtGui.QApplication.UnicodeUTF8)) self.label_11.setText(QtGui.QApplication.translate("NewAddressDialog", "Number of addresses to make based on your passphrase:", None, QtGui.QApplication.UnicodeUTF8))
self.label_10.setText(QtGui.QApplication.translate("NewAddressDialog", "Stream number: 1", None, QtGui.QApplication.UnicodeUTF8))
self.label_7.setText(QtGui.QApplication.translate("NewAddressDialog", "Retype passphrase", None, QtGui.QApplication.UnicodeUTF8))
self.groupBox.setTitle(QtGui.QApplication.translate("NewAddressDialog", "Randomly generate address", None, QtGui.QApplication.UnicodeUTF8)) self.groupBox.setTitle(QtGui.QApplication.translate("NewAddressDialog", "Randomly generate address", None, QtGui.QApplication.UnicodeUTF8))
self.label_2.setText(QtGui.QApplication.translate("NewAddressDialog", "Label (not shown to anyone except you)", None, QtGui.QApplication.UnicodeUTF8)) self.label_2.setText(QtGui.QApplication.translate("NewAddressDialog", "Label (not shown to anyone except you)", None, QtGui.QApplication.UnicodeUTF8))
self.radioButtonMostAvailable.setText(QtGui.QApplication.translate("NewAddressDialog", "Use the most available stream", None, QtGui.QApplication.UnicodeUTF8)) self.radioButtonMostAvailable.setText(QtGui.QApplication.translate("NewAddressDialog", "Use the most available stream", None, QtGui.QApplication.UnicodeUTF8))

View File

@ -90,52 +90,45 @@ The 'Random Number' option is selected by default but deterministic addresses ha
<string>Make deterministic addresses</string> <string>Make deterministic addresses</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="4"> <item row="6" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Passphrase</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="7">
<widget class="QLineEdit" name="lineEditPassphrase">
<property name="inputMethodHints">
<set>Qt::ImhHiddenText|Qt::ImhNoAutoUppercase|Qt::ImhNoPredictiveText</set>
</property>
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="2" column="0" colspan="4">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Retype passphrase</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="7">
<widget class="QLineEdit" name="lineEditPassphraseAgain">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="4" column="0" colspan="7">
<widget class="QLabel" name="label_8">
<property name="text">
<string>In addition to your passphrase, you must remember these numbers:</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_9"> <widget class="QLabel" name="label_9">
<property name="text"> <property name="text">
<string>Address version number: 2</string> <string>Address version number: 2</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="1"> <item row="5" column="0" colspan="3">
<widget class="QLabel" name="label_8">
<property name="text">
<string>In addition to your passphrase, you must remember these numbers:</string>
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QSpinBox" name="spinBoxNumberOfAddressesToMake">
<property name="minimum">
<number>1</number>
</property>
<property name="value">
<number>8</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Passphrase</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="3">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Number of addresses to make based on your passphrase:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<spacer name="horizontalSpacer"> <spacer name="horizontalSpacer">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
@ -148,14 +141,14 @@ The 'Random Number' option is selected by default but deterministic addresses ha
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="5" column="3"> <item row="6" column="2">
<widget class="QLabel" name="label_10"> <widget class="QLabel" name="label_10">
<property name="text"> <property name="text">
<string>Stream number: 1</string> <string>Stream number: 1</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="4" colspan="2"> <item row="6" column="3">
<spacer name="horizontalSpacer_2"> <spacer name="horizontalSpacer_2">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
@ -168,20 +161,27 @@ The 'Random Number' option is selected by default but deterministic addresses ha
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="6" column="0" colspan="5"> <item row="2" column="0">
<widget class="QLabel" name="label_11"> <widget class="QLabel" name="label_7">
<property name="text"> <property name="text">
<string>Number of addresses to make based on your passphrase:</string> <string>Retype passphrase</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="6" column="5" colspan="2"> <item row="3" column="0" colspan="4">
<widget class="QSpinBox" name="spinBoxNumberOfAddressesToMake"> <widget class="QLineEdit" name="lineEditPassphraseAgain">
<property name="minimum"> <property name="echoMode">
<number>1</number> <enum>QLineEdit::Password</enum>
</property> </property>
<property name="value"> </widget>
<number>8</number> </item>
<item row="1" column="0" colspan="4">
<widget class="QLineEdit" name="lineEditPassphrase">
<property name="inputMethodHints">
<set>Qt::ImhHiddenText|Qt::ImhNoAutoUppercase|Qt::ImhNoPredictiveText</set>
</property>
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property> </property>
</widget> </widget>
</item> </item>
@ -210,7 +210,7 @@ The 'Random Number' option is selected by default but deterministic addresses ha
<string>Use the most available stream</string> <string>Use the most available stream</string>
</property> </property>
<property name="checked"> <property name="checked">
<bool>false</bool> <bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>

View File

@ -6,9 +6,11 @@ __version__ = '1.3'
__all__ = [ __all__ = [
'OpenSSL', 'OpenSSL',
'ecc', 'ECC',
'cipher', 'Cipher',
'hash', 'hmac_sha256',
'hmac_sha512',
'pbkdf2'
] ]
from .openssl import OpenSSL from .openssl import OpenSSL

View File

@ -72,7 +72,7 @@ def base10_multiply(a,n):
def hex_to_point(h): return (decode(h[2:34],16),decode(h[34:],16)) def hex_to_point(h): return (decode(h[2:34],16),decode(h[34:],16))
def point_to_hex(p): return '04'+encode(p[0],16,32)+encode(p[1],16,32) def point_to_hex(p): return '04'+encode(p[0],16,64)+encode(p[1],16,64)
def multiply(privkey,pubkey): def multiply(privkey,pubkey):
return point_to_hex(base10_multiply(hex_to_point(pubkey),decode(privkey,16))) return point_to_hex(base10_multiply(hex_to_point(pubkey),decode(privkey,16)))

View File

@ -22,7 +22,7 @@ def encrypt(msg,hexPubkey):
# Decrypts message with hex private key # Decrypts message with hex private key
def decrypt(msg,hexPrivkey): def decrypt(msg,hexPrivkey):
return makeCryptor(hexPrivkey).decrypt(msg) return makeCryptor(hexPrivkey).decrypt(msg)
# Decrypts message with an existing pyelliptic.ecc.ECC object # Decrypts message with an existing pyelliptic.ECC.ECC object
def decryptFast(msg,cryptor): def decryptFast(msg,cryptor):
return cryptor.decrypt(msg) return cryptor.decrypt(msg)
# Signs with hex private key # Signs with hex private key