seed vault xfp collision

This commit is contained in:
scgbckbone 2023-10-09 03:35:56 +02:00 committed by doc-hex
parent bb6fea731e
commit c9cf5b7db8
3 changed files with 67 additions and 24 deletions

View File

@ -934,7 +934,7 @@ async def restore_main_secret(*a):
escape = None
msg = "Restore main wallet and its settings?\n\n"
if not in_seed_vault():
if not in_seed_vault(pa.tmp_value):
msg += (
"Press OK to forget current temporary wallet "
"settings, or press (1) to save & keep "

View File

@ -406,17 +406,13 @@ async def new_from_dice(nwords):
# send them to home menu, now with a wallet enabled
goto_top_menu(first_time=True)
def in_seed_vault(xfp=None):
def in_seed_vault(encoded):
# Test if indicated xfp (or currently active XFP) is in the seed vault already.
if xfp is None:
xfp = xfp2str(settings.get("xfp", 0))
seeds = settings.master_get("seeds", [])
if seeds and (xfp in [s[0] for s in seeds]):
return True
if seeds:
ss = stash.SecretStash.storage_serialize(encoded)
if ss in [s[1] for s in seeds]:
return True
return False
async def add_seed_to_vault(encoded, meta=None):
@ -433,7 +429,7 @@ async def add_seed_to_vault(encoded, meta=None):
new_xfp_str = xfp2str(new_xfp)
# do not offer to store secrets that are already in vault
if in_seed_vault(new_xfp_str):
if in_seed_vault(encoded):
return
# do not offer to store main seed
@ -796,9 +792,8 @@ class SeedVaultMenu(MenuSystem):
dis.fullscreen("Applying...")
xfp, encoded = item.arg
raw = pad_raw_secret(encoded)
await set_ephemeral_seed(raw, is_restore=True)
await set_ephemeral_seed(encoded, is_restore=True)
goto_top_menu()
@ -838,7 +833,7 @@ class SeedVaultMenu(MenuSystem):
else:
# in main settings
xs = SettingsObject()
xs.set_key(pad_raw_secret(encoded))
xs.set_key(encoded)
xs.load()
xs.blank()
del xs
@ -866,7 +861,7 @@ class SeedVaultMenu(MenuSystem):
xfp_str, encoded, name, meta = item.arg
# - first byte represents type of secret (internal encoding flag)
txt = SecretStash.summary(a2b_hex(encoded[0:2])[0])
txt = SecretStash.summary(encoded[0])
detail = "Name:\n%s\n\nMaster XFP:\n%s\n\nOrigin:\n%s\n\nSecret Type:\n%s" \
% (name, xfp_str, meta, txt)
@ -923,7 +918,8 @@ class SeedVaultMenu(MenuSystem):
rv.append(MenuItem("Temporary Seed", menu=make_ephemeral_seed_menu))
else:
for i, (xfp_str, encoded, name, meta) in enumerate(seeds):
is_active = (cur_xfp == xfp_str)
encoded = pad_raw_secret(encoded)
is_active = (encoded == pa.tmp_value)
submenu = [
MenuItem(name, f=cls._detail, arg=(xfp_str, encoded, name, meta)),
MenuItem('Use This Seed', f=cls._set, arg=(xfp_str, encoded)),

View File

@ -2,7 +2,8 @@
#
# Ephemeral Seeds tests
#
import pytest, time, re, os, shutil, pdb
import pytest, time, re, os, shutil, pdb, hashlib
from constants import simulator_fixed_tpub, simulator_fixed_words, simulator_fixed_xfp, simulator_fixed_xpub
from ckcc.protocol import CCProtocolPacker
from txn import fake_txn
@ -367,18 +368,19 @@ def import_ephemeral_xprv(microsd_path, virtdisk_path, goto_eph_seed_menu,
if extended_key is None:
node = BIP32Node.from_master_secret(os.urandom(32), netcode=netcode)
ek = node.hwif(as_private=True) + '\n'
if way == "sd":
fpath = microsd_path(fname)
elif way == "vdisk":
fpath = virtdisk_path(fname)
if way != "nfc":
with open(fpath, "w") as f:
f.write(ek)
else:
node = BIP32Node.from_wallet_key(extended_key)
assert extended_key == node.hwif(as_private=True)
ek = extended_key
if way == "sd":
fpath = microsd_path(fname)
elif way == "vdisk":
fpath = virtdisk_path(fname)
if way != "nfc":
with open(fpath, "w") as f:
f.write(ek)
if testnet:
assert "tprv" in ek
else:
@ -1117,4 +1119,49 @@ def test_seed_vault_modifications(settings_set, reset_seed_words, pick_menu_item
# still in ephemeral
assert title == m[0]
def test_xfp_collision(reset_seed_words, settings_set, import_ephemeral_xprv,
cap_story, need_keypress, pick_menu_item, cap_menu):
node = BIP32Node.from_master_secret(os.urandom(32), netcode="XTN")
xfp = node.fingerprint().hex().upper()
k0 = node.hwif(as_private=True)
# change chain code but presevre public key
node._chain_code = hashlib.sha256(node._chain_code).digest()
k1 = node.hwif(as_private=True)
assert k1 != k0
reset_seed_words()
settings_set("seedvault", 1)
settings_set("seeds", [])
import_ephemeral_xprv("sd", extended_key=k0, seed_vault=True, from_main=True)
title, story = cap_story()
assert "is in effect now" in story
need_keypress("y")
import_ephemeral_xprv("sd", extended_key=k1, seed_vault=True, from_main=False)
title, story = cap_story()
assert "is in effect now" in story
need_keypress("y")
pick_menu_item("Seed Vault")
m = cap_menu()
assert len(m) == 3 # two seeds and Restore Master
# same master fingerprints
assert xfp in m[0]
assert xfp in m[1]
# but only second is in use
pick_menu_item(m[1])
time.sleep(.1)
sm = cap_menu()
assert "Seed In Use" in sm
assert "Use This Seed" not in sm
need_keypress("x") # go back
pick_menu_item(m[0])
time.sleep(.1)
sm = cap_menu()
assert "Seed In Use" not in sm
assert "Use This Seed" in sm
# EOF