Exemple #1
0
 def read(self, ll):
     b = self.fd.read(ll * 2)
     if not b:
         return b
     assert len(b) % 2 == 0
     self.pos += len(b) // 2
     return a2b_hex(b)
Exemple #2
0
def test_b39():
    import bip39
    from ngu_tests import b39_vectors

    for raw, words, ms, xprv in b39_vectors.english:
        ms = a2b_hex(ms)
        x = HDNode()
        x.from_master(ms)
        assert x.serialize(0x0488ADE4, 1) == xprv
def encode_simple_cbor(data):
    buffer_data = a2b_hex(data)
    l = len(buffer_data)
    if l <= 0 or l >= 2**32:
        raise ValueError('length is too big')

    header = compose_header(l)

    encoded = header + buffer_data
    return encoded
Exemple #4
0
def check_digest(digest, payload):
  decoded = decode_bc32_data(payload)
  if decoded == None:
    raise ValueError('Unable to decode payload: {}'.format(payload))

  decoded_bytes = a2b_hex(decoded)
  sha = sha256_hash(decoded_bytes)
  decoded_digest = b2a_hex(sha).decode() # bytearray
  comp_digest = decode_bc32_data(digest) 
  if comp_digest != decoded_digest:
    raise ValueError('Invalid digest:\n  digest={}\n  payload={}\nssSspayload digest={}'.format(digest, payload, decoded_digest))
Exemple #5
0
    def my_gate(method, buf_io, arg2):
        # do a command/response over unix pipe
        bb = b2a_hex(buf_io).decode('ascii') if buf_io is not None else 'None'
        msg = '%d, %s, %d\n' % (method, bb, arg2)

        # send to real python
        req.write(msg)
        # must use readline here for response
        ln = resp.readline().decode('ascii')

        rv, buf = ln.strip().split(',')
        if len(buf):
            buf_io[:] = a2b_hex(buf.strip())

        return int(rv)
Exemple #6
0
    def read_flash():
        print("Reading SPI flash... ", end='')
        from sflash import SPIFlash
        a = SPIFlash.array
        req.write('-99, None, 0\n')
        addr = 0xe0000
        for i in range(0, 0x20000, 256):
            b = a2b_hex(resp.readline().strip())
            assert len(b) == 256
            a[addr + i:addr + i + 256] = b
        print("done")

        # robustness/error detection
        import sim_settings
        del sim_settings.sim_defaults
Exemple #7
0
async def clone_write_data(*a):
    # Write encrypted backup file, for cloning purposes, based on a public key
    # found on the SD Card.
    # - input file must already exist on inserted card
    from files import CardSlot, CardMissingError

    try:
        with CardSlot() as card:
            path = card.get_sd_root()
            with open(path + '/ccbk-start.json', 'rb') as fd:
                d = ujson.load(fd)
                his_pubkey = a2b_hex(d.get('pubkey'))
                # expect compress pubkey
                assert len(his_pubkey) == 33
                assert 2 <= his_pubkey[0] <= 3

            # remove any other clone-files on this card, so no confusion
            # on receiving end; unlikely they can work anyway since new key each time
            for path in card.get_paths():
                for fn, ftype, *var in uos.ilistdir(path):
                    if fn.endswith('-ccbk.7z'):
                        try:
                            uos.remove(path + '/' + fn)
                        except:
                            pass

    except (CardMissingError, OSError) as exc:
        # Standard msg shown if no SD card detected when we need one.
        await ux_show_story(
            "Start this process on the other Coldcard, which will write a file onto MicroSD card as the first step.\n\nInsert that card and try again here."
        )
        return

    # pick our own temp keys for this encryption
    pair = ngu.secp256k1.keypair()
    my_pubkey = pair.pubkey().to_bytes(False)
    session_key = pair.ecdh_multiply(his_pubkey)

    words = [b2a_hex(session_key).decode()]

    fname = b2a_hex(my_pubkey).decode() + '-ccbk.7z'

    await write_complete_backup(words, fname, allow_copies=False)

    await ux_show_story(
        "Done.\n\nTake this MicroSD card back to other Coldcard and continue from there."
    )
def decode_simple_cbor(data):
    data_buffer = a2b_hex(data)

    l = len(data_buffer)
    if l <= 0:
        raise ValueError('invalid length (<=0)')

    header = data_buffer[0]
    if header < 0x58:
        data_length = header - 0x40
        return hexlify(data_buffer[1:1 + data_length]).decode()
    elif header == 0x58:
        data_length = int.from_bytes(data_buffer[1:2], 'big')
        return hexlify(data_buffer[2:2 + data_length]).decode()
    elif header == 0x59:
        data_length = int.from_bytes(data_buffer[1:3], 'big')
        return hexlify(data_buffer[3:3 + data_length]).decode()
    elif header == 0x60:
        data_length = int.from_bytes(data_buffer[1:5], 'big')
        return hexlify(data_buffer[5:5 + data_length]).decode()
Exemple #9
0
def pin_stuff(submethod, buf_io):
    from pincodes import (PIN_ATTEMPT_SIZE, PIN_ATTEMPT_FMT, PA_ZERO_SECRET,
                        PA_SUCCESSFUL, PA_IS_BLANK, PA_HAS_DURESS, PA_HAS_BRICKME,
                        CHANGE_WALLET_PIN, CHANGE_DURESS_PIN, CHANGE_BRICKME_PIN,
                        CHANGE_SECRET, CHANGE_DURESS_SECRET, CHANGE_SECONDARY_WALLET_PIN )

    if len(buf_io) != PIN_ATTEMPT_SIZE: return ERANGE

    global SECRETS

    (magic, is_secondary,
            pin, pin_len,
            delay_achieved,
            delay_required,
            num_fails,
            attempt_target,
            state_flags,
            private_state,
            hmac,
            change_flags,
            old_pin, old_pin_len,
            new_pin, new_pin_len,
            secret) = ustruct.unpack_from(PIN_ATTEMPT_FMT, buf_io)

    # NOTE: using strings here, not bytes; real bootrom uses bytes
    pin = pin[0:pin_len].decode()
    old_pin = old_pin[0:old_pin_len].decode()
    new_pin = new_pin[0:new_pin_len].decode()

    kk = '_pin1' if not is_secondary else '_pin2'

    if submethod == 0:
        # setup
        state_flags = (PA_SUCCESSFUL | PA_IS_BLANK) if not SECRETS.get(kk, False) else 0

        if pin.startswith('77'):
            delay_required = int(pin.split('-')[1]) * 2
            num_fails = 3

    elif submethod == 1:
        # delay
        time.sleep(0.500)
        delay_achieved += 1

    elif submethod == 2:
        # Login

        expect = SECRETS.get(kk, '')
        if pin == expect:
            state_flags = PA_SUCCESSFUL

            ts = a2b_hex(SECRETS.get(kk+'_secret', '00'*72))

        elif pin == SECRETS.get(kk + '_duress', None):
            state_flags = PA_SUCCESSFUL

            ts = a2b_hex(SECRETS.get(kk+'_duress_secret', '00'*72))

        else:
            state_flags = 0
            return EPIN_AUTH_FAIL

        time.sleep(0.5)

        if ts == b'\0'*72:
            state_flags |= PA_ZERO_SECRET

        del ts

    elif submethod == 3:
        # CHANGE pin and/or wallet secrets

        cf = change_flags;

        # NOTE: this logic copied from real deal

        # must be here to do something.
        if cf == 0: return EPIN_RANGE_ERR;

        if cf & CHANGE_BRICKME_PIN:
            if is_secondary:
                # only main PIN holder can define brickme PIN
                return EPIN_PRIMARY_ONLY
            if cf != CHANGE_BRICKME_PIN:
                # only pin can be changed, nothing else.
                return EPIN_BAD_REQUEST

        if (cf & CHANGE_DURESS_SECRET) and (cf & CHANGE_SECRET):
            # can't change two secrets at once.
            return EPIN_BAD_REQUEST

        if (cf & CHANGE_SECONDARY_WALLET_PIN):
            if is_secondary:
                # only main user uses this call 
                return EPIN_BAD_REQUEST;

            if (cf != CHANGE_SECONDARY_WALLET_PIN):
                # only changing PIN, no secret-setting
                return EPIN_BAD_REQUEST;

            kk = '_pin2'

        
        # what PIN will we change
        pk = None
        if change_flags & (CHANGE_WALLET_PIN | CHANGE_SECONDARY_WALLET_PIN):
            pk = kk
        if change_flags & CHANGE_DURESS_PIN:
            pk = kk+'_duress'
        if change_flags & CHANGE_BRICKME_PIN:
            pk = kk+'_brickme'

        if pin == SECRETS.get(kk + '_duress', None):
            # acting duress mode... let them only change duress pin
            if pk == kk:
                pk = kk+'_duress'
            else:
                return EPIN_OLD_AUTH_FAIL

        if pk != None:
            # Must match old pin correctly, if it is defined.
            if SECRETS.get(pk, '') != old_pin:
                print("secel: wrong OLD pin (expect %s, got %s)" % (SECRETS[pk], old_pin))
                return EPIN_OLD_AUTH_FAIL

            # make change
            SECRETS[pk] = new_pin

        if change_flags & CHANGE_SECRET:
            SECRETS[kk+'_secret'] = str(b2a_hex(secret), 'ascii')
        if change_flags & CHANGE_DURESS_SECRET:
            SECRETS[kk+'_duress_secret'] = str(b2a_hex(secret), 'ascii')

        time.sleep(1.5)

    elif submethod == 4:
        # Fetch secrets
        duress_pin = SECRETS.get(kk+'_duress')

        if pin == duress_pin:
            secret = a2b_hex(SECRETS.get(kk+'_duress_secret', '00'*72))
        else:
            # main/sec secrets
            expect = SECRETS.get(kk, '')
            if pin == expect:
                secret = a2b_hex(SECRETS.get(kk+'_secret', '00'*72))
            else:
                return EPIN_AUTH_FAIL

    elif submethod == 5:
        # greenlight firmware
        from ckcc import genuine_led, led_pipe
        genuine_led = True
        led_pipe.write(b'\x01')


    hmac = b'69'*16

    ustruct.pack_into(PIN_ATTEMPT_FMT, buf_io, 0, magic, is_secondary,
            pin.encode(), pin_len, delay_achieved, delay_required,
            num_fails, attempt_target,
            state_flags, private_state, hmac,
            change_flags, old_pin.encode(), old_pin_len, new_pin.encode(), new_pin_len, secret)

    return 0
Exemple #10
0
def test_crc16w():
    # test vectors
    assert crc16w(a2b_hex('0411')) == a2b_hex('3343')
    assert crc16w(a2b_hex('ff')) == a2b_hex('0202')
    assert crc16w(a2b_hex('aa')) == a2b_hex('fe01')
    assert crc16w(a2b_hex('ffaa')) == a2b_hex('f183')
    assert crc16w(a2b_hex('07ccbebab2')) == a2b_hex('8598')
    assert crc16w(a2b_hex('ffaa5500')) == a2b_hex('26f4')
Exemple #11
0
    elif '--wrap' in sys.argv:
        # p2wsh-p2sh case
        sim_defaults['multisig'] = [["CC-2-of-4", [2, 4], [[1130956047, "tpubDF2rnouQaaYrUEy2JM1YD3RFzew4onawGM4X2Re67gguTf5CbHonBRiFGe3Xjz7DK88dxBFGf2i7K1hef3PM4cFKyUjcbJXddaY9F5tJBoP"], [3503269483, "tpubDFcrvj5n7gyatVbr8dHCUfHT4CGvL8hREBjtxc4ge7HZgqNuPhFimPRtVg6fRRwfXiQthV9EBjNbwbpgV2VoQeL1ZNXoAWXxP2L9vMtRjax"], [2389277556, "tpubDExj5FnaUnPAjjgzELoSiNRkuXJG8Cm1pbdiA4Hc5vkAZHphibeVcUp6mqH5LuNVKbtLVZxVSzyja5X26Cfmx6pzRH6gXBUJAH7MiqwNyuM"], [3190206587, "tpubDFiuHYSJhNbHaGtB5skiuDLg12tRboh2uVZ6KGXxr8WVr28pLcS7F3gv8SsHFa2tm1jtx3VAuw56YfgRkdo6DXyfp51oygTKY3nJFT5jBMt"]], {"pp": "48'/1'/0'/1'", "ch": "XTN", "ft": 26}]]
    else:
        # P2SH: 2of4 using BIP39 passwords: "Me", "Myself", "and I", and (empty string) on simulator
        sim_defaults['multisig'] = [['MeMyself', [2, 4], [[3503269483, 'tpubD9429UXFGCTKJ9NdiNK4rC5ygqSUkginycYHccqSg5gkmyQ7PZRHNjk99M6a6Y3NY8ctEUUJvCu6iCCui8Ju3xrHRu3Ez1CKB4ZFoRZDdP9'], [2389277556, 'tpubD97nVL37v5tWyMf9ofh5rznwhh1593WMRg6FT4o6MRJkKWANtwAMHYLrcJFsFmPfYbY1TE1LLQ4KBb84LBPt1ubvFwoosvMkcWJtMwvXgSc'], [3190206587, 'tpubD9ArfXowvGHnuECKdGXVKDMfZVGdephVWg8fWGWStH3VKHzT4ph3A4ZcgXWqFu1F5xGTfxncmrnf3sLC86dup2a8Kx7z3xQ3AgeNTQeFxPa'], [1130956047, 'tpubD8NXmKsmWp3a3DXhbihAYbYLGaRNVdTnr6JoSxxfXYQcmwVtW2hv8QoDwng6JtEonmJoL3cNEwfd2cLXMpGezwZ2vL2dQ7259bueNKj9C8n']], {'ch': 'XTN', 'pp': "45'"}]]
    sim_defaults['fee_limit'] = -1

if '--xfp' in sys.argv:
    # --xfp aabbccdd   => pretend we know that key (won't be able to sign)
    from ustruct import unpack
    from utils import xfp2str
    from ubinascii import unhexlify as a2b_hex

    xfp = sys.argv[sys.argv.index('--xfp') + 1]
    sim_defaults['xfp'] = unpack("<I", a2b_hex(xfp))[0]
    print("Override XFP: " + xfp2str(sim_defaults['xfp']))

if '--mainnet' in sys.argv:
    sim_defaults['chain'] = 'BTC'

if '--seed' in sys.argv:
    # --seed "word1 word2 ... word24" => import that seed phrase at start
    from ustruct import unpack
    from utils import xfp2str
    from seed import set_seed_value
    from main import pa
    from nvstore import settings

    words = sys.argv[sys.argv.index('--seed') + 1].split(' ')
    assert len(words) in {12, 18, 24}, "Expected space-separated words: add some quotes"
Exemple #12
0
def pin_stuff(submethod, buf_io):
    from pincodes import (PIN_ATTEMPT_SIZE, PIN_ATTEMPT_FMT_V1, PA_ZERO_SECRET,
                        PIN_ATTEMPT_SIZE_V1, CHANGE_LS_OFFSET,
                        PA_SUCCESSFUL, PA_IS_BLANK, PA_HAS_DURESS, PA_HAS_BRICKME,
                        CHANGE_WALLET_PIN, CHANGE_DURESS_PIN, CHANGE_BRICKME_PIN,
                        CHANGE_SECRET, CHANGE_DURESS_SECRET, CHANGE_SECONDARY_WALLET_PIN )

    if len(buf_io) != (PIN_ATTEMPT_SIZE if version.has_608 else PIN_ATTEMPT_SIZE_V1):
        return ERANGE

    global SECRETS

    (magic, is_secondary,
            pin, pin_len,
            delay_achieved,
            delay_required,
            num_fails,
            attempts_left,
            state_flags,
            private_state,
            hmac,
            change_flags,
            old_pin, old_pin_len,
            new_pin, new_pin_len,
            secret) = ustruct.unpack_from(PIN_ATTEMPT_FMT_V1, buf_io)

    # NOTE: ignoring mk2 additions for now, we have no need for it.

    # NOTE: using strings here, not bytes; real bootrom uses bytes
    pin = pin[0:pin_len].decode()
    old_pin = old_pin[0:old_pin_len].decode()
    new_pin = new_pin[0:new_pin_len].decode()

    kk = '_pin1' if not is_secondary else '_pin2'

    if submethod == 0:
        # setup
        state_flags = (PA_SUCCESSFUL | PA_IS_BLANK) if not SECRETS.get(kk, False) else 0

        if pin.startswith('77'):
            delay_required = int(pin.split('-')[1]) * 2
            num_fails = 3
        if pin.startswith('88'):
            attempts_left = 2
            num_fails = 11

        if version.has_608:
            attempts_left = 13
            num_fails = 0
            if 0:       # XXX  test
                num_fails = 10
                attempts_left = 3

    elif submethod == 1:
        # delay
        time.sleep(0.05)
        delay_achieved += 1

    elif submethod == 2:
        # Login

        expect = SECRETS.get(kk, '')
        if pin == expect:
            state_flags = PA_SUCCESSFUL

            ts = a2b_hex(SECRETS.get(kk+'_secret', '00'*72))

        elif pin == SECRETS.get(kk + '_duress', None):
            state_flags = PA_SUCCESSFUL

            ts = a2b_hex(SECRETS.get(kk+'_duress_secret', '00'*72))

        else:
            if version.has_608:
                num_fails += 1
                attempts_left -= 1
            else:
                state_flags = 0

            return EPIN_AUTH_FAIL

        time.sleep(0.05)

        if ts == b'\0'*72:
            state_flags |= PA_ZERO_SECRET

        if kk+'_duress' in SECRETS:
            state_flags |= PA_HAS_DURESS
        if kk+'_brickme' in SECRETS:
            state_flags |= PA_HAS_BRICKME

        del ts

    elif submethod == 3:
        # CHANGE pin and/or wallet secrets

        cf = change_flags

        # NOTE: this logic copied from real deal

        # must be here to do something.
        if cf == 0: return EPIN_RANGE_ERR;

        if cf & CHANGE_BRICKME_PIN:
            if is_secondary:
                # only main PIN holder can define brickme PIN
                return EPIN_PRIMARY_ONLY
            if cf != CHANGE_BRICKME_PIN:
                # only pin can be changed, nothing else.
                return EPIN_BAD_REQUEST

        if (cf & CHANGE_DURESS_SECRET) and (cf & CHANGE_SECRET):
            # can't change two secrets at once.
            return EPIN_BAD_REQUEST

        if (cf & CHANGE_SECONDARY_WALLET_PIN):
            if is_secondary:
                # only main user uses this call 
                return EPIN_BAD_REQUEST;

            if (cf != CHANGE_SECONDARY_WALLET_PIN):
                # only changing PIN, no secret-setting
                return EPIN_BAD_REQUEST;

            kk = '_pin2'

        
        # what PIN will we change
        pk = None
        if change_flags & (CHANGE_WALLET_PIN | CHANGE_SECONDARY_WALLET_PIN):
            pk = kk
        if change_flags & CHANGE_DURESS_PIN:
            pk = kk+'_duress'
        if change_flags & CHANGE_BRICKME_PIN:
            pk = kk+'_brickme'

        if pin == SECRETS.get(kk + '_duress', None):
            # acting duress mode... let them only change duress pin
            if pk == kk:
                pk = kk+'_duress'
            else:
                return EPIN_OLD_AUTH_FAIL

        if pk != None:
            # Must match old pin correctly, if it is defined.
            if SECRETS.get(pk, '') != old_pin:
                print("secel: wrong OLD pin (expect %s, got %s)" % (SECRETS[pk], old_pin))
                return EPIN_OLD_AUTH_FAIL

            # make change
            SECRETS[pk] = new_pin

            if not new_pin and pk != kk:
                del SECRETS[pk]

        if change_flags & CHANGE_SECRET:
            SECRETS[kk+'_secret'] = str(b2a_hex(secret), 'ascii')
        if change_flags & CHANGE_DURESS_SECRET:
            SECRETS[kk+'_duress_secret'] = str(b2a_hex(secret), 'ascii')

        time.sleep(0.05)

    elif submethod == 4:
        # Fetch secrets
        duress_pin = SECRETS.get(kk+'_duress')

        secret = None

        if pin == duress_pin:
            secret = a2b_hex(SECRETS.get(kk+'_duress_secret', '00'*72))
        else:
            if change_flags & CHANGE_DURESS_SECRET:
                # wants the duress secret
                expect = SECRETS.get(kk, '')
                if pin == expect:
                    secret = a2b_hex(SECRETS.get(kk+'_duress_secret', '00'*72))
            else:
                # main/secondary secret
                expect = SECRETS.get(kk, '')
                if pin == expect:
                    secret = a2b_hex(SECRETS.get(kk+'_secret', '00'*72))

        if secret is None:
            return EPIN_AUTH_FAIL

    elif submethod == 5:
        # greenlight firmware
        from ckcc import genuine_led, led_pipe
        genuine_led = True
        led_pipe.write(b'\x01')

    elif submethod == 6:
        if not version.has_608:
            return ENOENT

        # long secret read/change.
        cf = change_flags
        assert CHANGE_LS_OFFSET == 0xf00
        blk = (cf >> 8) & 0xf
        if blk > 13: return EPIN_RANGE_ERR
        off = blk * 32

        if 'ls' not in SECRETS:
            SECRETS['ls'] = bytearray(416)

        if (cf & CHANGE_SECRET):
            SECRETS['ls'][off:off+32] = secret
        else:
            secret = SECRETS['ls'][off:off+32]

    else:
        # bogus submethod
        return ENOENT


    hmac = b'69'*16

    ustruct.pack_into(PIN_ATTEMPT_FMT_V1, buf_io, 0, magic, is_secondary,
            pin.encode(), pin_len, delay_achieved, delay_required,
            num_fails, attempts_left,
            state_flags, private_state, hmac,
            change_flags, old_pin.encode(), old_pin_len, new_pin.encode(), new_pin_len, secret)

    return 0
Exemple #13
0
def str2xfp(txt):
    # Inverse of xfp2str
    import ustruct
    from ubinascii import unhexlify as a2b_hex
    return ustruct.unpack('<I', a2b_hex(txt))[0]
Exemple #14
0
def go():

    # see bootloader/data/ae_layout.h

    c1 = bytes([
        0xe1, 0x00, 0x55, 0x00, 0x00, 0x00, 0x8f, 0x2d, 0x8f, 0x80,   \
        0x8f, 0x43, 0xc3, 0x43, 0x00, 0x43, 0x8f, 0x46, 0xc6, 0x46,   \
        0x00, 0x46, 0x8f, 0x49, 0xc9, 0x49, 0x8f, 0x4b, 0xcb, 0x4b,   \
        0x8f, 0x4d, 0xc1, 0x41, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,   \
        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,   \
        0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,   \
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff   \
    ])

    c2 = bytes([
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x5c, 0x00,   \
        0xbc, 0x01, 0xfc, 0x01, 0xdc, 0x03, 0x9c, 0x01, 0xfc, 0x01,   \
        0xdc, 0x06, 0x9c, 0x01, 0xfc, 0x01, 0xdc, 0x09, 0xfc, 0x01,   \
        0xdc, 0x0b, 0xfc, 0x01, 0xdc, 0x01, 0x3c, 0x00   \
    ])


    if not ae.is_config_locked():
        ae.data[16:84] = c1
        ae.data[90:128] = c2
        assert len(ae.data) == 128
        b4 = bytes(ae.data)
        ae.write()
        ae.read()
        assert b4 == ae.data
        print("locking configzone")
        ae.LOCK(is_config=1)
        ae.reset_watchdog()
        ae.read()

    # assume all slots are blank
    ae.assume_data_blank()

    if not ae.is_slot_locked(KN_pairing):
        assert len(pairing_key) == 32
        ae.write_data_slot(KN_pairing, pairing_key)
    
        # cannot lock this slot, or else we can't burn it via DeriveKey
        #ae.LOCK(data=pairing_key+FF4, slot_num=KN_pairing, datazone=True)
    else:
        ae.d_slot[KN_pairing] = pairing_key+FF4

    # check pairing key works
    ae.reset_watchdog()
    ae.do_checkmac(KN_pairing, pairing_key)
    print("checkmac pairing works")

    if not ae.is_slot_locked(KN_words):
        assert len(words_key) == 32
        ae.write_data_slot(KN_words, words_key)
        ae.do_checkmac(KN_words, words_key)      # check write

        # always lock it
        ae.LOCK(data=words_key+b'\xff\xff\xff\xff', slot_num=KN_words, datazone=True)
    else:
        ae.d_slot[KN_words] = words_key+FF4

    # need both keys to be able to do this!
    ae.reset_watchdog()
    ae.do_checkmac(KN_pairing, pairing_key)
    ae.do_checkmac(KN_words, words_key)         # will fail if we didn't just auth w/ pairing key
    print("checkmac words works")

    ae.reset_watchdog()
    ae.do_checkmac(KN_pairing, pairing_key)
    hm = ae.hmac(KN_words, b'0'*32, diverse=False)      # production: will be diverse mode
    assert hm == a2b_hex('aadec702b4855df0c1838a48978d56a65e5871f291e835d0f833aa2fdfd30290'), b2a_hex(hm)
    print("HMAC(words, '0'*32) works")

    # Set PIN's to something known.
    # simple non-encrypted write can work while data unlocked
    if not ae.is_data_locked():
        for idx in range(4):
            ae.reset_watchdog()
            ae.write_data_slot(KN_pins[idx], BLANK)
            ae.write_data_slot(KN_secrets[idx], BLANK)
            if idx < len(KN_lastgood):
                ae.write_data_slot(KN_lastgood[idx], BLANK)

        ae.reset_watchdog()
        ae.write_data_slot(KN_brickme, BLANK)
        ae.write_data_slot(KN_firmware, BLANK)

        print("Locking data zone")
        ae.LOCK(datazone=True, ecc_slots=[], no_crc=1)
        ae.reset_watchdog()
        ae.read()

    print("Success")
Exemple #15
0
def test_vectors():

    pub = 'xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8'
    prv = 'xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi'
    m = HDNode()
    assert m.deserialize(prv) == V_XPRV
    assert m.serialize(V_XPUB, 0) == pub
    assert m.pubkey() == HDNode().from_master(
        a2b_hex('000102030405060708090a0b0c0d0e0f')).pubkey()

    # m/0'
    d = m.copy()
    d.derive(0, True)
    assert d.depth() == 1
    assert d.serialize(
        V_XPUB, 0
    ) == 'xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw'
    assert d.serialize(
        V_XPRV, 1
    ) == 'xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7'

    # m/0'/1
    d = m.copy()
    d.derive(0, True)
    d.derive(1, False)
    assert d.depth() == 2
    assert d.serialize(
        V_XPUB, 0
    ) == 'xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ'
    assert d.serialize(
        V_XPRV, 1
    ) == 'xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs'

    # m/0'/1/2'
    d.derive(2, True)
    assert d.depth() == 3
    assert d.serialize(
        V_XPUB, 0
    ) == 'xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5'
    assert d.serialize(
        V_XPRV, 1
    ) == 'xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM'

    # m/0'/1/2'/2
    d.derive(2, False)
    assert d.depth() == 4
    assert d.serialize(
        V_XPUB, 0
    ) == 'xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV'
    assert d.serialize(
        V_XPRV, 1
    ) == 'xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334'

    # m/0'/1/2'/2/1000000000
    d.derive(1000000000, False)
    assert d.depth() == 5
    assert d.serialize(
        V_XPUB, 0
    ) == 'xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy'
    assert d.serialize(
        V_XPRV, 1
    ) == 'xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76'

    # Test Vector 2
    m = HDNode()
    m.from_master(
        a2b_hex(
            'fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542'
        ))
    assert m.serialize(
        V_XPUB, 0
    ) == 'xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB'
    assert m.serialize(
        V_XPRV, 1
    ) == 'xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U'

    for sk, hard, xpub, xprv in [
        (0, False,
         'xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH',
         'xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt'
         ),
        (2147483647, True,
         'xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a',
         'xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9'
         ),
        (1, False,
         'xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon',
         'xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef'
         ),
        (2147483646, True,
         'xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL',
         'xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc'
         ),
        (2, False,
         'xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt',
         'xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j'
         ),
    ]:
        m.derive(sk, hard)
        assert m.serialize(V_XPUB, 0) == xpub
        assert m.serialize(V_XPRV, 1) == xprv
    assert m.depth() == 5

    # Test Vector 3
    m = HDNode()
    m.from_master(
        a2b_hex(
            '4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be'
        ))
    assert m.serialize(
        V_XPUB, 0
    ) == 'xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13'
    assert m.serialize(
        V_XPRV, 1
    ) == 'xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6'

    m.derive(0, 1)
    assert m.serialize(
        V_XPUB, 0
    ) == 'xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y'
    assert m.serialize(
        V_XPRV, 1
    ) == 'xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L'
Exemple #16
0
def str2xfp(txt):
    # Inverse of xfp2str
    return ustruct.unpack('<I', a2b_hex(txt))[0]
Exemple #17
0
 def a2b(self, x):
     return a2b_hex(x)
Exemple #18
0
 def BB(n):
     return a2b_hex(n.replace(' ',''))
Exemple #19
0
async def restore_from_dict(vals):
    # Restore from a dict of values. Already JSON decoded.
    # Reboot on success, return string on failure
    from main import pa, dis, settings
    from pincodes import AE_SECRET_LEN

    #print("Restoring from: %r" % vals)

    # step1: the private key
    # - prefer raw_secret over other values
    # - TODO: fail back to other values
    try:
        chain = chains.get_chain(vals.get('chain', 'BTC'))

        assert 'raw_secret' in vals
        raw = bytearray(AE_SECRET_LEN)
        rs = vals.pop('raw_secret')
        if len(rs) % 2:
            rs += '0'
        x = a2b_hex(rs)
        raw[0:len(x)] = x

        # check we can decode this right (might be different firmare)
        opmode, bits, node = stash.SecretStash.decode(raw)
        assert node

        # verify against xprv value (if we have it)
        if 'xprv' in vals:
            check_xprv = chain.serialize_private(node)
            assert check_xprv == vals['xprv'], 'xprv mismatch'

    except Exception as e:
        return ('Unable to decode raw_secret and '
                'restore the seed value!\n\n\n' + str(e))

    ls = None
    if ('long_secret' in vals) and version.has_608:
        try:
            ls = a2b_hex(vals.pop('long_secret'))
        except Exception as exc:
            sys.print_exception(exc)
            # but keep going.

    dis.fullscreen("Saving...")
    dis.progress_bar_show(.25)

    # clear (in-memory) settings and change also nvram key
    # - also captures xfp, xpub at this point
    pa.change(new_secret=raw)

    # force the right chain
    pa.new_main_secret(raw, chain)  # updates xfp/xpub

    # NOTE: don't fail after this point... they can muddle thru w/ just right seed

    if ls is not None:
        try:
            pa.ls_change(ls)
        except Exception as exc:
            sys.print_exception(exc)
            # but keep going

    # restore settings from backup file

    for idx, k in enumerate(vals):
        dis.progress_bar_show(idx / len(vals))
        if not k.startswith('setting.'):
            continue

        if k == 'xfp' or k == 'xpub': continue

        settings.set(k[8:], vals[k])

    # write out
    settings.save()

    if version.has_fatram and ('hsm_policy' in vals):
        import hsm
        hsm.restore_backup(vals['hsm_policy'])

    await ux_show_story(
        'Everything has been successfully restored. '
        'We must now reboot to install the '
        'updated settings and/or seed.',
        title='Success!')

    from machine import reset
    reset()
Exemple #20
0
import main
fname = getattr(main, 'FILENAME', '../../testing/data/2-of-2.psbt')
print("Input PSBT: " + fname)

is_hex = False
tl = 0
with open(fname, 'rb') as orig:
    while 1:
        here = orig.read(256)
        if not here: break

        if here[0:10] == b'70736274ff':
            is_hex = True

        if is_hex:
            here = a2b_hex(here)

        wr_fd.write(here)
        tl += len(here)

from psbt import psbtObject, FatalPSBTIssue

rd_fd = SFFile(0, tl)
obj = psbtObject.read_psbt(rd_fd)

# all these trival test cases now fail validation for various reasons...
try:
    obj.validate()
    print("should fail")
except AssertionError:
    pass
Exemple #21
0
if '-s' in sys.argv:
    # MicroSD menu
    from main import numpad
    numpad.inject('4')
    numpad.inject('y')
    numpad.inject('4')
    numpad.inject('y')

if '-a' in sys.argv:
    # Address Explorer
    from main import numpad
    numpad.inject('4')
    numpad.inject('y')
    numpad.inject('4')
    numpad.inject('8')
    numpad.inject('y')
    numpad.inject('y')

if '--xfp' in sys.argv:
    # --xfp aabbccdd   => pretend we know that key (won't be able to sign)
    from ustruct import unpack
    from utils import xfp2str
    from ubinascii import unhexlify as a2b_hex

    xfp = sys.argv[sys.argv.index('--xfp') + 1]
    sim_defaults['xfp'] = unpack(">I", a2b_hex(xfp))[0]
    print("Override XFP: " + xfp2str(sim_defaults['xfp']))

# EOF
Exemple #22
0
async def clone_start(*a):
    # Begins cloning process, on target device.
    from files import CardSlot, CardMissingError

    ch = await ux_show_story(
        '''Insert a MicroSD card and press OK to start. A small \
file with an ephemeral public key will be written.''')
    if ch != 'y': return

    # pick a random key pair, just for this cloning session
    pair = ngu.secp256k1.keypair()
    my_pubkey = pair.pubkey().to_bytes(False)

    # write to SD Card, fixed filename for ease of use
    try:
        with CardSlot() as card:
            fname, nice = card.pick_filename('ccbk-start.json', overwrite=True)

            with open(fname, 'wb') as fd:
                fd.write(ujson.dumps(dict(pubkey=b2a_hex(my_pubkey))))

    except CardMissingError:
        await needs_microsd()
        return
    except Exception as e:
        await ux_show_story('Error: ' + str(e))
        return

    # Wait for incoming clone file, allow retries
    ch = await ux_show_story(
        '''Keep power on this Coldcard, and take MicroSD card \
to source Coldcard. Select Advanced > MicroSD > Clone Coldcard to write to card. Bring that card \
back and press OK to complete clone process.''')

    while 1:
        if ch != 'y':
            # try to clean up, but card probably not there? No errors.
            try:
                with CardSlot() as card:
                    uos.remove(fname)
            except:
                pass

            await ux_dramatic_pause('Aborted.', 2)
            return

        # Hopefully we have a suitable 7z file now. Pubkey in the filename
        incoming = None
        try:
            with CardSlot() as card:
                for path in card.get_paths():
                    for fn, ftype, *var in uos.ilistdir(path):
                        if fn.endswith('-ccbk.7z'):
                            incoming = path + '/' + fn
                            his_pubkey = a2b_hex(fn[0:66])

                            assert len(his_pubkey) == 33
                            assert 2 <= his_pubkey[0] <= 3
                            break

        except CardMissingError:
            await needs_microsd()
            continue
        except Exception as e:
            pass

        if incoming:
            break

        ch = await ux_show_story(
            "Clone file not found. OK to try again, X to stop.")

    # calculate point
    session_key = pair.ecdh_multiply(his_pubkey)

    # "password" is that hex value
    words = [b2a_hex(session_key).decode()]

    def delme(xfn):
        # Callback to delete file after its read; could still fail but
        # need to start over in that case anyway.
        uos.remove(xfn)
        uos.remove(fname)  # ccbk-start.json

    # this will reset in successful case, no return (but delme is called)
    prob = await restore_complete_doit(incoming, words, file_cleanup=delme)

    if prob:
        await ux_show_story(prob, title='FAILED')