HKDF
HKDF
One strong secret, as many keys as the protocol needs.
- Digest
- keyLength you pick
- HMAC
- no key mode
- Security
- Not for passwords: HKDF adds no cost
- Family
- 1 in HKDF
Sample
- hex
- c2aff8621532163942d7bd28ec323af52af2b3e0effc8bd9d25c3e2aba60d917
- base64
- wq/4YhUyFjlC170o7DI69Srys+Dv/IvZ0lw+Krpg2Rc=
Options
Access
- Create
create("hkdf") - CLI
hashes hkdf 'hello world' - Tryplayground with the sample above
You already have a good secret. An ECDH shared secret, say, or a master key. What you don't have is the three separate keys the protocol wants from it. That's HKDF's job. TLS 1.3 builds its whole key schedule on it, and Signal does too.
It works in two steps. Extract runs HMAC with the salt as the key and squeezes your input into one pseudorandom key. Expand chains HMAC blocks over that key, with info and a counter, until there are enough bytes. Same secret, different info, unrelated keys. That's the whole trick.
create("hkdf").hash(Uint8Array.fromHex("0b".repeat(22)), {
salt: "000102030405060708090a0b0c",
info: "f0f1f2f3f4f5f6f7f8f9",
keyLength: 42,
}).digest;
// "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865"
Recognize it? It's test case 1 from RFC 5869. salt and info are hex. Leave the salt out and HKDF uses zeros, as the RFC says. So the same call gives the same key every time, and verify needs no salt. That's the opposite of scrypt and PBKDF2, which draw one. digest picks the hash under HMAC, sha256 by default. keyLength stops at 255 digests, 8160 bytes with SHA-256.
Some protocols call only one step. hkdfExtract and hkdfExpand from @agntn/hashes/hmac take bytes and a hasher, like hmac does.
Can it hash a password? Please don't. It costs one HMAC per block, so a guessable password stays guessable, only faster. That's what scrypt is for.