Beispiel #1
0
async def xor_restore_start(*a):
    # shown on import menu when no seed of any kind yet
    # - or operational system
    ch = await ux_show_story('''\
To import a seed split using XOR, you must import all the parts.
It does not matter the order (A/B/C or C/A/B) and the Coldcard
cannot determine when you have all the parts. You may stop at
any time and you will have a valid wallet.''')
    if ch == 'x': return

    global import_xor_parts
    import_xor_parts.clear()

    from pincodes import pa

    if not pa.is_secret_blank():
        msg = "Since you have a seed already on this Coldcard, the reconstructed XOR seed will be temporary and not saved. Wipe the seed first if you want to commit the new value into the secure element."
        if settings.get('words', True):
            msg += '''\n
Press (1) to include this Coldcard's seed words into the XOR seed set, or OK to continue without.'''

        ch = await ux_show_story(msg, escape='1')

        if ch == 'x':
            return
        elif ch == '1':
            with stash.SensitiveValues() as sv:
                if sv.mode == 'words':
                    words = bip39.b2a_words(sv.raw).split(' ')
                    import_xor_parts.append(words)

    return XORWordNestMenu(num_words=24)
Beispiel #2
0
    async def all_done(new_words):
        # So we have another part, might be done or not.
        global import_xor_parts
        assert len(new_words) == 24
        import_xor_parts.append(new_words)

        XORWordNestMenu.pop_all()

        num_parts = len(import_xor_parts)
        seed = xor32(*(bip39.a2b_words(w) for w in import_xor_parts))

        msg = "You've entered %d parts so far.\n\n" % num_parts
        if num_parts >= 2:
            chk_word = bip39.b2a_words(seed).split(' ')[-1]
            msg += "If you stop now, the 24th word of the XOR-combined seed phrase\nwill be:\n\n"
            msg += "24: %s\n\n" % chk_word

        if all((not x) for x in seed):
            # zero seeds are never right.
            msg += "ZERO WARNING\nProvided seed works out to all zeros "\
                    "right now. You may have doubled a part or made some other mistake.\n\n"

        msg += "Press (1) to enter next list of words, or (2) if done with all words."

        ch = await ux_show_story(msg,
                                 strict_escape=True,
                                 escape='12x',
                                 sensitive=True)

        if ch == 'x':
            # give up
            import_xor_parts.clear()  # concern: we are contaminated w/ secrets
            return None
        elif ch == '1':
            # do another list of words
            nxt = XORWordNestMenu(num_words=24)
            the_ux.push(nxt)
        elif ch == '2':
            # done; import on temp basis, or be the main secret
            from pincodes import pa
            enc = stash.SecretStash.encode(seed_phrase=seed)

            if pa.is_secret_blank():
                # save it since they have no other secret
                set_seed_value(encoded=enc)

                # update menu contents now that wallet defined
                goto_top_menu()
            else:
                pa.tmp_secret(enc)
                await ux_show_story(
                    "New master key in effect until next power down.")

        return None
Beispiel #3
0
    def __init__(self, secret=None, bypass_pw=False):
        if secret is None:
            # fetch the secret from bootloader/atecc508a
            from pincodes import pa

            if pa.is_secret_blank():
                raise ValueError('no secrets yet')

            self.secret = pa.fetch()
            self.spots = [self.secret]
        else:
            # sometimes we already know it
            #assert set(secret) != {0}
            self.secret = secret
            self.spots = []

        # backup during volatile bip39 encryption: do not use passphrase
        self._bip39pw = '' if bypass_pw else str(bip39_passphrase)
Beispiel #4
0
    def set_key(self, new_secret=None):
        # System settings (not secrets) are stored in SPI Flash, encrypted with this
        # key that is derived from main wallet secret. Call this method when the secret
        # is first loaded, or changes for some reason.
        from pincodes import pa
        from stash import blank_object

        key = None
        mine = False

        if not new_secret:
            if not pa.is_successful() or pa.is_secret_blank():
                # simple fixed key allows us to store a few things when logged out
                key = b'\0' * 32
            else:
                # read secret and use it.
                new_secret = pa.fetch()
                mine = True

        if new_secret:
            # hash up the secret... without decoding it or similar
            assert len(new_secret) >= 32

            s = sha256(new_secret)

            for round in range(5):
                s.update('pad')

                s = sha256(s.digest())

            key = s.digest()

            if mine:
                blank_object(new_secret)

        # for restore from backup case, or when changing (created) the seed
        self.nvram_key = key
Beispiel #5
0
def has_secrets():
    from pincodes import pa
    return not pa.is_secret_blank()
Beispiel #6
0
# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC.
#
# quickly main wipe seed; don't install anything new
from glob import numpad, dis
from pincodes import pa
from nvstore import settings
from pincodes import AE_SECRET_LEN, PA_IS_BLANK

if not pa.is_secret_blank():
    # clear settings associated with this key, since it will be no more
    settings.blank()

    # save a blank secret (all zeros is a special case, detected by bootloader)
    dis.fullscreen('Wipe Seed!')
    nv = bytes(AE_SECRET_LEN)
    pa.change(new_secret=nv)

    rv = pa.setup(pa.pin)
    pa.login()

    assert pa.is_secret_blank()

# reset top menu and go there
from actions import goto_top_menu
goto_top_menu()

numpad.abort_ux()