[{"data":1,"prerenderedAt":339},["ShallowReactive",2],{"navigation_docs":3,"-algorithms-hkdf":156,"-algorithms-hkdf-surround":334},[4,40],{"title":5,"path":6,"stem":7,"children":8,"icon":39},"Guide","\u002Fguide","1.guide\u002F01.index",[9,11,15,19,23,27,31,35],{"title":10,"path":6,"stem":7},"Getting Started",{"title":12,"path":13,"stem":14},"Hashing","\u002Fguide\u002Fhashing","1.guide\u002F02.hashing",{"title":16,"path":17,"stem":18},"HMAC and verify","\u002Fguide\u002Fverify","1.guide\u002F03.verify",{"title":20,"path":21,"stem":22},"Salted KDFs","\u002Fguide\u002Fkdf","1.guide\u002F04.kdf",{"title":24,"path":25,"stem":26},"CLI","\u002Fguide\u002Fcli","1.guide\u002F05.cli",{"title":28,"path":29,"stem":30},"Agents","\u002Fguide\u002Fagents","1.guide\u002F06.agents",{"title":32,"path":33,"stem":34},"Custom algorithms","\u002Fguide\u002Fcustom","1.guide\u002F07.custom",{"title":36,"path":37,"stem":38},"Playground","\u002Fguide\u002Fplayground","1.guide\u002F08.playground","i-lucide-book-open",{"title":41,"path":42,"stem":43,"children":44,"icon":155},"Algorithms","\u002Falgorithms","2.algorithms\u002F00.index",[45,47,51,55,59,63,67,71,75,79,83,87,91,95,99,103,107,111,115,119,123,127,131,135,139,143,147,151],{"title":46,"path":42,"stem":43},"Every algorithm",{"title":48,"path":49,"stem":50},"SHA-256","\u002Falgorithms\u002Fsha256","2.algorithms\u002F01.sha256",{"title":52,"path":53,"stem":54},"SHA-384","\u002Falgorithms\u002Fsha384","2.algorithms\u002F02.sha384",{"title":56,"path":57,"stem":58},"SHA-512","\u002Falgorithms\u002Fsha512","2.algorithms\u002F03.sha512",{"title":60,"path":61,"stem":62},"SHA-512Half","\u002Falgorithms\u002Fsha512-half","2.algorithms\u002F04.sha512-half",{"title":64,"path":65,"stem":66},"SHA3-256","\u002Falgorithms\u002Fsha3-256","2.algorithms\u002F05.sha3-256",{"title":68,"path":69,"stem":70},"SHA3-512","\u002Falgorithms\u002Fsha3-512","2.algorithms\u002F06.sha3-512",{"title":72,"path":73,"stem":74},"Keccak-256","\u002Falgorithms\u002Fkeccak256","2.algorithms\u002F07.keccak256",{"title":76,"path":77,"stem":78},"BLAKE2b","\u002Falgorithms\u002Fblake2b","2.algorithms\u002F08.blake2b",{"title":80,"path":81,"stem":82},"BLAKE2b-256","\u002Falgorithms\u002Fblake2b-256","2.algorithms\u002F09.blake2b-256",{"title":84,"path":85,"stem":86},"BLAKE2b-224","\u002Falgorithms\u002Fblake2b-224","2.algorithms\u002F10.blake2b-224",{"title":88,"path":89,"stem":90},"BLAKE2s","\u002Falgorithms\u002Fblake2s","2.algorithms\u002F11.blake2s",{"title":92,"path":93,"stem":94},"BLAKE3","\u002Falgorithms\u002Fblake3","2.algorithms\u002F12.blake3",{"title":96,"path":97,"stem":98},"BLAKE-256","\u002Falgorithms\u002Fblake256","2.algorithms\u002F13.blake256",{"title":100,"path":101,"stem":102},"RIPEMD-160","\u002Falgorithms\u002Fripemd160","2.algorithms\u002F14.ripemd160",{"title":104,"path":105,"stem":106},"HASH160","\u002Falgorithms\u002Fhash160","2.algorithms\u002F15.hash160",{"title":108,"path":109,"stem":110},"HASH256","\u002Falgorithms\u002Fhash256","2.algorithms\u002F16.hash256",{"title":112,"path":113,"stem":114},"MD5","\u002Falgorithms\u002Fmd5","2.algorithms\u002F17.md5",{"title":116,"path":117,"stem":118},"SHA-1","\u002Falgorithms\u002Fsha1","2.algorithms\u002F18.sha1",{"title":120,"path":121,"stem":122},"SHA-0","\u002Falgorithms\u002Fsha0","2.algorithms\u002F19.sha0",{"title":124,"path":125,"stem":126},"CRC-32","\u002Falgorithms\u002Fcrc32","2.algorithms\u002F20.crc32",{"title":128,"path":129,"stem":130},"CRC-16\u002FXMODEM","\u002Falgorithms\u002Fcrc16-xmodem","2.algorithms\u002F21.crc16-xmodem",{"title":132,"path":133,"stem":134},"xxHash (XXH64)","\u002Falgorithms\u002Fxxhash","2.algorithms\u002F22.xxhash",{"title":136,"path":137,"stem":138},"FNV-1a (64-bit)","\u002Falgorithms\u002Ffnv1a","2.algorithms\u002F23.fnv1a",{"title":140,"path":141,"stem":142},"scrypt","\u002Falgorithms\u002Fscrypt","2.algorithms\u002F24.scrypt",{"title":144,"path":145,"stem":146},"PBKDF2","\u002Falgorithms\u002Fpbkdf2","2.algorithms\u002F25.pbkdf2",{"title":148,"path":149,"stem":150},"HKDF","\u002Falgorithms\u002Fhkdf","2.algorithms\u002F26.hkdf",{"title":152,"path":153,"stem":154},"EVP_BytesToKey","\u002Falgorithms\u002Fevp-bytestokey","2.algorithms\u002F27.evp-bytestokey","i-lucide-library",{"id":157,"title":148,"body":158,"description":327,"extension":328,"links":329,"meta":330,"navigation":331,"path":149,"seo":332,"stem":150,"__hash__":333},"docs\u002F2.algorithms\u002F26.hkdf.md",{"type":159,"value":160,"toc":325},"minimark",[161,165,169,180,274,296,314,321],[162,163],"algorithm-facts",{"name":164},"hkdf",[166,167,168],"p",{},"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.",[166,170,171,172,176,177,179],{},"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 ",[173,174,175],"code",{},"info"," and a counter, until there are enough bytes. Same secret, different ",[173,178,175],{},", unrelated keys. That's the whole trick.",[181,182,187],"pre",{"className":183,"code":184,"language":185,"meta":186,"style":186},"language-ts shiki shiki-themes hashes hashes hashes","create(\"hkdf\").hash(Uint8Array.fromHex(\"0b\".repeat(22)), {\n  salt: \"000102030405060708090a0b0c\",\n  info: \"f0f1f2f3f4f5f6f7f8f9\",\n  keyLength: 42,\n}).digest;\n\u002F\u002F \"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865\"\n","ts","",[173,188,189,232,244,255,261,267],{"__ignoreMap":186},[190,191,194,198,202,206,209,212,215,218,220,223,226,229],"span",{"class":192,"line":193},"line",1,[190,195,197],{"class":196},"sK71F","create",[190,199,201],{"class":200},"s38Sx","(",[190,203,205],{"class":204},"shU9J","\"hkdf\"",[190,207,208],{"class":200},").",[190,210,211],{"class":196},"hash",[190,213,214],{"class":200},"(Uint8Array.",[190,216,217],{"class":196},"fromHex",[190,219,201],{"class":200},[190,221,222],{"class":204},"\"0b\"",[190,224,225],{"class":200},".",[190,227,228],{"class":196},"repeat",[190,230,231],{"class":200},"(22)), {\n",[190,233,235,238,241],{"class":192,"line":234},2,[190,236,237],{"class":200},"  salt: ",[190,239,240],{"class":204},"\"000102030405060708090a0b0c\"",[190,242,243],{"class":200},",\n",[190,245,247,250,253],{"class":192,"line":246},3,[190,248,249],{"class":200},"  info: ",[190,251,252],{"class":204},"\"f0f1f2f3f4f5f6f7f8f9\"",[190,254,243],{"class":200},[190,256,258],{"class":192,"line":257},4,[190,259,260],{"class":200},"  keyLength: 42,\n",[190,262,264],{"class":192,"line":263},5,[190,265,266],{"class":200},"}).digest;\n",[190,268,270],{"class":192,"line":269},6,[190,271,273],{"class":272},"scIB-","\u002F\u002F \"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865\"\n",[166,275,276,277,280,281,283,284,287,288,291,292,295],{},"Recognize it? It's test case 1 from RFC 5869. ",[173,278,279],{},"salt"," and ",[173,282,175],{}," 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. ",[173,285,286],{},"digest"," picks the hash under HMAC, ",[173,289,290],{},"sha256"," by default. ",[173,293,294],{},"keyLength"," stops at 255 digests, 8160 bytes with SHA-256.",[166,297,298,299,280,302,305,306,309,310,313],{},"Some protocols call only one step. ",[173,300,301],{},"hkdfExtract",[173,303,304],{},"hkdfExpand"," from ",[173,307,308],{},"@agntn\u002Fhashes\u002Fhmac"," take bytes and a hasher, like ",[173,311,312],{},"hmac"," does.",[166,315,316,317,320],{},"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 ",[318,319,140],"a",{"href":141}," is for.",[322,323,324],"style",{},"html pre.shiki code .sK71F, html code.shiki .sK71F{--shiki-light:var(--shiki-token-function);--shiki-default:var(--shiki-token-function);--shiki-dark:var(--shiki-token-function)}html pre.shiki code .s38Sx, html code.shiki .s38Sx{--shiki-light:var(--ui-text-highlighted);--shiki-default:var(--ui-text-highlighted);--shiki-dark:var(--ui-text-highlighted)}html pre.shiki code .shU9J, html code.shiki .shU9J{--shiki-light:var(--shiki-token-string);--shiki-default:var(--shiki-token-string);--shiki-dark:var(--shiki-token-string)}html pre.shiki code .scIB-, html code.shiki .scIB-{--shiki-light:var(--shiki-token-comment);--shiki-default:var(--shiki-token-comment);--shiki-dark:var(--shiki-token-comment)}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":186,"searchDepth":234,"depth":234,"links":326},[],"Extract then expand. One strong secret in and the separate keys a protocol needs out. No cost and no random salt","md",null,{},true,{"title":148,"description":327},"NmEoWDddj5_VF6FSyIJqKu0HZSUsXVmMIMJoK0PpOEg",[335,337],{"title":144,"path":145,"stem":146,"description":336,"children":-1},"HMAC run a few hundred thousand times. The NIST password KDF with a salt and iterations and a choice of hash",{"title":152,"path":153,"stem":154,"description":338,"children":-1},"The key and IV behind openssl enc without -pbkdf2 and behind CryptoJS with a passphrase. Old and weak and still everywhere",1790830341506]