[{"data":1,"prerenderedAt":594},["ShallowReactive",2],{"navigation_docs":3,"-ciphers-aes-cbc":156,"-ciphers-aes-cbc-surround":589},[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":155},"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],{"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","i-solar-library-linear",{"id":157,"title":136,"body":158,"description":582,"extension":583,"links":584,"meta":585,"navigation":586,"path":137,"seo":587,"stem":138,"__hash__":588},"docs\u002F2.ciphers\u002F24.aes-cbc.md",{"type":159,"value":160,"toc":578},"minimark",[161,165,174,186,351,354,411,414,419,426,478,481,485,488,539,550,571,574],[162,163],"cipher-facts",{"name":164},"aes-cbc",[166,167,168,169,173],"p",{},"CBC is cipher block chaining, the mode from NIST SP 800-38A that most CTFs with AES end up using. It's ",[170,171,172],"a",{"href":125},"AES"," with one step before every block. The plaintext block is XORed with the ciphertext block that came out just before it, then encrypted. The first block has nothing before it, so it gets the IV instead. Decryption runs it backwards: decrypt the block, then XOR with the previous ciphertext block, or with the IV for the first one.",[166,175,176,177,181,182,185],{},"The key is 32, 48 or 64 hex digits, same as in ECB. ",[178,179,180],"code",{},"iv"," is 32 hex digits, one block, and it's required. There's no default, because a silent all-zero IV is exactly the kind of thing that gives you the wrong plaintext with a straight face. Text and ciphertext work as in AES: UTF-8 with PKCS#7 padding in, lowercase hex out, and ",[178,183,184],{},"decode"," wants hex back.",[187,188,193],"pre",{"className":189,"code":190,"language":191,"meta":192,"style":192},"language-ts shiki shiki-themes github-light github-light poimandres","const cbc = create(\"aes-cbc\");\nconst key = \"2b7e151628aed2a6abf7158809cf4f3c\";\nconst iv = \"000102030405060708090a0b0c0d0e0f\";\ncbc.encode(\"ATTACK AT DAWN\", { key, iv }).text; \u002F\u002F \"9bae05a967f1cf1d7d3601f7ef8b4d79\"\ncbc.decode(\"9bae05a967f1cf1d7d3601f7ef8b4d79\", { key, iv }).text; \u002F\u002F \"ATTACK AT DAWN\"\n","ts","",[178,194,195,231,252,271,316],{"__ignoreMap":192},[196,197,200,204,208,211,215,219,223,226,228],"span",{"class":198,"line":199},"line",1,[196,201,203],{"class":202},"s1TYA","const",[196,205,207],{"class":206},"saoiD"," cbc",[196,209,210],{"class":202}," =",[196,212,214],{"class":213},"sULi6"," create",[196,216,218],{"class":217},"sKlNE","(",[196,220,222],{"class":221},"scVjq","\"",[196,224,164],{"class":225},"sQ7BG",[196,227,222],{"class":221},[196,229,230],{"class":217},");\n",[196,232,234,236,239,241,244,247,249],{"class":198,"line":233},2,[196,235,203],{"class":202},[196,237,238],{"class":206}," key",[196,240,210],{"class":202},[196,242,243],{"class":221}," \"",[196,245,246],{"class":225},"2b7e151628aed2a6abf7158809cf4f3c",[196,248,222],{"class":221},[196,250,251],{"class":217},";\n",[196,253,255,257,260,262,264,267,269],{"class":198,"line":254},3,[196,256,203],{"class":202},[196,258,259],{"class":206}," iv",[196,261,210],{"class":202},[196,263,243],{"class":221},[196,265,266],{"class":225},"000102030405060708090a0b0c0d0e0f",[196,268,222],{"class":221},[196,270,251],{"class":217},[196,272,274,278,281,284,286,288,291,293,296,298,301,303,306,309,312],{"class":198,"line":273},4,[196,275,277],{"class":276},"spVlQ","cbc",[196,279,280],{"class":217},".",[196,282,283],{"class":213},"encode",[196,285,218],{"class":217},[196,287,222],{"class":221},[196,289,290],{"class":225},"ATTACK AT DAWN",[196,292,222],{"class":221},[196,294,295],{"class":217},", {",[196,297,238],{"class":276},[196,299,300],{"class":217},",",[196,302,259],{"class":276},[196,304,305],{"class":217}," }).",[196,307,308],{"class":276},"text",[196,310,311],{"class":217},"; ",[196,313,315],{"class":314},"sjhu3","\u002F\u002F \"9bae05a967f1cf1d7d3601f7ef8b4d79\"\n",[196,317,319,321,323,325,327,329,332,334,336,338,340,342,344,346,348],{"class":198,"line":318},5,[196,320,277],{"class":276},[196,322,280],{"class":217},[196,324,184],{"class":213},[196,326,218],{"class":217},[196,328,222],{"class":221},[196,330,331],{"class":225},"9bae05a967f1cf1d7d3601f7ef8b4d79",[196,333,222],{"class":221},[196,335,295],{"class":217},[196,337,238],{"class":276},[196,339,300],{"class":217},[196,341,259],{"class":276},[196,343,305],{"class":217},[196,345,308],{"class":276},[196,347,311],{"class":217},[196,349,350],{"class":314},"\u002F\u002F \"ATTACK AT DAWN\"\n",[166,352,353],{},"OpenSSL gives the same bytes:",[187,355,359],{"className":356,"code":357,"language":358,"meta":192,"style":192},"language-bash shiki shiki-themes github-light github-light poimandres","printf %s \"ATTACK AT DAWN\" | openssl enc -aes-128-cbc -K 2b7e151628aed2a6abf7158809cf4f3c -iv 000102030405060708090a0b0c0d0e0f | xxd -p\n","bash",[178,360,361],{"__ignoreMap":192},[196,362,363,367,371,373,375,377,380,384,387,391,394,397,400,403,405,408],{"class":198,"line":199},[196,364,366],{"class":365},"s39Ir","printf",[196,368,370],{"class":369},"sX7Zv"," %s",[196,372,243],{"class":221},[196,374,290],{"class":225},[196,376,222],{"class":221},[196,378,379],{"class":202}," |",[196,381,383],{"class":382},"sseY5"," openssl",[196,385,386],{"class":369}," enc",[196,388,390],{"class":389},"sqT1Y"," -aes-128-cbc",[196,392,393],{"class":389}," -K",[196,395,396],{"class":369}," 2b7e151628aed2a6abf7158809cf4f3c",[196,398,399],{"class":389}," -iv",[196,401,402],{"class":369}," 000102030405060708090a0b0c0d0e0f",[196,404,379],{"class":202},[196,406,407],{"class":382}," xxd",[196,409,410],{"class":389}," -p\n",[166,412,413],{},"The block function is tested against the CBC-AES128, 192 and 256 vectors from NIST SP 800-38A, F.2.",[415,416,418],"h2",{"id":417},"what-the-chain-fixes","What the chain fixes",[166,420,421,422,425],{},"Thirty-two ",[178,423,424],{},"A","s, two equal blocks of plaintext. In ECB they come out as two equal blocks of ciphertext. Here:",[187,427,429],{"className":189,"code":428,"language":191,"meta":192,"style":192},"cbc.encode(\"A\".repeat(32), { key, iv }).text;\n\u002F\u002F ab74350f2f19b4ea4de050762e12dbc1 8d2f731d5ae2fa0858814a0e6df219ca 25292ca5cf9e35a0afb9452d5c640c6e\n",[178,430,431,473],{"__ignoreMap":192},[196,432,433,435,437,439,441,443,445,447,449,452,454,458,461,463,465,467,469,471],{"class":198,"line":199},[196,434,277],{"class":276},[196,436,280],{"class":217},[196,438,283],{"class":213},[196,440,218],{"class":217},[196,442,222],{"class":221},[196,444,424],{"class":225},[196,446,222],{"class":221},[196,448,280],{"class":217},[196,450,451],{"class":213},"repeat",[196,453,218],{"class":217},[196,455,457],{"class":456},"siHFe","32",[196,459,460],{"class":217},"), {",[196,462,238],{"class":276},[196,464,300],{"class":217},[196,466,259],{"class":276},[196,468,305],{"class":217},[196,470,308],{"class":276},[196,472,251],{"class":217},[196,474,475],{"class":198,"line":233},[196,476,477],{"class":314},"\u002F\u002F ab74350f2f19b4ea4de050762e12dbc1 8d2f731d5ae2fa0858814a0e6df219ca 25292ca5cf9e35a0afb9452d5c640c6e\n",[166,479,480],{},"Spaces added here to show the blocks. Nothing repeats, because the second block was mixed with the first one's ciphertext before AES saw it. But the same message under the same key and the same IV gives the same ciphertext again. That's why the IV should be new for every message.",[415,482,484],{"id":483},"what-it-doesnt-fix","What it doesn't fix",[166,486,487],{},"On decryption the previous ciphertext block, or the IV, is XORed in after AES. So whoever can change it changes the plaintext, bit for bit, without the key. Flip bytes in the IV and the first block says what you want:",[187,489,491],{"className":189,"code":490,"language":191,"meta":192,"style":192},"cbc.decode(\"9bae05a967f1cf1d7d3601f7ef8b4d79\", { key, iv: \"000102030405060708090a1f08080e0f\" }).text;\n\u002F\u002F \"ATTACK AT DUSK\"\n",[178,492,493,534],{"__ignoreMap":192},[196,494,495,497,499,501,503,505,507,509,511,513,515,518,521,523,526,528,530,532],{"class":198,"line":199},[196,496,277],{"class":276},[196,498,280],{"class":217},[196,500,184],{"class":213},[196,502,218],{"class":217},[196,504,222],{"class":221},[196,506,331],{"class":225},[196,508,222],{"class":221},[196,510,295],{"class":217},[196,512,238],{"class":276},[196,514,300],{"class":217},[196,516,259],{"class":517},"snHMy",[196,519,520],{"class":217},":",[196,522,243],{"class":221},[196,524,525],{"class":225},"000102030405060708090a1f08080e0f",[196,527,222],{"class":221},[196,529,305],{"class":217},[196,531,308],{"class":276},[196,533,251],{"class":217},[196,535,536],{"class":198,"line":233},[196,537,538],{"class":314},"\u002F\u002F \"ATTACK AT DUSK\"\n",[166,540,541,542,545,546,549],{},"That IV is the old one XORed with ",[178,543,544],{},"DAWN"," and ",[178,547,548],{},"DUSK"," at bytes 10 to 13. Nobody touched the key. Flip a byte in a ciphertext block instead and that block decrypts to garbage, while the next one gets the same flip. It's the bit flipping attack from every other CTF, and with an error that tells bad padding apart, it's also the padding oracle.",[166,551,552,553,556,557,559,560,563,564,566,567,570],{},"A key that isn't 32, 48 or 64 hex digits is an ",[178,554,555],{},"InvalidOptionError",", and so is an ",[178,558,180],{}," that isn't 32 hex digits. A missing key or IV is a ",[178,561,562],{},"MissingOptionError",". On ",[178,565,184],{},", hex that isn't whole 16-byte blocks is a ",[178,568,569],{},"CipherError",". So is a wrong key, since the padding almost never survives it. A wrong IV garbles only the first block. In a one-block message that breaks the padding, in a longer one it's almost always bytes that aren't UTF-8. But an IV that's only a little off, like the one above, decodes without a word.",[166,572,573],{},"No integrity check, plain TypeScript, not constant time. For puzzles and for seeing what the chain does. Don't protect anything real with it.",[575,576,577],"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}html pre.shiki code .snHMy, html code.shiki .snHMy{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#ADD7FF}",{"title":192,"searchDepth":233,"depth":233,"links":579},[580,581],{"id":417,"depth":233,"text":418},{"id":483,"depth":233,"text":484},"AES with the blocks chained. Every 16-byte block is mixed with the ciphertext before it, so equal blocks stop looking equal. UTF-8 text in, hex out.","md",null,{},true,{"title":136,"description":582},"SbMJahJChvba3pkyRRq2Lwz7TPkfhW66ZHHC7RLl0cE",[590,592],{"title":132,"path":133,"stem":134,"description":591,"children":-1},"AES with a tweak. Every 16-byte block is masked by its own position, so equal blocks stop looking equal. UTF-8 text in, hex out.",{"title":140,"path":141,"stem":142,"description":593,"children":-1},"AES as a keystream. Every segment of ciphertext is fed back into the register that makes the next one, 1, 8 or 128 bits at a time. UTF-8 text in, hex out, not a byte of padding.",1790272610901]