mirror of
https://github.com/Chia-Network/chia-blockchain.git
synced 2026-09-05 02:24:21 -05:00
* Added 'service' as a Keychain ctor param. Removed 'testing' * Detect existing keys in the Mac Keychain * Fix to allow migration of keys on macOS * Added dump_keyring.py tool to show decrypted contents of keyring.yaml * Prompt to save passphrase to macOS keychain * Master passphrase retrieval/removal from the macOS Keychain. Fixed typos. * Warn if errSecInteractionNotAllowed is detected when accessing the macOS Keychain * Fixed file_keyring synchronization test failures on macOS. Fixed sporadic test failures on macOS when fsevents are delivered for the keyring after deletion. TempKeyring-based tests now patch supports_os_passphrase_storage() to return False. * TempKeyring mocks-out legacy_keyring setup to allow tests to succeed on macOS (which could find existing keys in the Keychain) * Fixed pylint error * Use with_name instead of with_stem (which is new to Python 3.9) * Fixed keychain tests that started prompting for the keyring passphrase. * Fixed LGTM issues * Re-added the cleaning up temp keychain statement. This is being removed in a separate PR. * Linter fixes * Fixed keyring assignment on macOS when passphrase support is disabled. * Include 'can_save_passphrase' flag in keyring_status response * More linter fixes * Fixed determination of the user_passphrase_is_set flag. This was returning true for a newly created keyring without any keys (or passphrase set) * Removed the tidy_passphrase function per feedback * Added some comments based on feedback * Update chia/cmds/passphrase_funcs.py Co-authored-by: Adam Kelly <338792+aqk@users.noreply.github.com> Co-authored-by: Adam Kelly <338792+aqk@users.noreply.github.com>
134 lines
6.6 KiB
Python
134 lines
6.6 KiB
Python
import json
|
|
import unittest
|
|
from secrets import token_bytes
|
|
|
|
from blspy import AugSchemeMPL, PrivateKey
|
|
|
|
from tests.util.keyring import using_temp_file_keyring
|
|
from chia.util.keychain import Keychain, bytes_from_mnemonic, bytes_to_mnemonic, generate_mnemonic, mnemonic_to_seed
|
|
|
|
|
|
class TestKeychain(unittest.TestCase):
|
|
@using_temp_file_keyring()
|
|
def test_basic_add_delete(self):
|
|
kc: Keychain = Keychain(user="testing-1.8.0", service="chia-testing-1.8.0")
|
|
kc.delete_all_keys()
|
|
|
|
assert kc._get_free_private_key_index() == 0
|
|
assert len(kc.get_all_private_keys()) == 0
|
|
assert kc.get_first_private_key() is None
|
|
assert kc.get_first_public_key() is None
|
|
|
|
mnemonic = generate_mnemonic()
|
|
entropy = bytes_from_mnemonic(mnemonic)
|
|
assert bytes_to_mnemonic(entropy) == mnemonic
|
|
mnemonic_2 = generate_mnemonic()
|
|
|
|
# misspelled words in the mnemonic
|
|
bad_mnemonic = mnemonic.split(" ")
|
|
bad_mnemonic[6] = "ZZZZZZ"
|
|
self.assertRaisesRegex(
|
|
ValueError,
|
|
"'ZZZZZZ' is not in the mnemonic dictionary; may be misspelled",
|
|
bytes_from_mnemonic,
|
|
" ".join(bad_mnemonic),
|
|
)
|
|
|
|
kc.add_private_key(mnemonic, "")
|
|
assert kc._get_free_private_key_index() == 1
|
|
assert len(kc.get_all_private_keys()) == 1
|
|
|
|
kc.add_private_key(mnemonic_2, "")
|
|
kc.add_private_key(mnemonic_2, "") # checks to not add duplicates
|
|
assert kc._get_free_private_key_index() == 2
|
|
assert len(kc.get_all_private_keys()) == 2
|
|
|
|
assert kc._get_free_private_key_index() == 2
|
|
assert len(kc.get_all_private_keys()) == 2
|
|
assert len(kc.get_all_public_keys()) == 2
|
|
assert kc.get_all_private_keys()[0] == kc.get_first_private_key()
|
|
assert kc.get_all_public_keys()[0] == kc.get_first_public_key()
|
|
|
|
assert len(kc.get_all_private_keys()) == 2
|
|
|
|
seed_2 = mnemonic_to_seed(mnemonic, "")
|
|
seed_key_2 = AugSchemeMPL.key_gen(seed_2)
|
|
kc.delete_key_by_fingerprint(seed_key_2.get_g1().get_fingerprint())
|
|
assert kc._get_free_private_key_index() == 0
|
|
assert len(kc.get_all_private_keys()) == 1
|
|
|
|
kc.delete_all_keys()
|
|
assert kc._get_free_private_key_index() == 0
|
|
assert len(kc.get_all_private_keys()) == 0
|
|
|
|
kc.add_private_key(bytes_to_mnemonic(token_bytes(32)), "my passphrase")
|
|
kc.add_private_key(bytes_to_mnemonic(token_bytes(32)), "")
|
|
kc.add_private_key(bytes_to_mnemonic(token_bytes(32)), "third passphrase")
|
|
|
|
assert len(kc.get_all_public_keys()) == 3
|
|
assert len(kc.get_all_private_keys()) == 1
|
|
assert len(kc.get_all_private_keys(["my passphrase", ""])) == 2
|
|
assert len(kc.get_all_private_keys(["my passphrase", "", "third passphrase", "another"])) == 3
|
|
assert len(kc.get_all_private_keys(["my passhrase wrong"])) == 0
|
|
|
|
assert kc.get_first_private_key() is not None
|
|
assert kc.get_first_private_key(["bad passphrase"]) is None
|
|
assert kc.get_first_public_key() is not None
|
|
|
|
kc.delete_all_keys()
|
|
kc.add_private_key(bytes_to_mnemonic(token_bytes(32)), "my passphrase")
|
|
assert kc.get_first_public_key() is not None
|
|
|
|
@using_temp_file_keyring()
|
|
def test_bip39_eip2333_test_vector(self):
|
|
kc: Keychain = Keychain(user="testing-1.8.0", service="chia-testing-1.8.0")
|
|
kc.delete_all_keys()
|
|
|
|
mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
|
|
passphrase = "TREZOR"
|
|
print("entropy to seed:", mnemonic_to_seed(mnemonic, passphrase).hex())
|
|
master_sk = kc.add_private_key(mnemonic, passphrase)
|
|
tv_master_int = 5399117110774477986698372024995405256382522670366369834617409486544348441851
|
|
tv_child_int = 11812940737387919040225825939013910852517748782307378293770044673328955938106
|
|
assert master_sk == PrivateKey.from_bytes(tv_master_int.to_bytes(32, "big"))
|
|
child_sk = AugSchemeMPL.derive_child_sk(master_sk, 0)
|
|
assert child_sk == PrivateKey.from_bytes(tv_child_int.to_bytes(32, "big"))
|
|
|
|
def test_bip39_test_vectors_trezor(self):
|
|
with open("tests/util/bip39_test_vectors.json") as f:
|
|
all_vectors = json.loads(f.read())
|
|
|
|
for vector_list in all_vectors["english"]:
|
|
entropy_bytes = bytes.fromhex(vector_list[0])
|
|
mnemonic = vector_list[1]
|
|
seed = bytes.fromhex(vector_list[2])
|
|
|
|
assert bytes_from_mnemonic(mnemonic) == entropy_bytes
|
|
assert bytes_to_mnemonic(entropy_bytes) == mnemonic
|
|
assert mnemonic_to_seed(mnemonic, "TREZOR") == seed
|
|
|
|
def test_utf8_nfkd(self):
|
|
# Test code from trezor:
|
|
# Copyright (c) 2013 Pavol Rusnak
|
|
# Copyright (c) 2017 mruddy
|
|
# https://github.com/trezor/python-mnemonic/blob/master/test_mnemonic.py
|
|
# The same sentence in various UTF-8 forms
|
|
words_nfkd = "Pr\u030ci\u0301s\u030cerne\u030c z\u030clut\u030couc\u030cky\u0301 ku\u030an\u030c u\u0301pe\u030cl d\u030ca\u0301belske\u0301 o\u0301dy za\u0301ker\u030cny\u0301 uc\u030cen\u030c be\u030cz\u030ci\u0301 pode\u0301l zo\u0301ny u\u0301lu\u030a" # noqa: E501
|
|
words_nfc = "P\u0159\xed\u0161ern\u011b \u017elu\u0165ou\u010dk\xfd k\u016f\u0148 \xfap\u011bl \u010f\xe1belsk\xe9 \xf3dy z\xe1ke\u0159n\xfd u\u010de\u0148 b\u011b\u017e\xed pod\xe9l z\xf3ny \xfal\u016f" # noqa: E501
|
|
words_nfkc = "P\u0159\xed\u0161ern\u011b \u017elu\u0165ou\u010dk\xfd k\u016f\u0148 \xfap\u011bl \u010f\xe1belsk\xe9 \xf3dy z\xe1ke\u0159n\xfd u\u010de\u0148 b\u011b\u017e\xed pod\xe9l z\xf3ny \xfal\u016f" # noqa: E501
|
|
words_nfd = "Pr\u030ci\u0301s\u030cerne\u030c z\u030clut\u030couc\u030cky\u0301 ku\u030an\u030c u\u0301pe\u030cl d\u030ca\u0301belske\u0301 o\u0301dy za\u0301ker\u030cny\u0301 uc\u030cen\u030c be\u030cz\u030ci\u0301 pode\u0301l zo\u0301ny u\u0301lu\u030a" # noqa: E501
|
|
|
|
passphrase_nfkd = "Neuve\u030cr\u030citelne\u030c bezpec\u030cne\u0301 hesli\u0301c\u030cko"
|
|
passphrase_nfc = "Neuv\u011b\u0159iteln\u011b bezpe\u010dn\xe9 hesl\xed\u010dko"
|
|
passphrase_nfkc = "Neuv\u011b\u0159iteln\u011b bezpe\u010dn\xe9 hesl\xed\u010dko"
|
|
passphrase_nfd = "Neuve\u030cr\u030citelne\u030c bezpec\u030cne\u0301 hesli\u0301c\u030cko"
|
|
|
|
seed_nfkd = mnemonic_to_seed(words_nfkd, passphrase_nfkd)
|
|
seed_nfc = mnemonic_to_seed(words_nfc, passphrase_nfc)
|
|
seed_nfkc = mnemonic_to_seed(words_nfkc, passphrase_nfkc)
|
|
seed_nfd = mnemonic_to_seed(words_nfd, passphrase_nfd)
|
|
|
|
assert seed_nfkd == seed_nfc
|
|
assert seed_nfkd == seed_nfkc
|
|
assert seed_nfkd == seed_nfd
|