1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-15 20:19:23 +00:00
trezor-firmware/core/src/apps/common/seed.py

105 lines
3.1 KiB
Python
Raw Normal View History

from trezor import ui, wire
from trezor.crypto import bip32
2018-07-03 14:20:26 +00:00
2019-04-05 09:23:06 +00:00
from apps.common import HARDENED, cache, mnemonic, storage
2018-02-27 15:35:21 +00:00
from apps.common.request_passphrase import protect_by_passphrase
2018-11-14 18:58:07 +00:00
allow = list
2018-11-13 16:09:52 +00:00
class Keychain:
2018-11-14 18:58:07 +00:00
"""
Keychain provides an API for deriving HD keys from previously allowed
key-spaces.
"""
2018-11-13 16:09:52 +00:00
def __init__(self, seed: bytes, namespaces: list):
self.seed = seed
self.namespaces = namespaces
self.roots = [None] * len(namespaces)
def __del__(self):
for root in self.roots:
if root is not None:
root.__del__()
del self.roots
del self.seed
2018-11-14 18:58:07 +00:00
2019-04-05 09:23:06 +00:00
def validate_path(self, checked_path: list, checked_curve: str):
2019-04-04 09:41:23 +00:00
for curve, *path in self.namespaces:
2019-04-05 09:23:06 +00:00
if path == checked_path[: len(path)] and curve == checked_curve:
2019-04-09 14:32:52 +00:00
if "ed25519" in curve and not _path_hardened(checked_path):
2019-04-05 09:23:06 +00:00
break
2019-04-04 09:41:23 +00:00
return
raise wire.DataError("Forbidden key path")
2018-11-14 18:58:07 +00:00
def derive(self, node_path: list, curve_name: str = "secp256k1") -> bip32.HDNode:
# find the root node index
2018-11-14 18:58:07 +00:00
root_index = 0
for curve, *path in self.namespaces:
2018-11-14 18:58:07 +00:00
prefix = node_path[: len(path)]
suffix = node_path[len(path) :]
if curve == curve_name and path == prefix:
break
root_index += 1
else:
raise wire.DataError("Forbidden key path")
# create the root node if not cached
root = self.roots[root_index]
if root is None:
root = bip32.from_seed(self.seed, curve_name)
root.derive_path(path)
self.roots[root_index] = root
# TODO check for ed25519?
2018-11-14 18:58:07 +00:00
# derive child node from the root
node = root.clone()
2018-11-14 18:58:07 +00:00
node.derive_path(suffix)
2018-11-13 16:09:52 +00:00
return node
async def get_keychain(ctx: wire.Context, namespaces: list) -> Keychain:
if not storage.is_initialized():
2018-07-03 14:20:58 +00:00
raise wire.ProcessError("Device is not initialized")
2018-11-13 16:09:52 +00:00
seed = cache.get_seed()
if seed is None:
seed = await _compute_seed(ctx)
keychain = Keychain(seed, namespaces)
2018-11-13 16:09:52 +00:00
return keychain
2019-04-05 09:23:06 +00:00
def _path_hardened(path: list) -> bool:
# TODO: move to paths.py after #538 is fixed
for i in path:
if not (i & HARDENED):
return False
return True
2019-02-21 12:22:57 +00:00
@ui.layout_no_slide
async def _compute_seed(ctx: wire.Context) -> bytes:
passphrase = cache.get_passphrase()
if passphrase is None:
passphrase = await protect_by_passphrase(ctx)
cache.set_passphrase(passphrase)
seed = mnemonic.get_seed(passphrase)
cache.set_seed(seed)
return seed
2018-07-03 14:20:58 +00:00
def derive_node_without_passphrase(
2018-11-14 18:58:07 +00:00
path: list, curve_name: str = "secp256k1"
2018-07-03 14:20:58 +00:00
) -> bip32.HDNode:
if not storage.is_initialized():
2018-07-03 14:20:58 +00:00
raise Exception("Device is not initialized")
seed = mnemonic.get_seed(progress_bar=False)
node = bip32.from_seed(seed, curve_name)
node.derive_path(path)
return node
2018-05-11 13:31:53 +00:00
def remove_ed25519_prefix(pubkey: bytes) -> bytes:
2018-05-11 13:31:53 +00:00
# 0x01 prefix is not part of the actual public key, hence removed
return pubkey[1:]