[{"data":1,"prerenderedAt":538},["ShallowReactive",2],{"navigation_docs":3,"-ciphers-blowfish":180,"-ciphers-blowfish-surround":535},[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-solar-book-2-linear",{"title":37,"path":38,"stem":39,"children":40,"icon":179},"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],{"title":42,"path":38,"stem":39},"Overview",{"title":44,"path":45,"stem":46},"Caesar","\u002Fciphers\u002Fcaesar","2.ciphers\u002F01.caesar",{"title":48,"path":49,"stem":50},"ROT-13","\u002Fciphers\u002Frot13","2.ciphers\u002F02.rot13",{"title":52,"path":53,"stem":54},"ROT-47","\u002Fciphers\u002Frot47","2.ciphers\u002F03.rot47",{"title":56,"path":57,"stem":58},"Atbash","\u002Fciphers\u002Fatbash","2.ciphers\u002F04.atbash",{"title":60,"path":61,"stem":62},"Affine","\u002Fciphers\u002Faffine","2.ciphers\u002F05.affine",{"title":64,"path":65,"stem":66},"Vigenère","\u002Fciphers\u002Fvigenere","2.ciphers\u002F06.vigenere",{"title":68,"path":69,"stem":70},"Trithemius","\u002Fciphers\u002Ftrithemius","2.ciphers\u002F07.trithemius",{"title":72,"path":73,"stem":74},"Alberti","\u002Fciphers\u002Falberti","2.ciphers\u002F08.alberti",{"title":76,"path":77,"stem":78},"Playfair","\u002Fciphers\u002Fplayfair","2.ciphers\u002F09.playfair",{"title":80,"path":81,"stem":82},"Polybius square","\u002Fciphers\u002Fpolybius","2.ciphers\u002F10.polybius",{"title":84,"path":85,"stem":86},"Morse code","\u002Fciphers\u002Fmorse","2.ciphers\u002F11.morse",{"title":88,"path":89,"stem":90},"Bacon's cipher","\u002Fciphers\u002Fbacon","2.ciphers\u002F12.bacon",{"title":92,"path":93,"stem":94},"Tap code","\u002Fciphers\u002Ftap-code","2.ciphers\u002F13.tap-code",{"title":96,"path":97,"stem":98},"ADFGVX","\u002Fciphers\u002Fadfgvx","2.ciphers\u002F14.adfgvx",{"title":100,"path":101,"stem":102},"Bifid","\u002Fciphers\u002Fbifid","2.ciphers\u002F15.bifid",{"title":104,"path":105,"stem":106},"Rail fence","\u002Fciphers\u002Frail-fence","2.ciphers\u002F16.rail-fence",{"title":108,"path":109,"stem":110},"Columnar transposition","\u002Fciphers\u002Fcolumnar","2.ciphers\u002F17.columnar",{"title":112,"path":113,"stem":114},"Enigma M3","\u002Fciphers\u002Fenigma","2.ciphers\u002F18.enigma",{"title":116,"path":117,"stem":118},"Beaufort","\u002Fciphers\u002Fbeaufort","2.ciphers\u002F19.beaufort",{"title":120,"path":121,"stem":122},"Autokey","\u002Fciphers\u002Fautokey","2.ciphers\u002F20.autokey",{"title":124,"path":125,"stem":126},"AES (ECB)","\u002Fciphers\u002Faes","2.ciphers\u002F21.aes",{"title":128,"path":129,"stem":130},"Triple DES (ECB)","\u002Fciphers\u002Ftriple-des","2.ciphers\u002F22.triple-des",{"title":132,"path":133,"stem":134},"AES (LRW)","\u002Fciphers\u002Faes-lrw","2.ciphers\u002F23.aes-lrw",{"title":136,"path":137,"stem":138},"AES (CBC)","\u002Fciphers\u002Faes-cbc","2.ciphers\u002F24.aes-cbc",{"title":140,"path":141,"stem":142},"AES (CFB)","\u002Fciphers\u002Faes-cfb","2.ciphers\u002F25.aes-cfb",{"title":144,"path":145,"stem":146},"AES (CTR)","\u002Fciphers\u002Faes-ctr","2.ciphers\u002F26.aes-ctr",{"title":148,"path":149,"stem":150},"AES (CCM)","\u002Fciphers\u002Faes-ccm","2.ciphers\u002F27.aes-ccm",{"title":152,"path":153,"stem":154},"AES (OFB)","\u002Fciphers\u002Faes-ofb","2.ciphers\u002F28.aes-ofb",{"title":156,"path":157,"stem":158},"AES (OCB)","\u002Fciphers\u002Faes-ocb","2.ciphers\u002F29.aes-ocb",{"title":160,"path":161,"stem":162},"Triple DES (CBC)","\u002Fciphers\u002Ftriple-des-cbc","2.ciphers\u002F30.triple-des-cbc",{"title":164,"path":165,"stem":166},"Rijndael (ECB)","\u002Fciphers\u002Frijndael","2.ciphers\u002F31.rijndael",{"title":168,"path":169,"stem":170},"AES (XTS)","\u002Fciphers\u002Faes-xts","2.ciphers\u002F32.aes-xts",{"title":172,"path":173,"stem":174},"AES (CBC-MAC)","\u002Fciphers\u002Faes-cbc-mac","2.ciphers\u002F33.aes-cbc-mac",{"title":176,"path":177,"stem":178},"Blowfish (ECB)","\u002Fciphers\u002Fblowfish","2.ciphers\u002F34.blowfish","i-solar-library-linear",{"id":181,"title":176,"body":182,"description":528,"extension":529,"links":530,"meta":531,"navigation":532,"path":177,"seo":533,"stem":178,"__hash__":534},"docs\u002F2.ciphers\u002F34.blowfish.md",{"type":183,"value":184,"toc":524},"minimark",[185,189,193,206,341,344,406,413,418,421,424,427,434,438,445,493,496,517,520],[186,187],"cipher-facts",{"name":188},"blowfish",[190,191,192],"p",{},"Bruce Schneier published Blowfish in 1993 as a free replacement for DES, no patent and no license. The block is 64 bits, like DES. The key is anything from 32 to 448 bits, here as hex: an even number of digits from 8 to 112. Case doesn't matter and spaces are ignored.",[190,194,195,196,200,201,205],{},"Text goes in as UTF-8 with PKCS#7 padding, ciphertext comes out as lowercase hex, and ",[197,198,199],"code",{},"decode"," wants hex back. The mode is ECB, same as ",[202,203,204],"a",{"href":129},"Triple DES",".",[207,208,213],"pre",{"className":209,"code":210,"language":211,"meta":212,"style":212},"language-ts shiki shiki-themes github-light github-light poimandres","const blowfish = create(\"blowfish\");\nconst key = \"0123456789abcdeff0e1d2c3b4a59687\";\nblowfish.encode(\"ATTACK AT DAWN\", { key }).text; \u002F\u002F \"9e16058420b1546315051882f350a136\"\nblowfish.decode(\"9e16058420b1546315051882f350a136\", { key }).text; \u002F\u002F \"ATTACK AT DAWN\"\n","ts","",[197,214,215,251,272,310],{"__ignoreMap":212},[216,217,220,224,228,231,235,239,243,246,248],"span",{"class":218,"line":219},"line",1,[216,221,223],{"class":222},"s1TYA","const",[216,225,227],{"class":226},"saoiD"," blowfish",[216,229,230],{"class":222}," =",[216,232,234],{"class":233},"sULi6"," create",[216,236,238],{"class":237},"sKlNE","(",[216,240,242],{"class":241},"scVjq","\"",[216,244,188],{"class":245},"sQ7BG",[216,247,242],{"class":241},[216,249,250],{"class":237},");\n",[216,252,254,256,259,261,264,267,269],{"class":218,"line":253},2,[216,255,223],{"class":222},[216,257,258],{"class":226}," key",[216,260,230],{"class":222},[216,262,263],{"class":241}," \"",[216,265,266],{"class":245},"0123456789abcdeff0e1d2c3b4a59687",[216,268,242],{"class":241},[216,270,271],{"class":237},";\n",[216,273,275,278,280,283,285,287,290,292,295,297,300,303,306],{"class":218,"line":274},3,[216,276,188],{"class":277},"spVlQ",[216,279,205],{"class":237},[216,281,282],{"class":233},"encode",[216,284,238],{"class":237},[216,286,242],{"class":241},[216,288,289],{"class":245},"ATTACK AT DAWN",[216,291,242],{"class":241},[216,293,294],{"class":237},", {",[216,296,258],{"class":277},[216,298,299],{"class":237}," }).",[216,301,302],{"class":277},"text",[216,304,305],{"class":237},"; ",[216,307,309],{"class":308},"sjhu3","\u002F\u002F \"9e16058420b1546315051882f350a136\"\n",[216,311,313,315,317,319,321,323,326,328,330,332,334,336,338],{"class":218,"line":312},4,[216,314,188],{"class":277},[216,316,205],{"class":237},[216,318,199],{"class":233},[216,320,238],{"class":237},[216,322,242],{"class":241},[216,324,325],{"class":245},"9e16058420b1546315051882f350a136",[216,327,242],{"class":241},[216,329,294],{"class":237},[216,331,258],{"class":277},[216,333,299],{"class":237},[216,335,302],{"class":277},[216,337,305],{"class":237},[216,339,340],{"class":308},"\u002F\u002F \"ATTACK AT DAWN\"\n",[190,342,343],{},"OpenSSL agrees, but since 3.0 Blowfish lives in the legacy provider, so ask for it:",[207,345,349],{"className":346,"code":347,"language":348,"meta":212,"style":212},"language-bash shiki shiki-themes github-light github-light poimandres","printf %s \"ATTACK AT DAWN\" | openssl enc -bf-ecb -provider legacy -provider default -K 0123456789abcdeff0e1d2c3b4a59687 | xxd -p\n","bash",[197,350,351],{"__ignoreMap":212},[216,352,353,357,361,363,365,367,370,374,377,381,384,387,389,392,395,398,400,403],{"class":218,"line":219},[216,354,356],{"class":355},"s39Ir","printf",[216,358,360],{"class":359},"sX7Zv"," %s",[216,362,263],{"class":241},[216,364,289],{"class":245},[216,366,242],{"class":241},[216,368,369],{"class":222}," |",[216,371,373],{"class":372},"sseY5"," openssl",[216,375,376],{"class":359}," enc",[216,378,380],{"class":379},"sqT1Y"," -bf-ecb",[216,382,383],{"class":379}," -provider",[216,385,386],{"class":359}," legacy",[216,388,383],{"class":379},[216,390,391],{"class":359}," default",[216,393,394],{"class":379}," -K",[216,396,397],{"class":359}," 0123456789abcdeff0e1d2c3b4a59687",[216,399,369],{"class":222},[216,401,402],{"class":372}," xxd",[216,404,405],{"class":379}," -p\n",[190,407,408,409,412],{},"The tests run Eric Young's vectors, the ones Schneier ships with the reference code. 34 blocks under 8-byte keys, then one block under keys from 4 to 24 bytes. The 448-bit key is checked against PyCryptodome, because OpenSSL's command line cuts ",[197,410,411],{},"-K"," to 16 bytes.",[414,415,417],"h2",{"id":416},"where-the-s-boxes-come-from","Where the S-boxes come from",[190,419,420],{},"DES has eight fixed S-boxes, and for years people asked who picked them and why. Blowfish has no such question. It starts from the hex digits of pi: 18 words for the round keys, 1024 for four S-boxes of 256 words. Nobody chose them, so nobody could have hidden anything in them.",[190,422,423],{},"Then the key goes in. It gets XORed into the 18 round keys, repeated as many times as it takes. After that Blowfish encrypts a block of zeros and writes the result over the first two round keys. Then it encrypts that result and overwrites the next two. And so on, through the round keys and all four S-boxes, 521 encryptions in total. At the end every key has its own S-boxes.",[190,425,426],{},"That's also why a new key is expensive. Each one costs those 521 encryptions before the first real block. bcrypt took this on purpose and made it slower still, so guessing passwords gets expensive.",[190,428,429,430,433],{},"The pi words aren't pasted into the source. The library computes them once, on the first key, with Machin's formula in ",[197,431,432],{},"BigInt",". It takes a few dozen milliseconds, and after that they sit in memory.",[414,435,437],{"id":436},"why-ecb-leaks","Why ECB leaks",[190,439,440,441,444],{},"Sixteen ",[197,442,443],{},"A","s are two equal blocks, and they come out as two equal blocks:",[207,446,448],{"className":209,"code":447,"language":211,"meta":212,"style":212},"blowfish.encode(\"A\".repeat(16), { key }).text;\n\u002F\u002F 8e9fdf91ed9fbd73 8e9fdf91ed9fbd73 10c9d9248e4c6405\n",[197,449,450,488],{"__ignoreMap":212},[216,451,452,454,456,458,460,462,464,466,468,471,473,477,480,482,484,486],{"class":218,"line":219},[216,453,188],{"class":277},[216,455,205],{"class":237},[216,457,282],{"class":233},[216,459,238],{"class":237},[216,461,242],{"class":241},[216,463,443],{"class":245},[216,465,242],{"class":241},[216,467,205],{"class":237},[216,469,470],{"class":233},"repeat",[216,472,238],{"class":237},[216,474,476],{"class":475},"siHFe","16",[216,478,479],{"class":237},"), {",[216,481,258],{"class":277},[216,483,299],{"class":237},[216,485,302],{"class":277},[216,487,271],{"class":237},[216,489,490],{"class":218,"line":253},[216,491,492],{"class":308},"\u002F\u002F 8e9fdf91ed9fbd73 8e9fdf91ed9fbd73 10c9d9248e4c6405\n",[190,494,495],{},"Spaces added to show the blocks. The last one is only padding.",[190,497,498,499,502,503,506,507,509,510,513,514,516],{},"A key that isn't 8 to 112 hex digits, or has an odd number of them, is an ",[197,500,501],{},"InvalidOptionError",". A missing one is a ",[197,504,505],{},"MissingOptionError",". On ",[197,508,199],{},", ciphertext that isn't whole 8-byte blocks of hex is a ",[197,511,512],{},"CipherError",". A wrong key almost always breaks the padding, and that's a ",[197,515,512],{}," too. So are decrypted bytes that aren't UTF-8.",[190,518,519],{},"Nobody has broken full 16-round Blowfish. The block is the problem. Around 2^32 blocks under one key, two ciphertext blocks start to collide, and a collision leaks plaintext. Sweet32 did exactly that in 2016, to 3DES in HTTPS and to Blowfish in OpenVPN. Schneier himself has been telling people to use Twofish instead since 2007. This one is plain TypeScript, not constant time. Puzzles and learning, not secrets.",[521,522,523],"style",{},"html pre.shiki code .s1TYA, html code.shiki .s1TYA{--shiki-light:#D73A49;--shiki-default:#D73A49;--shiki-dark:#91B4D5}html pre.shiki code .saoiD, html code.shiki .saoiD{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#E4F0FB}html pre.shiki code .sULi6, html code.shiki .sULi6{--shiki-light:#6F42C1;--shiki-default:#6F42C1;--shiki-dark:#E4F0FBD0}html pre.shiki code .sKlNE, html code.shiki .sKlNE{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#A6ACCD}html pre.shiki code .scVjq, html code.shiki .scVjq{--shiki-light:#032F62;--shiki-default:#032F62;--shiki-dark:#A6ACCD}html pre.shiki code .sQ7BG, html code.shiki .sQ7BG{--shiki-light:#032F62;--shiki-default:#032F62;--shiki-dark:#5DE4C7}html pre.shiki code .spVlQ, html code.shiki .spVlQ{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#E4F0FB}html pre.shiki code .sjhu3, html code.shiki .sjhu3{--shiki-light:#6A737D;--shiki-light-font-style:inherit;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#767C9DB0;--shiki-dark-font-style:italic}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);}html pre.shiki code .s39Ir, html code.shiki .s39Ir{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#91B4D5}html pre.shiki code .sX7Zv, html code.shiki .sX7Zv{--shiki-light:#032F62;--shiki-default:#032F62;--shiki-dark:#ADD7FF}html pre.shiki code .sseY5, html code.shiki .sseY5{--shiki-light:#6F42C1;--shiki-default:#6F42C1;--shiki-dark:#91B4D5}html pre.shiki code .sqT1Y, html code.shiki .sqT1Y{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#ADD7FF}html pre.shiki code .siHFe, html code.shiki .siHFe{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#5DE4C7}",{"title":212,"searchDepth":253,"depth":253,"links":525},[526,527],{"id":416,"depth":253,"text":417},{"id":436,"depth":253,"text":437},"Schneier's 1993 Feistel cipher, with S-boxes cooked from the key and the digits of pi. Keys from 32 to 448 bits, UTF-8 text in, hex out.","md",null,{},true,{"title":176,"description":528},"dWXP37wFAQXuHbPg-V5wJPV_mP_IETxWoOpvUbRcrQ8",[536,530],{"title":172,"path":173,"stem":174,"description":537,"children":-1},"CBC with a zero IV where only the last block survives, and that block is the tag. Nothing gets encrypted. UTF-8 text in, hex out, text bytes plus the tag.",1790291185510]