1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-02-23 04:52:01 +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: if cancel_task in race.finished:
raise ActionCancelled raise ActionCancelled
else: else:
return Exception("Should not happen") # TODO return Exception("Should not happen") # TODO what to do here?
@check_state_and_log(ChannelState.TP1) @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: if challenge_message.challenge is None:
raise Exception("Invalid message") raise Exception("Invalid message")
sha_ctx = sha256(ctx.channel_ctx.get_handshake_hash())
code_code_entry_hash = sha256( sha_ctx.update(ctx.secret)
challenge_message.challenge sha_ctx.update(challenge_message.challenge)
+ ctx.secret sha_ctx.update(bytes("PairingMethod_CodeEntry", "utf-8"))
+ bytes("PairingMethod_CodeEntry", "utf-8") code_code_entry_hash = sha_ctx.digest()
).digest() # TODO add handshake hash
ctx.display_data.code_code_entry = ( ctx.display_data.code_code_entry = (
int.from_bytes(code_code_entry_hash, "big") % 1000000 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) @check_state_and_log(ChannelState.TP1, ChannelState.TP2)
def _handle_qr_code_is_included(ctx: PairingContext) -> None: def _handle_qr_code_is_included(ctx: PairingContext) -> None:
ctx.display_data.code_qr_code = sha256( sha_ctx = sha256(ctx.channel_ctx.get_handshake_hash())
ctx.secret + bytes("PairingMethod_QrCode", "utf-8") sha_ctx.update(ctx.secret)
).digest()[ sha_ctx.update(bytes("PairingMethod_QrCode", "utf-8"))
:16 ctx.display_data.code_qr_code = sha_ctx.digest()[:16]
] # TODO add handshake hash
ctx.display_data.display_qr_code = True ctx.display_data.display_qr_code = True
@check_state_and_log(ChannelState.TP1, ChannelState.TP2) @check_state_and_log(ChannelState.TP1, ChannelState.TP2)
def _handle_nfc_unidirectional_is_included(ctx: PairingContext) -> None: def _handle_nfc_unidirectional_is_included(ctx: PairingContext) -> None:
ctx.display_data.code_nfc_unidirectional = sha256( sha_ctx = sha256(ctx.channel_ctx.get_handshake_hash())
ctx.secret + bytes("PairingMethod_NfcUnidirectional", "utf-8") sha_ctx.update(ctx.secret)
).digest()[ sha_ctx.update(bytes("PairingMethod_NfcUnidirectional", "utf-8"))
:16 ctx.display_data.code_nfc_unidirectional = sha_ctx.digest()[:16]
] # TODO add handshake hash
ctx.display_data.display_nfc_unidirectional = True 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: if message.cpace_host_public_key is None:
raise ThpError("Message ThpCodeEntryCpaceHost has no public key") 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 assert ctx.display_data.code_code_entry is not None
ctx.cpace.generate_keys_and_secret( ctx.cpace.generate_keys_and_secret(
ctx.display_data.code_code_entry.to_bytes(6, "big") 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)) log.debug(__name__, "get_channel_state: %s", state_to_str(state))
return 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: def set_channel_state(self, state: ChannelState) -> None:
self.channel_cache.state = bytearray(state.to_bytes(1, "big")) self.channel_cache.state = bytearray(state.to_bytes(1, "big"))
if __debug__: if __debug__:
@ -178,7 +181,7 @@ class Channel:
else: else:
key_receive = self.channel_cache.get(CHANNEL_KEY_RECEIVE) key_receive = self.channel_cache.get(CHANNEL_KEY_RECEIVE)
nonce_receive = self.channel_cache.get_int(CHANNEL_NONCE_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 key_receive is not None
assert nonce_receive is not None assert nonce_receive is not None
@ -212,7 +215,7 @@ class Channel:
else: else:
key_send = self.channel_cache.get(CHANNEL_KEY_SEND) key_send = self.channel_cache.get(CHANNEL_KEY_SEND)
nonce_send = self.channel_cache.get_int(CHANNEL_NONCE_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 key_send is not None
assert nonce_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/ 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.host_public_key: bytes = cpace_host_public_key
self.shared_secret: bytes
self.trezor_private_key: bytes self.trezor_private_key: bytes
self.trezor_public_key: bytes self.trezor_public_key: bytes
self.shared_secret: bytes
def generate_keys_and_secret(self, code_code_entry: bytes) -> None: def generate_keys_and_secret(self, code_code_entry: bytes) -> None:
""" """
Generate ephemeral key pair and a shared secret using Elligator2 with X25519. Generate ephemeral key pair and a shared secret using Elligator2 with X25519.
""" """
pregenerator = sha512(_PREFIX + code_code_entry + _PADDING).digest()[ sha_ctx = sha512(_PREFIX)
:32 sha_ctx.update(code_code_entry)
] # TODO add handshake hash sha_ctx.update(_PADDING)
sha_ctx.update(self.handshake_hash)
pregenerator = sha_ctx.digest()[:32]
generator = elligator2.map_to_curve25519(pregenerator) generator = elligator2.map_to_curve25519(pregenerator)
self.trezor_private_key = random.bytes(32) self.trezor_private_key = random.bytes(32)
if __debug__: if __debug__: