You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
76 lines
2.2 KiB
76 lines
2.2 KiB
5 years ago
|
from storage.device import get_device_id
|
||
6 years ago
|
from trezor.crypto import hashlib, hmac, random
|
||
6 years ago
|
|
||
5 years ago
|
if False:
|
||
|
from typing import Optional
|
||
6 years ago
|
|
||
5 years ago
|
_cached_seed = None # type: Optional[bytes]
|
||
5 years ago
|
_cached_seed_without_passphrase = None # type: Optional[bytes]
|
||
5 years ago
|
_cached_passphrase = None # type: Optional[str]
|
||
|
_cached_passphrase_fprint = b"\x00\x00\x00\x00" # type: bytes
|
||
6 years ago
|
|
||
5 years ago
|
|
||
|
def get_state(prev_state: bytes = None, passphrase: str = None) -> Optional[bytes]:
|
||
6 years ago
|
if prev_state is None:
|
||
6 years ago
|
salt = random.bytes(32) # generate a random salt if no state provided
|
||
6 years ago
|
else:
|
||
6 years ago
|
salt = prev_state[:32] # use salt from provided state
|
||
|
if len(salt) != 32:
|
||
|
return None # invalid state
|
||
6 years ago
|
if passphrase is None:
|
||
6 years ago
|
if _cached_passphrase is None:
|
||
|
return None # we don't have any passphrase to compute the state
|
||
|
else:
|
||
|
passphrase = _cached_passphrase # use cached passphrase
|
||
|
return _compute_state(salt, passphrase)
|
||
6 years ago
|
|
||
7 years ago
|
|
||
6 years ago
|
def _compute_state(salt: bytes, passphrase: str) -> bytes:
|
||
|
# state = HMAC(passphrase, salt || device_id)
|
||
5 years ago
|
message = salt + get_device_id().encode()
|
||
6 years ago
|
state = hmac.new(passphrase.encode(), message, hashlib.sha256).digest()
|
||
6 years ago
|
return salt + state
|
||
6 years ago
|
|
||
|
|
||
5 years ago
|
def get_seed() -> Optional[bytes]:
|
||
6 years ago
|
return _cached_seed
|
||
6 years ago
|
|
||
|
|
||
5 years ago
|
def get_seed_without_passphrase() -> Optional[bytes]:
|
||
|
return _cached_seed_without_passphrase
|
||
|
|
||
|
|
||
5 years ago
|
def get_passphrase() -> Optional[str]:
|
||
6 years ago
|
return _cached_passphrase
|
||
6 years ago
|
|
||
|
|
||
5 years ago
|
def get_passphrase_fprint() -> bytes:
|
||
5 years ago
|
return _cached_passphrase_fprint
|
||
5 years ago
|
|
||
|
|
||
5 years ago
|
def has_passphrase() -> bool:
|
||
6 years ago
|
return _cached_passphrase is not None
|
||
|
|
||
6 years ago
|
|
||
5 years ago
|
def set_seed(seed: Optional[bytes]) -> None:
|
||
6 years ago
|
global _cached_seed
|
||
|
_cached_seed = seed
|
||
6 years ago
|
|
||
6 years ago
|
|
||
5 years ago
|
def set_seed_without_passphrase(seed: Optional[bytes]) -> None:
|
||
|
global _cached_seed_without_passphrase
|
||
|
_cached_seed_without_passphrase = seed
|
||
|
|
||
|
|
||
5 years ago
|
def set_passphrase(passphrase: Optional[str]) -> None:
|
||
5 years ago
|
global _cached_passphrase, _cached_passphrase_fprint
|
||
6 years ago
|
_cached_passphrase = passphrase
|
||
5 years ago
|
_cached_passphrase_fprint = _compute_state(b"FPRINT", passphrase or "")[:4]
|
||
6 years ago
|
|
||
|
|
||
5 years ago
|
def clear(keep_passphrase: bool = False) -> None:
|
||
6 years ago
|
set_seed(None)
|
||
5 years ago
|
set_seed_without_passphrase(None)
|
||
5 years ago
|
if not keep_passphrase:
|
||
6 years ago
|
set_passphrase(None)
|