[{"data":1,"prerenderedAt":577},["ShallowReactive",2],{"navigation_docs":3,"-ciphers-salsa20":276,"-ciphers-salsa20-surround":572},[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":256,"body":278,"description":565,"extension":566,"links":567,"meta":568,"navigation":569,"path":257,"seo":570,"stem":258,"__hash__":571},"docs\u002F2.ciphers\u002F54.salsa20.md",{"type":279,"value":280,"toc":559},"minimark",[281,285,289,292,297,305,308,311,315,322,332,441,452,467,471,474,478,481,516,531,534,552,555],[282,283],"cipher-facts",{"name":284},"salsa20",[286,287,288],"p",{},"Daniel J. Bernstein published Salsa20 in 2005 and sent it to eSTREAM. The twelve-round version, Salsa20\u002F12, made the final software portfolio in 2008. This one runs all twenty rounds, the way Bernstein specified it.",[286,290,291],{},"What's inside? No S-boxes, no tables, no multiplication. Add two 32-bit words, rotate, XOR into a third. That's ARX, and it's the whole cipher. No table lookups means no cache timing leaks, at least in code that bothers to be constant time. This code doesn't.",[293,294,296],"h2",{"id":295},"how-it-runs","How it runs",[286,298,299,300,304],{},"The state is sixteen 32-bit words in a 4×4 grid. Four constants sit on the diagonal, they spell ",[301,302,303],"code",{},"expand 32-byte k",". The key fills eight words, the nonce two, the block counter two.",[286,306,307],{},"Then twenty rounds. Odd rounds mix the columns, even rounds mix the rows. Each one is four quarter rounds, and each quarter round is four lines of add, rotate by 7, 9, 13 or 18, XOR. At the end the starting state gets added back word by word. Out come 64 bytes of keystream.",[286,309,310],{},"The next 64 bytes? Same thing with the counter one higher. The keystream gets XORed into the text, and decrypting is the same XOR again.",[293,312,314],{"id":313},"keys-nonce-and-counter","Keys, nonce and counter",[286,316,317,318,321],{},"The key is 64 hex digits, or 32 for the old 128-bit variant. That one copies the key into both halves and swaps the diagonal for ",[301,319,320],{},"expand 16-byte k",". Don't pick it for something new. It's here because eSTREAM tested it and some puzzles use it.",[286,323,324,327,328,331],{},[301,325,326],{},"nonce"," is 16 hex digits, 8 bytes, and required. ",[301,329,330],{},"counter"," says which block the text starts at, default 0. The counter is 64 bits in the cipher. Here it stops at 2^53 - 1, where JavaScript numbers stop being exact. Nobody encrypts that far anyway.",[333,334,339],"pre",{"className":335,"code":336,"language":337,"meta":338,"style":338},"language-ts shiki shiki-themes ciphers ciphers ciphers","const salsa = create(\"salsa20\");\nconst key = \"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f\";\nconst nonce = \"0001020304050607\";\nsalsa.encode(\"ATTACK AT DAWN\", { key, nonce }).text; \u002F\u002F \"6ff95b1e5b1c098f8252f7e87faa\"\nsalsa.decode(\"6ff95b1e5b1c098f8252f7e87faa\", { key, nonce }).text; \u002F\u002F \"ATTACK AT DAWN\"\n","ts","",[301,340,341,371,387,402,423],{"__ignoreMap":338},[342,343,346,350,354,357,361,364,368],"span",{"class":344,"line":345},"line",1,[342,347,349],{"class":348},"skH_V","const",[342,351,353],{"class":352},"s38Sx"," salsa ",[342,355,356],{"class":348},"=",[342,358,360],{"class":359},"sK71F"," create",[342,362,363],{"class":352},"(",[342,365,367],{"class":366},"shU9J","\"salsa20\"",[342,369,370],{"class":352},");\n",[342,372,374,376,379,381,384],{"class":344,"line":373},2,[342,375,349],{"class":348},[342,377,378],{"class":352}," key ",[342,380,356],{"class":348},[342,382,383],{"class":366}," \"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f\"",[342,385,386],{"class":352},";\n",[342,388,390,392,395,397,400],{"class":344,"line":389},3,[342,391,349],{"class":348},[342,393,394],{"class":352}," nonce ",[342,396,356],{"class":348},[342,398,399],{"class":366}," \"0001020304050607\"",[342,401,386],{"class":352},[342,403,405,408,411,413,416,419],{"class":344,"line":404},4,[342,406,407],{"class":352},"salsa.",[342,409,410],{"class":359},"encode",[342,412,363],{"class":352},[342,414,415],{"class":366},"\"ATTACK AT DAWN\"",[342,417,418],{"class":352},", { key, nonce }).text; ",[342,420,422],{"class":421},"scIB-","\u002F\u002F \"6ff95b1e5b1c098f8252f7e87faa\"\n",[342,424,426,428,431,433,436,438],{"class":344,"line":425},5,[342,427,407],{"class":352},[342,429,430],{"class":359},"decode",[342,432,363],{"class":352},[342,434,435],{"class":366},"\"6ff95b1e5b1c098f8252f7e87faa\"",[342,437,418],{"class":352},[342,439,440],{"class":421},"\u002F\u002F \"ATTACK AT DAWN\"\n",[286,442,443,444,447,448,451],{},"Fourteen bytes in, fourteen out. With ",[301,445,446],{},"counter: 1"," the same call skips the first 64 bytes of keystream and gives ",[301,449,450],{},"e06e7f189a4f5bccea997a85e0c2",". Handy when a puzzle hands you the middle of a stream.",[286,453,454,455,458,459,462,463,466],{},"Raw bytes without the hex? ",[301,456,457],{},"salsa20(data, key, nonce, counter)"," from ",[301,460,461],{},"@agntn\u002Fciphers\u002Fsalsa"," takes and returns ",[301,464,465],{},"Uint8Array",", and pulls in no registry.",[293,468,470],{"id":469},"checked-against","Checked against",[286,472,473],{},"The eSTREAM verified vectors, set 1 vector 0 for a 128-bit key and set 3 vector 243 for a 256-bit one, both ways. Crypto++'s vector where the counter starts at 2^32 - 1, so the carry into the high word gets tested too. All 1024 bytes of it, by digest.",[293,475,477],{"id":476},"the-nonce-is-the-whole-game","The nonce is the whole game",[286,479,480],{},"Same key, same nonce, same keystream. Encrypt two texts like that and watch:",[333,482,484],{"className":335,"code":483,"language":337,"meta":338,"style":338},"salsa.encode(\"ATTACK AT DAWN\", { key, nonce }).text; \u002F\u002F \"6ff95b1e5b1c098f8252f7e87faa\"\nsalsa.encode(\"ATTACK AT DUSK\", { key, nonce }).text; \u002F\u002F \"6ff95b1e5b1c098f8252f7fc7baf\"\n",[301,485,486,500],{"__ignoreMap":338},[342,487,488,490,492,494,496,498],{"class":344,"line":345},[342,489,407],{"class":352},[342,491,410],{"class":359},[342,493,363],{"class":352},[342,495,415],{"class":366},[342,497,418],{"class":352},[342,499,422],{"class":421},[342,501,502,504,506,508,511,513],{"class":344,"line":373},[342,503,407],{"class":352},[342,505,410],{"class":359},[342,507,363],{"class":352},[342,509,510],{"class":366},"\"ATTACK AT DUSK\"",[342,512,418],{"class":352},[342,514,515],{"class":421},"\u002F\u002F \"6ff95b1e5b1c098f8252f7fc7baf\"\n",[286,517,518,519,522,523,526,527,530],{},"Eleven bytes identical. XOR the two and you get ",[301,520,521],{},"DAWN"," XOR ",[301,524,525],{},"DUSK",", no key needed. Eight bytes of nonce is too short to pick at random safely, so use a counter. Or use ",[528,529,260],"a",{"href":261},", which has 24.",[286,532,533],{},"Nothing checks integrity either. Flip a ciphertext bit, the same plaintext bit flips. NaCl pairs Salsa with Poly1305 for exactly that reason.",[286,535,536,537,540,541,544,545,547,548,551],{},"A key that isn't 32 or 64 hex digits is an ",[301,538,539],{},"InvalidOptionError",", and so is a nonce that isn't 16 or a counter that isn't a whole number from 0 to 2^53 - 1. A missing key or nonce is a ",[301,542,543],{},"MissingOptionError",". On ",[301,546,430],{},", an odd number of hex digits is a ",[301,549,550],{},"CipherError",".",[286,553,554],{},"Plain TypeScript, not constant time, no tag. Fun to take apart. Not for secrets.",[556,557,558],"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":338,"searchDepth":373,"depth":373,"links":560},[561,562,563,564],{"id":295,"depth":373,"text":296},{"id":313,"depth":373,"text":314},{"id":469,"depth":373,"text":470},{"id":476,"depth":373,"text":477},"Bernstein's stream cipher from 2005. Twenty rounds of add, rotate and XOR turn key, nonce and counter into keystream. UTF-8 in, hex out, no padding.","md",null,{},true,{"title":256,"description":565},"XEZYgBDoQe5mg8VejhIKd_cFtXZPpr14CcrNeW2lejA",[573,575],{"title":252,"path":253,"stem":254,"description":574,"children":-1},"Repeating-key XOR. Vigenère on bytes, with a hex key of any length. UTF-8 text in and hex out, or hex on both sides.",{"title":260,"path":261,"stem":262,"description":576,"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.",1791184045554]