Merge pull request #506 from Bitmessage/encrypted_pubkeys

Encrypted pubkeys
This commit is contained in:
Jonathan Warren 2013-09-22 20:47:15 -07:00
commit d261829efb
28 changed files with 1020 additions and 473 deletions

View File

@ -1,5 +1,5 @@
APP=pybitmessage
VERSION=0.3.5
VERSION=0.4.0
RELEASE=1
ARCH_TYPE=`uname -m`
PREFIX?=/usr/local

View File

@ -2,8 +2,8 @@
GIT_APP=PyBitmessage
APP=pybitmessage
PREV_VERSION=0.3.5
VERSION=0.3.5
PREV_VERSION=0.4.0
VERSION=0.4.0
RELEASE=1
ARCH_TYPE=any
CURRDIR=`pwd`

View File

@ -1,6 +1,6 @@
# Maintainer: Bob Mottram (4096 bits) <bob@robotics.uk.to>
pkgname=pybitmessage
pkgver=0.3.5
pkgver=0.4.0
pkgrel=1
pkgdesc="Bitmessage is a P2P communications protocol used to send encrypted messages to another person or to many subscribers. It is decentralized and trustless, meaning that you need-not inherently trust any entities like root certificate authorities. It uses strong authentication which means that the sender of a message cannot be spoofed, and it aims to hide "non-content" data, like the sender and receiver of messages, from passive eavesdroppers like those running warrantless wiretapping programs."
arch=('any')

View File

@ -1,8 +1,8 @@
#!/bin/bash
APP=pybitmessage
PREV_VERSION=0.3.5
VERSION=0.3.5
PREV_VERSION=0.4.0
VERSION=0.4.0
RELEASE=1
ARCH_TYPE=all
DIR=${APP}-${VERSION}

View File

@ -1,8 +1,8 @@
#!/bin/bash
APP=pybitmessage
PREV_VERSION=0.3.5
VERSION=0.3.5
PREV_VERSION=0.4.0
VERSION=0.4.0
RELEASE=1
SOURCEDIR=.
ARCH_TYPE=`uname -m`

View File

@ -4,7 +4,7 @@
rm -f Makefile rpmpackage/*.spec
packagemonkey -n "PyBitmessage" --version "0.3.5" --dir "." -l "mit" \
packagemonkey -n "PyBitmessage" --version "0.4.0" --dir "." -l "mit" \
-e "Bob Mottram (4096 bits) <bob@robotics.uk.to>" \
--brief "Send encrypted messages" \
--desc "Bitmessage is a P2P communications protocol used to send " \

View File

@ -1,8 +1,8 @@
#!/bin/bash
APP=pybitmessage
PREV_VERSION=0.3.5
VERSION=0.3.5
PREV_VERSION=0.4.0
VERSION=0.4.0
RELEASE=1
BUILDDIR=~/petbuild
CURRDIR=`pwd`

4
rpm.sh
View File

@ -1,8 +1,8 @@
#!/bin/bash
APP=pybitmessage
PREV_VERSION=0.3.5
VERSION=0.3.5
PREV_VERSION=0.4.0
VERSION=0.4.0
RELEASE=1
SOURCEDIR=.
ARCH_TYPE=`uname -m`

View File

@ -1,5 +1,5 @@
Name: pybitmessage
Version: 0.3.5
Version: 0.4.0
Release: 1%{?dist}
Summary: Send encrypted messages
License: MIT

View File

@ -1,8 +1,8 @@
#!/bin/bash
APP=pybitmessage
PREV_VERSION=0.3.5
VERSION=0.3.5
PREV_VERSION=0.4.0
VERSION=0.4.0
RELEASE=1
ARCH_TYPE=`uname -m`
BUILDDIR=~/slackbuild

View File

@ -204,7 +204,6 @@ def decodeAddress(address):
else:
x00string = '\x00' * (20 - len(data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4]))
return status,addressVersionNumber,streamNumber,x00string+data[bytesUsedByVersionNumber+bytesUsedByStreamNumber:-4]
def addBMIfNotPresent(address):
address = str(address).strip()
@ -213,56 +212,6 @@ def addBMIfNotPresent(address):
else:
return address
def addressStream(address):
#returns the stream number of an address or False if there is a problem with the address.
#check for the BM- at the front of the address. If it isn't there, this address might be for a different version of Bitmessage
if address[:3] != 'BM-':
status = 'missingbm'
return False
#here we take off the BM-
integer = decodeBase58(address[3:])
#after converting to hex, the string will be prepended with a 0x and appended with a L
hexdata = hex(integer)[2:-1]
if len(hexdata) % 2 != 0:
hexdata = '0' + hexdata
#print 'hexdata', hexdata
data = hexdata.decode('hex')
checksum = data[-4:]
sha = hashlib.new('sha512')
sha.update(data[:-4])
currentHash = sha.digest()
#print 'sha after first hashing: ', sha.hexdigest()
sha = hashlib.new('sha512')
sha.update(currentHash)
#print 'sha after second hashing: ', sha.hexdigest()
if checksum != sha.digest()[0:4]:
print 'checksum failed'
status = 'checksumfailed'
return False
#else:
# print 'checksum PASSED'
addressVersionNumber, bytesUsedByVersionNumber = decodeVarint(data[:9])
#print 'addressVersionNumber', addressVersionNumber
#print 'bytesUsedByVersionNumber', bytesUsedByVersionNumber
if addressVersionNumber < 1:
print 'cannot decode version address version numbers this high'
status = 'versiontoohigh'
return False
streamNumber, bytesUsedByStreamNumber = decodeVarint(data[bytesUsedByVersionNumber:9+bytesUsedByVersionNumber])
#print streamNumber
status = 'success'
return streamNumber
if __name__ == "__main__":
print 'Let us make an address from scratch. Suppose we generate two random 32 byte values and call the first one the signing key and the second one the encryption key:'
privateSigningKey = '93d0b61371a54b53df143b954035d612f8efa8a3ed1cf842c2186bfd8f876665'

View File

@ -31,12 +31,12 @@ print 'Uncomment the next two lines to create a new random address with a slight
print 'Uncomment these next four lines to create new deterministic addresses.'
#passphrase = 'asdfasdfqwser'.encode('base64')
#jsonDeterministicAddresses = api.createDeterministicAddresses(passphrase, 2, 3, 1, False)
#jsonDeterministicAddresses = api.createDeterministicAddresses(passphrase, 2, 4, 1, False)
#print jsonDeterministicAddresses
#print json.loads(jsonDeterministicAddresses)
#print 'Uncomment this next line to print the first deterministic address that would be generated with the given passphrase. This will Not add it to the Bitmessage interface or the keys.dat file.'
#print api.getDeterministicAddress('asdfasdfqwser'.encode('base64'),3,1)
#print api.getDeterministicAddress('asdfasdfqwser'.encode('base64'),4,1)
#print 'Uncomment this line to subscribe to an address. (You must use your own address, this one is invalid).'
#print api.addSubscription('2D94G5d8yp237GGqAheoecBYpdehdT3dha','test sub'.encode('base64'))

View File

@ -182,7 +182,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
elif method == 'statusBar':
message, = params
shared.UISignalQueue.put(('updateStatusBar', message))
elif method == 'listAddresses':
elif method == 'listAddresses' or method == 'listAddresses2':
data = '{"addresses":['
configSections = shared.config.sections()
for addressInKeysFile in configSections:
@ -196,7 +196,10 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
chan = shared.config.getboolean(addressInKeysFile, 'chan')
else:
chan = False
data += json.dumps({'label': shared.config.get(addressInKeysFile, 'label'), 'address': addressInKeysFile, 'stream':
label = shared.config.get(addressInKeysFile, 'label')
if method == 'listAddresses2':
label = label.encode('base64')
data += json.dumps({'label': label, 'address': addressInKeysFile, 'stream':
streamNumber, 'enabled': shared.config.getboolean(addressInKeysFile, 'enabled'), 'chan': chan}, indent=4, separators=(',', ': '))
data += ']}'
return data
@ -276,7 +279,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
shared.apiAddressGeneratorReturnQueue.queue.clear()
streamNumberForAddress = 1
shared.addressGeneratorQueue.put((
'createRandomAddress', 3, streamNumberForAddress, label, 1, "", eighteenByteRipe, nonceTrialsPerByte, payloadLengthExtraBytes))
'createRandomAddress', 4, streamNumberForAddress, label, 1, "", eighteenByteRipe, nonceTrialsPerByte, payloadLengthExtraBytes))
return shared.apiAddressGeneratorReturnQueue.get()
elif method == 'createDeterministicAddresses':
if len(params) == 0:
@ -341,9 +344,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
raise APIError(23, 'Bool expected in eighteenByteRipe, saw %s instead' % type(eighteenByteRipe))
passphrase = self._decode(passphrase, "base64")
if addressVersionNumber == 0: # 0 means "just use the proper addressVersionNumber"
addressVersionNumber = 3
if addressVersionNumber != 3:
raise APIError(2,'The address version number currently must be 3 (or 0 which means auto-select). ' + addressVersionNumber + ' isn\'t supported.')
addressVersionNumber = 4
if addressVersionNumber != 3 and addressVersionNumber != 4:
raise APIError(2,'The address version number currently must be 3, 4, or 0 (which means auto-select). ' + addressVersionNumber + ' isn\'t supported.')
if streamNumber == 0: # 0 means "just use the most available stream"
streamNumber = 1
if streamNumber != 1:
@ -374,8 +377,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
if len(passphrase) == 0:
raise APIError(1, 'The specified passphrase is blank.')
passphrase = self._decode(passphrase, "base64")
if addressVersionNumber != 3:
raise APIError(2, 'The address version number currently must be 3. ' + addressVersionNumber + ' isn\'t supported.')
if addressVersionNumber != 3 and addressVersionNumber != 4:
raise APIError(2, 'The address version number currently must be 3 or 4. ' + addressVersionNumber + ' isn\'t supported.')
if streamNumber != 1:
raise APIError(3, ' The stream number must be 1. Others aren\'t supported.')
shared.apiAddressGeneratorReturnQueue.queue.clear()
@ -712,7 +715,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
inventoryHash = calculateInventoryHash(encryptedPayload)
objectType = 'msg'
shared.inventory[inventoryHash] = (
objectType, toStreamNumber, encryptedPayload, int(time.time()))
objectType, toStreamNumber, encryptedPayload, int(time.time()),'')
shared.inventorySets[toStreamNumber].add(inventoryHash)
with shared.printLock:
print 'Broadcasting inv for msg(API disseminatePreEncryptedMsg command):', inventoryHash.encode('hex')
@ -748,14 +751,15 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
pubkeyStreamNumber = decodeVarint(payload[pubkeyReadPosition:pubkeyReadPosition+10])[0]
inventoryHash = calculateInventoryHash(payload)
objectType = 'pubkey'
#todo: support v4 pubkeys
shared.inventory[inventoryHash] = (
objectType, pubkeyStreamNumber, payload, int(time.time()))
objectType, pubkeyStreamNumber, payload, int(time.time()),'')
shared.inventorySets[pubkeyStreamNumber].add(inventoryHash)
with shared.printLock:
print 'broadcasting inv within API command disseminatePubkey with hash:', inventoryHash.encode('hex')
shared.broadcastToSendDataQueues((
streamNumber, 'advertiseobject', inventoryHash))
elif method == 'getMessageDataByDestinationHash':
elif method == 'getMessageDataByDestinationHash' or method == 'getMessageDataByDestinationTag':
# Method will eventually be used by a particular Android app to
# select relevant messages. Do not yet add this to the api
# doc.
@ -763,24 +767,24 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
if len(params) != 1:
raise APIError(0, 'I need 1 parameter!')
requestedHash, = params
if len(requestedHash) != 40:
raise APIError(19, 'The length of hash should be 20 bytes (encoded in hex thus 40 characters).')
if len(requestedHash) != 32:
raise APIError(19, 'The length of hash should be 32 bytes (encoded in hex thus 64 characters).')
requestedHash = self._decode(requestedHash, "hex")
# This is not a particularly commonly used API function. Before we
# use it we'll need to fill out a field in our inventory database
# which is blank by default (first20bytesofencryptedmessage).
queryreturn = sqlQuery(
'''SELECT hash, payload FROM inventory WHERE first20bytesofencryptedmessage = '' and objecttype = 'msg' ; ''')
'''SELECT hash, payload FROM inventory WHERE tag = '' and objecttype = 'msg' ; ''')
with SqlBulkExecute() as sql:
for row in queryreturn:
hash, payload = row
readPosition = 16 # Nonce length + time length
readPosition += decodeVarint(payload[readPosition:readPosition+10])[1] # Stream Number length
t = (payload[readPosition:readPosition+20],hash)
sql.execute('''UPDATE inventory SET first20bytesofencryptedmessage=? WHERE hash=?; ''', *t)
t = (payload[readPosition:readPosition+32],hash)
sql.execute('''UPDATE inventory SET tag=? WHERE hash=?; ''', *t)
queryreturn = sqlQuery('''SELECT payload FROM inventory WHERE first20bytesofencryptedmessage = ?''',
queryreturn = sqlQuery('''SELECT payload FROM inventory WHERE tag = ?''',
requestedHash)
data = '{"receivedMessageDatas":['
for row in queryreturn:
@ -813,7 +817,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
networkStatus = 'connectedButHaveNotReceivedIncomingConnections'
else:
networkStatus = 'connectedAndReceivingIncomingConnections'
return json.dumps({'networkConnections':len(shared.connectedHostsList),'numberOfMessagesProcessed':shared.numberOfMessagesProcessed, 'numberOfBroadcastsProcessed':shared.numberOfBroadcastsProcessed, 'numberOfPubkeysProcessed':shared.numberOfPubkeysProcessed, 'networkStatus':networkStatus}, indent=4, separators=(',', ': '))
return json.dumps({'networkConnections':len(shared.connectedHostsList),'numberOfMessagesProcessed':shared.numberOfMessagesProcessed, 'numberOfBroadcastsProcessed':shared.numberOfBroadcastsProcessed, 'numberOfPubkeysProcessed':shared.numberOfPubkeysProcessed, 'networkStatus':networkStatus, 'softwareName':'PyBitmessage','softwareVersion':shared.softwareVersion}, indent=4, separators=(',', ': '))
else:
raise APIError(20, 'Invalid method: %s' % method)

View File

@ -334,7 +334,7 @@ class MyForm(QtGui.QMainWindow):
newItem.setTextColor(QtGui.QColor(137, 04, 177)) # magenta
self.ui.tableWidgetYourIdentities.setItem(0, 1, newItem)
newItem = QtGui.QTableWidgetItem(str(
addressStream(addressInKeysFile)))
decodeAddress(addressInKeysFile)[2]))
newItem.setFlags(
QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
if not isEnabled:
@ -1133,8 +1133,15 @@ class MyForm(QtGui.QMainWindow):
else:
streamNumberForAddress = int(
self.regenerateAddressesDialogInstance.ui.lineEditStreamNumber.text())
addressVersionNumber = int(
self.regenerateAddressesDialogInstance.ui.lineEditAddressVersionNumber.text())
try:
addressVersionNumber = int(
self.regenerateAddressesDialogInstance.ui.lineEditAddressVersionNumber.text())
except:
QMessageBox.about(self, _translate("MainWindow", "Bad address version number"), _translate(
"MainWindow", "Your address version number must be a number: either 3 or 4."))
if addressVersionNumber < 3 or addressVersionNumber > 4:
QMessageBox.about(self, _translate("MainWindow", "Bad address version number"), _translate(
"MainWindow", "Your address version number must be either 3 or 4."))
# self.addressGenerator = addressGenerator()
# self.addressGenerator.setup(addressVersionNumber,streamNumberForAddress,"unused address",self.regenerateAddressesDialogInstance.ui.spinBoxNumberOfAddressesToMake.value(),self.regenerateAddressesDialogInstance.ui.lineEditPassphrase.text().toUtf8(),self.regenerateAddressesDialogInstance.ui.checkBoxEighteenByteRipe.isChecked())
# QtCore.QObject.connect(self.addressGenerator, SIGNAL("writeNewAddressToTable(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), self.writeNewAddressToTable)
@ -1153,7 +1160,7 @@ class MyForm(QtGui.QMainWindow):
"MainWindow", "You didn't enter a chan name."))
return
shared.apiAddressGeneratorReturnQueue.queue.clear()
shared.addressGeneratorQueue.put(('createChan', 3, 1, self.str_chan + ' ' + str(self.newChanDialogInstance.ui.lineEditChanNameCreate.text().toUtf8()), self.newChanDialogInstance.ui.lineEditChanNameCreate.text().toUtf8()))
shared.addressGeneratorQueue.put(('createChan', 4, 1, self.str_chan + ' ' + str(self.newChanDialogInstance.ui.lineEditChanNameCreate.text().toUtf8()), self.newChanDialogInstance.ui.lineEditChanNameCreate.text().toUtf8()))
addressGeneratorReturnValue = shared.apiAddressGeneratorReturnQueue.get()
print 'addressGeneratorReturnValue', addressGeneratorReturnValue
if len(addressGeneratorReturnValue) == 0:
@ -1566,7 +1573,7 @@ class MyForm(QtGui.QMainWindow):
continue
except:
pass
if addressVersionNumber > 3 or addressVersionNumber <= 1:
if addressVersionNumber > 4 or addressVersionNumber <= 1:
QMessageBox.about(self, _translate("MainWindow", "Address version number"), _translate(
"MainWindow", "Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version.").arg(toAddress).arg(str(addressVersionNumber)))
continue
@ -2200,9 +2207,9 @@ class MyForm(QtGui.QMainWindow):
else:
# User selected 'Use the same stream as an existing
# address.'
streamNumberForAddress = addressStream(
self.dialog.ui.comboBoxExisting.currentText())
shared.addressGeneratorQueue.put(('createRandomAddress', 3, streamNumberForAddress, str(
streamNumberForAddress = decodeAddress(
self.dialog.ui.comboBoxExisting.currentText())[2]
shared.addressGeneratorQueue.put(('createRandomAddress', 4, streamNumberForAddress, str(
self.dialog.ui.newaddresslabel.text().toUtf8()), 1, "", self.dialog.ui.checkBoxEighteenByteRipe.isChecked()))
else:
if self.dialog.ui.lineEditPassphrase.text() != self.dialog.ui.lineEditPassphraseAgain.text():
@ -2213,7 +2220,7 @@ class MyForm(QtGui.QMainWindow):
"MainWindow", "Choose a passphrase"), _translate("MainWindow", "You really do need a passphrase."))
else:
streamNumberForAddress = 1 # this will eventually have to be replaced by logic to determine the most available stream number.
shared.addressGeneratorQueue.put(('createDeterministicAddresses', 3, streamNumberForAddress, "unused deterministic address", self.dialog.ui.spinBoxNumberOfAddressesToMake.value(
shared.addressGeneratorQueue.put(('createDeterministicAddresses', 4, streamNumberForAddress, "unused deterministic address", self.dialog.ui.spinBoxNumberOfAddressesToMake.value(
), self.dialog.ui.lineEditPassphrase.text().toUtf8(), self.dialog.ui.checkBoxEighteenByteRipe.isChecked()))
else:
print 'new address dialog box rejected'

View File

@ -2,8 +2,8 @@
# Form implementation generated from reading ui file 'newaddressdialog.ui'
#
# Created: Thu Jun 13 20:12:21 2013
# by: PyQt4 UI code generator 4.10.1
# Created: Sun Sep 15 23:53:31 2013
# by: PyQt4 UI code generator 4.10.2
#
# WARNING! All changes made in this file will be lost!
@ -178,7 +178,7 @@ class Ui_NewAddressDialog(object):
self.radioButtonDeterministicAddress.setText(_translate("NewAddressDialog", "Use a passphrase to make addresses", None))
self.checkBoxEighteenByteRipe.setText(_translate("NewAddressDialog", "Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter", None))
self.groupBoxDeterministic.setTitle(_translate("NewAddressDialog", "Make deterministic addresses", None))
self.label_9.setText(_translate("NewAddressDialog", "Address version number: 3", None))
self.label_9.setText(_translate("NewAddressDialog", "Address version number: 4", None))
self.label_8.setText(_translate("NewAddressDialog", "In addition to your passphrase, you must remember these numbers:", None))
self.label_6.setText(_translate("NewAddressDialog", "Passphrase", None))
self.label_11.setText(_translate("NewAddressDialog", "Number of addresses to make based on your passphrase:", None))
@ -191,13 +191,3 @@ class Ui_NewAddressDialog(object):
self.radioButtonExisting.setText(_translate("NewAddressDialog", "Use the same stream as an existing address", None))
self.label_4.setText(_translate("NewAddressDialog", "(saves you some bandwidth and processing power)", None))
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
NewAddressDialog = QtGui.QDialog()
ui = Ui_NewAddressDialog()
ui.setupUi(NewAddressDialog)
NewAddressDialog.show()
sys.exit(app.exec_())

View File

@ -99,7 +99,7 @@ The 'Random Number' option is selected by default but deterministic addresses ha
<item row="6" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Address version number: 3</string>
<string>Address version number: 4</string>
</property>
</widget>
</item>

View File

@ -2,8 +2,8 @@
# Form implementation generated from reading ui file 'regenerateaddresses.ui'
#
# Created: Tue Apr 30 12:21:16 2013
# by: PyQt4 UI code generator 4.9.4
# Created: Sun Sep 15 23:50:23 2013
# by: PyQt4 UI code generator 4.10.2
#
# WARNING! All changes made in this file will be lost!
@ -12,7 +12,16 @@ from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
_fromUtf8 = lambda s: s
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
class Ui_regenerateAddressesDialog(object):
def setupUi(self, regenerateAddressesDialog):
@ -56,13 +65,14 @@ class Ui_regenerateAddressesDialog(object):
self.label_2.setObjectName(_fromUtf8("label_2"))
self.gridLayout.addWidget(self.label_2, 4, 0, 1, 1)
self.lineEditAddressVersionNumber = QtGui.QLineEdit(self.groupBox)
self.lineEditAddressVersionNumber.setEnabled(False)
self.lineEditAddressVersionNumber.setEnabled(True)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.lineEditAddressVersionNumber.sizePolicy().hasHeightForWidth())
self.lineEditAddressVersionNumber.setSizePolicy(sizePolicy)
self.lineEditAddressVersionNumber.setMaximumSize(QtCore.QSize(31, 16777215))
self.lineEditAddressVersionNumber.setText(_fromUtf8(""))
self.lineEditAddressVersionNumber.setObjectName(_fromUtf8("lineEditAddressVersionNumber"))
self.gridLayout.addWidget(self.lineEditAddressVersionNumber, 4, 1, 1, 1)
spacerItem1 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
@ -101,15 +111,14 @@ class Ui_regenerateAddressesDialog(object):
QtCore.QMetaObject.connectSlotsByName(regenerateAddressesDialog)
def retranslateUi(self, regenerateAddressesDialog):
regenerateAddressesDialog.setWindowTitle(QtGui.QApplication.translate("regenerateAddressesDialog", "Regenerate Existing Addresses", None, QtGui.QApplication.UnicodeUTF8))
self.groupBox.setTitle(QtGui.QApplication.translate("regenerateAddressesDialog", "Regenerate existing addresses", None, QtGui.QApplication.UnicodeUTF8))
self.label_6.setText(QtGui.QApplication.translate("regenerateAddressesDialog", "Passphrase", None, QtGui.QApplication.UnicodeUTF8))
self.label_11.setText(QtGui.QApplication.translate("regenerateAddressesDialog", "Number of addresses to make based on your passphrase:", None, QtGui.QApplication.UnicodeUTF8))
self.label_2.setText(QtGui.QApplication.translate("regenerateAddressesDialog", "Address version Number:", None, QtGui.QApplication.UnicodeUTF8))
self.lineEditAddressVersionNumber.setText(QtGui.QApplication.translate("regenerateAddressesDialog", "3", None, QtGui.QApplication.UnicodeUTF8))
self.label_3.setText(QtGui.QApplication.translate("regenerateAddressesDialog", "Stream number:", None, QtGui.QApplication.UnicodeUTF8))
self.lineEditStreamNumber.setText(QtGui.QApplication.translate("regenerateAddressesDialog", "1", None, QtGui.QApplication.UnicodeUTF8))
self.checkBoxEighteenByteRipe.setText(QtGui.QApplication.translate("regenerateAddressesDialog", "Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter", None, QtGui.QApplication.UnicodeUTF8))
self.label_4.setText(QtGui.QApplication.translate("regenerateAddressesDialog", "You must check (or not check) this box just like you did (or didn\'t) when you made your addresses the first time.", None, QtGui.QApplication.UnicodeUTF8))
self.label.setText(QtGui.QApplication.translate("regenerateAddressesDialog", "If you have previously made deterministic addresses but lost them due to an accident (like hard drive failure), you can regenerate them here. If you used the random number generator to make your addresses then this form will be of no use to you.", None, QtGui.QApplication.UnicodeUTF8))
regenerateAddressesDialog.setWindowTitle(_translate("regenerateAddressesDialog", "Regenerate Existing Addresses", None))
self.groupBox.setTitle(_translate("regenerateAddressesDialog", "Regenerate existing addresses", None))
self.label_6.setText(_translate("regenerateAddressesDialog", "Passphrase", None))
self.label_11.setText(_translate("regenerateAddressesDialog", "Number of addresses to make based on your passphrase:", None))
self.label_2.setText(_translate("regenerateAddressesDialog", "Address version number:", None))
self.label_3.setText(_translate("regenerateAddressesDialog", "Stream number:", None))
self.lineEditStreamNumber.setText(_translate("regenerateAddressesDialog", "1", None))
self.checkBoxEighteenByteRipe.setText(_translate("regenerateAddressesDialog", "Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter", None))
self.label_4.setText(_translate("regenerateAddressesDialog", "You must check (or not check) this box just like you did (or didn\'t) when you made your addresses the first time.", None))
self.label.setText(_translate("regenerateAddressesDialog", "If you have previously made deterministic addresses but lost them due to an accident (like hard drive failure), you can regenerate them here. If you used the random number generator to make your addresses then this form will be of no use to you.", None))

View File

@ -86,14 +86,14 @@
<item row="4" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Address version Number:</string>
<string>Address version number:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="lineEditAddressVersionNumber">
<property name="enabled">
<bool>false</bool>
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
@ -108,7 +108,7 @@
</size>
</property>
<property name="text">
<string>3</string>
<string/>
</property>
</widget>
</item>

View File

@ -1,7 +1,7 @@
from setuptools import setup
name = "Bitmessage"
version = "0.3.5"
version = "0.4.0"
mainscript = ["bitmessagemain.py"]
setup(

View File

@ -25,20 +25,38 @@ class addressGenerator(threading.Thread):
command, addressVersionNumber, streamNumber, label, deterministicPassphrase = queueValue
eighteenByteRipe = False
numberOfAddressesToMake = 1
numberOfNullBytesDemandedOnFrontOfRipeHash = 1
elif queueValue[0] == 'joinChan':
command, chanAddress, label, deterministicPassphrase = queueValue
eighteenByteRipe = False
addressVersionNumber = decodeAddress(chanAddress)[1]
streamNumber = decodeAddress(chanAddress)[2]
numberOfAddressesToMake = 1
numberOfNullBytesDemandedOnFrontOfRipeHash = 1
elif len(queueValue) == 7:
command, addressVersionNumber, streamNumber, label, numberOfAddressesToMake, deterministicPassphrase, eighteenByteRipe = queueValue
try:
numberOfNullBytesDemandedOnFrontOfRipeHash = shared.config.getint(
'bitmessagesettings', 'numberofnullbytesonaddress')
except:
if eighteenByteRipe:
numberOfNullBytesDemandedOnFrontOfRipeHash = 2
else:
numberOfNullBytesDemandedOnFrontOfRipeHash = 1 # the default
elif len(queueValue) == 9:
command, addressVersionNumber, streamNumber, label, numberOfAddressesToMake, deterministicPassphrase, eighteenByteRipe, nonceTrialsPerByte, payloadLengthExtraBytes = queueValue
try:
numberOfNullBytesDemandedOnFrontOfRipeHash = shared.config.getint(
'bitmessagesettings', 'numberofnullbytesonaddress')
except:
if eighteenByteRipe:
numberOfNullBytesDemandedOnFrontOfRipeHash = 2
else:
numberOfNullBytesDemandedOnFrontOfRipeHash = 1 # the default
else:
sys.stderr.write(
'Programming error: A structure with the wrong number of values was passed into the addressGeneratorQueue. Here is the queueValue: %s\n' % repr(queueValue))
if addressVersionNumber < 3 or addressVersionNumber > 3:
if addressVersionNumber < 3 or addressVersionNumber > 4:
sys.stderr.write(
'Program error: For some reason the address generator queue has been given a request to create at least one version %s address which it cannot do.\n' % addressVersionNumber)
if nonceTrialsPerByte == 0:
@ -51,26 +69,121 @@ class addressGenerator(threading.Thread):
'bitmessagesettings', 'defaultpayloadlengthextrabytes')
if payloadLengthExtraBytes < shared.networkDefaultPayloadLengthExtraBytes:
payloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes
if addressVersionNumber == 3: # currently the only one supported.
if command == 'createRandomAddress':
if command == 'createRandomAddress':
shared.UISignalQueue.put((
'updateStatusBar', tr.translateText("MainWindow", "Generating one new address")))
# 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.
startTime = time.time()
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix = 0
potentialPrivSigningKey = OpenSSL.rand(32)
potentialPubSigningKey = pointMult(potentialPrivSigningKey)
while True:
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix += 1
potentialPrivEncryptionKey = OpenSSL.rand(32)
potentialPubEncryptionKey = pointMult(
potentialPrivEncryptionKey)
# print 'potentialPubSigningKey', potentialPubSigningKey.encode('hex')
# print 'potentialPubEncryptionKey',
# potentialPubEncryptionKey.encode('hex')
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 ripe.digest()[:numberOfNullBytesDemandedOnFrontOfRipeHash] == '\x00' * numberOfNullBytesDemandedOnFrontOfRipeHash:
break
print 'Generated address with ripe digest:', ripe.digest().encode('hex')
print 'Address generator calculated', numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix, 'addresses at', numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix / (time.time() - startTime), 'addresses per second before finding one with the correct ripe-prefix.'
address = encodeAddress(addressVersionNumber, streamNumber, ripe.digest())
# 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)
# print 'privEncryptionKeyWIF',privEncryptionKeyWIF
shared.config.add_section(address)
shared.config.set(address, 'label', label)
shared.config.set(address, 'enabled', 'true')
shared.config.set(address, 'decoy', 'false')
shared.config.set(address, 'noncetrialsperbyte', str(
nonceTrialsPerByte))
shared.config.set(address, 'payloadlengthextrabytes', str(
payloadLengthExtraBytes))
shared.config.set(
address, 'privSigningKey', privSigningKeyWIF)
shared.config.set(
address, 'privEncryptionKey', privEncryptionKeyWIF)
with open(shared.appdata + 'keys.dat', 'wb') as configfile:
shared.config.write(configfile)
# The API and the join and create Chan functionality
# both need information back from the address generator.
shared.apiAddressGeneratorReturnQueue.put(address)
shared.UISignalQueue.put((
'updateStatusBar', tr.translateText("MainWindow", "Done generating address. Doing work necessary to broadcast it...")))
shared.UISignalQueue.put(('writeNewAddressToTable', (
label, address, streamNumber)))
shared.reloadMyAddressHashes()
if addressVersionNumber == 3:
shared.workerQueue.put((
'sendOutOrStoreMyV3Pubkey', ripe.digest()))
elif addressVersionNumber == 4:
shared.workerQueue.put((
'sendOutOrStoreMyV4Pubkey', address))
elif command == 'createDeterministicAddresses' or command == 'getDeterministicAddress' or command == 'createChan' or command == 'joinChan':
if len(deterministicPassphrase) == 0:
sys.stderr.write(
'WARNING: You are creating deterministic address(es) using a blank passphrase. Bitmessage will do it but it is rather stupid.')
if command == 'createDeterministicAddresses':
statusbar = 'Generating ' + str(
numberOfAddressesToMake) + ' new addresses.'
shared.UISignalQueue.put((
'updateStatusBar', tr.translateText("MainWindow", "Generating one new address")))
'updateStatusBar', statusbar))
signingKeyNonce = 0
encryptionKeyNonce = 1
listOfNewAddressesToSendOutThroughTheAPI = [
] # We fill out this list no matter what although we only need it if we end up passing the info to the API.
for i in range(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.
# find one that has a RIPEMD hash 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.
startTime = time.time()
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix = 0
potentialPrivSigningKey = OpenSSL.rand(32)
potentialPubSigningKey = pointMult(potentialPrivSigningKey)
while True:
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix += 1
potentialPrivEncryptionKey = OpenSSL.rand(32)
potentialPrivSigningKey = hashlib.sha512(
deterministicPassphrase + encodeVarint(signingKeyNonce)).digest()[:32]
potentialPrivEncryptionKey = hashlib.sha512(
deterministicPassphrase + encodeVarint(encryptionKeyNonce)).digest()[:32]
potentialPubSigningKey = pointMult(
potentialPrivSigningKey)
potentialPubEncryptionKey = 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(
@ -78,193 +191,97 @@ class addressGenerator(threading.Thread):
ripe.update(sha.digest())
# print 'potential ripe.digest',
# ripe.digest().encode('hex')
if eighteenByteRipe:
if ripe.digest()[:2] == '\x00\x00':
break
else:
if ripe.digest()[:1] == '\x00':
break
print 'Generated address with ripe digest:', ripe.digest().encode('hex')
print 'Address generator calculated', numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix, 'addresses at', numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix / (time.time() - startTime), 'addresses per second before finding one with the correct ripe-prefix.'
address = encodeAddress(3, streamNumber, ripe.digest())
if ripe.digest()[:numberOfNullBytesDemandedOnFrontOfRipeHash] == '\x00' * numberOfNullBytesDemandedOnFrontOfRipeHash:
break
# 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
print 'ripe.digest', ripe.digest().encode('hex')
print 'Address generator calculated', numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix, 'addresses at', numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix / (time.time() - startTime), 'keys per second.'
address = encodeAddress(addressVersionNumber, streamNumber, ripe.digest())
privEncryptionKey = '\x80' + potentialPrivEncryptionKey
checksum = hashlib.sha256(hashlib.sha256(
privEncryptionKey).digest()).digest()[0:4]
privEncryptionKeyWIF = arithmetic.changebase(
privEncryptionKey + checksum, 256, 58)
# print 'privEncryptionKeyWIF',privEncryptionKeyWIF
shared.config.add_section(address)
shared.config.set(address, 'label', label)
shared.config.set(address, 'enabled', 'true')
shared.config.set(address, 'decoy', 'false')
shared.config.set(address, 'noncetrialsperbyte', str(
nonceTrialsPerByte))
shared.config.set(address, 'payloadlengthextrabytes', str(
payloadLengthExtraBytes))
shared.config.set(
address, 'privSigningKey', privSigningKeyWIF)
shared.config.set(
address, 'privEncryptionKey', privEncryptionKeyWIF)
with open(shared.appdata + 'keys.dat', 'wb') as configfile:
shared.config.write(configfile)
# The API and the join and create Chan functionality
# both need information back from the address generator.
shared.apiAddressGeneratorReturnQueue.put(address)
shared.UISignalQueue.put((
'updateStatusBar', tr.translateText("MainWindow", "Done generating address. Doing work necessary to broadcast it...")))
shared.UISignalQueue.put(('writeNewAddressToTable', (
label, address, streamNumber)))
shared.reloadMyAddressHashes()
shared.workerQueue.put((
'sendOutOrStoreMyV3Pubkey', ripe.digest()))
elif command == 'createDeterministicAddresses' or command == 'getDeterministicAddress' or command == 'createChan' or command == 'joinChan':
if len(deterministicPassphrase) == 0:
sys.stderr.write(
'WARNING: You are creating deterministic address(es) using a blank passphrase. Bitmessage will do it but it is rather stupid.')
if command == 'createDeterministicAddresses':
statusbar = 'Generating ' + str(
numberOfAddressesToMake) + ' new addresses.'
shared.UISignalQueue.put((
'updateStatusBar', statusbar))
signingKeyNonce = 0
encryptionKeyNonce = 1
listOfNewAddressesToSendOutThroughTheAPI = [
] # We fill out this list no matter what although we only need it if we end up passing the info to the API.
for i in range(numberOfAddressesToMake):
# This next section is a little bit strange. We're going to generate keys over and over until we
# find one that has a RIPEMD hash 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.
startTime = time.time()
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix = 0
while True:
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix += 1
potentialPrivSigningKey = hashlib.sha512(
deterministicPassphrase + encodeVarint(signingKeyNonce)).digest()[:32]
potentialPrivEncryptionKey = hashlib.sha512(
deterministicPassphrase + encodeVarint(encryptionKeyNonce)).digest()[:32]
potentialPubSigningKey = pointMult(
potentialPrivSigningKey)
potentialPubEncryptionKey = 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 eighteenByteRipe:
if ripe.digest()[:2] == '\x00\x00':
break
else:
if ripe.digest()[:1] == '\x00':
break
print 'ripe.digest', ripe.digest().encode('hex')
print 'Address generator calculated', numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix, 'addresses at', numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix / (time.time() - startTime), 'keys per second.'
address = encodeAddress(3, streamNumber, ripe.digest())
saveAddressToDisk = True
# If we are joining an existing chan, let us check to make sure it matches the provided Bitmessage address
if command == 'joinChan':
if address != chanAddress:
shared.apiAddressGeneratorReturnQueue.put('chan name does not match address')
saveAddressToDisk = False
if command == 'getDeterministicAddress':
saveAddressToDisk = True
# If we are joining an existing chan, let us check to make sure it matches the provided Bitmessage address
if command == 'joinChan':
if address != chanAddress:
shared.apiAddressGeneratorReturnQueue.put('chan name does not match address')
saveAddressToDisk = False
if command == 'getDeterministicAddress':
saveAddressToDisk = False
if saveAddressToDisk:
# 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)
if saveAddressToDisk:
# 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)
privEncryptionKey = '\x80' + \
potentialPrivEncryptionKey
checksum = hashlib.sha256(hashlib.sha256(
privEncryptionKey).digest()).digest()[0:4]
privEncryptionKeyWIF = arithmetic.changebase(
privEncryptionKey + checksum, 256, 58)
privEncryptionKey = '\x80' + \
potentialPrivEncryptionKey
checksum = hashlib.sha256(hashlib.sha256(
privEncryptionKey).digest()).digest()[0:4]
privEncryptionKeyWIF = arithmetic.changebase(
privEncryptionKey + checksum, 256, 58)
addressAlreadyExists = False
try:
shared.config.add_section(address)
except:
print address, 'already exists. Not adding it again.'
addressAlreadyExists = True
if not addressAlreadyExists:
print 'label:', label
shared.config.set(address, 'label', label)
shared.config.set(address, 'enabled', 'true')
shared.config.set(address, 'decoy', 'false')
if command == 'joinChan' or command == 'createChan':
shared.config.set(address, 'chan', 'true')
shared.config.set(address, 'noncetrialsperbyte', str(
nonceTrialsPerByte))
shared.config.set(address, 'payloadlengthextrabytes', str(
payloadLengthExtraBytes))
shared.config.set(
address, 'privSigningKey', privSigningKeyWIF)
shared.config.set(
address, 'privEncryptionKey', privEncryptionKeyWIF)
with open(shared.appdata + 'keys.dat', 'wb') as configfile:
shared.config.write(configfile)
addressAlreadyExists = False
try:
shared.config.add_section(address)
except:
print address, 'already exists. Not adding it again.'
addressAlreadyExists = True
if not addressAlreadyExists:
print 'label:', label
shared.config.set(address, 'label', label)
shared.config.set(address, 'enabled', 'true')
shared.config.set(address, 'decoy', 'false')
if command == 'joinChan' or command == 'createChan':
shared.config.set(address, 'chan', 'true')
shared.config.set(address, 'noncetrialsperbyte', str(
nonceTrialsPerByte))
shared.config.set(address, 'payloadlengthextrabytes', str(
payloadLengthExtraBytes))
shared.config.set(
address, 'privSigningKey', privSigningKeyWIF)
shared.config.set(
address, 'privEncryptionKey', privEncryptionKeyWIF)
with open(shared.appdata + 'keys.dat', 'wb') as configfile:
shared.config.write(configfile)
shared.UISignalQueue.put(('writeNewAddressToTable', (
label, address, str(streamNumber))))
listOfNewAddressesToSendOutThroughTheAPI.append(
address)
shared.myECCryptorObjects[ripe.digest()] = highlevelcrypto.makeCryptor(
potentialPrivEncryptionKey.encode('hex'))
shared.myAddressesByHash[
ripe.digest()] = address
shared.UISignalQueue.put(('writeNewAddressToTable', (
label, address, str(streamNumber))))
listOfNewAddressesToSendOutThroughTheAPI.append(
address)
shared.myECCryptorObjects[ripe.digest()] = highlevelcrypto.makeCryptor(
potentialPrivEncryptionKey.encode('hex'))
shared.myAddressesByHash[ripe.digest()] = address
tag = hashlib.sha512(hashlib.sha512(encodeVarint(
addressVersionNumber) + encodeVarint(streamNumber) + ripe.digest()).digest()).digest()[32:]
shared.myAddressesByTag[tag] = address
if addressVersionNumber == 3:
shared.workerQueue.put((
'sendOutOrStoreMyV3Pubkey', ripe.digest())) # If this is a chan address,
# the worker thread won't send out the pubkey over the network.
elif addressVersionNumber == 4:
shared.workerQueue.put((
'sendOutOrStoreMyV4Pubkey', address))
# Done generating addresses.
if command == 'createDeterministicAddresses' or command == 'joinChan' or command == 'createChan':
shared.apiAddressGeneratorReturnQueue.put(
listOfNewAddressesToSendOutThroughTheAPI)
shared.UISignalQueue.put((
'updateStatusBar', tr.translateText("MainWindow", "Done generating address")))
# shared.reloadMyAddressHashes()
elif command == 'getDeterministicAddress':
shared.apiAddressGeneratorReturnQueue.put(address)
#todo: return things to the API if createChan or joinChan assuming saveAddressToDisk
else:
raise Exception(
"Error in the addressGenerator thread. Thread was given a command it could not understand: " + command)
# Done generating addresses.
if command == 'createDeterministicAddresses' or command == 'joinChan' or command == 'createChan':
shared.apiAddressGeneratorReturnQueue.put(
listOfNewAddressesToSendOutThroughTheAPI)
shared.UISignalQueue.put((
'updateStatusBar', tr.translateText("MainWindow", "Done generating address")))
# shared.reloadMyAddressHashes()
elif command == 'getDeterministicAddress':
shared.apiAddressGeneratorReturnQueue.put(address)
#todo: return things to the API if createChan or joinChan assuming saveAddressToDisk
else:
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.

View File

@ -300,7 +300,7 @@ class receiveDataThread(threading.Thread):
with shared.inventoryLock:
for hash, storedValue in shared.inventory.items():
if hash not in self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware:
objectType, streamNumber, payload, receivedTime = storedValue
objectType, streamNumber, payload, receivedTime, tag = storedValue
if streamNumber == self.streamNumber and receivedTime > int(time.time()) - shared.maximumAgeOfObjectsThatIAdvertiseToOthers:
bigInvList[hash] = 0
numberOfObjectsInInvMessage = 0
@ -391,7 +391,7 @@ class receiveDataThread(threading.Thread):
# It is valid so far. Let's let our peers know about it.
objectType = 'broadcast'
shared.inventory[self.inventoryHash] = (
objectType, self.streamNumber, data, embeddedTime)
objectType, self.streamNumber, data, embeddedTime,'')
shared.inventorySets[self.streamNumber].add(self.inventoryHash)
shared.inventoryLock.release()
self.broadcastinv(self.inventoryHash)
@ -432,8 +432,8 @@ class receiveDataThread(threading.Thread):
broadcastVersion, broadcastVersionLength = decodeVarint(
data[readPosition:readPosition + 9])
readPosition += broadcastVersionLength
if broadcastVersion < 1 or broadcastVersion > 2:
print 'Cannot decode incoming broadcast versions higher than 2. Assuming the sender isn\'t being silly, you should upgrade Bitmessage because this message shall be ignored.'
if broadcastVersion < 1 or broadcastVersion > 3:
print 'Cannot decode incoming broadcast versions higher than 3. Assuming the sender isn\'t being silly, you should upgrade Bitmessage because this message shall be ignored.'
return
if broadcastVersion == 1:
beginningOfPubkeyPosition = readPosition # used when we add the pubkey to our pubkey table
@ -502,6 +502,10 @@ class receiveDataThread(threading.Thread):
print 'ECDSA verify failed', err
return
# verify passed
fromAddress = encodeAddress(
sendersAddressVersion, sendersStream, ripe.digest())
with shared.printLock:
print 'fromAddress:', fromAddress
# 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
@ -515,16 +519,11 @@ class receiveDataThread(threading.Thread):
'\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF' + '\xFF\xFF\xFF\xFF' + data[beginningOfPubkeyPosition:endOfPubkeyPosition],
int(time.time()),
'yes')
# shared.workerQueue.put(('newpubkey',(sendersAddressVersion,sendersStream,ripe.digest())))
# This will check to see whether we happen to be awaiting this
# pubkey in order to send a message. If we are, it will do the
# POW and send it.
self.possibleNewPubkey(ripe.digest())
self.possibleNewPubkey(ripe=ripe.digest())
fromAddress = encodeAddress(
sendersAddressVersion, sendersStream, ripe.digest())
with shared.printLock:
print 'fromAddress:', fromAddress
if messageEncodingType == 2:
subject, body = self.decodeType2Message(message)
@ -665,7 +664,7 @@ class receiveDataThread(threading.Thread):
# This will check to see whether we happen to be awaiting this
# pubkey in order to send a message. If we are, it will do the POW
# and send it.
self.possibleNewPubkey(ripe.digest())
self.possibleNewPubkey(ripe=ripe.digest())
fromAddress = encodeAddress(
sendersAddressVersion, sendersStream, ripe.digest())
@ -709,6 +708,150 @@ class receiveDataThread(threading.Thread):
with shared.printLock:
print 'Time spent processing this interesting broadcast:', time.time() - self.messageProcessingStartTime
if broadcastVersion == 3:
cleartextStreamNumber, cleartextStreamNumberLength = decodeVarint(
data[readPosition:readPosition + 10])
readPosition += cleartextStreamNumberLength
embeddedTag = data[readPosition:readPosition+32]
readPosition += 32
if embeddedTag not in shared.MyECSubscriptionCryptorObjects:
with shared.printLock:
print 'We\'re not interested in this broadcast.'
return
# We are interested in this broadcast because of its tag.
cryptorObject = shared.MyECSubscriptionCryptorObjects[embeddedTag]
try:
decryptedData = cryptorObject.decrypt(data[readPosition:])
print 'EC decryption successful'
except Exception as err:
with shared.printLock:
print 'Broadcast version 3 decryption Unsuccessful.'
return
signedBroadcastVersion, readPosition = decodeVarint(
decryptedData[:10])
beginningOfPubkeyPosition = readPosition # used when we add the pubkey to our pubkey table
sendersAddressVersion, sendersAddressVersionLength = decodeVarint(
decryptedData[readPosition:readPosition + 9])
if sendersAddressVersion < 4:
print 'Cannot decode senderAddressVersion less than 4 for broadcast version number 3. Assuming the sender isn\'t being silly, you should upgrade Bitmessage because this message shall be ignored.'
return
readPosition += sendersAddressVersionLength
sendersStream, sendersStreamLength = decodeVarint(
decryptedData[readPosition:readPosition + 9])
if sendersStream != cleartextStreamNumber:
print 'The stream number outside of the encryption on which the POW was completed doesn\'t match the stream number inside the encryption. Ignoring broadcast.'
return
readPosition += sendersStreamLength
behaviorBitfield = decryptedData[readPosition:readPosition + 4]
readPosition += 4
sendersPubSigningKey = '\x04' + \
decryptedData[readPosition:readPosition + 64]
readPosition += 64
sendersPubEncryptionKey = '\x04' + \
decryptedData[readPosition:readPosition + 64]
readPosition += 64
if sendersAddressVersion >= 3:
requiredAverageProofOfWorkNonceTrialsPerByte, varintLength = decodeVarint(
decryptedData[readPosition:readPosition + 10])
readPosition += varintLength
print 'sender\'s requiredAverageProofOfWorkNonceTrialsPerByte is', requiredAverageProofOfWorkNonceTrialsPerByte
requiredPayloadLengthExtraBytes, varintLength = decodeVarint(
decryptedData[readPosition:readPosition + 10])
readPosition += varintLength
print 'sender\'s requiredPayloadLengthExtraBytes is', requiredPayloadLengthExtraBytes
endOfPubkeyPosition = readPosition
sha = hashlib.new('sha512')
sha.update(sendersPubSigningKey + sendersPubEncryptionKey)
ripeHasher = hashlib.new('ripemd160')
ripeHasher.update(sha.digest())
calculatedRipe = ripeHasher.digest()
calculatedTag = hashlib.sha512(hashlib.sha512(encodeVarint(
sendersAddressVersion) + encodeVarint(sendersStream) + calculatedRipe).digest()).digest()[32:]
if calculatedTag != embeddedTag:
print 'The tag and encryption key used to encrypt this message doesn\'t match the keys inbedded in the message itself. Ignoring message.'
return
messageEncodingType, messageEncodingTypeLength = decodeVarint(
decryptedData[readPosition:readPosition + 9])
if messageEncodingType == 0:
return
readPosition += messageEncodingTypeLength
messageLength, messageLengthLength = decodeVarint(
decryptedData[readPosition:readPosition + 9])
readPosition += messageLengthLength
message = decryptedData[readPosition:readPosition + messageLength]
readPosition += messageLength
readPositionAtBottomOfMessage = readPosition
signatureLength, signatureLengthLength = decodeVarint(
decryptedData[readPosition:readPosition + 9])
readPosition += signatureLengthLength
signature = decryptedData[
readPosition:readPosition + signatureLength]
try:
if not highlevelcrypto.verify(decryptedData[:readPositionAtBottomOfMessage], signature, sendersPubSigningKey.encode('hex')):
print 'ECDSA verify failed'
return
print 'ECDSA verify passed'
except Exception as err:
print 'ECDSA verify failed', err
return
# verify passed
fromAddress = encodeAddress(
sendersAddressVersion, sendersStream, calculatedRipe)
with shared.printLock:
print 'fromAddress:', fromAddress
# Let's store the public key in case we want to reply to this person.
sqlExecute(
'''INSERT INTO pubkeys VALUES (?,?,?,?)''',
calculatedRipe,
'\x00\x00\x00\x00\x00\x00\x00\x01' + decryptedData[beginningOfPubkeyPosition:endOfPubkeyPosition],
int(time.time()),
'yes')
# This will check to see whether we happen to be awaiting this
# pubkey in order to send a message. If we are, it will do the
# POW and send it.
self.possibleNewPubkey(address = fromAddress)
if messageEncodingType == 2:
subject, body = self.decodeType2Message(message)
elif messageEncodingType == 1:
body = message
subject = ''
elif messageEncodingType == 0:
print 'messageEncodingType == 0. Doing nothing with the message.'
else:
body = 'Unknown encoding type.\n\n' + repr(message)
subject = ''
toAddress = '[Broadcast subscribers]'
if messageEncodingType != 0:
t = (self.inventoryHash, toAddress, fromAddress, subject, int(
time.time()), body, 'inbox', messageEncodingType, 0)
helper_inbox.insert(t)
shared.UISignalQueue.put(('displayNewInboxMessage', (
self.inventoryHash, toAddress, fromAddress, subject, body)))
# If we are behaving as an API then we might need to run an
# outside command to let some program know that a new message
# has arrived.
if shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'):
try:
apiNotifyPath = shared.config.get(
'bitmessagesettings', 'apinotifypath')
except:
apiNotifyPath = ''
if apiNotifyPath != '':
call([apiNotifyPath, "newBroadcast"])
# Display timing data
with shared.printLock:
print 'Time spent processing this interesting broadcast:', time.time() - self.messageProcessingStartTime