Algorithms

HKDF

Extract then expand. One strong secret in and the separate keys a protocol needs out. No cost and no random salt
IDhkdf26 / 27HKDF · variable
Hash / Cryptographic

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
5 options, 0 required

Sample

hex
c2aff8621532163942d7bd28ec323af52af2b3e0effc8bd9d25c3e2aba60d917
base64
wq/4YhUyFjlC170o7DI69Srys+Dv/IvZ0lw+Krpg2Rc=

Options

encodingstring
default hex
Output encoding: hex, base64, base64url, binary
saltstring
optional
Salt in hex; zeros when omitted
infostring
optional
Context in hex that binds the key to its use
digeststring
default sha256
Underlying hash: sha256, sha384, sha512, sha3-256, sha3-512
keyLengthnumber
default 32
Output key length in bytes, at most 255 digests

Access

Createcreate("hkdf")
CLIhashes 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.

ts
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.