[{"data":1,"prerenderedAt":697},["ShallowReactive",2],{"navigation_docs":3,"-ciphers-aes-cfb":156,"-ciphers-aes-cfb-surround":692},[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":140,"body":158,"description":685,"extension":686,"links":687,"meta":688,"navigation":689,"path":141,"seo":690,"stem":142,"__hash__":691},"docs\u002F2.ciphers\u002F25.aes-cfb.md",{"type":159,"value":160,"toc":681},"minimark",[161,165,169,181,189,200,412,427,484,487,492,507,548,551,555,558,647,650,674,677],[162,163],"cipher-facts",{"name":164},"aes-cfb",[166,167,168],"p",{},"CFB is cipher feedback, another mode from NIST SP 800-38A. It turns AES into something that works like a stream cipher. There's a register, 16 bytes, and it starts as the IV. AES encrypts the register, and the leftmost bits of the result get XORed into the plaintext. What comes out is the ciphertext, and that ciphertext gets shifted into the register from the right. Then again, until the text runs out.",[166,170,171,172,176,177,180],{},"How many bits per step is ",[173,174,175],"code",{},"segment",". 128 is the default, a whole block at a time, and it's what ",[173,178,179],{},"openssl enc -aes-128-cfb"," means. 8 is one byte per step, 1 is one bit. Those two cost a full AES call per byte or per bit. Slow, but some protocols use them anyway.",[166,182,183,184,188],{},"Two things differ from ",[185,186,187],"a",{"href":137},"CBC",". AES only runs forward, decryption too, because the keystream is made the same way on both sides. And there's no padding. Fourteen bytes of text give fourteen bytes of ciphertext.",[166,190,191,192,195,196,199],{},"The key is 32, 48 or 64 hex digits, ",[173,193,194],{},"iv"," is 32 and it's required, same as in CBC. ",[173,197,198],{},"decode"," wants hex back, any whole number of bytes.",[201,202,207],"pre",{"className":203,"code":204,"language":205,"meta":206,"style":206},"language-ts shiki shiki-themes github-light github-light poimandres","const cfb = create(\"aes-cfb\");\nconst key = \"2b7e151628aed2a6abf7158809cf4f3c\";\nconst iv = \"000102030405060708090a0b0c0d0e0f\";\ncfb.encode(\"ATTACK AT DAWN\", { key, iv }).text; \u002F\u002F \"11aa338dda2612f78e2973a8cce1\"\ncfb.encode(\"ATTACK AT DAWN\", { key, iv, segment: 8 }).text; \u002F\u002F \"11585d087981d10c0863f5b2c8dd\"\ncfb.decode(\"11aa338dda2612f78e2973a8cce1\", { key, iv }).text; \u002F\u002F \"ATTACK AT DAWN\"\n","ts","",[173,208,209,245,266,285,330,377],{"__ignoreMap":206},[210,211,214,218,222,225,229,233,237,240,242],"span",{"class":212,"line":213},"line",1,[210,215,217],{"class":216},"s1TYA","const",[210,219,221],{"class":220},"saoiD"," cfb",[210,223,224],{"class":216}," =",[210,226,228],{"class":227},"sULi6"," create",[210,230,232],{"class":231},"sKlNE","(",[210,234,236],{"class":235},"scVjq","\"",[210,238,164],{"class":239},"sQ7BG",[210,241,236],{"class":235},[210,243,244],{"class":231},");\n",[210,246,248,250,253,255,258,261,263],{"class":212,"line":247},2,[210,249,217],{"class":216},[210,251,252],{"class":220}," key",[210,254,224],{"class":216},[210,256,257],{"class":235}," \"",[210,259,260],{"class":239},"2b7e151628aed2a6abf7158809cf4f3c",[210,262,236],{"class":235},[210,264,265],{"class":231},";\n",[210,267,269,271,274,276,278,281,283],{"class":212,"line":268},3,[210,270,217],{"class":216},[210,272,273],{"class":220}," iv",[210,275,224],{"class":216},[210,277,257],{"class":235},[210,279,280],{"class":239},"000102030405060708090a0b0c0d0e0f",[210,282,236],{"class":235},[210,284,265],{"class":231},[210,286,288,292,295,298,300,302,305,307,310,312,315,317,320,323,326],{"class":212,"line":287},4,[210,289,291],{"class":290},"spVlQ","cfb",[210,293,294],{"class":231},".",[210,296,297],{"class":227},"encode",[210,299,232],{"class":231},[210,301,236],{"class":235},[210,303,304],{"class":239},"ATTACK AT DAWN",[210,306,236],{"class":235},[210,308,309],{"class":231},", {",[210,311,252],{"class":290},[210,313,314],{"class":231},",",[210,316,273],{"class":290},[210,318,319],{"class":231}," }).",[210,321,322],{"class":290},"text",[210,324,325],{"class":231},"; ",[210,327,329],{"class":328},"sjhu3","\u002F\u002F \"11aa338dda2612f78e2973a8cce1\"\n",[210,331,333,335,337,339,341,343,345,347,349,351,353,355,357,361,364,368,370,372,374],{"class":212,"line":332},5,[210,334,291],{"class":290},[210,336,294],{"class":231},[210,338,297],{"class":227},[210,340,232],{"class":231},[210,342,236],{"class":235},[210,344,304],{"class":239},[210,346,236],{"class":235},[210,348,309],{"class":231},[210,350,252],{"class":290},[210,352,314],{"class":231},[210,354,273],{"class":290},[210,356,314],{"class":231},[210,358,360],{"class":359},"snHMy"," segment",[210,362,363],{"class":231},":",[210,365,367],{"class":366},"siHFe"," 8",[210,369,319],{"class":231},[210,371,322],{"class":290},[210,373,325],{"class":231},[210,375,376],{"class":328},"\u002F\u002F \"11585d087981d10c0863f5b2c8dd\"\n",[210,378,380,382,384,386,388,390,393,395,397,399,401,403,405,407,409],{"class":212,"line":379},6,[210,381,291],{"class":290},[210,383,294],{"class":231},[210,385,198],{"class":227},[210,387,232],{"class":231},[210,389,236],{"class":235},[210,391,392],{"class":239},"11aa338dda2612f78e2973a8cce1",[210,394,236],{"class":235},[210,396,309],{"class":231},[210,398,252],{"class":290},[210,400,314],{"class":231},[210,402,273],{"class":290},[210,404,319],{"class":231},[210,406,322],{"class":290},[210,408,325],{"class":231},[210,410,411],{"class":328},"\u002F\u002F \"ATTACK AT DAWN\"\n",[166,413,414,415,418,419,422,423,426],{},"The first byte is ",[173,416,417],{},"11"," in both. No accident, both XOR it with the first byte of AES over the IV. After that the register differs and so does everything else. OpenSSL gives the same bytes, with ",[173,420,421],{},"-aes-128-cfb8"," or ",[173,424,425],{},"-aes-128-cfb1"," for the smaller segments:",[201,428,432],{"className":429,"code":430,"language":431,"meta":206,"style":206},"language-bash shiki shiki-themes github-light github-light poimandres","printf %s \"ATTACK AT DAWN\" | openssl enc -aes-128-cfb -K 2b7e151628aed2a6abf7158809cf4f3c -iv 000102030405060708090a0b0c0d0e0f | xxd -p\n","bash",[173,433,434],{"__ignoreMap":206},[210,435,436,440,444,446,448,450,453,457,460,464,467,470,473,476,478,481],{"class":212,"line":213},[210,437,439],{"class":438},"s39Ir","printf",[210,441,443],{"class":442},"sX7Zv"," %s",[210,445,257],{"class":235},[210,447,304],{"class":239},[210,449,236],{"class":235},[210,451,452],{"class":216}," |",[210,454,456],{"class":455},"sseY5"," openssl",[210,458,459],{"class":442}," enc",[210,461,463],{"class":462},"sqT1Y"," -aes-128-cfb",[210,465,466],{"class":462}," -K",[210,468,469],{"class":442}," 2b7e151628aed2a6abf7158809cf4f3c",[210,471,472],{"class":462}," -iv",[210,474,475],{"class":442}," 000102030405060708090a0b0c0d0e0f",[210,477,452],{"class":216},[210,479,480],{"class":455}," xxd",[210,482,483],{"class":462}," -p\n",[166,485,486],{},"The mode is tested against the CFB1, CFB8 and CFB128 vectors from NIST SP 800-38A, F.3.",[488,489,491],"h2",{"id":490},"flipping-bits","Flipping bits",[166,493,494,495,498,499,502,503,506],{},"The plaintext is XORed with a keystream, so a flipped ciphertext bit flips the same plaintext bit. Nobody needs the key for that. ",[173,496,497],{},"DAWN"," and ",[173,500,501],{},"DUSK"," differ by ",[173,504,505],{},"00140405",", XOR that into the last four bytes:",[201,508,510],{"className":203,"code":509,"language":205,"meta":206,"style":206},"cfb.decode(\"11aa338dda2612f78e2973bcc8e4\", { key, iv }).text;\n\u002F\u002F \"ATTACK AT DUSK\"\n",[173,511,512,543],{"__ignoreMap":206},[210,513,514,516,518,520,522,524,527,529,531,533,535,537,539,541],{"class":212,"line":213},[210,515,291],{"class":290},[210,517,294],{"class":231},[210,519,198],{"class":227},[210,521,232],{"class":231},[210,523,236],{"class":235},[210,525,526],{"class":239},"11aa338dda2612f78e2973bcc8e4",[210,528,236],{"class":235},[210,530,309],{"class":231},[210,532,252],{"class":290},[210,534,314],{"class":231},[210,536,273],{"class":290},[210,538,319],{"class":231},[210,540,322],{"class":290},[210,542,265],{"class":231},[210,544,545],{"class":212,"line":247},[210,546,547],{"class":328},"\u002F\u002F \"ATTACK AT DUSK\"\n",[166,549,550],{},"It worked cleanly because those bytes are the last segment. A flip anywhere earlier also lands in the register, and the next 16 bytes come out as garbage. In CBC the flip goes to the next block and the garbage stays in its own. Here it's the other way around.",[488,552,554],{"id":553},"zerologon","Zerologon",[166,556,557],{},"CFB-8 with an all-zero IV has one famous hole. Take a key where AES of the zero block starts with a zero byte, that's 1 key in 256. Encrypt zero bytes and the keystream byte is zero, so the ciphertext byte is zero. That zero goes into the register, and the register stays all zeros. Forever.",[201,559,561],{"className":203,"code":560,"language":205,"meta":206,"style":206},"cfb.encode(\"\\0\".repeat(8), { key: \"0000000000000000000000000000005f\", iv: \"0\".repeat(32), segment: 8 }).text;\n\u002F\u002F \"0000000000000000\"\n",[173,562,563,642],{"__ignoreMap":206},[210,564,565,567,569,571,573,575,579,581,583,586,588,591,594,596,598,600,603,605,607,609,611,613,616,618,620,622,624,627,630,632,634,636,638,640],{"class":212,"line":213},[210,566,291],{"class":290},[210,568,294],{"class":231},[210,570,297],{"class":227},[210,572,232],{"class":231},[210,574,236],{"class":235},[210,576,578],{"class":577},"stM5N","\\0",[210,580,236],{"class":235},[210,582,294],{"class":231},[210,584,585],{"class":227},"repeat",[210,587,232],{"class":231},[210,589,590],{"class":366},"8",[210,592,593],{"class":231},"), {",[210,595,252],{"class":359},[210,597,363],{"class":231},[210,599,257],{"class":235},[210,601,602],{"class":239},"0000000000000000000000000000005f",[210,604,236],{"class":235},[210,606,314],{"class":231},[210,608,273],{"class":359},[210,610,363],{"class":231},[210,612,257],{"class":235},[210,614,615],{"class":239},"0",[210,617,236],{"class":235},[210,619,294],{"class":231},[210,621,585],{"class":227},[210,623,232],{"class":231},[210,625,626],{"class":366},"32",[210,628,629],{"class":231},"),",[210,631,360],{"class":359},[210,633,363],{"class":231},[210,635,367],{"class":366},[210,637,319],{"class":231},[210,639,322],{"class":290},[210,641,265],{"class":231},[210,643,644],{"class":212,"line":247},[210,645,646],{"class":328},"\u002F\u002F \"0000000000000000\"\n",[166,648,649],{},"That's CVE-2020-1472. Netlogon used AES-CFB8 with a zero IV, so sending zeros as the client credential worked for one session key in 256. A few hundred tries and you could log in as any machine account, the domain controller's included. CFB-128 doesn't do this, the whole register is replaced every block.",[166,651,652,653,656,657,659,660,662,663,666,667,669,670,673],{},"A key that isn't 32, 48 or 64 hex digits is an ",[173,654,655],{},"InvalidOptionError",". So is an ",[173,658,194],{}," that isn't 32 hex digits, and a ",[173,661,175],{}," that isn't 1, 8 or 128. A missing key or IV is a ",[173,664,665],{},"MissingOptionError",". On ",[173,668,198],{},", an odd number of hex digits is a ",[173,671,672],{},"CipherError",". With no padding, nothing tells a wrong key apart except the UTF-8 check. Most wrong keys fail it, but a short message can come out as valid garbage. A wrong IV garbles the first 16 bytes and leaves the rest alone.",[166,675,676],{},"No integrity check, plain TypeScript, not constant time. For puzzles and for Zerologon on a whiteboard. Don't protect anything real with it.",[678,679,680],"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 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}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 .stM5N, html code.shiki .stM5N{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#5FB3A1}",{"title":206,"searchDepth":247,"depth":247,"links":682},[683,684],{"id":490,"depth":247,"text":491},{"id":553,"depth":247,"text":554},"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.","md",null,{},true,{"title":140,"description":685},"QzjQkQmsLxNSmfXC4A2SBBjQ6EgA_pBv_K78lzGKwf0",[693,695],{"title":136,"path":137,"stem":138,"description":694,"children":-1},"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.",{"title":144,"path":145,"stem":146,"description":696,"children":-1},"AES over a counter. Each block of the keystream is the next counter value run through AES, XORed into the text. UTF-8 text in, hex out, no padding, and decrypting is the same step.",1790272611043]