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.
trezor-firmware/core/src/apps/misc/get_ecdh_session_key.py

73 lines
2.3 KiB

6 years ago
from ustruct import pack, unpack
from trezor import wire
from trezor.crypto.hashlib import sha256
from trezor.messages.ECDHSessionKey import ECDHSessionKey
from trezor.ui.text import Text
6 years ago
from trezor.utils import chunks
from apps.common import HARDENED
6 years ago
from apps.common.confirm import require_confirm
from apps.common.keychain import get_keychain
from apps.common.paths import AlwaysMatchingSchema
from .sign_identity import serialize_identity, serialize_identity_without_proto
async def get_ecdh_session_key(ctx, msg):
if msg.ecdsa_curve_name is None:
6 years ago
msg.ecdsa_curve_name = "secp256k1"
keychain = await get_keychain(ctx, msg.ecdsa_curve_name, [AlwaysMatchingSchema])
identity = serialize_identity(msg.identity)
await require_confirm_ecdh_session_key(ctx, msg.identity)
address_n = get_ecdh_path(identity, msg.identity.index or 0)
node = keychain.derive(address_n)
6 years ago
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(serialize_identity_without_proto(identity), 18)
6 years ago
proto = identity.proto.upper() if identity.proto else "identity"
text = Text("Decrypt %s" % proto)
text.mono(*lines)
await require_confirm(ctx, text)
def get_ecdh_path(identity: str, index: int):
6 years ago
identity_hash = sha256(pack("<I", index) + identity).digest()
6 years ago
address_n = (17,) + unpack("<IIII", identity_hash[:16])
address_n = [HARDENED | x for x in address_n]
return address_n
def ecdh(seckey: bytes, peer_public_key: bytes, curve: str) -> bytes:
6 years ago
if curve == "secp256k1":
from trezor.crypto.curve import secp256k1
6 years ago
session_key = secp256k1.multiply(seckey, peer_public_key)
6 years ago
elif curve == "nist256p1":
from trezor.crypto.curve import nist256p1
6 years ago
session_key = nist256p1.multiply(seckey, peer_public_key)
6 years ago
elif curve == "curve25519":
from trezor.crypto.curve import curve25519
6 years ago
if peer_public_key[0] != 0x40:
raise wire.DataError("Curve25519 public key should start with 0x40")
6 years ago
session_key = b"\x04" + curve25519.multiply(seckey, peer_public_key[1:])
else:
raise wire.DataError("Unsupported curve for ECDH: " + curve)
return session_key