mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-31 01:11:35 +00:00
Merge pull request #4937 from SomberNight/revert_password_v2
keystore: revert KDF change
This commit is contained in:
commit
fa389a4e06
2 changed files with 29 additions and 34 deletions
|
@ -116,9 +116,11 @@ def DecodeAES_bytes(secret: bytes, ciphertext: bytes) -> bytes:
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
PW_HASH_VERSION_LATEST = 2
|
PW_HASH_VERSION_LATEST = 1
|
||||||
KNOWN_PW_HASH_VERSIONS = (1, 2)
|
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 KNOWN_PW_HASH_VERSIONS
|
||||||
|
assert PW_HASH_VERSION_LATEST in SUPPORTED_PW_HASH_VERSIONS
|
||||||
|
|
||||||
|
|
||||||
class UnexpectedPasswordHashVersion(InvalidPassword):
|
class UnexpectedPasswordHashVersion(InvalidPassword):
|
||||||
|
@ -126,23 +128,30 @@ class UnexpectedPasswordHashVersion(InvalidPassword):
|
||||||
self.version = version
|
self.version = version
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "{unexpected}: {version}\n{please_update}".format(
|
return "{unexpected}: {version}\n{instruction}".format(
|
||||||
unexpected=_("Unexpected password hash version"),
|
unexpected=_("Unexpected password hash version"),
|
||||||
version=self.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')
|
pw = to_bytes(password, 'utf8')
|
||||||
|
if version not in SUPPORTED_PW_HASH_VERSIONS:
|
||||||
|
raise UnsupportedPasswordHashVersion(version)
|
||||||
if version == 1:
|
if version == 1:
|
||||||
return sha256d(pw)
|
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:
|
else:
|
||||||
assert version not in KNOWN_PW_HASH_VERSIONS
|
assert version not in KNOWN_PW_HASH_VERSIONS
|
||||||
raise UnexpectedPasswordHashVersion(version)
|
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:
|
if version not in KNOWN_PW_HASH_VERSIONS:
|
||||||
raise UnexpectedPasswordHashVersion(version)
|
raise UnexpectedPasswordHashVersion(version)
|
||||||
# derive key from password
|
# derive key from password
|
||||||
if version == 1:
|
secret = _hash_password(password, version=version)
|
||||||
salt = b''
|
|
||||||
elif version == 2:
|
|
||||||
salt = bytes(os.urandom(16))
|
|
||||||
else:
|
|
||||||
assert False, version
|
|
||||||
secret = _hash_password(password, version=version, salt=salt)
|
|
||||||
# encrypt given data
|
# encrypt given data
|
||||||
e = EncodeAES_bytes(secret, to_bytes(data, "utf8"))
|
ciphertext = EncodeAES_bytes(secret, to_bytes(data, "utf8"))
|
||||||
# return base64(salt + encrypted data)
|
|
||||||
ciphertext = salt + e
|
|
||||||
ciphertext_b64 = base64.b64encode(ciphertext)
|
ciphertext_b64 = base64.b64encode(ciphertext)
|
||||||
return ciphertext_b64.decode('utf8')
|
return ciphertext_b64.decode('utf8')
|
||||||
|
|
||||||
|
@ -176,13 +177,7 @@ def pw_decode(data: str, password: Union[bytes, str, None], *, version: int) ->
|
||||||
raise UnexpectedPasswordHashVersion(version)
|
raise UnexpectedPasswordHashVersion(version)
|
||||||
data_bytes = bytes(base64.b64decode(data))
|
data_bytes = bytes(base64.b64decode(data))
|
||||||
# derive key from password
|
# derive key from password
|
||||||
if version == 1:
|
secret = _hash_password(password, version=version)
|
||||||
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)
|
|
||||||
# decrypt given data
|
# decrypt given data
|
||||||
try:
|
try:
|
||||||
d = to_string(DecodeAES_bytes(secret, data_bytes), "utf8")
|
d = to_string(DecodeAES_bytes(secret, data_bytes), "utf8")
|
||||||
|
|
|
@ -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,
|
from electrum.bip32 import (bip32_root, bip32_public_derivation, bip32_private_derivation,
|
||||||
xpub_from_xprv, xpub_type, is_xprv, is_bip32_derivation,
|
xpub_from_xprv, xpub_type, is_xprv, is_bip32_derivation,
|
||||||
is_xpub, convert_bip32_path_to_list_of_uint32)
|
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 import ecc, crypto, constants
|
||||||
from electrum.ecc import number_to_string, string_to_number
|
from electrum.ecc import number_to_string, string_to_number
|
||||||
from electrum.transaction import opcodes
|
from electrum.transaction import opcodes
|
||||||
|
@ -219,7 +219,7 @@ class Test_bitcoin(SequentialTestCase):
|
||||||
"""Make sure AES is homomorphic."""
|
"""Make sure AES is homomorphic."""
|
||||||
payload = u'\u66f4\u7a33\u5b9a\u7684\u4ea4\u6613\u5e73\u53f0'
|
payload = u'\u66f4\u7a33\u5b9a\u7684\u4ea4\u6613\u5e73\u53f0'
|
||||||
password = u'secret'
|
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)
|
enc = crypto.pw_encode(payload, password, version=version)
|
||||||
dec = crypto.pw_decode(enc, password, version=version)
|
dec = crypto.pw_decode(enc, password, version=version)
|
||||||
self.assertEqual(dec, payload)
|
self.assertEqual(dec, payload)
|
||||||
|
@ -228,7 +228,7 @@ class Test_bitcoin(SequentialTestCase):
|
||||||
def test_aes_encode_without_password(self):
|
def test_aes_encode_without_password(self):
|
||||||
"""When not passed a password, pw_encode is noop on the payload."""
|
"""When not passed a password, pw_encode is noop on the payload."""
|
||||||
payload = u'\u66f4\u7a33\u5b9a\u7684\u4ea4\u6613\u5e73\u53f0'
|
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)
|
enc = crypto.pw_encode(payload, None, version=version)
|
||||||
self.assertEqual(payload, enc)
|
self.assertEqual(payload, enc)
|
||||||
|
|
||||||
|
@ -236,7 +236,7 @@ class Test_bitcoin(SequentialTestCase):
|
||||||
def test_aes_deencode_without_password(self):
|
def test_aes_deencode_without_password(self):
|
||||||
"""When not passed a password, pw_decode is noop on the payload."""
|
"""When not passed a password, pw_decode is noop on the payload."""
|
||||||
payload = u'\u66f4\u7a33\u5b9a\u7684\u4ea4\u6613\u5e73\u53f0'
|
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)
|
enc = crypto.pw_decode(payload, None, version=version)
|
||||||
self.assertEqual(payload, enc)
|
self.assertEqual(payload, enc)
|
||||||
|
|
||||||
|
@ -246,7 +246,7 @@ class Test_bitcoin(SequentialTestCase):
|
||||||
payload = u"blah"
|
payload = u"blah"
|
||||||
password = u"uber secret"
|
password = u"uber secret"
|
||||||
wrong_password = u"not the password"
|
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)
|
enc = crypto.pw_encode(payload, password, version=version)
|
||||||
with self.assertRaises(InvalidPassword):
|
with self.assertRaises(InvalidPassword):
|
||||||
crypto.pw_decode(enc, wrong_password, version=version)
|
crypto.pw_decode(enc, wrong_password, version=version)
|
||||||
|
|
Loading…
Add table
Reference in a new issue