from micropython import const from ubinascii import hexlify from trezor import config from trezor.crypto import random from apps.common import cache HOMESCREEN_MAXSIZE = 16384 _STORAGE_VERSION = b'\x01' _APP = const(0x01) # app namespace _DEVICE_ID = const(0x00) # bytes _VERSION = const(0x01) # int _MNEMONIC = const(0x02) # str _LANGUAGE = const(0x03) # str _LABEL = const(0x04) # str _USE_PASSPHRASE = const(0x05) # bool (0x01 or empty) _HOMESCREEN = const(0x06) # bytes _NEEDS_BACKUP = const(0x07) # bool (0x01 or empty) _FLAGS = const(0x08) # int _U2F_COUNTER = const(0x09) # int _PASSPHRASE_SOURCE = const(0x0A) # int _UNFINISHED_BACKUP = const(0x0B) # bool (0x01 or empty) _AUTOLOCK_DELAY_MS = const(0x0C) # int def _new_device_id() -> str: return hexlify(random.bytes(12)).decode().upper() def get_device_id() -> str: dev_id = config.get(_APP, _DEVICE_ID, True).decode() # public if not dev_id: dev_id = _new_device_id() config.set(_APP, _DEVICE_ID, dev_id.encode(), True) # public return dev_id def is_initialized() -> bool: return bool(config.get(_APP, _VERSION)) def get_label() -> str: return config.get(_APP, _LABEL, True).decode() # public def get_mnemonic() -> str: return config.get(_APP, _MNEMONIC).decode() def has_passphrase() -> bool: return bool(config.get(_APP, _USE_PASSPHRASE)) def get_homescreen() -> bytes: return config.get(_APP, _HOMESCREEN, True) # public def load_mnemonic(mnemonic: str, needs_backup: bool) -> None: config.set(_APP, _MNEMONIC, mnemonic.encode()) config.set(_APP, _VERSION, _STORAGE_VERSION) if needs_backup: config.set(_APP, _NEEDS_BACKUP, b'\x01') else: config.set(_APP, _NEEDS_BACKUP, b'') def needs_backup() -> bool: return bool(config.get(_APP, _NEEDS_BACKUP)) def set_backed_up() -> None: config.set(_APP, _NEEDS_BACKUP, b'') def unfinished_backup() -> bool: return bool(config.get(_APP, _UNFINISHED_BACKUP)) def set_unfinished_backup(state: bool) -> None: if state: config.set(_APP, _UNFINISHED_BACKUP, b'\x01') else: config.set(_APP, _UNFINISHED_BACKUP, b'') def get_passphrase_source() -> int: b = config.get(_APP, _PASSPHRASE_SOURCE) if b == b'\x01': return 1 elif b == b'\x02': return 2 else: return 0 def load_settings(label: str=None, use_passphrase: bool=None, homescreen: bytes=None, passphrase_source: int=None) -> None: if label is not None: config.set(_APP, _LABEL, label.encode(), True) # public if use_passphrase is True: config.set(_APP, _USE_PASSPHRASE, b'\x01') if use_passphrase is False: config.set(_APP, _USE_PASSPHRASE, b'') if homescreen is not None: if homescreen[:8] == b'TOIf\x90\x00\x90\x00': if len(homescreen) <= HOMESCREEN_MAXSIZE: config.set(_APP, _HOMESCREEN, homescreen, True) # public else: config.set(_APP, _HOMESCREEN, b'', True) # public if passphrase_source is not None: if passphrase_source in [0, 1, 2]: config.set(_APP, _PASSPHRASE_SOURCE, bytes([passphrase_source])) def get_flags() -> int: b = config.get(_APP, _FLAGS) if b is None: return 0 else: return int.from_bytes(b, 'big') def set_flags(flags: int) -> None: b = config.get(_APP, _FLAGS) if b is None: b = 0 else: b = int.from_bytes(b, 'big') flags = (flags | b) & 0xFFFFFFFF if flags != b: config.set(_APP, _FLAGS, flags.to_bytes(4, 'big')) def get_autolock_delay_ms() -> int: b = config.get(_APP, _AUTOLOCK_DELAY_MS) if b is None: return 10 * 60 * 1000 else: return int.from_bytes(b, 'big') def set_autolock_delay_ms(delay_ms: int) -> None: if delay_ms < 60 * 1000: delay_ms = 60 * 1000 config.set(_APP, _AUTOLOCK_DELAY_MS, delay_ms.to_bytes(4, 'big')) def next_u2f_counter() -> int: b = config.get(_APP, _U2F_COUNTER) if b is None: b = 0 else: b = int.from_bytes(b, 'big') + 1 set_u2f_counter(b) return b def set_u2f_counter(cntr: int): config.set(_APP, _U2F_COUNTER, cntr.to_bytes(4, 'big')) def wipe(): config.wipe() cache.clear()