1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-27 16:48:09 +00:00
trezor-firmware/src/apps/common/storage.py

169 lines
3.5 KiB
Python
Raw Normal View History

2016-09-29 10:29:43 +00:00
from micropython import const
2016-11-23 13:46:55 +00:00
import ustruct
import utime
2016-09-26 11:06:28 +00:00
from trezor import config
2016-11-23 13:46:55 +00:00
from trezor import utils
_APP = const(1)
_DEVICE_ID = const(0) # str
_VERSION = const(1) # varint
_MNEMONIC = const(2) # str
_LANGUAGE = const(3) # str
_LABEL = const(4) # str
_PIN = const(5) # bytes
_PIN_FAILS = const(6) # varint
_PASSPHRASE_PROTECTION = const(7) # varint
# pin lock
# ===
_locked = True
def is_locked() -> bool:
return is_protected_by_pin() and _locked
def unlock(user_pin: str, failure_callback=None) -> bool:
global _locked
if not is_protected_by_pin():
return True
# increment the pin fail counter before checking the pin
fails = bytes_to_int(config_get(_PIN_FAILS)) + 1
config_set_checked(_PIN_FAILS, int_to_bytes(fails))
if const_equal(config_get(_PIN), user_pin.encode()):
# unlock and reset the counter
_locked = False
config_set(_PIN_FAILS, int_to_bytes(0))
return True
else:
# lock, run the callback (ie for ui) and sleep for a quadratic delay
_locked = True
delay_ms = fails * fails * 1000
2016-12-12 14:20:20 +00:00
try:
if failure_callback:
2016-11-23 13:46:55 +00:00
failure_callback(delay_ms)
2016-12-12 14:20:20 +00:00
finally:
utime.sleep_ms(delay_ms)
2016-11-23 13:46:55 +00:00
return False
def lock():
global _locked
_locked = True
def const_equal(a: bytes, b: bytes) -> bool:
return a == b
2016-09-26 11:06:28 +00:00
2016-11-23 13:46:55 +00:00
# settings
# ===
2016-09-26 11:06:28 +00:00
def get_device_id() -> str:
2016-11-23 13:46:55 +00:00
dev_id = config_get(_DEVICE_ID).decode()
if not dev_id:
2016-11-23 13:46:55 +00:00
dev_id = new_device_id()
config_set(_DEVICE_ID, dev_id.encode())
return dev_id
2016-09-26 11:06:28 +00:00
def is_initialized() -> bool:
2016-11-23 13:46:55 +00:00
return bool(config_get(_VERSION))
2016-09-26 11:06:28 +00:00
2016-10-06 13:03:54 +00:00
def is_protected_by_pin() -> bool:
2016-11-23 13:46:55 +00:00
return bool(config_get(_PIN))
2016-10-06 13:03:54 +00:00
def is_protected_by_passphrase() -> bool:
2016-11-23 13:46:55 +00:00
return bool(bytes_to_int(config_get(_PASSPHRASE_PROTECTION)))
2016-11-15 10:50:45 +00:00
def get_pin() -> str:
2016-11-23 13:46:55 +00:00
return config_get(_PIN).decode()
2016-11-15 10:50:45 +00:00
def get_label() -> str:
2016-11-23 13:46:55 +00:00
return config_get(_LABEL).decode()
def get_mnemonic() -> str:
2016-11-23 13:46:55 +00:00
utils.ensure(is_initialized())
utils.ensure(not is_locked())
return config_get(_MNEMONIC).decode()
# settings configuration
# ===
def load_mnemonic(mnemonic: str):
2016-11-23 13:46:55 +00:00
utils.ensure(not is_initialized())
2016-11-23 13:46:55 +00:00
config_set(_VERSION, int_to_bytes(1))
config_set(_MNEMONIC, mnemonic.encode())
2016-11-23 13:46:55 +00:00
def load_settings(language: str=None,
label: str=None,
pin: str=None,
passphrase_protection: bool=None):
utils.ensure(is_initialized())
utils.ensure(not is_locked())
2016-11-23 13:46:55 +00:00
if language is not None:
config_set(_LANGUAGE, language.encode())
if label is not None:
config_set(_LABEL, label.encode())
if pin is not None:
config_set(_PIN, pin.encode())
if passphrase_protection is not None:
config_set(_PASSPHRASE_PROTECTION,
int_to_bytes(passphrase_protection))
2016-11-23 13:46:55 +00:00
def wipe():
lock()
2016-11-23 13:46:55 +00:00
config.wipe()
2016-11-23 13:46:55 +00:00
def new_device_id() -> str:
from ubinascii import hexlify
from trezor.crypto import random
return hexlify(random.bytes(12)).decode('ascii').upper()
2016-11-23 13:46:55 +00:00
def config_get(key: int) -> bytes:
return config.get(_APP, key)
def config_set(key: int, value: bytes):
config.set(_APP, key, value)
def config_set_checked(key, value: bytes):
config_set(key, value)
check = config_get(key)
if check != value:
utils.halt('config.set failed')
2016-12-12 14:20:20 +00:00
# TODO: store ints as varints
2016-11-23 13:46:55 +00:00
def int_to_bytes(i: int) -> bytes:
return ustruct.pack('>L', i) if i else bytes()
def bytes_to_int(b: bytes) -> int:
return ustruct.unpack('>L', b) if b else 0