tfix issue #1061: normalize trezor passphrases. Add passphrases to restore from seed with trezor. - electrum - Electrum Bitcoin wallet HTML git clone https://git.parazyd.org/electrum DIR Log DIR Files DIR Refs DIR Submodules --- DIR commit 15636282e421fb3e3fddd32638a931b65a9d4e8c DIR parent c56fe45ad7b93cdb63b6dbb27f72d97c9e789258 HTML Author: ThomasV <thomasv@gitorious> Date: Thu, 5 Mar 2015 17:09:39 +0100 fix issue #1061: normalize trezor passphrases. Add passphrases to restore from seed with trezor. Diffstat: M lib/wallet.py | 4 ++-- M plugins/trezor.py | 44 +++++++++++++++++++------------ 2 files changed, 29 insertions(+), 19 deletions(-) --- DIR diff --git a/lib/wallet.py b/lib/wallet.py t@@ -1321,9 +1321,9 @@ class BIP32_Wallet(Deterministic_Wallet): seed = self.get_seed(password) self.add_cosigner_seed(seed, self.root_name, password) - def add_cosigner_seed(self, seed, name, password): + def add_cosigner_seed(self, seed, name, password, passphrase=''): # we don't store the seed, only the master xpriv - xprv, xpub = bip32_root(self.mnemonic_to_seed(seed,'')) + xprv, xpub = bip32_root(self.mnemonic_to_seed(seed, passphrase)) xprv, xpub = bip32_private_derivation(xprv, "m/", self.root_derivation) self.add_master_public_key(name, xpub) self.add_master_private_key(name, xprv, password) DIR diff --git a/plugins/trezor.py b/plugins/trezor.py t@@ -5,6 +5,7 @@ from struct import pack from sys import stderr from time import sleep from base64 import b64encode, b64decode +import unicodedata import electrum from electrum.account import BIP32_Account t@@ -15,7 +16,6 @@ from electrum.transaction import deserialize from electrum.wallet import BIP32_HD_Wallet from electrum.util import print_error -from electrum_gui.qt.password_dialog import make_password_dialog, run_password_dialog from electrum_gui.qt.util import ok_cancel_buttons, EnterButton try: t@@ -36,6 +36,21 @@ def give_error(message): print_error(message) raise Exception(message) + +def trezor_passphrase_dialog(msg): + from electrum_gui.qt.password_dialog import make_password_dialog, run_password_dialog + d = QDialog() + d.setModal(1) + d.setLayout(make_password_dialog(d, None, msg, False)) + confirmed, p, passphrase = run_password_dialog(d, None, None) + if not confirmed: + return None + if passphrase is None: + passphrase = '' # Even blank string is valid Trezor passphrase + passphrase = unicodedata.normalize('NFKD', unicode(passphrase)) + return passphrase + + class Plugin(BasePlugin): def fullname(self): t@@ -117,9 +132,13 @@ class Plugin(BasePlugin): return wallet = TrezorWallet(storage) self.wallet = wallet + passphrase = trezor_passphrase_dialog(_("Please enter your Trezor passphrase.") + '\n' + _("Press OK if you do not use one.")) + if passphrase is None: + QMessageBox.critical(None, _('Error'), _("Password request canceled"), _('OK')) + return password = wizard.password_dialog() wallet.add_seed(seed, password) - wallet.add_cosigner_seed(' '.join(seed.split()), 'x/', password) + wallet.add_cosigner_seed(seed, 'x/', password, passphrase) wallet.create_main_account(password) # disable trezor plugin self.set_enabled(False) t@@ -244,7 +263,8 @@ class TrezorWallet(BIP32_HD_Wallet): # trezor uses bip39 import pbkdf2, hashlib, hmac PBKDF2_ROUNDS = 2048 - mnemonic = ' '.join(mnemonic.split()) + mnemonic = unicodedata.normalize('NFKD', ' '.join(mnemonic.split())) + passphrase = unicodedata.normalize('NFKD', passphrase) return pbkdf2.PBKDF2(mnemonic, 'mnemonic' + passphrase, iterations = PBKDF2_ROUNDS, macmodule = hmac, digestmodule = hashlib.sha512).read(64) def derive_xkeys(self, root, derivation, password): t@@ -475,13 +495,12 @@ class TrezorQtGuiMixin(object): return proto.Cancel() return proto.PinMatrixAck(pin=pin) - def callback_PassphraseRequest(self, msg): - confirmed, p, passphrase = self.password_dialog() - if not confirmed: + def callback_PassphraseRequest(self, req): + msg = _("Please enter your Trezor passphrase.") + passphrase = trezor_passphrase_dialog(msg) + if passphrase is None: QMessageBox.critical(None, _('Error'), _("Password request canceled"), _('OK')) return proto.Cancel() - if passphrase is None: - passphrase='' # Even blank string is valid Trezor passphrase return proto.PassphraseAck(passphrase=passphrase) def callback_WordRequest(self, msg): t@@ -490,15 +509,6 @@ class TrezorQtGuiMixin(object): word = raw_input() return proto.WordAck(word=word) - def password_dialog(self, msg=None): - if not msg: - msg = _("Please enter your Trezor password") - - d = QDialog() - d.setModal(1) - d.setLayout( make_password_dialog(d, None, msg, False) ) - return run_password_dialog(d, None, None) - def pin_dialog(self, msg): d = QDialog(None) d.setModal(1)