diff --git a/src/apps/wallet/__init__.py b/src/apps/wallet/__init__.py index cfedbd4f04..a288315b9a 100644 --- a/src/apps/wallet/__init__.py +++ b/src/apps/wallet/__init__.py @@ -6,6 +6,7 @@ from trezor.messages.wire_types import \ SignTx, \ SignMessage, VerifyMessage, \ SignIdentity, \ + GetECDHSessionKey, \ CipherKeyValue @@ -51,6 +52,12 @@ def dispatch_SignIdentity(*args, **kwargs): return sign_identity(*args, **kwargs) +@unimport +def dispatch_GetECDHSessionKey(*args, **kwargs): + from .ecdh import get_ecdh_session_key + return get_ecdh_session_key(*args, **kwargs) + + @unimport def dispatch_CipherKeyValue(*args, **kwargs): from .cipher_key_value import cipher_key_value @@ -65,4 +72,5 @@ def boot(): register(SignMessage, protobuf_workflow, dispatch_SignMessage) register(VerifyMessage, protobuf_workflow, dispatch_VerifyMessage) register(SignIdentity, protobuf_workflow, dispatch_SignIdentity) + register(GetECDHSessionKey, protobuf_workflow, dispatch_GetECDHSessionKey) register(CipherKeyValue, protobuf_workflow, dispatch_CipherKeyValue) diff --git a/src/apps/wallet/ecdh.py b/src/apps/wallet/ecdh.py new file mode 100644 index 0000000000..4d671a4200 --- /dev/null +++ b/src/apps/wallet/ecdh.py @@ -0,0 +1,58 @@ +from trezor import ui +from trezor.crypto.hashlib import sha256 +from trezor.messages.ECDHSessionKey import ECDHSessionKey +from ustruct import pack, unpack +from trezor.utils import chunks, serialize_identity +from apps.common.confirm import require_confirm +from trezor.ui.text import Text + +from ..common import seed + + +async def get_ecdh_session_key(ctx, msg): + if msg.ecdsa_curve_name is None: + msg.ecdsa_curve_name = 'secp256k1' + + identity = serialize_identity(msg.identity) + + await require_confirm_ecdh_session_key(ctx, identity) + + address_n = get_ecdh_path(identity, msg.identity.index or 0) + node = await seed.derive_node(ctx, address_n, msg.ecdsa_curve_name) + + session_key = ecdh(seckey=node.private_key(), + peer_public_key=msg.peer_public_key, + curve=msg.ecdsa_curve_name) + return ECDHSessionKey(session_key=session_key) + + +async def require_confirm_ecdh_session_key(ctx, identity): + lines = chunks(identity, 18) + content = Text('Decrypt', ui.ICON_DEFAULT, ui.MONO, *lines, max_lines=5) + await require_confirm(ctx, content) + + +def get_ecdh_path(identity: str, index: int): + identity_hash = sha256(pack(' bytes: + if curve == 'secp256k1': + from trezor.crypto.curve import secp256k1 + session_key = secp256k1.multiply(seckey, peer_public_key) + elif curve == 'nist256p1': + from trezor.crypto.curve import nist256p1 + session_key = nist256p1.multiply(seckey, peer_public_key) + elif curve == 'curve25519': + from trezor.crypto.curve import curve25519 + if peer_public_key[0] != 0x40: + raise ValueError('Curve25519 public key should start with 0x40') + session_key = b'\x04' + curve25519.multiply(seckey, peer_public_key[1:]) + else: + raise ValueError('Unsupported curve for ECDH: ' + curve) + + return session_key