Ejemplo n.º 1
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 = trezorcrypto.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
Ejemplo n.º 2
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 = trezorcrypto.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())
Ejemplo n.º 3
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 = trezorcrypto.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 trezorcrypto.sha256(s.digest()).digest()
Ejemplo n.º 4
0
    def save(self):
        # Render as JSON, encrypt and write it
        self.curr_dict['_version'] = self.curr_dict.get('_version', 0) + 1

        addr = self.next_addr()
        print(
            '===============================================================')
        print('SAVING SETTINGS! _version={} addr={}'.format(
            self.curr_dict['_version'], hex(addr)))
        print(
            '===============================================================')

        flash_offset = (addr - SETTINGS_FLASH_START) // BLOCK_SIZE
        aes = self.get_aes(flash_offset)

        chk = trezorcrypto.sha256()

        # Create the JSON string as bytes
        json_buf = ujson.dumps(self.curr_dict).encode('utf8')

        # Ensure data is not too big
        # TODO: Check that null byte at the end is handled properly (no overflow)
        if len(json_buf) > DATA_SIZE:
            # TODO: Proper error handling
            assert false, 'JSON data is larger than'.format(DATA_SIZE)

        # Create a zero-filled byte buf
        padded_buf = bytearray(DATA_SIZE)

        # Copy the json data into the padded buffer
        for i in range(len(json_buf)):
            padded_buf[i] = json_buf[i]
        del json_buf

        # Add the data and padding to the AES and SHA
        encrypted_buf = aes.encrypt(padded_buf)
        chk.update(padded_buf)

        # Build the final buf for writing to flash
        save_buf = bytearray(BLOCK_SIZE)
        for i in range(len(encrypted_buf)):
            save_buf[i] = encrypted_buf[
                i]  # TODO: How to do this with slice notation so it doesn't truncate destination?

        digest = chk.digest()
        for i in range(32):
            save_buf[BLOCK_SIZE - 32 + i] = digest[i]

        # print('addr={}\nbuf={}'.format(hex(addr),b2a_hex(save_buf)))
        self.flash.write(addr, save_buf)

        # We don't overwrite the old entry here, even though it's now useless, as that can
        # cause flash to have ECC errors.

        self.addr = addr
        self.is_dirty = 0
        print("Settings.save(): wrote @ {}".format(hex(addr)))
Ejemplo n.º 5
0
    def set_key(self, new_secret=None):
        # System settings (not secrets) are stored in internal 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 common 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 = trezorcrypto.sha256(new_secret)

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

                s = trezorcrypto.sha256(s.digest())

            key = s.digest()

            if mine:
                blank_object(new_secret)

        # for restore from backup case, or when changing (created) the seed
        self.aes_key = key
Ejemplo n.º 6
0
def create_new_wallet_seed():
    # Pick a new random seed, and

    # await ux_dramatic_pause('Generating...', 4)
    # TODO: Show screen to indicate delay?

    # always full 24-word (256 bit) entropy
    seed = bytearray(32)
    noise.random_bytes(seed)

    # hash to mitigate any potential bias in Avalanche RNG
    seed = trezorcrypto.sha256(seed).digest()
    print('create_new_wallet(): New seed = {}'.format(b2a_hex(seed)))

    return seed
Ejemplo n.º 7
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()
Ejemplo n.º 8
0
    def __init__(self,
                 start,
                 length=0,
                 max_size=1,
                 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 = trezorcrypto.sha256()
        else:
            self.readonly = True

        from common import sf
        self.sf = sf
Ejemplo n.º 9
0
def sha256(s):
    return trezorcrypto.sha256(s).digest()
Ejemplo n.º 10
0
    def load(self):
        # Search all slots for any we can read, decrypt that,
        # and pick the newest one (in unlikely case of dups)

        try:
            # reset
            self.curr_dict.clear()
            self.overrides.clear()
            self.addr = 0
            self.is_dirty = 0

            for addr in SLOT_ADDRS:
                buf = uctypes.bytearray_at(addr, 4)
                if buf[0] == buf[1] == buf[2] == buf[3] == 0xff:
                    # Save this so we can start at an empty slot when no decodable data
                    # is found (we can't just start at the beginning since it might
                    # not be erased).
                    # print('  Slot is ERASED')
                    # erased (probably)
                    continue

                # check if first 2 bytes makes sense for JSON
                flash_offset = (addr - SETTINGS_FLASH_START) // BLOCK_SIZE
                aes = self.get_aes(flash_offset)
                chk = aes.decrypt(b'{"')

                if chk != buf[0:2]:
                    # doesn't look like JSON, so skip it
                    # print(' Slot does not contain JSON')
                    continue

                # probably good, so prepare to read it
                aes = self.get_aes(flash_offset)
                chk = trezorcrypto.sha256()
                expect = None

                # Copy the data - our flash is memory mapped, so we read directly by address
                buf = uctypes.bytearray_at(addr, DATA_SIZE)

                # Get a bytearray for the SHA256 at the end
                expected_sha = uctypes.bytearray_at(addr + DATA_SIZE, 32)

                # Decrypt and check hash
                b = aes.decrypt(buf)

                # Add the decrypted result to the SHA
                chk.update(b)

                try:
                    # verify hash in last 32 bytes
                    assert expected_sha == chk.digest()

                    # FOUNDATION
                    # loads() can't work from a byte array, and converting to
                    # bytes here would copy it; better to use file emulation.
                    # print('json = {}'.format(b))
                    d = ujson.load(BytesIO(b))
                except:
                    # One in 65k or so chance to come here w/ garbage decoded, so
                    # not an error.
                    # print('ERROR?  Unable to decode JSON')
                    continue

                curr_version = d.get('_version', 0)
                if curr_version > self.curr_dict.get('_version', -1):
                    # print('Found candidate JSON: {}'.format(d))
                    # A newer entry was found
                    self.curr_dict = d
                    self.addr = addr

            # If we loaded settings, then we're done
            if self.addr:
                return

            # Add some che
            # if self.

            # If no entries were found, which means this is either the first boot or we have corrupt settings, so raise an exception so we erase and set default
            # raise ValueError('Flash is either blank or corrupt, so me must reset to recover to avoid a crash!')
            self.curr_dict = self.default_values()
            self.overrides.clear()
            self.addr = 0

        except Exception as e:
            print('Exception in settings.load(): e={}'.format(e))
            self.reset()
            self.is_dirty = True
            self.write_out()