[{"data":1,"prerenderedAt":569},["ShallowReactive",2],{"navigation_docs":3,"-ciphers-chacha20":276,"-ciphers-chacha20-surround":564},[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":264,"body":278,"description":557,"extension":558,"links":559,"meta":560,"navigation":561,"path":265,"seo":562,"stem":266,"__hash__":563},"docs\u002F2.ciphers\u002F56.chacha20.md",{"type":279,"value":280,"toc":551},"minimark",[281,285,289,292,297,305,308,312,323,326,434,441,448,451,466,470,473,477,512,521,527,544,547],[282,283],"cipher-facts",{"name":284},"chacha20",[286,287,288],"p",{},"Salsa, then ChaCha. Both names are dances, and both ciphers are Bernstein's. ChaCha came in 2008 as \"a variant of Salsa20\". Same ARX idea, same twenty rounds, but every word gets touched more often per round. Better diffusion for the same work.",[286,290,291],{},"And this is the one that won. RFC 7539 put it next to Poly1305 in 2015, RFC 8439 replaced that in 2018, and now TLS 1.3, WireGuard and SSH all run it. Not bad for a dance.",[293,294,296],"h2",{"id":295},"how-it-runs","How it runs",[286,298,299,300,304],{},"Sixteen 32-bit words again. The first row is the constant ",[301,302,303],"code",{},"expand 32-byte k",", then two rows of key, then the counter and the nonce. Salsa scatters them across the grid. ChaCha keeps them in rows.",[286,306,307],{},"The quarter round changes too. It's add, XOR, rotate by 16, 12, 8 and 7, and each word gets updated twice. Ten column rounds alternate with ten diagonal rounds. Add the starting state back and you have 64 bytes of keystream.",[293,309,311],{"id":310},"keys-nonce-and-counter","Keys, nonce and counter",[286,313,314,315,318,319,322],{},"The key is 64 hex digits. ",[301,316,317],{},"nonce"," is 24 hex digits, the 96 bits of RFC 8439, and required. ",[301,320,321],{},"counter"," is the block counter of the first 64 bytes, from 0 to 4294967295, default 0.",[286,324,325],{},"The RFC's own example starts at counter 1, because its AEAD spends block 0 on the Poly1305 key. libsodium starts plain ChaCha20 at 0. Wrong counter and every byte comes out different, so try both:",[327,328,333],"pre",{"className":329,"code":330,"language":331,"meta":332,"style":332},"language-ts shiki shiki-themes ciphers ciphers ciphers","const chacha = create(\"chacha20\");\nconst key = \"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f\";\nconst nonce = \"000000000000004a00000000\";\nchacha.encode(\"ATTACK AT DAWN\", { key, nonce }).text; \u002F\u002F \"ee514a01f8eb1508d512dec13d5a\"\nchacha.encode(\"ATTACK AT DAWN\", { key, nonce, counter: 1 }).text; \u002F\u002F \"631b05b20350f9a07bfe632eef2d\"\n","ts","",[301,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"," chacha ",[336,349,350],{"class":342},"=",[336,352,354],{"class":353},"sK71F"," create",[336,356,357],{"class":346},"(",[336,359,361],{"class":360},"shU9J","\"chacha20\"",[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}," \"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f\"",[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}," \"000000000000004a00000000\"",[336,395,380],{"class":346},[336,397,399,402,405,407,410,413],{"class":338,"line":398},4,[336,400,401],{"class":346},"chacha.",[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 \"ee514a01f8eb1508d512dec13d5a\"\n",[336,418,420,422,424,426,428,431],{"class":338,"line":419},5,[336,421,401],{"class":346},[336,423,404],{"class":353},[336,425,357],{"class":346},[336,427,409],{"class":360},[336,429,430],{"class":346},", { key, nonce, counter: 1 }).text; ",[336,432,433],{"class":415},"\u002F\u002F \"631b05b20350f9a07bfe632eef2d\"\n",[286,435,436,437,440],{},"That's the key and nonce from RFC 8439 section 2.4.2. Node's ",[301,438,439],{},"createCipheriv(\"chacha20\")"," wants the counter glued in front of the nonce, four bytes little endian, and gives the same bytes.",[286,442,443,444,447],{},"The counter is 32 bits, so one nonce covers 256 GiB. A text that runs past block 4294967295 is an ",[301,445,446],{},"InvalidOptionError",", not a silent wrap.",[286,449,450],{},"Original ChaCha had a 64-bit counter and a 64-bit nonce. The RFC moved 32 bits from one to the other. Up to block 2^32 - 1 both give the same keystream, if the first four bytes of the RFC nonce are zero.",[286,452,453,454,457,458,461,462,465],{},"Bytes without hex? ",[301,455,456],{},"chacha20(data, key, nonce, counter)"," from ",[301,459,460],{},"@agntn\u002Fciphers\u002Fchacha"," takes and returns ",[301,463,464],{},"Uint8Array",".",[293,467,469],{"id":468},"checked-against","Checked against",[286,471,472],{},"RFC 8439 everywhere it has a number. The block function from section 2.3.2, the sunscreen text from 2.4.2, and test vectors #1 and #3 from appendix A.2, the last one Jabberwocky at counter 42.",[293,474,476],{"id":475},"same-old-nonce-problem","Same old nonce problem",[327,478,480],{"className":329,"code":479,"language":331,"meta":332,"style":332},"chacha.encode(\"ATTACK AT DAWN\", { key, nonce }).text; \u002F\u002F \"ee514a01f8eb1508d512dec13d5a\"\nchacha.encode(\"ATTACK AT DUSK\", { key, nonce }).text; \u002F\u002F \"ee514a01f8eb1508d512ded5395f\"\n",[301,481,482,496],{"__ignoreMap":332},[336,483,484,486,488,490,492,494],{"class":338,"line":339},[336,485,401],{"class":346},[336,487,404],{"class":353},[336,489,357],{"class":346},[336,491,409],{"class":360},[336,493,412],{"class":346},[336,495,416],{"class":415},[336,497,498,500,502,504,507,509],{"class":338,"line":367},[336,499,401],{"class":346},[336,501,404],{"class":353},[336,503,357],{"class":346},[336,505,506],{"class":360},"\"ATTACK AT DUSK\"",[336,508,412],{"class":346},[336,510,511],{"class":415},"\u002F\u002F \"ee514a01f8eb1508d512ded5395f\"\n",[286,513,514,515,518,519,465],{},"Look familiar? It's ",[516,517,256],"a",{"href":257}," all over again. A better mixing function doesn't help when the keystream repeats. Twelve bytes of nonce is still too few to pick at random, so count them, or take ",[516,520,268],{"href":269},[286,522,523,524,526],{},"No integrity either. For that there's ",[516,525,272],{"href":273},", and in practice nobody should send plain ChaCha20 anywhere.",[286,528,529,530,532,533,536,537,540,541,465],{},"A key that isn't 64 hex digits is an ",[301,531,446],{},", and so is a nonce that isn't 24 or a counter off the range. A missing key or nonce is a ",[301,534,535],{},"MissingOptionError",". On ",[301,538,539],{},"decode",", an odd number of hex digits is a ",[301,542,543],{},"CipherError",[286,545,546],{},"Plain TypeScript, not constant time. The real ChaCha20 is in your TLS library already.",[548,549,550],"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":552},[553,554,555,556],{"id":295,"depth":367,"text":296},{"id":310,"depth":367,"text":311},{"id":468,"depth":367,"text":469},{"id":475,"depth":367,"text":476},"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.","md",null,{},true,{"title":264,"description":557},"POckasywKQhYUhTQBiBQQwj8clx-7xkSFTH_3TLAPik",[565,567],{"title":260,"path":261,"stem":262,"description":566,"children":-1},"Salsa20 with a 24-byte nonce, the stream inside NaCl's secretbox. HSalsa20 turns the key and half the nonce into a subkey. UTF-8 in, hex out.",{"title":268,"path":269,"stem":270,"description":568,"children":-1},"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.",1791184045627]