Functional Weave
Code in Python

crypto.hmac-sha256@1.0.0

README.md

1,691 bytes · view raw

# crypto.hmac-sha256

`hmacSha256(key, message)` is the 32-byte HMAC-SHA256 tag of `message` under
`key`, as RFC 2104 defines HMAC and RFC 4231 pins it for SHA-256. It is what
signs an HS256 JWT (`auth.jwt`), a webhook payload or a signed cookie.

Bytes in and out are lists of integers 0 to 255, as everywhere in the registry
(see `encoding.hex`). A text secret or message goes through `encoding.utf8`
first.

The construction is `H((K xor opad) || H((K xor ipad) || message))` with the
key zero-padded to SHA-256's 64-byte block, or first hashed to 32 bytes when
it is longer than 64. That last rule is the one a naive implementation misses,
and RFC 4231 test cases 6 and 7 (a 131-byte key) are among the vectors. The
empty key is allowed, as the RFC allows it, but a real key should be at least
32 random bytes (RFC 2104 section 3; RFC 7518 requires it for HS256).

**Compare tags with `crypto.constant-time-equal`.** Comparing with `==` stops
at the first differing byte, and the time that takes tells an attacker how
many leading bytes of a forged tag were right.

TypeScript and Rust build on `crypto.sha256` and so run anywhere, the browser
included, with no `node:crypto` or `crypto.subtle`; Python uses the standard
library's `hmac`. Test case 5 of RFC 4231 publishes only the first 16 bytes of
its tag; its vector holds the full 32, computed with Python's `hmac` module as
the reference, and begins with the RFC's 16.

Source: RFC 2104, HMAC: Keyed-Hashing for Message Authentication
(https://www.rfc-editor.org/rfc/rfc2104); RFC 4231, Identifiers and Test
Vectors for HMAC-SHA-224, HMAC-SHA-256, HMAC-SHA-384, and HMAC-SHA-512,
section 4 (https://www.rfc-editor.org/rfc/rfc4231).