[{"data":1,"prerenderedAt":674},["ShallowReactive",2],{"navigation_docs":3,"-ciphers-aes-cbc-mac":180,"-ciphers-aes-cbc-mac-surround":669},[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":172,"body":182,"description":662,"extension":663,"links":664,"meta":665,"navigation":666,"path":173,"seo":667,"stem":174,"__hash__":668},"docs\u002F2.ciphers\u002F33.aes-cbc-mac.md",{"type":183,"value":184,"toc":657},"minimark",[185,189,193,201,345,354,361,470,476,481,488,502,506,519,553,559,563,575,612,633,650,653],[186,187],"cipher-facts",{"name":188},"aes-cbc-mac",[190,191,192],"p",{},"This one doesn't hide anything. The text goes out as plain bytes, and the only new thing is a 16-byte tag on the end that proves whoever wrote it had the key. It's the oldest MAC built from a block cipher, FIPS 113 from 1985 with DES inside, and ISO\u002FIEC 9797-1 calls it MAC Algorithm 1.",[190,194,195,196,200],{},"The recipe is ",[197,198,199],"a",{"href":137},"CBC"," with the IV set to zeros. Every block gets XORed with the previous result and encrypted, and at the end you throw away everything except the last block. That block is the tag. A text that doesn't fill its last block gets zeros up to 16 bytes, and an empty one becomes one block of zeros.",[202,203,208],"pre",{"className":204,"code":205,"language":206,"meta":207,"style":207},"language-ts shiki shiki-themes github-light github-light poimandres","const mac = create(\"aes-cbc-mac\");\nconst key = \"2b7e151628aed2a6abf7158809cf4f3c\";\nmac.encode(\"ATTACK AT DAWN\", { key }).text;\n\u002F\u002F \"41545441434b204154204441574e\" + \"1efa905609cc69e415825c40f80501e8\"\nmac.decode(\"41545441434b204154204441574e1efa905609cc69e415825c40f80501e8\", { key }).text;\n\u002F\u002F \"ATTACK AT DAWN\"\n","ts","",[209,210,211,247,268,303,310,339],"code",{"__ignoreMap":207},[212,213,216,220,224,227,231,235,239,242,244],"span",{"class":214,"line":215},"line",1,[212,217,219],{"class":218},"s1TYA","const",[212,221,223],{"class":222},"saoiD"," mac",[212,225,226],{"class":218}," =",[212,228,230],{"class":229},"sULi6"," create",[212,232,234],{"class":233},"sKlNE","(",[212,236,238],{"class":237},"scVjq","\"",[212,240,188],{"class":241},"sQ7BG",[212,243,238],{"class":237},[212,245,246],{"class":233},");\n",[212,248,250,252,255,257,260,263,265],{"class":214,"line":249},2,[212,251,219],{"class":218},[212,253,254],{"class":222}," key",[212,256,226],{"class":218},[212,258,259],{"class":237}," \"",[212,261,262],{"class":241},"2b7e151628aed2a6abf7158809cf4f3c",[212,264,238],{"class":237},[212,266,267],{"class":233},";\n",[212,269,271,275,278,281,283,285,288,290,293,295,298,301],{"class":214,"line":270},3,[212,272,274],{"class":273},"spVlQ","mac",[212,276,277],{"class":233},".",[212,279,280],{"class":229},"encode",[212,282,234],{"class":233},[212,284,238],{"class":237},[212,286,287],{"class":241},"ATTACK AT DAWN",[212,289,238],{"class":237},[212,291,292],{"class":233},", {",[212,294,254],{"class":273},[212,296,297],{"class":233}," }).",[212,299,300],{"class":273},"text",[212,302,267],{"class":233},[212,304,306],{"class":214,"line":305},4,[212,307,309],{"class":308},"sjhu3","\u002F\u002F \"41545441434b204154204441574e\" + \"1efa905609cc69e415825c40f80501e8\"\n",[212,311,313,315,317,320,322,324,327,329,331,333,335,337],{"class":214,"line":312},5,[212,314,274],{"class":273},[212,316,277],{"class":233},[212,318,319],{"class":229},"decode",[212,321,234],{"class":233},[212,323,238],{"class":237},[212,325,326],{"class":241},"41545441434b204154204441574e1efa905609cc69e415825c40f80501e8",[212,328,238],{"class":237},[212,330,292],{"class":233},[212,332,254],{"class":273},[212,334,297],{"class":233},[212,336,300],{"class":273},[212,338,267],{"class":233},[212,340,342],{"class":214,"line":341},6,[212,343,344],{"class":308},"\u002F\u002F \"ATTACK AT DAWN\"\n",[190,346,347,348,350,351,353],{},"The first fourteen bytes are just ",[209,349,287],{}," in hex. Anyone can read them. ",[209,352,319],{}," runs the MAC again over those bytes and compares, and only then hands the text back.",[190,355,356,357,360],{},"Take a text of exactly one block and the tag is the first block that ",[209,358,359],{},"aes-cbc"," gives with a zero IV:",[202,362,364],{"className":204,"code":363,"language":206,"meta":207,"style":207},"create(\"aes-cbc\").encode(\"ATTACK AT DAWN!!\", { key, iv: \"00\".repeat(16) }).text;\n\u002F\u002F \"541ff0c92b9251ae06c624c4a8ab2a85\" + \"c4c37a672a17ac138199e2ad092b90ae\"\nmac.encode(\"ATTACK AT DAWN!!\", { key }).text;\n\u002F\u002F \"41545441434b204154204441574e2121\" + \"541ff0c92b9251ae06c624c4a8ab2a85\"\n",[209,365,366,434,439,465],{"__ignoreMap":207},[212,367,368,371,373,375,377,379,382,384,386,388,391,393,395,397,400,404,407,409,412,414,416,419,421,425,428,430,432],{"class":214,"line":215},[212,369,370],{"class":229},"create",[212,372,234],{"class":233},[212,374,238],{"class":237},[212,376,359],{"class":241},[212,378,238],{"class":237},[212,380,381],{"class":233},").",[212,383,280],{"class":229},[212,385,234],{"class":233},[212,387,238],{"class":237},[212,389,390],{"class":241},"ATTACK AT DAWN!!",[212,392,238],{"class":237},[212,394,292],{"class":233},[212,396,254],{"class":273},[212,398,399],{"class":233},",",[212,401,403],{"class":402},"snHMy"," iv",[212,405,406],{"class":233},":",[212,408,259],{"class":237},[212,410,411],{"class":241},"00",[212,413,238],{"class":237},[212,415,277],{"class":233},[212,417,418],{"class":229},"repeat",[212,420,234],{"class":233},[212,422,424],{"class":423},"siHFe","16",[212,426,427],{"class":233},")",[212,429,297],{"class":233},[212,431,300],{"class":273},[212,433,267],{"class":233},[212,435,436],{"class":214,"line":249},[212,437,438],{"class":308},"\u002F\u002F \"541ff0c92b9251ae06c624c4a8ab2a85\" + \"c4c37a672a17ac138199e2ad092b90ae\"\n",[212,440,441,443,445,447,449,451,453,455,457,459,461,463],{"class":214,"line":270},[212,442,274],{"class":273},[212,444,277],{"class":233},[212,446,280],{"class":229},[212,448,234],{"class":233},[212,450,238],{"class":237},[212,452,390],{"class":241},[212,454,238],{"class":237},[212,456,292],{"class":233},[212,458,254],{"class":273},[212,460,297],{"class":233},[212,462,300],{"class":273},[212,464,267],{"class":233},[212,466,467],{"class":214,"line":305},[212,468,469],{"class":308},"\u002F\u002F \"41545441434b204154204441574e2121\" + \"541ff0c92b9251ae06c624c4a8ab2a85\"\n",[190,471,472,473,475],{},"The second block from ",[209,474,359],{}," is its PKCS#7 padding, which the MAC doesn't have.",[477,478,480],"h2",{"id":479},"the-options","The options",[190,482,483,484,487],{},"Only ",[209,485,486],{},"key",", 32, 48 or 64 hex digits. No IV, no nonce. The IV has to be zero. An IV that travels with the message lets anyone change the first block and fix the tag by changing the IV the same way. And since nothing is random, the same text under the same key always gets the same tag.",[190,489,490,493,494,497,498,501],{},[209,491,492],{},"openssl enc"," has no MAC mode, so the reference is Node's ",[209,495,496],{},"createCipheriv(\"aes-128-cbc\")"," with a zero IV and padding off, over the zero-padded text, and taking the last block. It matches. The tests also check the last block of the NIST SP 800-38A CBC example and the tag of empty text, which is AES of a zero block, the ",[209,499,500],{},"L"," from RFC 4493.",[477,503,505],{"id":504},"what-the-tag-catches","What the tag catches",[190,507,508,511,512,515,516,406],{},[209,509,510],{},"DAWN"," to ",[209,513,514],{},"DUSK",", same as in ",[197,517,518],{"href":149},"CCM",[202,520,522],{"className":204,"code":521,"language":206,"meta":207,"style":207},"mac.decode(\"41545441434b204154204455534b1efa905609cc69e415825c40f80501e8\", { key });\n\u002F\u002F CipherError: [aes-cbc-mac] Tag does not match: wrong key, or the text was changed\n",[209,523,524,548],{"__ignoreMap":207},[212,525,526,528,530,532,534,536,539,541,543,545],{"class":214,"line":215},[212,527,274],{"class":273},[212,529,277],{"class":233},[212,531,319],{"class":229},[212,533,234],{"class":233},[212,535,238],{"class":237},[212,537,538],{"class":241},"41545441434b204154204455534b1efa905609cc69e415825c40f80501e8",[212,540,238],{"class":237},[212,542,292],{"class":233},[212,544,254],{"class":273},[212,546,547],{"class":233}," });\n",[212,549,550],{"class":214,"line":249},[212,551,552],{"class":308},"\u002F\u002F CipherError: [aes-cbc-mac] Tag does not match: wrong key, or the text was changed\n",[190,554,555,556,558],{},"A new tag for ",[209,557,514],{}," needs the key. A wrong key ends the same way.",[477,560,562],{"id":561},"what-it-doesnt","What it doesn't",[190,564,565,566,568,569,571,572,574],{},"Zero padding has a hole. ",[209,567,287],{}," and ",[209,570,287],{}," with two zero bytes on the end pad to the same block, so they get the same tag, and ",[209,573,319],{}," takes both:",[202,576,578],{"className":204,"code":577,"language":206,"meta":207,"style":207},"mac.decode(\"41545441434b204154204441574e00001efa905609cc69e415825c40f80501e8\", { key }).text;\n\u002F\u002F \"ATTACK AT DAWN\\0\\0\"\n",[209,579,580,607],{"__ignoreMap":207},[212,581,582,584,586,588,590,592,595,597,599,601,603,605],{"class":214,"line":215},[212,583,274],{"class":273},[212,585,277],{"class":233},[212,587,319],{"class":229},[212,589,234],{"class":233},[212,591,238],{"class":237},[212,593,594],{"class":241},"41545441434b204154204441574e00001efa905609cc69e415825c40f80501e8",[212,596,238],{"class":237},[212,598,292],{"class":233},[212,600,254],{"class":273},[212,602,297],{"class":233},[212,604,300],{"class":273},[212,606,267],{"class":233},[212,608,609],{"class":214,"line":249},[212,610,611],{"class":308},"\u002F\u002F \"ATTACK AT DAWN\\0\\0\"\n",[190,613,614,615,618,619,622,623,625,626,629,630,632],{},"The bigger one is length. CBC-MAC is only safe when every message has the same length. Know the tag ",[209,616,617],{},"t"," of a one-block message ",[209,620,621],{},"m",", and ",[209,624,621],{}," followed by ",[209,627,628],{},"m XOR t"," has the same tag ",[209,631,617],{},", no key needed. That's why CMAC exists, and why CCM puts the length into its first block. A lot of CTFs are built on exactly this.",[190,634,635,636,639,640,643,644,646,647,277],{},"A key that isn't 32, 48 or 64 hex digits is an ",[209,637,638],{},"InvalidOptionError",", a missing one is a ",[209,641,642],{},"MissingOptionError",". On ",[209,645,319],{},", hex that isn't whole bytes, input shorter than the tag, or a tag that doesn't match is a ",[209,648,649],{},"CipherError",[190,651,652],{},"Plain TypeScript, not constant time. It's here for the forgeries, not for signing anything real.",[654,655,656],"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 .snHMy, html code.shiki .snHMy{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#ADD7FF}html pre.shiki code .siHFe, html code.shiki .siHFe{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#5DE4C7}",{"title":207,"searchDepth":249,"depth":249,"links":658},[659,660,661],{"id":479,"depth":249,"text":480},{"id":504,"depth":249,"text":505},{"id":561,"depth":249,"text":562},"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.","md",null,{},true,{"title":172,"description":662},"G2QUpbU_lOISELZyG0bdM2x4004Pupis0FHXwd_piao",[670,672],{"title":168,"path":169,"stem":170,"description":671,"children":-1},"The disk mode that replaced LRW. Every block masked by its sector and its position, a short last block steals from the one before, and nothing is padded. UTF-8 text in, hex out.",{"title":176,"path":177,"stem":178,"description":673,"children":-1},"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.",1790291185467]