Module crypto/hmac
HMAC (RFC 2104) — generic over any Digest implementor
(plans/archive/STD_API_AUDIT.md §7 P0 item 7: "blocks JWT/SigV4/webhooks").
{ hmac_sha256_hex } :: import("std/crypto/hmac");
sig := hmac_sha256_hex(key_bytes, message_bytes);
Stability
unstable — the values are right and tested against the RFC 2202 and
RFC 4231 vectors, including the key-longer-than-the-block case
(tests/crypto/digest.test.yo), and the naming follows the
hmac_<hash> / hmac_<hash>_hex pattern the rest of std/crypto
uses. What is not settled is everything around the one-shot: HMAC here
is one call over a whole message, so there is no way to authenticate a
stream too large to hold (the Digest trait it is written over has no
reset, which is the same open row). Key material is an ordinary
ArrayList(u8) and is never zeroized — the K', ikey and okey
buffers are left to the allocator — so this is not the module to build
a long-lived key store on. constant_time_eq also lives here for want
of a subtle-style home; it is a byte comparison with no timing
dependence on the CONTENTS, and it is what verification must use
instead of == on a hex String.
Functions
HMAC over any Digest: H((K' ^ opad) || H((K' ^ ipad) || message)),
with K' the key hashed down (if longer than the block) then
zero-padded to the block size.
Parameters
| Name | Type | Notes |
|---|---|---|
D | Type | comptime |
key | ArrayList(u8) | |
message | ArrayList(u8) |
Returns: ArrayList(u8)
Constant-time byte comparison — verify MACs with this, never ==:
an early-exit compare leaks WHERE the first mismatch sits, which lets an
attacker forge a MAC byte-by-byte over the network.
Parameters
| Name | Type | Notes |
|---|---|---|
a | ArrayList(u8) | |
b | ArrayList(u8) |
Returns: bool