What changed, and why it matters
This commit replaces ordinary byte-string comparisons with a constant-time equality check (consteq) when verifying authentication tags in Trezor's THP (Trezor Host Protocol) cryptography. In theory, a standard '==' comparison can leak timing information that might help an attacker forge or tamper with encrypted messages. The change is defensive and reduces the risk of timing side-channels, but the commit itself does not claim a fix for any known exploitable vulnerability.
Treat as a defensive security hardening patch. Review whether other tag/MAC comparisons in the firmware use consteq, and consider whether the Python runtime on the device makes consteq effective (e.g., no early-exit optimizations). No immediate incident response is indicated unless a separate advisory is published.
Security signals we found
Use of constant-time comparison (consteq) for cryptographic authentication tags
Change is in THP/Noise handshake and AES-GCM decryption path
Timing side-channel hardening in a hardware-wallet firmware crypto module
No changelog entry and no explicit security advisory language in commit
Evidence from the diff
The patch changes four tag-comparison sites in core/src/trezor/wire/thp/crypto.py from Python’s ‘==’ operator to utils.consteq. The affected sites are: (1) dec() return comparing the computed AES-GCM tag to the supplied tag; (2) BusyDecoder.finish_and_check_tag(); (3) Handshake static-pubkey tag verification; and (4) Handshake encrypted-payload tag verification. AES-GCM authentication tags should be compared in constant time to avoid leaking the position or number of matching bytes, which can be relevant in some oracle or forgery scenarios. The patch is a hardening measure rather than a complete rewrite of the protocol.
Changed components
core/src/trezor/wire/thp/crypto.pyTHP (Trezor Host Protocol) handshakeAES-GCM decryption and tag verificationNoise_XX_25519_AESGCM_SHA256 handshake implementationInspect captured patch +4 / −4
diff --git a/core/src/trezor/wire/thp/crypto.py b/core/src/trezor/wire/thp/crypto.py
index 1908866a..58e5114b 100644
--- a/core/src/trezor/wire/thp/crypto.py
+++ b/core/src/trezor/wire/thp/crypto.py
@@ -54,7 +54,7 @@ def dec(
aes_ctx.auth(auth_data)
aes_ctx.decrypt_in_place(buffer)
computed_tag = aes_ctx.finish()
- return computed_tag == tag
+ return utils.consteq(computed_tag, tag)
class BusyDecoder:
@@ -69,7 +69,7 @@ class BusyDecoder:
def finish_and_check_tag(self, tag: bytes) -> bool:
computed_tag = self.aes_ctx.finish()
- return computed_tag == tag
+ return utils.consteq(computed_tag, tag)
PROTOCOL_NAME = b"Noise_XX_25519_AESGCM_SHA256\x00\x00\x00\x00"
@@ -173,7 +173,7 @@ class Handshake:
:PUBKEY_LENGTH
]
tag = aes_ctx.finish()
- if tag != encrypted_host_static_public_key[-16:]:
+ if not utils.consteq(tag, encrypted_host_static_public_key[-16:]):
raise ThpDecryptionError()
self.ck, self.k = _hkdf(
@@ -191,7 +191,7 @@ class Handshake:
__name__, "th2 - dec (key: %s, nonce: %d)", hexlify_if_bytes(self.k), 0
)
tag = aes_ctx.finish()
- if tag != encrypted_payload[-16:]:
+ if not utils.consteq(tag, encrypted_payload[-16:]):
raise ThpDecryptionError()
self.key_receive, self.key_send = _hkdf(self.ck, b"")
Why this scored 60/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.