[{"data":1,"prerenderedAt":507},["ShallowReactive",2],{"navigation_docs":3,"-ciphers-xchacha20":276,"-ciphers-xchacha20-surround":502},[4,36],{"title":5,"path":6,"stem":7,"children":8,"icon":35},"Guide","\u002Fguide","1.guide\u002F01.index",[9,11,15,19,23,27,31],{"title":10,"path":6,"stem":7},"Getting Started",{"title":12,"path":13,"stem":14},"Encode and decode","\u002Fguide\u002Ftransform","1.guide\u002F02.transform",{"title":16,"path":17,"stem":18},"Analysis","\u002Fguide\u002Fanalysis","1.guide\u002F03.analysis",{"title":20,"path":21,"stem":22},"CLI","\u002Fguide\u002Fcli","1.guide\u002F04.cli",{"title":24,"path":25,"stem":26},"Agents","\u002Fguide\u002Fagents","1.guide\u002F05.agents",{"title":28,"path":29,"stem":30},"Custom ciphers","\u002Fguide\u002Fcustom","1.guide\u002F06.custom",{"title":32,"path":33,"stem":34},"Playground","\u002Fguide\u002Fplayground","1.guide\u002F07.playground","i-lucide-book-open",{"title":37,"path":38,"stem":39,"children":40,"icon":275},"Ciphers","\u002Fciphers","2.ciphers\u002F00.index",[41,43,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,155,159,163,167,171,175,179,183,187,191,195,199,203,207,211,215,219,223,227,231,235,239,243,247,251,255,259,263,267,271],{"title":42,"path":38,"stem":39},"Overview",{"title":44,"path":45,"stem":46},"Classical","\u002Fciphers\u002Fclassical","2.ciphers\u002F01.classical",{"title":48,"path":49,"stem":50},"Caesar","\u002Fciphers\u002Fcaesar","2.ciphers\u002F02.caesar",{"title":52,"path":53,"stem":54},"ROT-13","\u002Fciphers\u002Frot13","2.ciphers\u002F03.rot13",{"title":56,"path":57,"stem":58},"ROT-47","\u002Fciphers\u002Frot47","2.ciphers\u002F04.rot47",{"title":60,"path":61,"stem":62},"Atbash","\u002Fciphers\u002Fatbash","2.ciphers\u002F05.atbash",{"title":64,"path":65,"stem":66},"Affine","\u002Fciphers\u002Faffine","2.ciphers\u002F06.affine",{"title":68,"path":69,"stem":70},"Vigenère","\u002Fciphers\u002Fvigenere","2.ciphers\u002F07.vigenere",{"title":72,"path":73,"stem":74},"Beaufort","\u002Fciphers\u002Fbeaufort","2.ciphers\u002F08.beaufort",{"title":76,"path":77,"stem":78},"Autokey","\u002Fciphers\u002Fautokey","2.ciphers\u002F09.autokey",{"title":80,"path":81,"stem":82},"Trithemius","\u002Fciphers\u002Ftrithemius","2.ciphers\u002F10.trithemius",{"title":84,"path":85,"stem":86},"Alberti","\u002Fciphers\u002Falberti","2.ciphers\u002F11.alberti",{"title":88,"path":89,"stem":90},"Playfair","\u002Fciphers\u002Fplayfair","2.ciphers\u002F12.playfair",{"title":92,"path":93,"stem":94},"Polybius square","\u002Fciphers\u002Fpolybius","2.ciphers\u002F13.polybius",{"title":96,"path":97,"stem":98},"Morse code","\u002Fciphers\u002Fmorse","2.ciphers\u002F14.morse",{"title":100,"path":101,"stem":102},"Bacon's cipher","\u002Fciphers\u002Fbacon","2.ciphers\u002F15.bacon",{"title":104,"path":105,"stem":106},"Tap code","\u002Fciphers\u002Ftap-code","2.ciphers\u002F16.tap-code",{"title":108,"path":109,"stem":110},"A1Z26","\u002Fciphers\u002Fa1z26","2.ciphers\u002F17.a1z26",{"title":112,"path":113,"stem":114},"Book cipher","\u002Fciphers\u002Fbook","2.ciphers\u002F18.book",{"title":116,"path":117,"stem":118},"ADFGVX","\u002Fciphers\u002Fadfgvx","2.ciphers\u002F19.adfgvx",{"title":120,"path":121,"stem":122},"Bifid","\u002Fciphers\u002Fbifid","2.ciphers\u002F20.bifid",{"title":124,"path":125,"stem":126},"Straddling checkerboard","\u002Fciphers\u002Fstraddling-checkerboard","2.ciphers\u002F21.straddling-checkerboard",{"title":128,"path":129,"stem":130},"Rail fence","\u002Fciphers\u002Frail-fence","2.ciphers\u002F22.rail-fence",{"title":132,"path":133,"stem":134},"Columnar transposition","\u002Fciphers\u002Fcolumnar","2.ciphers\u002F23.columnar",{"title":136,"path":137,"stem":138},"Route transposition","\u002Fciphers\u002Froute","2.ciphers\u002F24.route",{"title":140,"path":141,"stem":142},"Enigma M3","\u002Fciphers\u002Fenigma","2.ciphers\u002F25.enigma",{"title":144,"path":145,"stem":146},"Block","\u002Fciphers\u002Fblock","2.ciphers\u002F26.block",{"title":148,"path":149,"stem":150},"AES (ECB)","\u002Fciphers\u002Faes","2.ciphers\u002F27.aes",{"title":152,"path":153,"stem":154},"AES (CBC)","\u002Fciphers\u002Faes-cbc","2.ciphers\u002F28.aes-cbc",{"title":156,"path":157,"stem":158},"AES (CFB)","\u002Fciphers\u002Faes-cfb","2.ciphers\u002F29.aes-cfb",{"title":160,"path":161,"stem":162},"AES (OFB)","\u002Fciphers\u002Faes-ofb","2.ciphers\u002F30.aes-ofb",{"title":164,"path":165,"stem":166},"AES (CTR)","\u002Fciphers\u002Faes-ctr","2.ciphers\u002F31.aes-ctr",{"title":168,"path":169,"stem":170},"AES (CCM)","\u002Fciphers\u002Faes-ccm","2.ciphers\u002F32.aes-ccm",{"title":172,"path":173,"stem":174},"AES (OCB)","\u002Fciphers\u002Faes-ocb","2.ciphers\u002F33.aes-ocb",{"title":176,"path":177,"stem":178},"AES (LRW)","\u002Fciphers\u002Faes-lrw","2.ciphers\u002F34.aes-lrw",{"title":180,"path":181,"stem":182},"AES (XTS)","\u002Fciphers\u002Faes-xts","2.ciphers\u002F35.aes-xts",{"title":184,"path":185,"stem":186},"AES (CBC-MAC)","\u002Fciphers\u002Faes-cbc-mac","2.ciphers\u002F36.aes-cbc-mac",{"title":188,"path":189,"stem":190},"AES (passphrase)","\u002Fciphers\u002Faes-passphrase","2.ciphers\u002F37.aes-passphrase",{"title":192,"path":193,"stem":194},"Rijndael (ECB)","\u002Fciphers\u002Frijndael","2.ciphers\u002F38.rijndael",{"title":196,"path":197,"stem":198},"DES (ECB)","\u002Fciphers\u002Fdes","2.ciphers\u002F39.des",{"title":200,"path":201,"stem":202},"DESX (ECB)","\u002Fciphers\u002Fdesx","2.ciphers\u002F40.desx",{"title":204,"path":205,"stem":206},"Triple DES (ECB)","\u002Fciphers\u002Ftriple-des","2.ciphers\u002F41.triple-des",{"title":208,"path":209,"stem":210},"Triple DES (CBC)","\u002Fciphers\u002Ftriple-des-cbc","2.ciphers\u002F42.triple-des-cbc",{"title":212,"path":213,"stem":214},"Blowfish (ECB)","\u002Fciphers\u002Fblowfish","2.ciphers\u002F43.blowfish",{"title":216,"path":217,"stem":218},"IDEA (ECB)","\u002Fciphers\u002Fidea","2.ciphers\u002F44.idea",{"title":220,"path":221,"stem":222},"Lucifer (ECB)","\u002Fciphers\u002Flucifer","2.ciphers\u002F45.lucifer",{"title":224,"path":225,"stem":226},"MARS (ECB)","\u002Fciphers\u002Fmars","2.ciphers\u002F46.mars",{"title":228,"path":229,"stem":230},"Serpent (ECB)","\u002Fciphers\u002Fserpent","2.ciphers\u002F47.serpent",{"title":232,"path":233,"stem":234},"CAST5 (ECB)","\u002Fciphers\u002Fcast5","2.ciphers\u002F48.cast5",{"title":236,"path":237,"stem":238},"OpenPGP (passphrase)","\u002Fciphers\u002Fopenpgp","2.ciphers\u002F49.openpgp",{"title":240,"path":241,"stem":242},"Stream","\u002Fciphers\u002Fstream","2.ciphers\u002F50.stream",{"title":244,"path":245,"stem":246},"Rabbit","\u002Fciphers\u002Frabbit","2.ciphers\u002F51.rabbit",{"title":248,"path":249,"stem":250},"RC4","\u002Fciphers\u002Frc4","2.ciphers\u002F52.rc4",{"title":252,"path":253,"stem":254},"XOR","\u002Fciphers\u002Fxor","2.ciphers\u002F53.xor",{"title":256,"path":257,"stem":258},"Salsa20","\u002Fciphers\u002Fsalsa20","2.ciphers\u002F54.salsa20",{"title":260,"path":261,"stem":262},"XSalsa20","\u002Fciphers\u002Fxsalsa20","2.ciphers\u002F55.xsalsa20",{"title":264,"path":265,"stem":266},"ChaCha20","\u002Fciphers\u002Fchacha20","2.ciphers\u002F56.chacha20",{"title":268,"path":269,"stem":270},"XChaCha20","\u002Fciphers\u002Fxchacha20","2.ciphers\u002F57.xchacha20",{"title":272,"path":273,"stem":274},"ChaCha20-Poly1305","\u002Fciphers\u002Fchacha20-poly1305","2.ciphers\u002F58.chacha20-poly1305","i-lucide-library",{"id":277,"title":268,"body":278,"description":495,"extension":496,"links":497,"meta":498,"navigation":499,"path":269,"seo":500,"stem":270,"__hash__":501},"docs\u002F2.ciphers\u002F57.xchacha20.md",{"type":279,"value":280,"toc":490},"minimark",[281,285,293,296,301,304,310,314,326,435,446,453,466,470,473,483,486],[282,283],"cipher-facts",{"name":284},"xchacha20",[286,287,288,289,292],"p",{},"Remember how ",[290,291,260],"a",{"href":261}," stretched the Salsa20 nonce? XChaCha20 does exactly that to ChaCha20. libsodium has it, and draft-irtf-cfrg-xchacha by Scott Arciszewski writes it down.",[286,294,295],{},"Why bother? Twelve random bytes of nonce collide after about 2^48 messages. Sounds like a lot until you run a busy server for a few years. Twenty-four bytes, and you can stop counting.",[297,298,300],"h2",{"id":299},"how-it-runs","How it runs",[286,302,303],{},"Two steps, both cheap. HChaCha20 runs the ChaCha rounds over the key and the first 16 nonce bytes, where counter and nonce would sit. Nothing gets added back. The first and last rows of the result are a fresh 256-bit subkey.",[286,305,306,307,309],{},"Then ",[290,308,264],{"href":265}," runs under that subkey. Its 12-byte nonce is four zero bytes and the last 8 bytes of yours.",[297,311,313],{"id":312},"keys-nonce-and-counter","Keys, nonce and counter",[286,315,316,317,321,322,325],{},"The key is 64 hex digits. ",[318,319,320],"code",{},"nonce"," is 48 hex digits and required. ",[318,323,324],{},"counter"," is the ChaCha20 block counter, 0 to 4294967295, default 0.",[327,328,333],"pre",{"className":329,"code":330,"language":331,"meta":332,"style":332},"language-ts shiki shiki-themes ciphers ciphers ciphers","const xchacha = create(\"xchacha20\");\nconst key = \"808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f\";\nconst nonce = \"404142434445464748494a4b4c4d4e4f5051525354555658\";\nxchacha.encode(\"ATTACK AT DAWN\", { key, nonce }).text; \u002F\u002F \"50659adb696b8e4c33e8d71d20c7\"\nxchacha.decode(\"50659adb696b8e4c33e8d71d20c7\", { key, nonce }).text; \u002F\u002F \"ATTACK AT DAWN\"\n","ts","",[318,334,335,365,381,396,417],{"__ignoreMap":332},[336,337,340,344,348,351,355,358,362],"span",{"class":338,"line":339},"line",1,[336,341,343],{"class":342},"skH_V","const",[336,345,347],{"class":346},"s38Sx"," xchacha ",[336,349,350],{"class":342},"=",[336,352,354],{"class":353},"sK71F"," create",[336,356,357],{"class":346},"(",[336,359,361],{"class":360},"shU9J","\"xchacha20\"",[336,363,364],{"class":346},");\n",[336,366,368,370,373,375,378],{"class":338,"line":367},2,[336,369,343],{"class":342},[336,371,372],{"class":346}," key ",[336,374,350],{"class":342},[336,376,377],{"class":360}," \"808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f\"",[336,379,380],{"class":346},";\n",[336,382,384,386,389,391,394],{"class":338,"line":383},3,[336,385,343],{"class":342},[336,387,388],{"class":346}," nonce ",[336,390,350],{"class":342},[336,392,393],{"class":360}," \"404142434445464748494a4b4c4d4e4f5051525354555658\"",[336,395,380],{"class":346},[336,397,399,402,405,407,410,413],{"class":338,"line":398},4,[336,400,401],{"class":346},"xchacha.",[336,403,404],{"class":353},"encode",[336,406,357],{"class":346},[336,408,409],{"class":360},"\"ATTACK AT DAWN\"",[336,411,412],{"class":346},", { key, nonce }).text; ",[336,414,416],{"class":415},"scIB-","\u002F\u002F \"50659adb696b8e4c33e8d71d20c7\"\n",[336,418,420,422,425,427,430,432],{"class":338,"line":419},5,[336,421,401],{"class":346},[336,423,424],{"class":353},"decode",[336,426,357],{"class":346},[336,428,429],{"class":360},"\"50659adb696b8e4c33e8d71d20c7\"",[336,431,412],{"class":346},[336,433,434],{"class":415},"\u002F\u002F \"ATTACK AT DAWN\"\n",[286,436,437,438,441,442,445],{},"That's the key and nonce from the draft's examples. Spot the ",[318,439,440],{},"58"," at the end? It's not a typo here. The draft really skips ",[318,443,444],{},"57",".",[286,447,448,449,452],{},"The draft has two examples, one from counter 0 and one from counter 1, and both decrypt the same text. libsodium's ",[318,450,451],{},"crypto_stream_xchacha20"," starts at 0. Its AEAD starts at 1, same as ChaCha20-Poly1305.",[286,454,455,458,459,462,463,445],{},[318,456,457],{},"xchacha20(data, key, nonce, counter)"," from ",[318,460,461],{},"@agntn\u002Fciphers\u002Fchacha"," does the same on ",[318,464,465],{},"Uint8Array",[297,467,469],{"id":468},"checked-against","Checked against",[286,471,472],{},"The HChaCha20 vector from section 2.2.1 of draft-irtf-cfrg-xchacha-03, and the dhole text from appendix A.2 at both counters. Every byte of both ciphertexts, by digest.",[286,474,475,476,479,480,445],{},"A key that isn't 64 hex digits is an ",[318,477,478],{},"InvalidOptionError",", and so is a nonce that isn't 48 or a counter off the range. A missing key or nonce is a ",[318,481,482],{},"MissingOptionError",[286,484,485],{},"Random nonces are fine now. Reused ones still aren't, and there's still no tag. Plain TypeScript, puzzles only.",[487,488,489],"style",{},"html pre.shiki code .skH_V, html code.shiki .skH_V{--shiki-light:var(--shiki-token-keyword);--shiki-default:var(--shiki-token-keyword);--shiki-dark:var(--shiki-token-keyword)}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 .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 .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":332,"searchDepth":367,"depth":367,"links":491},[492,493,494],{"id":299,"depth":367,"text":300},{"id":312,"depth":367,"text":313},{"id":468,"depth":367,"text":469},"ChaCha20 with a 24-byte nonce you can pick at random. HChaCha20 turns the key and 16 nonce bytes into a subkey. UTF-8 in, hex out, no padding.","md",null,{},true,{"title":268,"description":495},"Ztg3sEmvjkInC059nxQJwbn76X9iPd36dk14NSofRuo",[503,505],{"title":264,"path":265,"stem":266,"description":504,"children":-1},"Salsa20 reshuffled, as RFC 8439 runs it in TLS and WireGuard. A 256-bit key, a 96-bit nonce and a 32-bit counter. UTF-8 in, hex out, no padding.",{"title":272,"path":273,"stem":274,"description":506,"children":-1},"The RFC 8439 AEAD of TLS 1.3 and WireGuard. ChaCha20 encrypts, Poly1305 tags, and decoding refuses a changed byte. Hex out with a 16-byte tag.",1791184045818]