diff --git a/common/protob/messages-crypto.proto b/common/protob/messages-crypto.proto index 8841fbc6ba..911b8b7dbe 100644 --- a/common/protob/messages-crypto.proto +++ b/common/protob/messages-crypto.proto @@ -13,8 +13,8 @@ option java_outer_classname = "TrezorMessageCrypto"; */ message CipherKeyValue { repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node - optional string key = 2; // key component of key:value - optional bytes value = 3; // value component of key:value + required string key = 2; // key component of key:value + required bytes value = 3; // value component of key:value optional bool encrypt = 4; // are we encrypting (True) or decrypting (False)? optional bool ask_on_encrypt = 5; // should we ask on encrypt operation? optional bool ask_on_decrypt = 6; // should we ask on decrypt operation? @@ -26,7 +26,7 @@ message CipherKeyValue { * @end */ message CipheredKeyValue { - optional bytes value = 1; // ciphered/deciphered value + required bytes value = 1; // ciphered/deciphered value } /** @@ -49,10 +49,10 @@ message IdentityType { * @next Failure */ message SignIdentity { - optional IdentityType identity = 1; // identity - optional bytes challenge_hidden = 2; // non-visible challenge - optional string challenge_visual = 3; // challenge shown on display (e.g. date+time) - optional string ecdsa_curve_name = 4; // ECDSA curve name to use + required IdentityType identity = 1; // identity + optional bytes challenge_hidden = 2 [default=""]; // non-visible challenge + optional string challenge_visual = 3 [default=""]; // challenge shown on display (e.g. date+time) + optional string ecdsa_curve_name = 4; // ECDSA curve name to use } /** @@ -61,8 +61,8 @@ message SignIdentity { */ message SignedIdentity { optional string address = 1; // identity address - optional bytes public_key = 2; // identity public key - optional bytes signature = 3; // signature of the identity data + required bytes public_key = 2; // identity public key + required bytes signature = 3; // signature of the identity data } /** @@ -72,8 +72,8 @@ message SignedIdentity { * @next Failure */ message GetECDHSessionKey { - optional IdentityType identity = 1; // identity - optional bytes peer_public_key = 2; // peer's public key + required IdentityType identity = 1; // identity + required bytes peer_public_key = 2; // peer's public key optional string ecdsa_curve_name = 3; // ECDSA curve name to use } @@ -82,7 +82,7 @@ message GetECDHSessionKey { * @end */ message ECDHSessionKey { - optional bytes session_key = 1; // ECDH session key + required bytes session_key = 1; // ECDH session key } /** diff --git a/core/Makefile b/core/Makefile index d1eb834238..8059152bf3 100644 --- a/core/Makefile +++ b/core/Makefile @@ -108,6 +108,7 @@ mypy: src/main.py \ src/apps/bitcoin \ src/apps/cardano \ + src/apps/misc \ src/apps/webauthn ## code generation: diff --git a/core/src/apps/misc/cipher_key_value.py b/core/src/apps/misc/cipher_key_value.py index 6111d9f259..cc18609658 100644 --- a/core/src/apps/misc/cipher_key_value.py +++ b/core/src/apps/misc/cipher_key_value.py @@ -7,8 +7,12 @@ from apps.common.confirm import require_confirm from apps.common.keychain import get_keychain from apps.common.paths import AlwaysMatchingSchema +if False: + from trezor.messages.CipherKeyValue import CipherKeyValue + from trezor.wire import Context -async def cipher_key_value(ctx, msg): + +async def cipher_key_value(ctx: Context, msg: CipherKeyValue) -> CipheredKeyValue: keychain = await get_keychain(ctx, "secp256k1", [AlwaysMatchingSchema]) if len(msg.value) % 16 > 0: @@ -30,10 +34,10 @@ async def cipher_key_value(ctx, msg): return CipheredKeyValue(value=value) -def compute_cipher_key_value(msg, seckey: bytes) -> bytes: - data = msg.key - data += "E1" if msg.ask_on_encrypt else "E0" - data += "D1" if msg.ask_on_decrypt else "D0" +def compute_cipher_key_value(msg: CipherKeyValue, seckey: bytes) -> bytes: + data = msg.key.encode() + data += b"E1" if msg.ask_on_encrypt else b"E0" + data += b"D1" if msg.ask_on_decrypt else b"D0" data = hmac(hmac.SHA512, seckey, data).digest() key = data[:32] if msg.iv and len(msg.iv) == 16: diff --git a/core/src/apps/misc/get_ecdh_session_key.py b/core/src/apps/misc/get_ecdh_session_key.py index a789809c92..d6a86c3d3c 100644 --- a/core/src/apps/misc/get_ecdh_session_key.py +++ b/core/src/apps/misc/get_ecdh_session_key.py @@ -13,8 +13,16 @@ from apps.common.paths import AlwaysMatchingSchema from .sign_identity import serialize_identity, serialize_identity_without_proto +if False: + from trezor.messages.GetECDHSessionKey import GetECDHSessionKey + from trezor.messages.IdentityType import IdentityType -async def get_ecdh_session_key(ctx, msg): + from apps.common.paths import Bip32Path + + +async def get_ecdh_session_key( + ctx: wire.Context, msg: GetECDHSessionKey +) -> ECDHSessionKey: if msg.ecdsa_curve_name is None: msg.ecdsa_curve_name = "secp256k1" @@ -34,7 +42,9 @@ async def get_ecdh_session_key(ctx, msg): return ECDHSessionKey(session_key=session_key) -async def require_confirm_ecdh_session_key(ctx, identity): +async def require_confirm_ecdh_session_key( + ctx: wire.Context, identity: IdentityType +) -> None: lines = chunks(serialize_identity_without_proto(identity), 18) proto = identity.proto.upper() if identity.proto else "identity" text = Text("Decrypt %s" % proto) @@ -42,11 +52,10 @@ async def require_confirm_ecdh_session_key(ctx, identity): await require_confirm(ctx, text) -def get_ecdh_path(identity: str, index: int): - identity_hash = sha256(pack(" Bip32Path: + identity_hash = sha256(pack(" Entropy: text = Text("Confirm entropy") text.bold("Do you really want", "to send entropy?") text.normal("Continue only if you", "know what you are doing!") diff --git a/core/src/apps/misc/sign_identity.py b/core/src/apps/misc/sign_identity.py index 09f83f6a87..0c1741b954 100644 --- a/core/src/apps/misc/sign_identity.py +++ b/core/src/apps/misc/sign_identity.py @@ -1,18 +1,27 @@ from ustruct import pack, unpack -from trezor import ui +from trezor import ui, wire from trezor.crypto.hashlib import sha256 from trezor.messages.SignedIdentity import SignedIdentity from trezor.ui.text import Text from trezor.utils import chunks -from apps.common import HARDENED, coins +from apps.common import HARDENED, coininfo from apps.common.confirm import require_confirm from apps.common.keychain import get_keychain from apps.common.paths import AlwaysMatchingSchema +if False: + from typing import List, Optional, Union -async def sign_identity(ctx, msg): + from trezor.messages.IdentityType import IdentityType + from trezor.messages.SignIdentity import SignIdentity + from trezor.ui.text import TextContent + + from apps.common.paths import Bip32Path + + +async def sign_identity(ctx: wire.Context, msg: SignIdentity) -> SignedIdentity: if msg.ecdsa_curve_name is None: msg.ecdsa_curve_name = "secp256k1" @@ -24,9 +33,10 @@ async def sign_identity(ctx, msg): address_n = get_identity_path(identity, msg.identity.index or 0) node = keychain.derive(address_n) - coin = coins.by_name("Bitcoin") + coin = coininfo.by_name("Bitcoin") if msg.ecdsa_curve_name == "secp256k1": - address = node.address(coin.address_type) # hardcoded bitcoin address type + # hardcoded bitcoin address type + address: Optional[str] = node.address(coin.address_type) else: address = None pubkey = node.public_key() @@ -70,8 +80,10 @@ async def sign_identity(ctx, msg): return SignedIdentity(address=address, public_key=pubkey, signature=signature) -async def require_confirm_sign_identity(ctx, identity, challenge_visual): - lines = [] +async def require_confirm_sign_identity( + ctx: wire.Context, identity: IdentityType, challenge_visual: Optional[str] +) -> None: + lines: List[TextContent] = [] if challenge_visual: lines.append(challenge_visual) @@ -84,7 +96,7 @@ async def require_confirm_sign_identity(ctx, identity, challenge_visual): await require_confirm(ctx, text) -def serialize_identity(identity): +def serialize_identity(identity: IdentityType) -> str: s = "" if identity.proto: s += identity.proto + "://" @@ -99,7 +111,7 @@ def serialize_identity(identity): return s -def serialize_identity_without_proto(identity): +def serialize_identity_without_proto(identity: IdentityType) -> str: proto = identity.proto identity.proto = None # simplify serialized identity string s = serialize_identity(identity) @@ -107,17 +119,20 @@ def serialize_identity_without_proto(identity): return s -def get_identity_path(identity: str, index: int): - identity_hash = sha256(pack(" Bip32Path: + identity_hash = sha256(pack(" bytes: from trezor.crypto.hashlib import sha256 @@ -133,19 +148,22 @@ def sign_challenge( data = challenge_hidden elif sigtype == "signify": if curve != "ed25519": - raise ValueError("Unsupported curve") + raise wire.DataError("Unsupported curve") data = challenge_hidden elif sigtype == "ssh": if curve != "ed25519": data = sha256(challenge_hidden).digest() else: data = challenge_hidden - else: + elif isinstance(sigtype, coininfo.CoinInfo): # sigtype is coin challenge = ( - sha256(challenge_hidden).digest() + sha256(challenge_visual).digest() + sha256(challenge_hidden).digest() + + sha256(challenge_visual.encode()).digest() ) data = message_digest(sigtype, challenge) + else: + raise wire.DataError("Unsupported sigtype") if curve == "secp256k1": signature = secp256k1.sign(seckey, data) @@ -154,7 +172,7 @@ def sign_challenge( elif curve == "ed25519": signature = ed25519.sign(seckey, data) else: - raise ValueError("Unknown curve") + raise wire.DataError("Unknown curve") if curve == "ed25519": signature = b"\x00" + signature