2016-09-29 10:29:43 +00:00
|
|
|
from micropython import const
|
2018-02-27 15:35:21 +00:00
|
|
|
from ubinascii import hexlify
|
2016-09-26 11:06:28 +00:00
|
|
|
from trezor import config
|
2018-02-27 15:35:21 +00:00
|
|
|
from trezor.crypto import random
|
|
|
|
from apps.common import cache
|
2016-11-23 13:46:55 +00:00
|
|
|
|
2018-03-08 22:45:17 +00:00
|
|
|
HOMESCREEN_MAXSIZE = 16384
|
|
|
|
|
2017-10-24 11:58:40 +00:00
|
|
|
_STORAGE_VERSION = b'\x01'
|
2016-11-23 13:46:55 +00:00
|
|
|
|
2017-12-14 20:59:47 +00:00
|
|
|
_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) # 0x01 or empty
|
|
|
|
_HOMESCREEN = const(0x06) # bytes
|
2018-02-05 13:54:46 +00:00
|
|
|
_NEEDS_BACKUP = const(0x07) # 0x01 or empty
|
2018-02-14 22:50:08 +00:00
|
|
|
_FLAGS = const(0x08) # int
|
2018-02-28 17:53:52 +00:00
|
|
|
_U2F_COUNTER = const(0x09) # int
|
2016-09-26 11:06:28 +00:00
|
|
|
|
|
|
|
|
2018-03-12 14:01:13 +00:00
|
|
|
def _new_device_id() -> str:
|
|
|
|
return hexlify(random.bytes(12)).decode().upper()
|
|
|
|
|
|
|
|
|
2016-10-14 13:35:44 +00:00
|
|
|
def get_device_id() -> str:
|
2018-02-07 13:59:09 +00:00
|
|
|
dev_id = config.get(_APP, _DEVICE_ID, True).decode() # public
|
2016-12-15 11:33:39 +00:00
|
|
|
if not dev_id:
|
2018-03-12 14:01:13 +00:00
|
|
|
dev_id = _new_device_id()
|
2018-02-07 13:59:09 +00:00
|
|
|
config.set(_APP, _DEVICE_ID, dev_id.encode(), True) # public
|
2016-11-23 13:46:55 +00:00
|
|
|
return dev_id
|
2016-09-26 11:06:28 +00:00
|
|
|
|
|
|
|
|
2016-10-14 13:35:44 +00:00
|
|
|
def is_initialized() -> bool:
|
2017-10-24 11:58:40 +00:00
|
|
|
return bool(config.get(_APP, _VERSION))
|
2016-11-15 10:50:45 +00:00
|
|
|
|
|
|
|
|
2016-10-14 13:35:44 +00:00
|
|
|
def get_label() -> str:
|
2018-02-05 10:48:12 +00:00
|
|
|
return config.get(_APP, _LABEL, True).decode() # public
|
2016-12-15 11:48:33 +00:00
|
|
|
|
|
|
|
|
2016-10-14 13:35:44 +00:00
|
|
|
def get_mnemonic() -> str:
|
2017-10-24 11:58:40 +00:00
|
|
|
return config.get(_APP, _MNEMONIC).decode()
|
2016-11-23 13:46:55 +00:00
|
|
|
|
|
|
|
|
2017-10-24 11:58:40 +00:00
|
|
|
def has_passphrase() -> bool:
|
|
|
|
return bool(config.get(_APP, _USE_PASSPHRASE))
|
2016-10-14 13:35:44 +00:00
|
|
|
|
|
|
|
|
2017-12-13 01:41:59 +00:00
|
|
|
def get_homescreen() -> bytes:
|
2018-02-05 10:48:12 +00:00
|
|
|
return config.get(_APP, _HOMESCREEN, True) # public
|
2017-12-13 01:41:59 +00:00
|
|
|
|
|
|
|
|
2018-02-14 22:50:08 +00:00
|
|
|
def load_mnemonic(mnemonic: str, needs_backup: bool) -> None:
|
2017-10-24 11:58:40 +00:00
|
|
|
config.set(_APP, _MNEMONIC, mnemonic.encode())
|
2018-02-05 13:54:46 +00:00
|
|
|
config.set(_APP, _VERSION, _STORAGE_VERSION)
|
|
|
|
if needs_backup:
|
|
|
|
config.set(_APP, _NEEDS_BACKUP, b'\x01')
|
|
|
|
else:
|
|
|
|
config.set(_APP, _NEEDS_BACKUP, b'')
|
2016-10-14 13:35:44 +00:00
|
|
|
|
|
|
|
|
2018-02-26 23:19:43 +00:00
|
|
|
def needs_backup() -> bool:
|
|
|
|
return bool(config.get(_APP, _NEEDS_BACKUP))
|
|
|
|
|
|
|
|
|
|
|
|
def set_backed_up() -> None:
|
|
|
|
config.set(_APP, _NEEDS_BACKUP, b'')
|
|
|
|
|
|
|
|
|
2018-02-14 22:50:08 +00:00
|
|
|
def load_settings(label: str=None, use_passphrase: bool=None, homescreen: bytes=None) -> None:
|
2017-10-24 11:58:40 +00:00
|
|
|
if label is not None:
|
2018-02-05 10:48:12 +00:00
|
|
|
config.set(_APP, _LABEL, label.encode(), True) # public
|
2017-10-24 11:58:40 +00:00
|
|
|
if use_passphrase is True:
|
|
|
|
config.set(_APP, _USE_PASSPHRASE, b'\x01')
|
|
|
|
if use_passphrase is False:
|
|
|
|
config.set(_APP, _USE_PASSPHRASE, b'')
|
2017-12-13 01:41:59 +00:00
|
|
|
if homescreen is not None:
|
|
|
|
if homescreen[:8] == b'TOIf\x90\x00\x90\x00':
|
2018-03-08 22:45:17 +00:00
|
|
|
if len(homescreen) <= HOMESCREEN_MAXSIZE:
|
|
|
|
config.set(_APP, _HOMESCREEN, homescreen, True) # public
|
2017-12-13 01:41:59 +00:00
|
|
|
else:
|
2018-02-05 10:48:12 +00:00
|
|
|
config.set(_APP, _HOMESCREEN, b'', True) # public
|
2016-12-15 11:48:33 +00:00
|
|
|
|
|
|
|
|
2018-02-14 22:50:08 +00:00
|
|
|
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'))
|
|
|
|
|
|
|
|
|
2018-02-28 17:53:52 +00:00
|
|
|
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):
|
2018-02-28 17:58:42 +00:00
|
|
|
config.set(_APP, _U2F_COUNTER, cntr.to_bytes(4, 'big'))
|
2018-02-28 17:53:52 +00:00
|
|
|
|
|
|
|
|
2016-11-23 13:46:55 +00:00
|
|
|
def wipe():
|
|
|
|
config.wipe()
|
2017-05-08 20:31:21 +00:00
|
|
|
cache.clear()
|