1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-02-22 12:32:02 +00:00

feat(core): incorporate handshake hash into pairing

This commit is contained in:
M1nd3r 2024-07-22 13:38:43 +02:00
parent 45e2819789
commit 1bf927c943
3 changed files with 31 additions and 25 deletions

View File

@ -132,7 +132,7 @@ async def show_display_data(ctx: PairingContext, expected_types: Container[int]
if cancel_task in race.finished:
raise ActionCancelled
else:
return Exception("Should not happen") # TODO
return Exception("Should not happen") # TODO what to do here?
@check_state_and_log(ChannelState.TP1)
@ -149,12 +149,11 @@ async def _handle_code_entry_is_included(ctx: PairingContext) -> None:
if challenge_message.challenge is None:
raise Exception("Invalid message")
code_code_entry_hash = sha256(
challenge_message.challenge
+ ctx.secret
+ bytes("PairingMethod_CodeEntry", "utf-8")
).digest() # TODO add handshake hash
sha_ctx = sha256(ctx.channel_ctx.get_handshake_hash())
sha_ctx.update(ctx.secret)
sha_ctx.update(challenge_message.challenge)
sha_ctx.update(bytes("PairingMethod_CodeEntry", "utf-8"))
code_code_entry_hash = sha_ctx.digest()
ctx.display_data.code_code_entry = (
int.from_bytes(code_code_entry_hash, "big") % 1000000
)
@ -163,21 +162,19 @@ async def _handle_code_entry_is_included(ctx: PairingContext) -> None:
@check_state_and_log(ChannelState.TP1, ChannelState.TP2)
def _handle_qr_code_is_included(ctx: PairingContext) -> None:
ctx.display_data.code_qr_code = sha256(
ctx.secret + bytes("PairingMethod_QrCode", "utf-8")
).digest()[
:16
] # TODO add handshake hash
sha_ctx = sha256(ctx.channel_ctx.get_handshake_hash())
sha_ctx.update(ctx.secret)
sha_ctx.update(bytes("PairingMethod_QrCode", "utf-8"))
ctx.display_data.code_qr_code = sha_ctx.digest()[:16]
ctx.display_data.display_qr_code = True
@check_state_and_log(ChannelState.TP1, ChannelState.TP2)
def _handle_nfc_unidirectional_is_included(ctx: PairingContext) -> None:
ctx.display_data.code_nfc_unidirectional = sha256(
ctx.secret + bytes("PairingMethod_NfcUnidirectional", "utf-8")
).digest()[
:16
] # TODO add handshake hash
sha_ctx = sha256(ctx.channel_ctx.get_handshake_hash())
sha_ctx.update(ctx.secret)
sha_ctx.update(bytes("PairingMethod_NfcUnidirectional", "utf-8"))
ctx.display_data.code_nfc_unidirectional = sha_ctx.digest()[:16]
ctx.display_data.display_nfc_unidirectional = True
@ -208,7 +205,10 @@ async def _handle_code_entry_cpace(
if message.cpace_host_public_key is None:
raise ThpError("Message ThpCodeEntryCpaceHost has no public key")
ctx.cpace = Cpace(message.cpace_host_public_key)
ctx.cpace = Cpace(
message.cpace_host_public_key,
ctx.channel_ctx.get_handshake_hash(),
)
assert ctx.display_data.code_code_entry is not None
ctx.cpace.generate_keys_and_secret(
ctx.display_data.code_code_entry.to_bytes(6, "big")

View File

@ -76,6 +76,9 @@ class Channel:
log.debug(__name__, "get_channel_state: %s", state_to_str(state))
return state
def get_handshake_hash(self) -> bytes:
return self.channel_cache.get(CHANNEL_HANDSHAKE_HASH) or b""
def set_channel_state(self, state: ChannelState) -> None:
self.channel_cache.state = bytearray(state.to_bytes(1, "big"))
if __debug__:
@ -178,7 +181,7 @@ class Channel:
else:
key_receive = self.channel_cache.get(CHANNEL_KEY_RECEIVE)
nonce_receive = self.channel_cache.get_int(CHANNEL_NONCE_RECEIVE)
auth_data = self.channel_cache.get(CHANNEL_HANDSHAKE_HASH)
auth_data = self.get_handshake_hash()
assert key_receive is not None
assert nonce_receive is not None
@ -212,7 +215,7 @@ class Channel:
else:
key_send = self.channel_cache.get(CHANNEL_KEY_SEND)
nonce_send = self.channel_cache.get_int(CHANNEL_NONCE_SEND)
auth_data = self.channel_cache.get(CHANNEL_HANDSHAKE_HASH)
auth_data = self.get_handshake_hash()
assert key_send is not None
assert nonce_send is not None

View File

@ -11,19 +11,22 @@ class Cpace:
CPace, a balanced composable PAKE: https://datatracker.ietf.org/doc/draft-irtf-cfrg-cpace/
"""
def __init__(self, cpace_host_public_key: bytes) -> None:
def __init__(self, cpace_host_public_key: bytes, handshake_hash: bytes) -> None:
self.handshake_hash: bytes = handshake_hash
self.host_public_key: bytes = cpace_host_public_key
self.shared_secret: bytes
self.trezor_private_key: bytes
self.trezor_public_key: bytes
self.shared_secret: bytes
def generate_keys_and_secret(self, code_code_entry: bytes) -> None:
"""
Generate ephemeral key pair and a shared secret using Elligator2 with X25519.
"""
pregenerator = sha512(_PREFIX + code_code_entry + _PADDING).digest()[
:32
] # TODO add handshake hash
sha_ctx = sha512(_PREFIX)
sha_ctx.update(code_code_entry)
sha_ctx.update(_PADDING)
sha_ctx.update(self.handshake_hash)
pregenerator = sha_ctx.digest()[:32]
generator = elligator2.map_to_curve25519(pregenerator)
self.trezor_private_key = random.bytes(32)
if __debug__: