From e47004303fcb88a88942f8f65d538bb101df2c4f Mon Sep 17 00:00:00 2001 From: Kyu Crane Date: Thu, 30 Jul 2015 07:42:26 -0400 Subject: [PATCH] Improve support for behavior bitfield Added option for mobile address creation, to allow testing of mobile send and receive with cleartext RIPE hash. --- src/api.py | 30 ++++++++++++++++++++++--- src/bitmessagecurses/__init__.py | 24 +++++++++++++------- src/bitmessageqt/__init__.py | 15 ++++++++++--- src/bitmessageqt/newaddressdialog.py | 9 ++++++-- src/bitmessageqt/newaddressdialog.ui | 9 +++++++- src/bitmessageqt/regenerateaddresses.py | 8 +++++-- src/bitmessageqt/regenerateaddresses.ui | 9 +++++++- src/class_addressGenerator.py | 12 ++++++---- src/class_objectProcessor.py | 12 ++++++++-- src/class_singleWorker.py | 18 +++++++-------- src/shared.py | 23 +++++++++++++++++++ 11 files changed, 134 insertions(+), 35 deletions(-) diff --git a/src/api.py b/src/api.py index f142953b..2c46142d 100644 --- a/src/api.py +++ b/src/api.py @@ -220,24 +220,34 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): elif len(params) == 1: label, = params eighteenByteRipe = False + behaviorBits = shared.BEHAVIOR_SENDACK, nonceTrialsPerByte = shared.config.get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') payloadLengthExtraBytes = shared.config.get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 2: label, eighteenByteRipe = params + behaviorBits = shared.BEHAVIOR_SENDACK, nonceTrialsPerByte = shared.config.get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') payloadLengthExtraBytes = shared.config.get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 3: label, eighteenByteRipe, totalDifficulty = params + behaviorBits = shared.BEHAVIOR_SENDACK, nonceTrialsPerByte = int( shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = shared.config.get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 4: label, eighteenByteRipe, totalDifficulty, smallMessageDifficulty = params + behaviorBits = shared.BEHAVIOR_SENDACK, + nonceTrialsPerByte = int( + shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) + payloadLengthExtraBytes = int( + shared.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) + elif len(params) == 5: + label, eighteenByteRipe, totalDifficulty, smallMessageDifficulty, behaviorBits = params nonceTrialsPerByte = int( shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = int( @@ -252,7 +262,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): shared.apiAddressGeneratorReturnQueue.queue.clear() streamNumberForAddress = 1 shared.addressGeneratorQueue.put(( - 'createRandomAddress', 4, streamNumberForAddress, label, 1, "", eighteenByteRipe, nonceTrialsPerByte, payloadLengthExtraBytes)) + 'createRandomAddress', 4, streamNumberForAddress, label, 1, "", eighteenByteRipe, behaviorBits, nonceTrialsPerByte, payloadLengthExtraBytes)) return shared.apiAddressGeneratorReturnQueue.get() def HandleCreateDeterministicAddresses(self, params): @@ -264,6 +274,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): addressVersionNumber = 0 streamNumber = 0 eighteenByteRipe = False + behaviorBits = shared.BEHAVIOR_SENDACK, nonceTrialsPerByte = shared.config.get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') payloadLengthExtraBytes = shared.config.get( @@ -273,6 +284,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): addressVersionNumber = 0 streamNumber = 0 eighteenByteRipe = False + behaviorBits = shared.BEHAVIOR_SENDACK, nonceTrialsPerByte = shared.config.get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') payloadLengthExtraBytes = shared.config.get( @@ -281,6 +293,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): passphrase, numberOfAddresses, addressVersionNumber = params streamNumber = 0 eighteenByteRipe = False + behaviorBits = shared.BEHAVIOR_SENDACK, nonceTrialsPerByte = shared.config.get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') payloadLengthExtraBytes = shared.config.get( @@ -288,24 +301,34 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): elif len(params) == 4: passphrase, numberOfAddresses, addressVersionNumber, streamNumber = params eighteenByteRipe = False + behaviorBits = shared.BEHAVIOR_SENDACK, nonceTrialsPerByte = shared.config.get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') payloadLengthExtraBytes = shared.config.get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 5: passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe = params + behaviorBits = shared.BEHAVIOR_SENDACK, nonceTrialsPerByte = shared.config.get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') payloadLengthExtraBytes = shared.config.get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 6: passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe, totalDifficulty = params + behaviorBits = shared.BEHAVIOR_SENDACK, nonceTrialsPerByte = int( shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = shared.config.get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 7: passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe, totalDifficulty, smallMessageDifficulty = params + behaviorBits = shared.BEHAVIOR_SENDACK, + nonceTrialsPerByte = int( + shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) + payloadLengthExtraBytes = int( + shared.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) + elif len(params) == 8: + passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe, totalDifficulty, smallMessageDifficulty, behaviorBits = params nonceTrialsPerByte = int( shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = int( @@ -333,7 +356,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): logger.debug('Requesting that the addressGenerator create %s addresses.', numberOfAddresses) shared.addressGeneratorQueue.put( ('createDeterministicAddresses', addressVersionNumber, streamNumber, - 'unused API address', numberOfAddresses, passphrase, eighteenByteRipe, nonceTrialsPerByte, payloadLengthExtraBytes)) + 'unused API address', numberOfAddresses, passphrase, eighteenByteRipe, behaviorBits, nonceTrialsPerByte, payloadLengthExtraBytes)) data = '{"addresses":[' queueReturn = shared.apiAddressGeneratorReturnQueue.get() for item in queueReturn: @@ -349,6 +372,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): passphrase, addressVersionNumber, streamNumber = params numberOfAddresses = 1 eighteenByteRipe = False + behaviorBits = shared.BEHAVIOR_SENDACK, if len(passphrase) == 0: raise APIError(1, 'The specified passphrase is blank.') passphrase = self._decode(passphrase, "base64") @@ -360,7 +384,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): logger.debug('Requesting that the addressGenerator create %s addresses.', numberOfAddresses) shared.addressGeneratorQueue.put( ('getDeterministicAddress', addressVersionNumber, - streamNumber, 'unused API address', numberOfAddresses, passphrase, eighteenByteRipe)) + streamNumber, 'unused API address', numberOfAddresses, passphrase, eighteenByteRipe, behaviorBits)) return shared.apiAddressGeneratorReturnQueue.get() def HandleCreateChan(self, params): diff --git a/src/bitmessagecurses/__init__.py b/src/bitmessagecurses/__init__.py index 77d09729..49db05b6 100644 --- a/src/bitmessagecurses/__init__.py +++ b/src/bitmessagecurses/__init__.py @@ -427,11 +427,15 @@ def handlech(c, stdscr): if r == d.DIALOG_OK: stream = decodeAddress(addrs[int(t)][1])[2] shorten = False + behaviorBits = shared.BEHAVIOR_SENDACK, r, t = d.checklist("Miscellaneous options", - choices=[("1", "Spend time shortening the address", shorten)]) - if r == d.DIALOG_OK and "1" in t: - shorten = True - shared.addressGeneratorQueue.put(("createRandomAddress", 4, stream, label, 1, "", shorten)) + choices=[("1", "Spend time shortening the address", shorten), ("2", "Create a mobile address")]) + if r == d.DIALOG_OK: + if "1" in t: + shorten = True + if "2" in t: + behaviorBits += shared.BEHAVIOR_NEEDRIPE, + shared.addressGeneratorQueue.put(("createRandomAddress", 4, stream, label, 1, "", shorten, behaviorBits)) elif t == "2": d.set_background_title("Make deterministic addresses") r, t = d.passwordform("Enter passphrase", @@ -447,15 +451,19 @@ def handlech(c, stdscr): number = t stream = 1 shorten = False + behaviorBits = shared.BEHAVIOR_SENDACK, r, t = d.checklist("Miscellaneous options", - choices=[("1", "Spend time shortening the address", shorten)]) - if r == d.DIALOG_OK and "1" in t: - shorten = True + choices=[("1", "Spend time shortening the address", shorten), ("2", "Create a mobile address")]) + if r == d.DIALOG_OK: + if "1" in t: + shorten = True + if "2" in t: + behaviorBits += shared.BEHAVIOR_NEEDRIPE, d.scrollbox(unicode("In addition to your passphrase, be sure to remember the following numbers:\n" "\n * Address version number: "+str(4)+"\n" " * Stream number: "+str(stream)), exit_label="Continue") - shared.addressGeneratorQueue.put(('createDeterministicAddresses', 4, stream, "unused deterministic address", number, str(passphrase), shorten)) + shared.addressGeneratorQueue.put(('createDeterministicAddresses', 4, stream, "unused deterministic address", number, str(passphrase), shorten, behaviorBits)) else: d.scrollbox(unicode("Passphrases do not match"), exit_label="Continue") elif t == "2": # Send a message diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 1819628b..12e9e99b 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1405,8 +1405,11 @@ class MyForm(QtGui.QMainWindow): QMessageBox.about(self, _translate("MainWindow", "Bad address version number"), _translate( "MainWindow", "Your address version number must be either 3 or 4.")) return + behaviorBits = shared.BEHAVIOR_SENDACK, + if self.dialog.ui.checkBoxMobile.isChecked(): + behaviorBits += shared.BEHAVIOR_NEEDRIPE, shared.addressGeneratorQueue.put(('createDeterministicAddresses', addressVersionNumber, streamNumberForAddress, "regenerated deterministic address", self.regenerateAddressesDialogInstance.ui.spinBoxNumberOfAddressesToMake.value( - ), self.regenerateAddressesDialogInstance.ui.lineEditPassphrase.text().toUtf8(), self.regenerateAddressesDialogInstance.ui.checkBoxEighteenByteRipe.isChecked())) + ), self.regenerateAddressesDialogInstance.ui.lineEditPassphrase.text().toUtf8(), self.regenerateAddressesDialogInstance.ui.checkBoxEighteenByteRipe.isChecked(), behaviorBits)) self.ui.tabWidget.setCurrentIndex(3) def click_actionJoinChan(self): @@ -2635,8 +2638,11 @@ more work your computer must do to send the message. A Time-To-Live of four or f # address.' streamNumberForAddress = decodeAddress( self.dialog.ui.comboBoxExisting.currentText())[2] + behaviorBits = shared.BEHAVIOR_SENDACK, + if self.dialog.ui.checkBoxMobile.isChecked(): + behaviorBits += shared.BEHAVIOR_NEEDRIPE, shared.addressGeneratorQueue.put(('createRandomAddress', 4, streamNumberForAddress, str( - self.dialog.ui.newaddresslabel.text().toUtf8()), 1, "", self.dialog.ui.checkBoxEighteenByteRipe.isChecked())) + self.dialog.ui.newaddresslabel.text().toUtf8()), 1, "", self.dialog.ui.checkBoxEighteenByteRipe.isChecked(), behaviorBits)) else: if self.dialog.ui.lineEditPassphrase.text() != self.dialog.ui.lineEditPassphraseAgain.text(): QMessageBox.about(self, _translate("MainWindow", "Passphrase mismatch"), _translate( @@ -2646,8 +2652,11 @@ more work your computer must do to send the message. A Time-To-Live of four or f "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. + behaviorBits = shared.BEHAVIOR_SENDACK, + if self.dialog.ui.checkBoxMobile.isChecked(): + behaviorBits += shared.BEHAVIOR_NEEDRIPE, 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())) + ), self.dialog.ui.lineEditPassphrase.text().toUtf8(), self.dialog.ui.checkBoxEighteenByteRipe.isChecked(), behaviorBits)) else: print 'new address dialog box rejected' diff --git a/src/bitmessageqt/newaddressdialog.py b/src/bitmessageqt/newaddressdialog.py index afe6fa2d..12e770e1 100644 --- a/src/bitmessageqt/newaddressdialog.py +++ b/src/bitmessageqt/newaddressdialog.py @@ -64,6 +64,9 @@ class Ui_NewAddressDialog(object): self.checkBoxEighteenByteRipe = QtGui.QCheckBox(NewAddressDialog) self.checkBoxEighteenByteRipe.setObjectName(_fromUtf8("checkBoxEighteenByteRipe")) self.formLayout.setWidget(9, QtGui.QFormLayout.SpanningRole, self.checkBoxEighteenByteRipe) + self.checkBoxMobile = QtGui.QCheckBox(NewAddressDialog) + self.checkBoxMobile.setObjectName(_fromUtf8("checkBoxMobile")) + self.formLayout.setWidget(10, QtGui.QFormLayout.SpanningRole, self.checkBoxMobile) self.groupBoxDeterministic = QtGui.QGroupBox(NewAddressDialog) self.groupBoxDeterministic.setObjectName(_fromUtf8("groupBoxDeterministic")) self.gridLayout = QtGui.QGridLayout(self.groupBoxDeterministic) @@ -149,7 +152,7 @@ class Ui_NewAddressDialog(object): self.buttonBox.setOrientation(QtCore.Qt.Horizontal) self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok) self.buttonBox.setObjectName(_fromUtf8("buttonBox")) - self.formLayout.setWidget(10, QtGui.QFormLayout.SpanningRole, self.buttonBox) + self.formLayout.setWidget(11, QtGui.QFormLayout.SpanningRole, self.buttonBox) self.retranslateUi(NewAddressDialog) QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), NewAddressDialog.accept) @@ -167,7 +170,8 @@ class Ui_NewAddressDialog(object): NewAddressDialog.setTabOrder(self.lineEditPassphrase, self.lineEditPassphraseAgain) NewAddressDialog.setTabOrder(self.lineEditPassphraseAgain, self.spinBoxNumberOfAddressesToMake) NewAddressDialog.setTabOrder(self.spinBoxNumberOfAddressesToMake, self.checkBoxEighteenByteRipe) - NewAddressDialog.setTabOrder(self.checkBoxEighteenByteRipe, self.buttonBox) + NewAddressDialog.setTabOrder(self.checkBoxEighteenByteRipe, self.checkBoxMobile) + NewAddressDialog.setTabOrder(self.checkBoxMobile, self.buttonBox) def retranslateUi(self, NewAddressDialog): NewAddressDialog.setWindowTitle(_translate("NewAddressDialog", "Create new Address", None)) @@ -177,6 +181,7 @@ class Ui_NewAddressDialog(object): self.radioButtonRandomAddress.setText(_translate("NewAddressDialog", "Use a random number generator to make an address", None)) 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.checkBoxMobile.setText(_translate("NewAddressDialog", "Require messages sent to you include your address unencrypted (saves resources, for mobile)", None)) self.groupBoxDeterministic.setTitle(_translate("NewAddressDialog", "Make deterministic addresses", 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)) diff --git a/src/bitmessageqt/newaddressdialog.ui b/src/bitmessageqt/newaddressdialog.ui index a9eda5c3..1f57d0fd 100644 --- a/src/bitmessageqt/newaddressdialog.ui +++ b/src/bitmessageqt/newaddressdialog.ui @@ -90,6 +90,13 @@ The 'Random Number' option is selected by default but deterministic addresses ha + + + + Require messages sent to you include your address(es) unencrypted (saves resources, for mobile) + + + @@ -284,7 +291,7 @@ The 'Random Number' option is selected by default but deterministic addresses ha horizontalSpacer_3 - + diff --git a/src/bitmessageqt/regenerateaddresses.py b/src/bitmessageqt/regenerateaddresses.py index 7129b632..bcf56d91 100644 --- a/src/bitmessageqt/regenerateaddresses.py +++ b/src/bitmessageqt/regenerateaddresses.py @@ -94,11 +94,14 @@ class Ui_regenerateAddressesDialog(object): self.gridLayout.addItem(spacerItem2, 5, 2, 1, 3) self.checkBoxEighteenByteRipe = QtGui.QCheckBox(self.groupBox) self.checkBoxEighteenByteRipe.setObjectName(_fromUtf8("checkBoxEighteenByteRipe")) - self.gridLayout.addWidget(self.checkBoxEighteenByteRipe, 6, 0, 1, 5) + self.gridLayout.addWidget(self.checkBoxEighteenByteRipe, 7, 0, 1, 5) + self.checkBoxMobile = QtGui.QCheckBox(self.groupBox) + self.checkBoxMobile.setObjectName(_fromUtf8("checkBoxMobile")) + self.gridLayout.addWidget(self.checkBoxMobile, 6, 0, 1, 5) self.label_4 = QtGui.QLabel(self.groupBox) self.label_4.setWordWrap(True) self.label_4.setObjectName(_fromUtf8("label_4")) - self.gridLayout.addWidget(self.label_4, 7, 0, 1, 5) + self.gridLayout.addWidget(self.label_4, 8, 0, 1, 5) self.label = QtGui.QLabel(self.groupBox) self.label.setWordWrap(True) self.label.setObjectName(_fromUtf8("label")) @@ -119,6 +122,7 @@ class Ui_regenerateAddressesDialog(object): 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.checkBoxMobile.setText(_translate("regenerateAddressesDialog", "Require messages sent to you include your address(es) unencrypted (saves resources, for mobile)", 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)) diff --git a/src/bitmessageqt/regenerateaddresses.ui b/src/bitmessageqt/regenerateaddresses.ui index e58a20e9..2937314f 100644 --- a/src/bitmessageqt/regenerateaddresses.ui +++ b/src/bitmessageqt/regenerateaddresses.ui @@ -168,13 +168,20 @@ + + + Require messages sent to you include your address(es) unencrypted (saves resources, for mobile) + + + + Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter - + You must check (or not check) this box just like you did (or didn't) when you made your addresses the first time. diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index af25b210..b32ec769 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -25,17 +25,19 @@ class addressGenerator(threading.Thread): if queueValue[0] == 'createChan': command, addressVersionNumber, streamNumber, label, deterministicPassphrase = queueValue eighteenByteRipe = False + behaviorBits = () numberOfAddressesToMake = 1 numberOfNullBytesDemandedOnFrontOfRipeHash = 1 elif queueValue[0] == 'joinChan': command, chanAddress, label, deterministicPassphrase = queueValue eighteenByteRipe = False + behaviorBits = () addressVersionNumber = decodeAddress(chanAddress)[1] streamNumber = decodeAddress(chanAddress)[2] numberOfAddressesToMake = 1 numberOfNullBytesDemandedOnFrontOfRipeHash = 1 - elif len(queueValue) == 7: - command, addressVersionNumber, streamNumber, label, numberOfAddressesToMake, deterministicPassphrase, eighteenByteRipe = queueValue + elif len(queueValue) == 8: + command, addressVersionNumber, streamNumber, label, numberOfAddressesToMake, deterministicPassphrase, eighteenByteRipe, behaviorBits = queueValue try: numberOfNullBytesDemandedOnFrontOfRipeHash = shared.config.getint( 'bitmessagesettings', 'numberofnullbytesonaddress') @@ -44,8 +46,8 @@ class addressGenerator(threading.Thread): numberOfNullBytesDemandedOnFrontOfRipeHash = 2 else: numberOfNullBytesDemandedOnFrontOfRipeHash = 1 # the default - elif len(queueValue) == 9: - command, addressVersionNumber, streamNumber, label, numberOfAddressesToMake, deterministicPassphrase, eighteenByteRipe, nonceTrialsPerByte, payloadLengthExtraBytes = queueValue + elif len(queueValue) == 10: + command, addressVersionNumber, streamNumber, label, numberOfAddressesToMake, deterministicPassphrase, eighteenByteRipe, behaviorBits, nonceTrialsPerByte, payloadLengthExtraBytes = queueValue try: numberOfNullBytesDemandedOnFrontOfRipeHash = shared.config.getint( 'bitmessagesettings', 'numberofnullbytesonaddress') @@ -119,6 +121,7 @@ class addressGenerator(threading.Thread): shared.config.set(address, 'label', label) shared.config.set(address, 'enabled', 'true') shared.config.set(address, 'decoy', 'false') + shared.setConfigFromBehaviorBitfield(address, shared.createBitfield(*behaviorBits)) shared.config.set(address, 'noncetrialsperbyte', str( nonceTrialsPerByte)) shared.config.set(address, 'payloadlengthextrabytes', str( @@ -236,6 +239,7 @@ class addressGenerator(threading.Thread): shared.config.set(address, 'label', label) shared.config.set(address, 'enabled', 'true') shared.config.set(address, 'decoy', 'false') + shared.setConfigFromBehaviorBitfield(address, shared.createBitfield(*behaviorBits)) if command == 'joinChan' or command == 'createChan': shared.config.set(address, 'chan', 'true') shared.config.set(address, 'noncetrialsperbyte', str( diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index f9972fe6..21c8213d 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -342,7 +342,12 @@ class objectProcessor(threading.Thread): for key, cryptorObject in shared.myECCryptorObjects.items(): try: - decryptedData = cryptorObject.decrypt(data[readPosition:]) + mobileRipe = key.lstrip('\x00') + if data[readPosition:readPosition+len(mobileRipe)] == mobileRipe: + decryptedData = cryptorObject.decrypt(data[readPosition+len(mobileRipe):]) + logger.info('Received a mobile message containing our unencrypted address.') + else: + decryptedData = cryptorObject.decrypt(data[readPosition:]) toRipe = key # This is the RIPE hash of my pubkeys. We need this below to compare to the destination_ripe included in the encrypted data. initialDecryptionSuccessful = True logger.info('EC decryption successful using key associated with ripe hash: %s.' % key.encode('hex')) @@ -575,7 +580,10 @@ class objectProcessor(threading.Thread): shared.workerQueue.put(('sendbroadcast', '')) if self.ackDataHasAVaildHeader(ackData): - shared.checkAndShareObjectWithPeers(ackData[24:]) + if shared.config.getboolean(toAddress, 'notsendack'): + logger.info('Ack data was provided even though we do not send it. Ignoring.') + else: + shared.checkAndShareObjectWithPeers(ackData[24:]) # Display timing data timeRequiredToAttemptToDecryptMessage = time.time( diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 02177309..8c4861b2 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -106,7 +106,7 @@ class singleWorker(threading.Thread): payload += '\x00\x00\x00\x01' # object type: pubkey payload += encodeVarint(addressVersionNumber) # Address version number payload += encodeVarint(streamNumber) - payload += '\x00\x00\x00\x01' # bitfield of features supported by me (see the wiki). + payload += shared.createBehaviorBitfieldFromConfig(myAddress) # bitfield of features supported by me (see the wiki). try: privSigningKeyBase58 = shared.config.get( @@ -191,7 +191,7 @@ class singleWorker(threading.Thread): payload += '\x00\x00\x00\x01' # object type: pubkey payload += encodeVarint(addressVersionNumber) # Address version number payload += encodeVarint(streamNumber) - payload += '\x00\x00\x00\x01' # bitfield of features supported by me (see the wiki). + payload += shared.createBehaviorBitfieldFromConfig(myAddress) # bitfield of features supported by me (see the wiki). try: privSigningKeyBase58 = shared.config.get( @@ -277,7 +277,7 @@ class singleWorker(threading.Thread): payload += encodeVarint(addressVersionNumber) # Address version number payload += encodeVarint(streamNumber) - dataToEncrypt = '\x00\x00\x00\x01' # bitfield of features supported by me (see the wiki). + dataToEncrypt = shared.createBehaviorBitfieldFromConfig(myAddress) # bitfield of features supported by me (see the wiki). try: privSigningKeyBase58 = shared.config.get( @@ -410,7 +410,7 @@ class singleWorker(threading.Thread): dataToEncrypt = encodeVarint(addressVersionNumber) dataToEncrypt += encodeVarint(streamNumber) - dataToEncrypt += '\x00\x00\x00\x01' # behavior bitfield + dataToEncrypt += shared.createBehaviorBitfieldFromConfig(fromaddress) # behavior bitfield dataToEncrypt += pubSigningKey[1:] dataToEncrypt += pubEncryptionKey[1:] if addressVersionNumber >= 3: @@ -641,7 +641,7 @@ class singleWorker(threading.Thread): # Mobile users may ask us to include their address's RIPE hash on a message # unencrypted. Before we actually do it the sending human must check a box # in the settings menu to allow it. - if shared.isBitSetWithinBitfield(behaviorBitfield,30): # if receiver is a mobile device who expects that their address RIPE is included unencrypted on the front of the message.. + if shared.isBitSetWithinBitfield(behaviorBitfield,shared.BEHAVIOR_NEEDRIPE): # if receiver is a mobile device who expects that their address RIPE is included unencrypted on the front of the message.. if not shared.safeConfigGetBoolean('bitmessagesettings','willinglysendtomobile'): # if we are Not willing to include the receiver's RIPE hash on the message.. logger.info('The receiver is a mobile user but the sender (you) has not selected that you are willing to send to mobiles. Aborting send.') shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,tr.translateText("MainWindow",'Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1').arg(l10n.formatTimestamp())))) @@ -687,7 +687,7 @@ class singleWorker(threading.Thread): else: # if we are sending a message to ourselves or a chan.. with shared.printLock: print 'Sending a message. First 150 characters of message:', repr(message[:150]) - behaviorBitfield = '\x00\x00\x00\x01' + behaviorBitfield = shared.createBehaviorBitfieldFromConfig(toaddress) try: privEncryptionKeyBase58 = shared.config.get( @@ -710,7 +710,7 @@ class singleWorker(threading.Thread): # Now we can start to assemble our message. payload = encodeVarint(fromAddressVersionNumber) payload += encodeVarint(fromStreamNumber) - payload += '\x00\x00\x00\x01' # Bitfield of features and behaviors that can be expected from me. (See https://bitmessage.org/wiki/Protocol_specification#Pubkey_bitfield_features ) + payload += shared.createBehaviorBitfieldFromConfig(fromaddress) # Bitfield of features and behaviors that can be expected from me. (See https://bitmessage.org/wiki/Protocol_specification#Pubkey_bitfield_features ) # We need to convert our private keys to public keys in order # to include them. @@ -764,7 +764,7 @@ class singleWorker(threading.Thread): with shared.printLock: print 'Not bothering to include ackdata because we are sending to ourselves or a chan.' fullAckPayload = '' - elif not shared.isBitSetWithinBitfield(behaviorBitfield,31): + elif not shared.isBitSetWithinBitfield(behaviorBitfield,shared.BEHAVIOR_SENDACK): with shared.printLock: print 'Not bothering to include ackdata because the receiver said that they won\'t relay it anyway.' fullAckPayload = '' @@ -790,7 +790,7 @@ class singleWorker(threading.Thread): encryptedPayload += '\x00\x00\x00\x02' # object type: msg encryptedPayload += encodeVarint(1) # msg version encryptedPayload += encodeVarint(toStreamNumber) - if shared.isBitSetWithinBitfield(behaviorBitfield,30): # if receiver is a mobile device who expects that their address RIPE is included unencrypted on the front of the message.. + if shared.isBitSetWithinBitfield(behaviorBitfield,shared.BEHAVIOR_NEEDRIPE): # if receiver is a mobile device who expects that their address RIPE is included unencrypted on the front of the message.. encryptedPayload += toRipe.lstrip('\x00') encryptedPayload += encrypted target = 2 ** 64 / (requiredAverageProofOfWorkNonceTrialsPerByte*(len(encryptedPayload) + 8 + requiredPayloadLengthExtraBytes + ((TTL*(len(encryptedPayload)+8+requiredPayloadLengthExtraBytes))/(2 ** 16)))) diff --git a/src/shared.py b/src/shared.py index d82f00a5..ad340e54 100644 --- a/src/shared.py +++ b/src/shared.py @@ -116,6 +116,10 @@ frozen = getattr(sys,'frozen', None) # security. trustedPeer = None +# Behavior bitfield constants +BEHAVIOR_SENDACK = 31 +BEHAVIOR_NEEDRIPE = 30 + #Compiled struct for packing/unpacking headers #New code should use CreatePacket instead of Header.pack Header = Struct('!L12sL4s') @@ -473,6 +477,25 @@ def isBitSetWithinBitfield(fourByteString, n): x, = unpack('>L', fourByteString) return x & 2**n != 0 +def createBitfield(*fields): + x = 0 + for n in fields: + n = 31 - n + x |= 2**n + return pack('>L', x) + +def createBehaviorBitfieldFromConfig(myAddress): + fields = () + if not config.getboolean(myAddress, 'notsendack'): + fields += BEHAVIOR_SENDACK, + if config.getboolean(myAddress, 'needripe'): + fields += BEHAVIOR_NEEDRIPE, + return createBitfield(*fields) + +def setConfigFromBehaviorBitfield(address, bitfield): + config.set(address, 'notsendack', str(not isBitSetWithinBitfield(bitfield, BEHAVIOR_SENDACK))) + config.set(address, 'needripe', str(isBitSetWithinBitfield(bitfield, BEHAVIOR_NEEDRIPE))) + def decryptAndCheckPubkeyPayload(data, address): """