From 0c9a03ac5481dfdf8e7b3e86d8a2e51e2c2a7463 Mon Sep 17 00:00:00 2001 From: SomberNight Date: Tue, 18 Dec 2018 15:37:29 +0100 Subject: [PATCH] keystore: revert KDF change from #4838 making the KDF expensive is blocked on #4909 --- electrum/crypto.py | 53 +++++++++++++++------------------- electrum/tests/test_bitcoin.py | 10 +++---- 2 files changed, 29 insertions(+), 34 deletions(-) diff --git a/electrum/crypto.py b/electrum/crypto.py index 7df21156b..3046f0c14 100644 --- a/electrum/crypto.py +++ b/electrum/crypto.py @@ -116,9 +116,11 @@ def DecodeAES_bytes(secret: bytes, ciphertext: bytes) -> bytes: return s -PW_HASH_VERSION_LATEST = 2 -KNOWN_PW_HASH_VERSIONS = (1, 2) +PW_HASH_VERSION_LATEST = 1 +KNOWN_PW_HASH_VERSIONS = (1, 2, ) +SUPPORTED_PW_HASH_VERSIONS = (1, ) assert PW_HASH_VERSION_LATEST in KNOWN_PW_HASH_VERSIONS +assert PW_HASH_VERSION_LATEST in SUPPORTED_PW_HASH_VERSIONS class UnexpectedPasswordHashVersion(InvalidPassword): @@ -126,23 +128,30 @@ class UnexpectedPasswordHashVersion(InvalidPassword): self.version = version def __str__(self): - return "{unexpected}: {version}\n{please_update}".format( + return "{unexpected}: {version}\n{instruction}".format( unexpected=_("Unexpected password hash version"), version=self.version, - please_update=_('You are most likely using an outdated version of Electrum. Please update.')) + instruction=_('You are most likely using an outdated version of Electrum. Please update.')) -def _hash_password(password: Union[bytes, str], *, version: int, salt: bytes) -> bytes: +class UnsupportedPasswordHashVersion(InvalidPassword): + def __init__(self, version): + self.version = version + + def __str__(self): + return "{unsupported}: {version}\n{instruction}".format( + unsupported=_("Unsupported password hash version"), + version=self.version, + instruction=f"To open this wallet, try 'git checkout password_v{self.version}'.\n" + "Alternatively, restore from seed.") + + +def _hash_password(password: Union[bytes, str], *, version: int) -> bytes: pw = to_bytes(password, 'utf8') + if version not in SUPPORTED_PW_HASH_VERSIONS: + raise UnsupportedPasswordHashVersion(version) if version == 1: return sha256d(pw) - elif version == 2: - if not isinstance(salt, bytes) or len(salt) < 16: - raise Exception('too weak salt', salt) - return hashlib.pbkdf2_hmac(hash_name='sha256', - password=pw, - salt=b'ELECTRUM_PW_HASH_V2'+salt, - iterations=50_000) else: assert version not in KNOWN_PW_HASH_VERSIONS raise UnexpectedPasswordHashVersion(version) @@ -154,17 +163,9 @@ def pw_encode(data: str, password: Union[bytes, str, None], *, version: int) -> if version not in KNOWN_PW_HASH_VERSIONS: raise UnexpectedPasswordHashVersion(version) # derive key from password - if version == 1: - salt = b'' - elif version == 2: - salt = bytes(os.urandom(16)) - else: - assert False, version - secret = _hash_password(password, version=version, salt=salt) + secret = _hash_password(password, version=version) # encrypt given data - e = EncodeAES_bytes(secret, to_bytes(data, "utf8")) - # return base64(salt + encrypted data) - ciphertext = salt + e + ciphertext = EncodeAES_bytes(secret, to_bytes(data, "utf8")) ciphertext_b64 = base64.b64encode(ciphertext) return ciphertext_b64.decode('utf8') @@ -176,13 +177,7 @@ def pw_decode(data: str, password: Union[bytes, str, None], *, version: int) -> raise UnexpectedPasswordHashVersion(version) data_bytes = bytes(base64.b64decode(data)) # derive key from password - if version == 1: - salt = b'' - elif version == 2: - salt, data_bytes = data_bytes[:16], data_bytes[16:] - else: - assert False, version - secret = _hash_password(password, version=version, salt=salt) + secret = _hash_password(password, version=version) # decrypt given data try: d = to_string(DecodeAES_bytes(secret, data_bytes), "utf8") diff --git a/electrum/tests/test_bitcoin.py b/electrum/tests/test_bitcoin.py index 752e50173..2b74907f7 100644 --- a/electrum/tests/test_bitcoin.py +++ b/electrum/tests/test_bitcoin.py @@ -11,7 +11,7 @@ from electrum.bitcoin import (public_key_to_p2pkh, address_from_private_key, from electrum.bip32 import (bip32_root, bip32_public_derivation, bip32_private_derivation, xpub_from_xprv, xpub_type, is_xprv, is_bip32_derivation, is_xpub, convert_bip32_path_to_list_of_uint32) -from electrum.crypto import sha256d, KNOWN_PW_HASH_VERSIONS +from electrum.crypto import sha256d, SUPPORTED_PW_HASH_VERSIONS from electrum import ecc, crypto, constants from electrum.ecc import number_to_string, string_to_number from electrum.transaction import opcodes @@ -219,7 +219,7 @@ class Test_bitcoin(SequentialTestCase): """Make sure AES is homomorphic.""" payload = u'\u66f4\u7a33\u5b9a\u7684\u4ea4\u6613\u5e73\u53f0' password = u'secret' - for version in KNOWN_PW_HASH_VERSIONS: + for version in SUPPORTED_PW_HASH_VERSIONS: enc = crypto.pw_encode(payload, password, version=version) dec = crypto.pw_decode(enc, password, version=version) self.assertEqual(dec, payload) @@ -228,7 +228,7 @@ class Test_bitcoin(SequentialTestCase): def test_aes_encode_without_password(self): """When not passed a password, pw_encode is noop on the payload.""" payload = u'\u66f4\u7a33\u5b9a\u7684\u4ea4\u6613\u5e73\u53f0' - for version in KNOWN_PW_HASH_VERSIONS: + for version in SUPPORTED_PW_HASH_VERSIONS: enc = crypto.pw_encode(payload, None, version=version) self.assertEqual(payload, enc) @@ -236,7 +236,7 @@ class Test_bitcoin(SequentialTestCase): def test_aes_deencode_without_password(self): """When not passed a password, pw_decode is noop on the payload.""" payload = u'\u66f4\u7a33\u5b9a\u7684\u4ea4\u6613\u5e73\u53f0' - for version in KNOWN_PW_HASH_VERSIONS: + for version in SUPPORTED_PW_HASH_VERSIONS: enc = crypto.pw_decode(payload, None, version=version) self.assertEqual(payload, enc) @@ -246,7 +246,7 @@ class Test_bitcoin(SequentialTestCase): payload = u"blah" password = u"uber secret" wrong_password = u"not the password" - for version in KNOWN_PW_HASH_VERSIONS: + for version in SUPPORTED_PW_HASH_VERSIONS: enc = crypto.pw_encode(payload, password, version=version) with self.assertRaises(InvalidPassword): crypto.pw_decode(enc, wrong_password, version=version)