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:
parent
45e2819789
commit
1bf927c943
@ -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")
|
||||||
|
@ -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
|
||||||
|
@ -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__:
|
||||||
|
Loading…
Reference in New Issue
Block a user