std/digest/hmac

std/digest/src/hmac.trb

Hmac, HMAC (RFC 2104) over any Hasher: SCRAM (postgres, mongodb), S3's Signature Version 4, JWT's HS256, SMTP's CRAM-MD5. HmacSha256, HmacSha1 and HmacMd5 name the three combinations the packages after std need.

The key is folded into the hasher once, not once a round. Hmac.keyed pads the key to a block, hashes the two pads into a fresh inner and outer hasher, and keeps only those two - never the key itself. From there, Hmac is a hasher itself: Hmac.add feeds the message into the (already-keyed) inner hasher, and Hmac.finished closes it and folds the result into a copy of the outer one. A round of Hmac.pbkdf2 copies the keyed Hmac - copying a value costs its size, not its history - so 4 096 rounds hash the key's two blocks once between them, not 8 192 times.

type Hmac

type Hmac<H: Hasher>

HMAC over H, keyed once and reused: the shape of Sha256 and the rest, so it is fed the same way.

Examples

print HmacSha256.of("key".bytes(), "message".bytes()).hex()

fn keyed

static fn keyed(key: Bytes): Self

A fresh Hmac keyed with key: the key alone, folded into an inner and an outer hasher and then forgotten.

fn add

var fn add(bytes: Bytes)

Feeds the next bytes of the message.

fn finished

fn finished(): Digest

The MAC of everything added so far. self is unchanged - the inner and outer hashers are copied first - so an Hmac keeps being fed after this, exactly as Sha256.finished leaves its hasher open.

fn of

static fn of(key: Bytes, message: Bytes): Digest

The MAC of message under key, in one call.

alias HmacSha256

type HmacSha256 = Hmac<Sha256>

HMAC-SHA-256: SCRAM-SHA-256, AWS Signature Version 4, JWT's HS256.

alias HmacSha1

type HmacSha1 = Hmac<Sha1>

HMAC-SHA-1: SCRAM-SHA-1 (mongodb), and the older signature schemes that have not moved to SHA-256.

alias HmacMd5

type HmacMd5 = Hmac<Md5>

HMAC-MD5: SMTP's CRAM-MD5, the one place HMAC still meets Md5.