[{"data":1,"prerenderedAt":590},["ShallowReactive",2],{"navigation_docs":3,"-ciphers-desx":204,"-ciphers-desx-surround":585},[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":203},"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],{"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",{"title":180,"path":181,"stem":182},"DES (ECB)","\u002Fciphers\u002Fdes","2.ciphers\u002F35.des",{"title":184,"path":185,"stem":186},"DESX (ECB)","\u002Fciphers\u002Fdesx","2.ciphers\u002F36.desx",{"title":188,"path":189,"stem":190},"IDEA (ECB)","\u002Fciphers\u002Fidea","2.ciphers\u002F37.idea",{"title":192,"path":193,"stem":194},"Lucifer (ECB)","\u002Fciphers\u002Flucifer","2.ciphers\u002F38.lucifer",{"title":196,"path":197,"stem":198},"MARS (ECB)","\u002Fciphers\u002Fmars","2.ciphers\u002F39.mars",{"title":200,"path":201,"stem":202},"Serpent (ECB)","\u002Fciphers\u002Fserpent","2.ciphers\u002F40.serpent","i-solar-library-linear",{"id":205,"title":184,"body":206,"description":578,"extension":579,"links":580,"meta":581,"navigation":582,"path":185,"seo":583,"stem":186,"__hash__":584},"docs\u002F2.ciphers\u002F36.desx.md",{"type":207,"value":208,"toc":574},"minimark",[209,213,217,220,231,242,245,257,389,392,467,470,475,485,488,492,499,546,549,570],[210,211],"cipher-facts",{"name":212},"desx",[214,215,216],"p",{},"By the early 1980s everyone could see the 56-bit key of DES was the weak spot. Triple DES fixes that by running the cipher three times. Ron Rivest had a cheaper idea in 1984. Leave DES alone and XOR the block with one extra 64-bit key before it goes in and with another after it comes out. That's the whole cipher. RSA shipped it in BSAFE as DESX.",[214,218,219],{},"So every 8-byte block goes like this:",[221,222,227],"pre",{"className":223,"code":225,"language":226},[224],"language-text","C = K_out ⊕ DES_K(P ⊕ K_in)\n","text",[228,229,225],"code",{"__ignoreMap":230},"",[214,232,233,234,237,238,241],{},"The key is 48 hex digits, three parts of 16. First the DES key, then ",[228,235,236],{},"K_in",", then ",[228,239,240],{},"K_out",". That's 56 + 64 + 64 = 184 bits once the DES parity bits are gone. Case doesn't matter and spaces are ignored, so spacing the parts out works fine.",[214,243,244],{},"Mind the order. The Polish Wikipedia and Botan list the input whitening key first and the DES key second. OpenSSL puts the DES key first, and so does this cipher, because OpenSSL is what you'll check it against.",[214,246,247,248,251,252,256],{},"Text goes in as UTF-8 with PKCS#7 padding, ciphertext comes out as lowercase hex, and ",[228,249,250],{},"decode"," wants hex back. The mode is ECB, same as ",[253,254,255],"a",{"href":181},"DES",".",[221,258,262],{"className":259,"code":260,"language":261,"meta":230,"style":230},"language-ts shiki shiki-themes github-light github-light poimandres","const desx = create(\"desx\");\nconst key = \"0123456789abcdef f0e1d2c3b4a59687 1122334455667788\";\ndesx.encode(\"ATTACK AT DAWN\", { key }).text; \u002F\u002F \"e66c99d05c13ecf7cb70b505d3d77a8e\"\ndesx.decode(\"e66c99d05c13ecf7cb70b505d3d77a8e\", { key }).text; \u002F\u002F \"ATTACK AT DAWN\"\n","ts",[228,263,264,300,321,358],{"__ignoreMap":230},[265,266,269,273,277,280,284,288,292,295,297],"span",{"class":267,"line":268},"line",1,[265,270,272],{"class":271},"s1TYA","const",[265,274,276],{"class":275},"saoiD"," desx",[265,278,279],{"class":271}," =",[265,281,283],{"class":282},"sULi6"," create",[265,285,287],{"class":286},"sKlNE","(",[265,289,291],{"class":290},"scVjq","\"",[265,293,212],{"class":294},"sQ7BG",[265,296,291],{"class":290},[265,298,299],{"class":286},");\n",[265,301,303,305,308,310,313,316,318],{"class":267,"line":302},2,[265,304,272],{"class":271},[265,306,307],{"class":275}," key",[265,309,279],{"class":271},[265,311,312],{"class":290}," \"",[265,314,315],{"class":294},"0123456789abcdef f0e1d2c3b4a59687 1122334455667788",[265,317,291],{"class":290},[265,319,320],{"class":286},";\n",[265,322,324,327,329,332,334,336,339,341,344,346,349,351,354],{"class":267,"line":323},3,[265,325,212],{"class":326},"spVlQ",[265,328,256],{"class":286},[265,330,331],{"class":282},"encode",[265,333,287],{"class":286},[265,335,291],{"class":290},[265,337,338],{"class":294},"ATTACK AT DAWN",[265,340,291],{"class":290},[265,342,343],{"class":286},", {",[265,345,307],{"class":326},[265,347,348],{"class":286}," }).",[265,350,226],{"class":326},[265,352,353],{"class":286},"; ",[265,355,357],{"class":356},"sjhu3","\u002F\u002F \"e66c99d05c13ecf7cb70b505d3d77a8e\"\n",[265,359,361,363,365,367,369,371,374,376,378,380,382,384,386],{"class":267,"line":360},4,[265,362,212],{"class":326},[265,364,256],{"class":286},[265,366,250],{"class":282},[265,368,287],{"class":286},[265,370,291],{"class":290},[265,372,373],{"class":294},"e66c99d05c13ecf7cb70b505d3d77a8e",[265,375,291],{"class":290},[265,377,343],{"class":286},[265,379,307],{"class":326},[265,381,348],{"class":286},[265,383,226],{"class":326},[265,385,353],{"class":286},[265,387,388],{"class":356},"\u002F\u002F \"ATTACK AT DAWN\"\n",[214,390,391],{},"OpenSSL has DESX only in CBC mode, in the legacy provider. With a zero IV the first block of CBC is ECB, so a text that fits in one block gives the same bytes:",[221,393,397],{"className":394,"code":395,"language":396,"meta":230,"style":230},"language-bash shiki shiki-themes github-light github-light poimandres","printf %s \"ATTACK\" | openssl enc -desx-cbc -provider legacy -provider default -K 0123456789abcdeff0e1d2c3b4a596871122334455667788 -iv 0000000000000000 | xxd -p\n# ea779f4b4f979f31\n","bash",[228,398,399,462],{"__ignoreMap":230},[265,400,401,405,409,411,414,416,419,423,426,430,433,436,438,441,444,447,450,454,456,459],{"class":267,"line":268},[265,402,404],{"class":403},"s39Ir","printf",[265,406,408],{"class":407},"sX7Zv"," %s",[265,410,312],{"class":290},[265,412,413],{"class":294},"ATTACK",[265,415,291],{"class":290},[265,417,418],{"class":271}," |",[265,420,422],{"class":421},"sseY5"," openssl",[265,424,425],{"class":407}," enc",[265,427,429],{"class":428},"sqT1Y"," -desx-cbc",[265,431,432],{"class":428}," -provider",[265,434,435],{"class":407}," legacy",[265,437,432],{"class":428},[265,439,440],{"class":407}," default",[265,442,443],{"class":428}," -K",[265,445,446],{"class":407}," 0123456789abcdeff0e1d2c3b4a596871122334455667788",[265,448,449],{"class":428}," -iv",[265,451,453],{"class":452},"siHFe"," 0000000000000000",[265,455,418],{"class":271},[265,457,458],{"class":421}," xxd",[265,460,461],{"class":428}," -p\n",[265,463,464],{"class":267,"line":302},[265,465,466],{"class":356},"# ea779f4b4f979f31\n",[214,468,469],{},"The tests check the nine DESX vectors from Botan 2, with the key parts reordered, and OpenSSL output for whole texts, one block at a time. Zero whitening keys have to give plain DES too.",[471,472,474],"h2",{"id":473},"why-two-xors-help","Why two XORs help",[214,476,477,478,480,481,484],{},"The XORs cost nothing, and DES stays one pass, so DESX is as fast as ",[253,479,255],{"href":181}," and three times faster than ",[253,482,483],{"href":129},"Triple DES",". Brute force gets much worse though. Guessing the DES key alone tells you nothing, because you don't know what went into DES or what came out. Kilian and Rogaway proved in 1996 that a generic key search against DESX costs about 2^119 \u002F m DES runs, where m is how many plaintext and ciphertext pairs the attacker has.",[214,486,487],{},"Against attacks on DES itself the gain is much smaller. Differential and linear cryptanalysis get a bit harder, nothing like the jump brute force takes. And in 2000 Biryukov and Wagner found a slide attack on DESX, 2^32.5 known plaintexts and 2^87.5 work. Nowhere near practical, but a lot less than 184 bits.",[471,489,491],{"id":490},"why-ecb-leaks","Why ECB leaks",[214,493,494,495,498],{},"Same as every ECB here. Sixteen ",[228,496,497],{},"A","s are two equal blocks, and they come out as two equal blocks:",[221,500,502],{"className":259,"code":501,"language":261,"meta":230,"style":230},"desx.encode(\"A\".repeat(16), { key }).text;\n\u002F\u002F 7df87a008ee59961 7df87a008ee59961 f5cb6e9d23564414\n",[228,503,504,541],{"__ignoreMap":230},[265,505,506,508,510,512,514,516,518,520,522,525,527,530,533,535,537,539],{"class":267,"line":268},[265,507,212],{"class":326},[265,509,256],{"class":286},[265,511,331],{"class":282},[265,513,287],{"class":286},[265,515,291],{"class":290},[265,517,497],{"class":294},[265,519,291],{"class":290},[265,521,256],{"class":286},[265,523,524],{"class":282},"repeat",[265,526,287],{"class":286},[265,528,529],{"class":452},"16",[265,531,532],{"class":286},"), {",[265,534,307],{"class":326},[265,536,348],{"class":286},[265,538,226],{"class":326},[265,540,320],{"class":286},[265,542,543],{"class":267,"line":302},[265,544,545],{"class":356},"\u002F\u002F 7df87a008ee59961 7df87a008ee59961 f5cb6e9d23564414\n",[214,547,548],{},"Spaces added to show the blocks. The last one is only padding.",[214,550,551,552,555,556,559,560,562,563,566,567,569],{},"A key that isn't 48 hex digits is an ",[228,553,554],{},"InvalidOptionError",", a missing one a ",[228,557,558],{},"MissingOptionError",". On ",[228,561,250],{},", ciphertext that isn't whole 8-byte blocks of hex is a ",[228,564,565],{},"CipherError",". A wrong key almost always breaks the padding, and that's a ",[228,568,565],{}," too. So are decrypted bytes that aren't UTF-8. This one is plain TypeScript over bit arrays, slow and not constant time. Puzzles and learning, not secrets.",[571,572,573],"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":230,"searchDepth":302,"depth":302,"links":575},[576,577],{"id":473,"depth":302,"text":474},{"id":490,"depth":302,"text":491},"Rivest's cheap fix for the DES key, one XOR before and one after. Same speed as DES, 184 key bits, UTF-8 text in, hex out.","md",null,{},true,{"title":184,"description":578},"PDWQissgLeO_osLNsHq8BAginz8-GSXw1HTYR22k0mw",[586,588],{"title":180,"path":181,"stem":182,"description":587,"children":-1},"The Data Encryption Standard, one pass of 16 Feistel rounds under a 56-bit key. UTF-8 text in, hex out, and every 8-byte block encrypted on its own.",{"title":188,"path":189,"stem":190,"description":589,"children":-1},"Lai and Massey's cipher from early PGP. No S-boxes, just XOR, addition and multiplication on 16-bit words under a 128-bit key. UTF-8 text in, hex out.",1790332462648]