예제 #1
0
    def encryption_key(self, salt):
        # Return a 32-byte derived secret to be used for our own internal encryption purposes
        # 0x80000000 - 0xCC30 = 2147431376
        node = self.derive_path("m/2147431408'/0'")     # plan: 0' will be an index for other apps

        acc = tcc.sha256(salt)
        acc.update(node.private_key())
        acc.update(salt)

        pk = tcc.sha256(acc.digest()).digest()

        self.register(pk)
        return pk
예제 #2
0
파일: chains.py 프로젝트: mluczak/firmware
    def hash_message(cls, msg):
        # Perform sha256 for message-signing purposes (only)
        s = tcc.sha256()

        prefix = cls.msg_signing_prefix()
        assert len(prefix) < 253
        s.update(bytes([len(prefix)]))
        s.update(prefix)

        assert len(msg) < 253
        s.update(bytes([len(msg)]))
        s.update(msg)

        return tcc.sha256(s.digest()).digest()
예제 #3
0
파일: usb.py 프로젝트: jimmysong/firmware
    def handle_crypto_setup(self, version, his_pubkey):
        # pick a one-time key pair for myself, and return the pubkey for that
        # determine what the session key will be for this connection
        assert version == 0x1
        assert len(his_pubkey) == 64

        # pick a random key pair, just for this session
        my_key = tcc.secp256k1.generate_secret()
        my_pubkey = tcc.secp256k1.publickey(my_key, False)

        #print('my pubkey = ' + str(b2a_hex(my_pubkey)))
        #print('his pubkey = ' + str(b2a_hex(his_pubkey)))

        pt = tcc.secp256k1.multiply(my_key, b'\x04' + his_pubkey)
        assert pt[0] == 4
        self.session_key = tcc.sha256(pt[1:]).digest()

        #print("session = " + str(b2a_hex(self.session_key)))

        # Would be nice to have nonce in addition to the counter, but
        # library not ready for that, and also harder on the desktop side.
        self.encrypt = tcc.AES(tcc.AES.CTR | tcc.AES.Encrypt, self.session_key)
        self.decrypt = tcc.AES(tcc.AES.CTR | tcc.AES.Decrypt, self.session_key)

        from main import settings
        xfp = settings.get('xfp', 0)
        xpub = settings.get('xpub', '')

        assert my_pubkey[0] == 0x04
        return b'mypb' + my_pubkey[1:] + pack('<II', xfp, len(xpub)) + xpub
예제 #4
0
파일: usb.py 프로젝트: jimmysong/firmware
    async def handle_upload(self, offset, total_size, data):
        from main import dis, sf, hsm_active
        from utils import check_firmware_hdr
        from sigheader import FW_HEADER_OFFSET, FW_HEADER_SIZE

        # maintain a running SHA256 over what's received
        if offset == 0:
            self.file_checksum = tcc.sha256()

        assert offset % 256 == 0, 'alignment'
        assert offset + len(data) <= total_size <= MAX_UPLOAD_LEN, 'long'

        if hsm_active:
            # additional restrictions in HSM mode
            assert offset + len(data) <= total_size <= MAX_TXN_LEN, 'psbt'
            if offset == 0:
                assert data[0:5] == b'psbt\xff', 'psbt'

        for pos in range(offset, offset + len(data), 256):
            if pos % 4096 == 0:
                # erase here
                dis.fullscreen("Receiving...", offset / total_size)

                sf.sector_erase(pos)

                while sf.is_busy():
                    await sleep_ms(10)

            # write up to 256 bytes
            here = data[pos - offset:pos - offset + 256]

            self.file_checksum.update(here)

            # Very special case for firmware upgrades: intercept and modify
            # header contents on the fly, and also fail faster if wouldn't work
            # on this specific hardware.
            # - workaround: ckcc-protocol upgrade process understates the file
            #   length and appends hdr, but that's kinda a bug, so support both
            if (pos == (FW_HEADER_OFFSET & ~255)
                    or pos == (total_size - FW_HEADER_SIZE)
                    or pos == total_size):

                prob = check_firmware_hdr(memoryview(here)[-128:],
                                          None,
                                          bad_magic_ok=True)
                if prob:
                    raise ValueError(prob)

            sf.write(pos, here)

            # full page write: 0.6 to 3ms
            while sf.is_busy():
                await sleep_ms(1)

        if offset + len(data) >= total_size and not hsm_active:
            # probably done
            dis.progress_bar_show(1.0)
            ux.restore_menu()

        return offset
예제 #5
0
    def save_visualization(self, msg, sign_text=False):
        # write text into spi flash, maybe signing it as we go
        # - return length and checksum
        txt_len = msg.seek(0, 2)
        msg.seek(0)

        chk = self.chain.hash_message(msg_len=txt_len) if sign_text else None

        with SFFile(TXN_OUTPUT_OFFSET, max_size=txt_len+300, message="Visualizing...") as fd:
            await fd.erase()

            while 1:
                blk = msg.read(256).encode('ascii')
                if not blk: break
                if chk:
                    chk.update(blk)
                fd.write(blk)

            if chk:
                from ubinascii import b2a_base64
                # append the signature
                digest = tcc.sha256(chk.digest()).digest()
                sig = sign_message_digest(digest, 'm', None)
                fd.write(b2a_base64(sig).decode('ascii').strip())
                fd.write('\n')

            return (fd.tell(), fd.checksum.digest())
예제 #6
0
파일: actions.py 프로젝트: yahiheb/firmware
async def list_files(*A):
    # list files, don't do anything with them?
    fn = await file_picker(
        'Lists all files on MicroSD. Select one and SHA256(file contents) will be shown.',
        min_size=0)
    if not fn: return

    import tcc
    from utils import B2A
    chk = tcc.sha256()

    try:
        with CardSlot() as card:
            with open(fn, 'rb') as fp:
                while 1:
                    data = fp.read(1024)
                    if not data: break
                    chk.update(data)
    except CardMissingError:
        await needs_microsd()
        return

    basename = fn.rsplit('/', 1)[-1]

    ch = await ux_show_story('''SHA256(%s)\n\n%s\n\nPress 6 to delete.''' %
                             (basename, B2A(chk.digest())),
                             escape='6')

    if ch == '6':
        from files import securely_blank_file
        securely_blank_file(fn)

    return
예제 #7
0
    async def approve_msg_sign(self, msg_text, address, subpath):
        # Maybe approve indicated message to be signed.
        # return 'y' or 'x'
        sha = tcc.sha256(msg_text).digest()
        with AuditLogger('messages', sha, self.never_log) as log:

            if self.must_log and log.is_unsaved:
                self.refuse(log, "Could not log details, and must_log is set")
                return 'x'

            log.info('Message signing requested:')
            log.info('SHA256(msg) = ' + b2a_hex(sha).decode('ascii'))
            log.info('\n%d bytes to be signed by %s => %s' %
                     (len(msg_text), subpath, address))

            if not self.msg_paths:
                self.refuse(log, "Message signing not permitted")
                return 'x'

            if not match_deriv_path(self.msg_paths, subpath):
                self.refuse(log, 'Message signing not enabled for that path')
                return 'x'

            self.approve(log, 'Message signing allowed')

        return 'y'
예제 #8
0
    def p2sh_address(cls, addr_fmt, witdeem_script):
        # Multisig and general P2SH support
        # - witdeem => witness script for segwit, or redeem script otherwise
        # - redeem script can be generated from witness script if needed.
        # - this function needs a witdeem script to be provided, not simple to make
        # - more verification needed to prove it's change/included address (NOT HERE)
        # - reference: <https://bitcoincore.org/en/segwit_wallet_dev/>
        # - returns: str(address)

        assert addr_fmt & AFC_SCRIPT, 'for p2sh only'
        assert witdeem_script, "need witness/redeem script"

        if addr_fmt & AFC_SEGWIT:
            digest = tcc.sha256(witdeem_script).digest()
        else:
            digest = hash160(witdeem_script)

        if addr_fmt & AFC_BECH32:
            # bech32 encoded segwit p2sh
            addr = tcc.codecs.bech32_encode(cls.bech32_hrp, 0, digest)
        elif addr_fmt == AF_P2WSH_P2SH:
            # segwit p2wsh encoded as classic P2SH
            addr = tcc.codecs.b58_encode(cls.b58_script +
                                         hash160(b'\x00\x20' + digest))
        else:
            # P2SH classic
            addr = tcc.codecs.b58_encode(cls.b58_script + digest)

        return addr
예제 #9
0
파일: usb.py 프로젝트: jimmysong/firmware
    async def handle_download(self, offset, length, file_number):
        # let them read from where we store the signed txn
        # - filenumber can be 0 or 1: uploaded txn, or result
        from main import sf

        # limiting memory use here, should be MAX_BLK_LEN really
        length = min(length, MAX_BLK_LEN)

        assert 0 <= file_number < 2, 'bad fnum'
        assert 0 <= offset <= MAX_TXN_LEN, "bad offset"
        assert 1 <= length, 'len'

        # maintain a running SHA256 over what's sent
        if offset == 0:
            self.file_checksum = tcc.sha256()

        pos = (MAX_TXN_LEN * file_number) + offset

        resp = bytearray(4 + length)
        resp[0:4] = b'biny'
        sf.read(pos, memoryview(resp)[4:])

        self.file_checksum.update(memoryview(resp)[4:])

        return resp
예제 #10
0
 def encode_key(cls, prevout):
     # hash up the txid and output number, truncate, and encode as base64
     # - truncating at (mod3) bytes so no padding on b64 output
     # - expects a COutPoint
     md = tcc.sha256('OutptValueCache')
     md.update(prevout.serialize())
     return b2a_base64(md.digest()[:15])[:-1].decode()
예제 #11
0
async def test_sflash():
    dis.clear()
    dis.text(None, 18, 'Serial Flash')
    dis.show()

    #if ckcc.is_simulator(): return

    from main import sf
    from ustruct import pack
    import tcc

    msize = 1024 * 1024
    sf.chip_erase()

    for phase in [0, 1]:
        steps = 7 * 4
        for i in range(steps):
            dis.progress_bar(i / steps)
            dis.show()
            await sleep_ms(250)
            if not sf.is_busy(): break

        assert not sf.is_busy(), "sflash erase didn't finish"

        # leave chip blank
        if phase == 1: break

        buf = bytearray(32)
        for addr in range(0, msize, 1024):
            sf.read(addr, buf)
            assert set(buf) == {255}, "sflash not blank:" + repr(buf)

            rnd = tcc.sha256(pack('I', addr)).digest()
            sf.write(addr, rnd)
            sf.read(addr, buf)
            assert buf == rnd, "sflash write failed"

            dis.progress_bar_show(addr / msize)

        # check no aliasing, also right size part
        for addr in range(0, msize, 1024):
            expect = tcc.sha256(pack('I', addr)).digest()
            sf.read(addr, buf)
            assert buf == expect, "sflash readback failed"

            dis.progress_bar_show(addr / msize)
예제 #12
0
    def hash_message(cls, msg=None, msg_len=0):
        # Perform sha256 for message-signing purposes (only)
        # - or get setup for that, if msg == None
        s = tcc.sha256()

        s.update(cls.msg_signing_prefix())

        msg_len = msg_len or len(msg)

        s.update(ser_compact_size(msg_len))

        if msg is None:
            return s

        s.update(msg)

        return tcc.sha256(s.digest()).digest()
예제 #13
0
파일: seed.py 프로젝트: yahiheb/firmware
async def add_dice_rolls(count, seed, judge_them):
    from main import dis
    from display import FontTiny, FontLarge

    md = tcc.sha256(seed)
    pr = PressRelease()

    # fixed parts of screen
    dis.clear()
    y = 38
    dis.text(0, y, "Press 1-6 for each dice")
    y += 13
    dis.text(0, y, "roll to mix in.")
    dis.save()

    while 1:
        # Note: cannot scroll this msg because 5=up arrow
        dis.restore()
        dis.text(None, 0, '%d rolls' % count, FontLarge)

        hx = str(b2a_hex(md.digest()), 'ascii')
        dis.text(0, 20, hx[0:32], FontTiny)
        dis.text(0, 20 + 7, hx[32:], FontTiny)

        dis.show()

        ch = await pr.wait()

        if ch in '123456':
            count += 1

            dis.restore()
            dis.text(None, 0, '%d rolls' % count, FontLarge)
            dis.show()

            # this is slow enough to see
            md.update(ch)

        elif ch == 'x':
            # Because the change (roll) has already been applied,
            # only let them abort if it's early still
            if count < 10 and judge_them:
                return 0, seed
        elif ch == 'y':
            if count < 99 and judge_them:
                if not count:
                    return 0, seed
                ok = await ux_confirm('''\
You only provided %d dice rolls, and each roll adds only 2.585 bits of entropy. \
For 128-bit security, which is considered the minimum, you need 50 rolls, and \
for 256-bits of security, 99 rolls.''' % count)
                if not ok: continue
            break

    if count:
        seed = md.digest()

    return count, seed
예제 #14
0
    def get_hash256(self, val, hasher=None):
        # return the double-sha256 of a value, without loading it into memory
        pos, ll = val
        rv = hasher or tcc.sha256()

        self.fd.seek(pos)
        while ll:
            here = self.fd.read_into(psbt_tmp256)
            if not here: break
            if here > ll:
                here = ll
            rv.update(memoryview(psbt_tmp256)[0:here])
            ll -= here

        if hasher:
            return

        return tcc.sha256(rv.digest()).digest()
예제 #15
0
def calc_hmac_key(text_password):
    # Calculate a 32-byte key based on user's text password, PBKDF2_ITER_COUNT,
    # and device serial number as salt.
    import version

    salt = tcc.sha256(b'pepper' + version.serial_number().encode()).digest()
    pw = tcc.pbkdf2('hmac-sha256', text_password, salt,
                    PBKDF2_ITER_COUNT).key()

    return pw
예제 #16
0
    def make_txn_sighash(self, replace_idx, replacement, sighash_type):
        # calculate the hash value for one input of current transaction
        # - blank all script inputs
        # - except one single tx in, which is provided
        # - serialize that without witness data
        # - append SIGHASH_ALL=1 value (LE32)
        # - sha256 over that
        fd = self.fd
        old_pos = fd.tell()
        rv = tcc.sha256()

        # version number
        rv.update(pack('<i', self.txn_version))  # nVersion

        # inputs
        rv.update(ser_compact_size(self.num_inputs))
        for in_idx, txi in self.input_iter():

            if in_idx == replace_idx:
                assert not self.inputs[in_idx].witness_utxo
                assert not self.inputs[in_idx].is_segwit
                assert replacement.scriptSig
                rv.update(replacement.serialize())
            else:
                txi.scriptSig = b''
                rv.update(txi.serialize())

        # outputs
        rv.update(ser_compact_size(self.num_outputs))
        for out_idx, txo in self.output_iter():
            rv.update(txo.serialize())

        # locktime
        rv.update(pack('<I', self.lock_time))

        assert sighash_type == SIGHASH_ALL, "only SIGHASH_ALL supported"
        # SIGHASH_ALL==1 value
        rv.update(b'\x01\x00\x00\x00')

        fd.seek(old_pos)

        # double SHA256
        return tcc.sha256(rv.digest()).digest()
예제 #17
0
파일: backups.py 프로젝트: syscoin/firmware
async def test_7z():
    # test full 7z round-trip
    # Altho cleartext mode is not for real, if the code is written, I must test it.
    from backups import write_complete_backup, restore_complete_doit
    from sffile import SFFile
    import tcc
    from main import settings, sf, numpad

    today = tcc.random.uniform(1000000)

    import machine
    machine.reset = lambda: None

    for chain in ['BTC', 'XTN']:
        for words in ([], ['abc', 'def']):
            settings.set('check', today)
            settings.set('chain', chain)

            ll, sha = await write_complete_backup(words, None, True)

            result = SFFile(0, ll).read()

            if words:
                #open('debug.7z', 'wb').write(result)
                assert ll > 800
                assert len(sha) == 32
                assert result[0:6] == b"7z\xbc\xaf'\x1c"
                assert tcc.sha256(result).digest() == sha
                assert len(set(result)) >= 240  # encrypted
            else:
                sr = str(result, 'ascii')
                print("Backup contents:\n" + sr)
                assert sr[0] == '#', result
                assert 'Coldcard' in sr
                assert len(set(sr)) < 100  # cleartext, english
                assert ('chain = "%s"' % chain) in result

            # test restore
            # - cant wipe flash, since the backup file is there
            # - cant wipe all settings becuase PIN and stuff is simulated there
            del settings.current['check']

            with SFFile(0, ll) as fd:
                numpad.inject('y')  # for 'success' message
                await restore_complete_doit(fd, words)

                assert settings.get('check') == today, \
                            (settings.get('check'), '!=',  today)
                assert settings.get('chain') == chain, \
                            (settings.get('chain'), '!=',  chain)

            today += 3

            import ux
            ux.restore_menu()
예제 #18
0
    def calc_txid(self, poslen):
        # Given the (pos,len) of a transaction, return the txid for that.
        # - doesn't validate data
        # - does detected witness txn vs. old style
        # - simple dsha256() if old style txn, other wise witness must be skipped

        # see if witness encoding in effect
        fd = self.fd
        fd.seek(poslen[0])

        txn_version, marker, flags = unpack("<iBB", fd.read(6))
        has_witness = (marker == 0 and flags != 0x0)

        if not has_witness:
            # txn does not have witness data, so txid==wtxix
            return self.get_hash256(poslen)

        rv = tcc.sha256()

        # de/reserialize much of the txn -- but not the witness data
        rv.update(pack("<i", txn_version))

        body_start = fd.tell()

        # determine how long ins + outs are...
        num_in = deser_compact_size(fd)
        _skip_n_objs(fd, num_in, 'CTxIn')
        num_out = deser_compact_size(fd)
        _skip_n_objs(fd, num_out, 'CTxOut')

        body_len = fd.tell() - body_start

        # hash the bulk of txn
        self.get_hash256((body_start, body_len), hasher=rv)

        # assume last 4 bytes are the lock_time
        fd.seek(sum(poslen) - 4)

        rv.update(fd.read(4))

        return tcc.sha256(rv.digest()).digest()
예제 #19
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 main 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 = tcc.sha256(new_secret)

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

                s = tcc.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
예제 #20
0
async def make_new_wallet():
    # Pick a new random seed, and 

    await ux_dramatic_pause('Generating...', 4)

    # always full 24-word (256 bit) entropy
    seed = bytearray(32)
    rng_bytes(seed)

    assert len(set(seed)) > 4       # TRNG failure

    # hash to mitigate bias in TRNG
    seed = tcc.sha256(seed).digest()

    await approve_word_list(seed)
예제 #21
0
    def __init__(self, start, length=0, max_size=None, message=None, pre_erased=False):
        if not pre_erased:
            assert start % blksize == 0 # 'misaligned'
        self.start = start
        self.pos = 0
        self.length = length        # byte-wise length
        self.message = message

        if max_size != None:
            self.max_size = PADOUT(max_size) if not pre_erased else max_size
            self.readonly = False
            self.checksum = tcc.sha256()
        else:
            self.readonly = True

        from main import sf
        self.sf = sf
예제 #22
0
    def save(self):
        # render as JSON, encrypt and write it.

        self.current['_age'] = self.current.get('_age', 1) + 1

        sf, pos = self.find_spot(self.my_pos)

        aes = self.get_aes(tcc.AES.Encrypt, pos)

        with SFFile(pos, max_size=4096, pre_erased=True) as fd:
            chk = tcc.sha256()

            # first the json data
            d = ujson.dumps(self.current)

            # pad w/ zeros
            dat_len = len(d)
            pad_len = (4096 - 32) - dat_len
            assert pad_len >= 0, 'too big'

            self.capacity = dat_len / 4096

            fd.write(aes.update(d))
            chk.update(d)
            del d

            while pad_len > 0:
                here = min(32, pad_len)

                pad = bytes(here)
                fd.write(aes.update(pad))
                chk.update(pad)

                pad_len -= here

            fd.write(aes.update(chk.digest()))
            assert fd.tell() == 4096

        # erase old copy of data
        if self.my_pos and self.my_pos != pos:
            sf.wait_done()
            sf.sector_erase(self.my_pos)
            sf.wait_done()

        self.my_pos = pos
        self.is_dirty = 0
예제 #23
0
    def calculate_key(self, password, progress_fcn=None):
        # do the expected key-derivation
        # emulate CKeyInfo::CalculateDigest in p7zip_9.38.1/CPP/7zip/Crypto/7zAes.cpp
        rounds = 1 << self.rounds_pow

        password = encode_utf_16_le(password)

        result = sha256()

        for i in range(rounds):
            result.update(self.salt)
            result.update(password)
            temp = pack('<Q', i)
            result.update(temp)
            if i % 1000 == 0 and progress_fcn:
                progress_fcn(i/rounds)
            
        return result.digest()
예제 #24
0
파일: usb.py 프로젝트: jimmysong/firmware
    def __init__(self):
        self.dev = pyb.USB_HID()

        # We keep a running hash over whatever has been uploaded
        # - reset at offset zero, can be read back anytime
        self.file_checksum = tcc.sha256()

        # handle simulator
        self.blockable = getattr(self.dev, 'pipe', self.dev)

        #self.msg = bytearray(MAX_MSG_LEN)
        from sram2 import usb_buf
        self.msg = usb_buf
        assert len(self.msg) == MAX_MSG_LEN

        self.encrypted_req = False

        # these will be tcc.AES objects later
        self.encrypt = None
        self.decrypt = None
예제 #25
0
    async def handle_upload(self, offset, total_size, data):
        from main import dis, sf

        # maintain a running SHA256 over what's received
        if offset == 0:
            self.file_checksum = tcc.sha256()

        assert offset % 256 == 0, 'alignment'
        assert offset + len(data) <= total_size <= MAX_UPLOAD_LEN, 'long'

        rb = bytearray(256)
        for pos in range(offset, offset + len(data), 256):
            if pos % 4096 == 0:
                # erase here
                sf.sector_erase(pos)

                dis.fullscreen("Receiving...")
                dis.progress_bar_show(offset / total_size)

                while sf.is_busy():
                    await sleep_ms(10)

            # write up to 256 bytes
            here = data[pos - offset:pos - offset + 256]
            sf.write(pos, here)

            # full page write: 0.6 to 3ms
            while sf.is_busy():
                await sleep_ms(1)

            # use actual read back for verify
            sf.read(pos, rb)
            self.file_checksum.update(rb[0:len(here)])

        if offset + len(data) >= total_size:
            # probably done
            dis.progress_bar_show(1.0)
            ux.restore_menu()

        return offset
예제 #26
0
 def get_id_hash(self):
     # hash over card config and serial # details
     import tcc
     info = pyb.SDCard().info()
     assert info and len(info) >= 5  # need micropython changes
     return tcc.sha256(repr(info)).digest()
예제 #27
0
    def load(self):
        # Search all slots for any we can read, decrypt that,
        # and pick the newest one (in unlikely case of dups)
        from main import sf

        # reset
        self.current = {}
        self.my_pos = 0
        self.is_dirty = 0

        # 4k, but last 32 bytes are a SHA (itself encrypted)
        global _tmp

        buf = bytearray(4)
        empty = 0
        for pos in SLOTS:
            gc.collect()

            sf.read(pos, buf)
            if buf[0] == buf[1] == buf[2] == buf[3] == 0xff:
                # erased (probably)
                empty += 1
                continue

            # check if first 2 bytes makes sense for JSON
            aes = self.get_aes(tcc.AES.Encrypt, pos)
            chk = aes.update(b'{"')

            if chk != buf[0:2]:
                # doesn't look like JSON meant for me
                continue

            # probably good, read it
            aes = self.get_aes(tcc.AES.Encrypt, pos)

            chk = tcc.sha256()
            expect = None

            with SFFile(pos, length=4096, pre_erased=True) as fd:
                for i in range(4096 / 32):
                    b = aes.update(fd.read(32))
                    if i != 127:
                        _tmp[i * 32:(i * 32) + 32] = b
                        chk.update(b)
                    else:
                        expect = b

            try:
                # verify checksum in last 32 bytes
                assert expect == chk.digest()

                # loads() can't work from a byte array, and converting to
                # bytes here would copy it; better to use file emulation.
                d = ujson.load(BytesIO(_tmp))
            except:
                # One in 65k or so chance to come here w/ garbage decoded, so
                # not an error.
                continue

            got_age = d.get('_age', 0)
            if got_age > self.current.get('_age', -1):
                # likely winner
                self.current = d
                self.my_pos = pos
                #print("NV: data @ %d w/ age=%d" % (pos, got_age))
            else:
                # stale data seen; clean it up.
                assert self.current['_age'] > 0
                print("NV: cleanup @ %d" % pos)
                sf.sector_erase(pos)
                sf.wait_done()

        # 4k is a large object, sigh, for us right now. cleanup
        gc.collect()

        # done, if we found something
        if self.my_pos:
            return

        # nothing found.
        self.my_pos = 0
        self.current = self.default_values()

        if empty == len(SLOTS):
            # Whole thing is blank. Bad for plausible deniability. Write 3 slots
            # with garbage. They will be wasted space until it fills.
            blks = list(SLOTS)
            tcc.random.shuffle(blks)

            for pos in blks[0:3]:
                for i in range(0, 4096, 256):
                    h = tcc.random.bytes(256)
                    sf.wait_done()
                    sf.write(pos + i, h)
예제 #28
0
def sha256(s):
    return tcc.sha256(s).digest()
예제 #29
0
async def make_new_wallet():
    # pick a new random seed, and force them to
    # write it down, then save it.

    from main import dis
    from uasyncio import sleep_ms

    # CONCERN: memory is really contaminated with secrets in this process, much more so
    # than during normal operation. Maybe we should block USB and force a reboot as well?

    # LESSON LEARNED: if the user is writting down the words, as we have
    # vividly instructed, then it's a big deal to lose those words and have to start
    # over. So confirm that action, and don't volunteer it.

    # dramatic pause
    await ux_dramatic_pause('Generating...', 4)

    # always full 24-word (256 bit) entropy
    seed = bytearray(32)
    rng_bytes(seed)

    assert len(set(seed)) > 4, "impossible luck?"

    # hash to mitigate bias in TRNG
    seed = tcc.sha256(seed).digest()

    words = tcc.bip39.from_data(seed).split(' ')
    assert len(words) == 24

    #print('words: ' + ' '.join(words))

    while 1:
        # show the seed words
        ch = await show_words(words, escape='6')

        if ch == 'x':
            # user abort
            if await ux_confirm("Throw away those words and stop this process?"
                                ):
                return
            else:
                continue

        if ch == '6':
            # wants to skip the quiz (undocumented)
            if await ux_confirm(
                    "Skipping the quiz means you might have "
                    "recorded the seed wrong and will be crying later."):
                break

        # Perform a test, to check they wrote them down
        ch = await word_quiz(words)
        if ch == 'x':
            # user abort quiz
            if await ux_confirm(
                    "Throw away those words and stop this process? Press X to see the word list again and restart the quiz."
            ):
                return

            # show the words again, but don't change them
            continue

        # quiz passed
        break

    # Done!
    set_seed_value(words)

    # send them to home menu, now with a wallet enabled
    goto_top_menu()
예제 #30
0
 def __init__(self, d=None):
     self.rv = tcc.sha256()
     print('Hashing: ', end='')
     if d:
         self.update(d)