<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Parag Mali - tag: authenticated-encryption</title><description>Posts tagged authenticated-encryption.</description><link>https://paragmali.com/</link><language>en-US</language><lastBuildDate>Sat, 25 Jul 2026 08:57:51 GMT</lastBuildDate><atom:link href="https://paragmali.com/tags/authenticated-encryption/rss.xml" rel="self" type="application/rss+xml"/><item><title>How AES Breaks in Real Life: The Attacks That Never Touched the Cipher</title><link>https://paragmali.com/blog/how-aes-breaks-in-real-life-the-attacks-that-never-touched-t/</link><guid isPermaLink="true">https://paragmali.com/blog/how-aes-breaks-in-real-life-the-attacks-that-never-touched-t/</guid><description>AES-the-cipher has never been broken in the field -- its deployments have. KRACK, repeated GCM nonces, and cache timing broke the wrapper, never the block.</description><pubDate>Fri, 17 Jul 2026 00:00:00 GMT</pubDate><content:encoded>
**AES-the-cipher has never been broken in the field. Your AES traffic was decrypted anyway.** The best publicly known attack on the full cipher costs about $2^{126}$ operations for AES-128 -- its own authors say it does &quot;not threaten the practical use of AES in any way&quot; [@biclique-2011]. Yet real Wi-Fi sessions were decrypted, real HTTPS connections were forged, and real AES keys were lifted out of running servers. None of it touched the 128-bit block math. AES is a *permutation*, not a cryptosystem: to protect a message you wrap it in an *implementation*, a *mode*, and a *protocol*, and it was those three wrappers that failed -- a T-table lookup leaked the key through cache timing [@bernstein-2005; @osvik-shamir-tromer-2006]; 184 live HTTPS servers repeated an AES-GCM nonce and weaponized Joux&apos;s 2006 forbidden attack into forgery [@nonce-disrespecting-2016; @joux-2006]; and KRACK&apos;s replayed handshake rewound the AES-CCMP nonce and reused a keystream [@krack-2017]. Every fix changed *how AES is used*, never AES.
&lt;h2&gt;1. AES Is Unbroken. Your AES Traffic Was Decrypted Anyway.&lt;/h2&gt;
&lt;p&gt;The best publicly known attack on the full AES cipher costs roughly $2^{126}$ operations for AES-128 -- a number so far beyond feasible that its own discoverers wrote it does &quot;not threaten the practical use of AES in any way&quot; [@biclique-2011]. To put $2^{126}$ in scale: if every one of the billions of computers on Earth checked a billion keys a second, you would still wait longer than the age of the universe, many times over. By any honest measure, the cipher stands.&lt;/p&gt;
&lt;p&gt;And yet, in the same decade that number was published, attackers decrypted live Wi-Fi sessions, forged authenticated HTTPS connections, and lifted AES keys straight out of running servers -- none of them going anywhere near that $2^{126}$ wall. How does a cipher nobody can break keep producing decrypted traffic and stolen keys?&lt;/p&gt;
&lt;p&gt;The resolution is the thesis of this article, and you can hold it right now: &lt;strong&gt;none of these breaks touched the 128-bit block math.&lt;/strong&gt; AES is a keyed &lt;em&gt;permutation&lt;/em&gt; -- a function that scrambles one 16-byte block into another -- and nothing more. It is not a cryptosystem. To protect a real message you wrap that permutation in three things: an &lt;em&gt;implementation&lt;/em&gt; that computes it on real silicon, a &lt;em&gt;mode&lt;/em&gt; that chains it across a message, and a &lt;em&gt;protocol&lt;/em&gt; that establishes keys and drives the mode. Each wrapper is a new, independent way to fail. And it was the wrappers, every time, that failed.&lt;/p&gt;
&lt;p&gt;That gives you a diagnostic sentence to carry through the rest of this piece. When your encrypted traffic falls, the question is never &quot;was AES broken?&quot; It is: &lt;em&gt;which layer around AES failed -- the implementation, the mode, or the protocol?&lt;/em&gt; By the end you will be able to drop KRACK, the GCM nonce scandal, and tomorrow&apos;s not-yet-published incident into that one question on sight.&lt;/p&gt;

To break AES in the field, you never touch AES. The table lookup leaks, the nonce repeats, the handshake rewinds -- and the 128-bit block math never moves.
&lt;p&gt;This is Part 1 of &lt;em&gt;How It Breaks in Real Life&lt;/em&gt;, a series with a single recurring claim: the primitive&apos;s mathematics almost never caused the break; the deployment did -- the nonce, the padding, key generation, a downgrade, a validation bug, or a deprecated-but-still-live algorithm. AES is the cleanest case, which is why it goes first. Its companion piece, &lt;em&gt;How AES Would Break&lt;/em&gt;, asks what it would take to move the block itself: the key schedule, related-key cryptanalysis, the slow erosion of the security margin. That is the &lt;em&gt;would-break-in-theory&lt;/em&gt; story. This is the &lt;em&gt;did-break-in-the-field&lt;/em&gt; one.&lt;/p&gt;
&lt;p&gt;If the cipher was intact and the block math never moved, then everything that broke was built &lt;em&gt;around&lt;/em&gt; it. To see how &quot;unbroken cipher&quot; and &quot;decrypted traffic&quot; can both be true, you have to go back to what AES actually is -- and, more to the point, what it is not.&lt;/p&gt;
&lt;h2&gt;2. Why a Cipher Is Not a Cryptosystem&lt;/h2&gt;
&lt;p&gt;In October 2000, after a three-year open competition in which the world&apos;s cryptographers were &lt;em&gt;invited to attack&lt;/em&gt; the candidates, NIST selected Joan Daemen and Vincent Rijmen&apos;s Rijndael as the Advanced Encryption Standard [@nist-press-2000]. The choice followed a public evaluation of fifteen submissions narrowed to five finalists, judged on security, performance, and efficiency from servers to smart cards [@nist-aes-dev; @nist-jres-r1-1999; @nist-jres-r2-2001]. That adversarial process is why the core math has held for over two decades -- and why, when things break in the field, the fault lies elsewhere. Winning the competition made Rijndael a &lt;em&gt;cipher&lt;/em&gt;, not a cryptosystem.&lt;/p&gt;
&lt;p&gt;Here is the distinction the whole article turns on. AES, standardized as FIPS 197 in 2001 and editorially refreshed in 2023 with &lt;em&gt;no technical change&lt;/em&gt; to the algorithm, is a keyed &lt;strong&gt;128-bit permutation&lt;/strong&gt; [@fips-197]. It maps one 128-bit block to one 128-bit block under a 128-, 192-, or 256-bit key, and that is &lt;em&gt;all&lt;/em&gt; it does.AES applies 10, 12, or 14 rounds for the 128-, 192-, and 256-bit keys. The round function is identical across all three; key size changes only the round count and the key schedule that feeds it [@fips-197]. It has no notion of a message longer than 16 bytes, no integrity, no session or conversation. Feed it the same block and key twice and you get the same output twice. On its own it cannot safely encrypt a paragraph, let alone a Wi-Fi session.&lt;/p&gt;

A **block cipher** is a keyed permutation on fixed-size blocks -- AES maps one 16-byte block to another under a key. A **mode of operation** (CTR, CCM, GCM, and others) is the wrapper that chains that permutation across an arbitrary-length message and, in authenticated modes, adds integrity. The block cipher is the engine; the mode is the car. You do not drive an engine.
&lt;p&gt;To turn that engine into something that protects real data, you add three wrappers, and each one is a new, independent failure surface:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;an &lt;strong&gt;implementation&lt;/strong&gt; that computes the permutation on a real CPU, and may leak through timing or cache behavior;&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;&lt;a href=&quot;https://paragmali.com/blog/the-ciphertext-was-unbreakable-the-attacker-rewrote-it-anyw/&quot; rel=&quot;noopener&quot;&gt;mode of operation&lt;/a&gt;&lt;/strong&gt; that chains the permutation across a whole message and, in AEAD modes, adds integrity -- and imposes a contract on how you feed it nonces;&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;protocol&lt;/strong&gt; that establishes keys and drives the mode, and can mismanage them.&lt;/li&gt;
&lt;/ul&gt;

flowchart TD
    B[&quot;AES 128-bit permutation -- never broken in the field&quot;]
    I[&quot;Implementation layer -- computes the block in code or silicon&quot;]
    M[&quot;Mode layer -- chains the block, adds integrity, imposes a nonce contract&quot;]
    P[&quot;Protocol layer -- establishes keys and drives the mode&quot;]
    B --&amp;gt; I --&amp;gt; M --&amp;gt; P
    I -. break .-&amp;gt; AtkI[&quot;Cache timing leaks the key&quot;]
    M -. break .-&amp;gt; AtkM[&quot;A repeated nonce reuses a keystream&quot;]
    P -. break .-&amp;gt; AtkP[&quot;A replayed handshake rewinds the nonce&quot;]
&lt;p&gt;This map is the lens for everything that follows. The block sits at the center, untouched. The implementation wraps it, the mode wraps that, the protocol wraps that -- and the three field breaks in this article land on the three outer rings, in order, working outward from the silicon.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; AES has a &lt;strong&gt;128-bit block size&lt;/strong&gt; for all three variants; only the &lt;em&gt;key&lt;/em&gt; is 128, 192, or 256 bits. When this article says &quot;the 128-bit block math never moved,&quot; it means the block permutation, not the key. Hold onto a foreshadow: key size will turn out to be irrelevant to every break here. Against nonce reuse and a reinstalled handshake key, AES-256 fails exactly as fast as AES-128; against cache timing it is just as vulnerable, though a longer key takes proportionally more leakage to extract.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;One more piece of honesty before we watch the wrappers fail. The series this article opens says the primitive&apos;s math &lt;em&gt;almost&lt;/em&gt; never causes the break -- &quot;almost,&quot; not &quot;never&quot; -- and the hedge is load-bearing.Every break in this article is independent of key size. That is not a rhetorical flourish; it is a literal property of cache timing, nonce reuse, and handshake replay, none of which involve guessing key bits.&lt;/p&gt;

Some deployed primitives genuinely fell as *math*, not deployment. DES died to brute force because its 56-bit key was too short, which is *why* NIST ran the AES competition in the first place. RC4&apos;s keystream biases were turned into real plaintext recovery against TLS [@alfardan-2013]. MD5 and SHA-1 fell to collision attacks -- the SHAttered project produced the first SHA-1 collision at roughly $2^{63}$ hash computations [@shattered-2017]. Those are real breaks of the primitive&apos;s mathematics. AES is simply not one of them, which is what makes its deployment-versus-primitive split so clean. Never harden &quot;almost never&quot; into &quot;the math never breaks.&quot;
&lt;p&gt;Three wrappers, three contracts, three ways to fail -- none of them the cipher. Before watching each one break in the field, you need to see the contracts up close: what a mode actually promises, what a nonce is, and why the humble table lookup is a loaded gun.&lt;/p&gt;
&lt;h2&gt;3. The Layers Around the Block, and the Contracts They Impose&lt;/h2&gt;
&lt;p&gt;Every one of the three field breaks is the violation of a single, specific promise. If you see the promise clearly now, the break will look obvious later. So here are all three contracts, one per layer, in order.&lt;/p&gt;
&lt;h3&gt;The implementation contract: a lookup should not leak what it looked up&lt;/h3&gt;
&lt;p&gt;Computing AES the naive way -- byte by byte through its S-box and its field multiplications -- is slow in software. So fast implementations fold an entire round into precomputed lookup tables. Four tables of about 1 KB each, conventionally called &lt;code&gt;T0&lt;/code&gt; through &lt;code&gt;T3&lt;/code&gt;, turn each output column of a round into &lt;code&gt;T0[a] XOR T1[b] XOR T2[c] XOR T3[d]&lt;/code&gt;: four reads and three XORs, so a full round is four of those -- sixteen reads in all [@bernstein-2005].&lt;/p&gt;

A set of precomputed lookup tables (typically four tables of 256 four-byte entries, about 4 KB total) that fold AES&apos;s SubBytes, ShiftRows, and MixColumns steps into a handful of table reads per round. It is purely a speed optimization. The block permutation it computes is identical to the slow version -- but *how* it computes it now depends on secret-derived indices.
&lt;p&gt;The hidden assumption is that a table read takes the same time regardless of which entry you read. On a real CPU with a cache hierarchy, that is &lt;em&gt;false&lt;/em&gt;: the first access to a memory line is slow, a cached line is fast, and an attacker can measure the difference. And the indices &lt;code&gt;a, b, c, d&lt;/code&gt; are secret -- state bytes derived from the key XORed with the plaintext. So which table lines get touched, and therefore the timing, depends on the key. The implementation&apos;s contract is that a data-dependent lookup must not leak the data. The cache breaks it for free.&lt;/p&gt;
&lt;h3&gt;The mode contract: never repeat a (key, nonce) pair&lt;/h3&gt;
&lt;p&gt;A mode turns the one-block permutation into something that encrypts messages and detects tampering. Modern modes aim for AEAD.&lt;/p&gt;

Authenticated Encryption with Associated Data: a mode that provides confidentiality *and* integrity at once. It encrypts the plaintext and produces an authentication tag over both the ciphertext and some associated data (headers, sequence numbers) that is authenticated but not encrypted. GCM and CCM are AEAD modes; if the tag does not verify, the receiver rejects the message.
&lt;p&gt;The workhorse construction is counter mode. AES is run on a counter to produce a &lt;em&gt;keystream&lt;/em&gt;, and the keystream is XORed with the plaintext: keystream block $k_i = \mathrm{AES}_K(\text{nonce} \parallel i)$, and ciphertext $C_i = P_i \oplus k_i$. This is elegant and fast and fully parallel. It also carries one absolute obligation.&lt;/p&gt;

A **nonce** is a &quot;number used once.&quot; In counter-based modes the pair (key, nonce) must be **unique for every encryption under that key**. The nonce need not be secret or random -- a counter is fine -- but it must never repeat. This is the single most load-bearing rule in practical symmetric cryptography, and it is the rule every mode-and-protocol break in this article violates.
&lt;p&gt;Watch what happens if you break it. If two messages are encrypted under the same key &lt;em&gt;and the same nonce&lt;/em&gt;, they get the &lt;em&gt;same&lt;/em&gt; keystream. XOR the two ciphertexts and the keystream cancels:&lt;/p&gt;
&lt;p&gt;$$C_1 \oplus C_2 = (P_1 \oplus k) \oplus (P_2 \oplus k) = P_1 \oplus P_2$$&lt;/p&gt;
&lt;p&gt;The key never appears. The attacker who captures two same-nonce ciphertexts learns the XOR of the two plaintexts, and if they know or can guess one, they get the other -- with the cipher fully intact.&lt;/p&gt;

The failure that follows from a repeated (key, nonce) in a counter-based mode: identical keystream for two messages, so $C_1 \oplus C_2 = P_1 \oplus P_2$. The plaintext XOR leaks and the key is never touched. This one mechanic drives *both* the GCM break and the WPA2/CCMP break later in this article.
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; A block cipher in a counter-based mode is a keystream generator. Feed it the same (key, nonce) twice and you get the same keystream, so $C_1 \oplus C_2 = P_1 \oplus P_2$ -- the plaintext XOR leaks and the key is never touched. The nonce-uniqueness contract is the one promise that stops this. Break it and the strongest cipher in the world protects nothing.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You can watch the cancellation happen. Nothing below is real AES -- the toy keystream stands in for AES-CTR output -- but the XOR algebra is exactly the algebra of the real break.&lt;/p&gt;
&lt;p&gt;{`
// Same (key, nonce) =&amp;gt; same keystream for BOTH messages. That is the whole bug.
const keystream = [0x9e, 0x37, 0xb1, 0xa4, 0x55, 0x0c, 0xd2, 0x6f];&lt;/p&gt;
&lt;p&gt;function xorBytes(a, b) {
  const out = [];
  for (let i = 0; i &amp;lt; a.length; i++) out.push(a[i] ^ b[i]);
  return out;
}
const toBytes = (s) =&amp;gt; Array.from(s).map((c) =&amp;gt; c.charCodeAt(0));&lt;/p&gt;
&lt;p&gt;const p1 = toBytes(&quot;ATTACK 0&quot;);
const p2 = toBytes(&quot;defend!!&quot;);&lt;/p&gt;
&lt;p&gt;const c1 = xorBytes(p1, keystream);   // what the attacker sees
const c2 = xorBytes(p2, keystream);   // what the attacker sees&lt;/p&gt;
&lt;p&gt;const leaked = xorBytes(c1, c2);      // C1 ^ C2, computed with NO key
const truth  = xorBytes(p1, p2);      // P1 ^ P2, the secret relationship&lt;/p&gt;
&lt;p&gt;console.log(&quot;C1 ^ C2 =&quot;, leaked.join(&quot;,&quot;));
console.log(&quot;P1 ^ P2 =&quot;, truth.join(&quot;,&quot;));
console.log(&quot;keystream cancelled?&quot;, JSON.stringify(leaked) === JSON.stringify(truth));
// Know one plaintext, recover the other. The cipher stayed perfectly strong.
`}&lt;/p&gt;
&lt;p&gt;GCM adds one more thing to worry about. Its integrity tag is built from a secret authentication subkey derived from the key alone, and &lt;a href=&quot;https://paragmali.com/blog/one-number-used-twice-how-a-repeated-nonce-hands-over-your-p/&quot; rel=&quot;noopener&quot;&gt;a repeated nonce&lt;/a&gt; exposes that subkey to attack as well -- which is how confidentiality loss becomes &lt;em&gt;forgery&lt;/em&gt;. We will pull that thread in the next section.&lt;/p&gt;
&lt;p&gt;Even with perfectly unique nonces, GCM has a budget. With random 96-bit nonces, NIST caps a single key at fewer than $2^{32}$ invocations, because random 96-bit values begin colliding around the birthday bound [@sp-800-38d]. Uniqueness is not just a coding rule; it is a counting problem.&lt;/p&gt;

When AES-GCM came to TLS 1.2, RFC 5288 let the implementation choose part of each record&apos;s nonce -- an &quot;explicit nonce&quot; -- and its own security-considerations text carried a &quot;Counter Reuse&quot; warning that a repeated counter is catastrophic [@rfc-5288]. The contract was not merely implied; it was written down, in the same document that shipped the feature. A decade later, a scan of the live Internet found servers breaking it anyway.
&lt;h3&gt;The protocol contract: install a key once, so its nonce only ever counts up&lt;/h3&gt;
&lt;p&gt;A mode still needs a protocol to establish keys and supply nonces. WPA2&apos;s 4-way handshake derives a fresh Pairwise Transient Key, and AES-CCMP then encrypts each frame with a nonce built from an incrementing packet number; CCM, like GCM, forbids repeating that counter under one key [@sp-800-38c; @ieee-80211i-2004]. The assumption is simple and, on its face, obviously true: a key is installed exactly once, so the packet number only ever counts &lt;em&gt;up&lt;/em&gt; and never rewinds.&lt;/p&gt;
&lt;p&gt;Here are the three contracts side by side. Keep the last column in view -- it is the bill each violation runs up.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;What it is&lt;/th&gt;
&lt;th&gt;The contract it imposes&lt;/th&gt;
&lt;th&gt;What a violation costs&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Implementation&lt;/td&gt;
&lt;td&gt;Code or silicon that computes the AES round&lt;/td&gt;
&lt;td&gt;A data-dependent lookup must not leak the data&lt;/td&gt;
&lt;td&gt;Cache/timing side channel recovers the key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mode&lt;/td&gt;
&lt;td&gt;CTR, GCM, CCM chaining the block across a message&lt;/td&gt;
&lt;td&gt;The (key, nonce) pair must be unique per encryption&lt;/td&gt;
&lt;td&gt;Keystream reuse leaks $P_1 \oplus P_2$; in GCM, forgery&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Protocol&lt;/td&gt;
&lt;td&gt;Handshake and key management driving the mode&lt;/td&gt;
&lt;td&gt;A key is installed once, so its nonce only counts up&lt;/td&gt;
&lt;td&gt;A reinstalled key rewinds the nonce, forcing reuse&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Three contracts, each reasonable, each &lt;em&gt;unenforced by the cipher&lt;/em&gt; -- the permutation cannot know whether you fed it a repeated nonce or read a leaky table. Which raises the only question that matters: in the real world, running on real servers and real routers, do these contracts actually hold? They do not. Here is where, when, and how each one broke.&lt;/p&gt;
&lt;h2&gt;4. Three Field Breaks, Three Layers, One Pattern&lt;/h2&gt;
&lt;p&gt;The comfortable belief is &quot;we standardized a strong cipher, so our encrypted traffic is safe.&quot; What follows are three independent refutations of that inference -- one at each layer around the block, ordered by when the field break landed. Read them as a catalog, not a lineage: these are not ciphers that replaced one another but three &lt;em&gt;simultaneous&lt;/em&gt; layers, every real deployment has all three at once, and the chronology is the attacker&apos;s frontier moving &lt;em&gt;outward&lt;/em&gt; as each inner layer hardened.&lt;/p&gt;

timeline
    title From the silicon outward -- one pattern, three layers
    2005-2006 : Implementation layer : Cache timing recovers AES keys (Bernstein, Osvik-Shamir-Tromer)
    2016 : Mode layer : 184 HTTPS servers repeat a GCM nonce (Böck et al., weaponizing Joux 2006)
    2017 : Protocol layer : KRACK rewinds the AES-CCMP nonce (Vanhoef and Piessens)
&lt;h3&gt;Generation 1: the implementation leaked (2005-2006)&lt;/h3&gt;
&lt;p&gt;In 2005, Daniel J. Bernstein did something the FIPS 197 math says is impossible: he recovered a full AES key &lt;em&gt;remotely&lt;/em&gt;, over a network -- without breaking AES at all [@bernstein-2005; @bernstein-index]. The target was a server doing nothing but AES under clean timing conditions, so the demonstration was remote in principle rather than turnkey -- and alarming precisely because it was not purely local. It ran ordinary T-table AES, whose secret-dependent indices left the encryption&apos;s timing faintly correlated with the key; enough samples pinned the key bytes. A year later, Dag Arne Osvik, Adi Shamir, and Eran Tromer formalized the idea into two reusable cache attacks -- &lt;strong&gt;Prime+Probe&lt;/strong&gt; and &lt;strong&gt;Evict+Time&lt;/strong&gt; -- recovering keys with a modest number of encryptions on a shared machine [@osvik-shamir-tromer-2006].&lt;/p&gt;

Recovering a secret from the physical *side effects* of a computation -- its timing, its cache footprint, its power draw -- rather than from the algorithm&apos;s inputs and outputs. A cache-timing attack on T-table AES watches which cache lines the lookups touch; because the touched lines depend on key-derived indices, the access pattern leaks the key.
&lt;p&gt;The mechanism is worth seeing as a chain, because every link is outside the cipher:&lt;/p&gt;

flowchart LR
    K[&quot;Secret index = key byte XOR plaintext byte&quot;] --&amp;gt; L[&quot;Which T-table cache line is touched&quot;]
    L --&amp;gt; M[&quot;Cache hit or miss changes measurable timing&quot;]
    M --&amp;gt; R[&quot;Attacker narrows and then pins the key byte&quot;]
&lt;p&gt;You can feel the leak in miniature. A real CPU caches memory in lines of 64 bytes, so a 256-entry table falls into a handful of cache lines. The attacker never sees the secret index -- only which &lt;em&gt;line&lt;/em&gt; was touched. Watch a single observation cut the keyspace:&lt;/p&gt;
&lt;p&gt;{`
// A CPU caches memory in 64-byte lines, so 256 one-byte table entries fall into
// a few &quot;cache lines.&quot; The attacker sees ONLY which line was touched -- not the index.
const LINE = 64;
const touchedLine = (index) =&amp;gt; Math.floor(index / LINE);&lt;/p&gt;
&lt;p&gt;const secretKeyByte = 0xB7;                   // unknown to the attacker
const plaintextByte = 0x2A;                   // attacker-chosen, known
const realIndex = secretKeyByte ^ plaintextByte;
const observed = touchedLine(realIndex);      // the only thing that leaks&lt;/p&gt;
&lt;p&gt;// Which key bytes are consistent with the observed cache line?
const candidates = [];
for (let k = 0; k &amp;lt; 256; k++) {
  if (touchedLine(k ^ plaintextByte) === observed) candidates.push(k);
}
console.log(&quot;observed cache line:&quot;, observed);
console.log(&quot;key-byte candidates remaining:&quot;, candidates.length, &quot;of 256&quot;);
console.log(&quot;true key byte still in the set?&quot;, candidates.includes(secretKeyByte));
// One measurement: 256 -&amp;gt; 64. Vary the known plaintext, intersect the sets, and the byte falls out.
`}&lt;/p&gt;
&lt;p&gt;The insight is the sharpest edge of the whole thesis, so state it plainly.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Cache timing recovers AES keys in the field -- that is real, and it is the reason &quot;AES is unbroken&quot; does not mean &quot;your key is safe.&quot; But the leak lives in the T-table&apos;s &lt;em&gt;memory-access pattern&lt;/em&gt;, not in the permutation. The table is a speed optimization; swap it for a leak-free implementation and the key stops leaking while the cipher stays byte-for-byte identical. Keys fall, the cipher stands. Keep that distinction sharp -- collapsing it is the reader&apos;s default error.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The fix pointed straight at the next era, and it changed how AES is &lt;em&gt;computed&lt;/em&gt;, never what AES computes. Two responses followed: &lt;strong&gt;constant-time bitsliced software&lt;/strong&gt;, which replaces the tables with data-independent boolean logic so no secret ever indexes memory [@kasper-schwabe-2009]; and, decisively, &lt;strong&gt;hardware AES-NI&lt;/strong&gt;, which executes each round in silicon with no lookup tables and data-independent latency [@intel-aes-ni]. Once AES-NI reached mainstream CPUs in the early 2010s, this surface largely closed -- and the attacker&apos;s frontier moved one ring outward, to the mode.The formalization is due to &lt;strong&gt;Osvik, Shamir, and Tromer&lt;/strong&gt; -- not Biham, a common misattribution [@osvik-shamir-tromer-2006].&lt;/p&gt;
&lt;h3&gt;Generation 2: the mode&apos;s contract was violated (2006, then 2016)&lt;/h3&gt;
&lt;p&gt;In June 2006, Antoine Joux submitted a public comment to NIST with a quietly devastating observation about GCM, now known as the &quot;forbidden attack&quot; [@joux-2006]. GCM, designed by David McGrew and John Viega, authenticates with a &lt;a href=&quot;https://paragmali.com/blog/the-tag-verified-the-cipher-held-the-forgery-went-through-a-/&quot; rel=&quot;noopener&quot;&gt;one-time polynomial MAC&lt;/a&gt; over the field $\mathrm{GF}(2^{128})$, keyed by a secret subkey derived from the encryption key alone [@mcgrew-viega-2004].&lt;/p&gt;

GCM&apos;s authentication secret, computed as $H = \mathrm{AES}_K(0^{128})$ -- the encryption of an all-zero block under the key. Every authentication tag is a polynomial in $H$ evaluated over the ciphertext, masked by $\mathrm{AES}_K(J_0)$ where $J_0$ comes from the nonce. Security depends on $H$ staying secret, which in turn depends on the nonce never repeating.
&lt;p&gt;Joux&apos;s point: if a (key, nonce) pair repeats, the mask $\mathrm{AES}_K(J_0)$ is &lt;em&gt;identical&lt;/em&gt; across the two messages, so the difference of their tags becomes a polynomial equation over $\mathrm{GF}(2^{128})$ whose unknown is $H$. Solve for the roots and you recover $H$; with $H$ in hand, you can forge a valid authentication tag for a message you chose -- universal forgery [@joux-2006]. The confidentiality loss from keystream reuse was already bad; this makes &lt;em&gt;integrity&lt;/em&gt; fall too.&lt;/p&gt;

flowchart TD
    N[&quot;Same (key, nonce) used for two messages&quot;] --&amp;gt; KS[&quot;Identical CTR keystream&quot;]
    KS --&amp;gt; C[&quot;C1 XOR C2 equals P1 XOR P2, confidentiality lost&quot;]
    N --&amp;gt; J[&quot;Identical tag mask AES_K of J0&quot;]
    J --&amp;gt; EQ[&quot;Tag difference becomes a polynomial equation in H over GF(2 to the 128)&quot;]
    EQ --&amp;gt; F[&quot;Roots reveal the subkey H, enabling forgery&quot;]
&lt;p&gt;For ten years this was a footnote -- a warning about a contract nobody, surely, would break. Then, in 2016, Hanno Böck, Aaron Zauner, Sean Devlin, Juraj Somorovsky, and Philipp Jovanovic scanned the Internet and found it broken in the wild [@nonce-disrespecting-2016]. Their paper, &quot;Nonce-Disrespecting Adversaries,&quot; reported &lt;strong&gt;184 live HTTPS servers actually repeating GCM nonces&lt;/strong&gt; -- &quot;which fully breaks the authenticity of the connections&quot; -- among them large corporations, financial institutions, and a credit-card company, plus more than 70,000 servers using random nonces at volume risk.&lt;/p&gt;
&lt;p&gt;They then did the thing Joux only described: they weaponized the repeats into working forgeries and injected content into live sessions. The root cause was mundane and entirely operational -- buggy hardware and firmware nonce generators, and counters that reset. The mode&apos;s assumption failed; AES did exactly what it was told.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; GCM will not stop you from repeating a nonce. Never generate a nonce you might repeat across process restarts, threads, forks, or virtual-machine clones and snapshots. A saved counter that resets to zero on restart is worse than useless -- it guarantees the reuse. AES-256 offers exactly zero protection here: key size is irrelevant to nonce reuse.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Two precisions keep this honest. First, the mechanism is layer-agnostic in the worst way: this is the &lt;em&gt;same keystream-reuse atom&lt;/em&gt; from Section 3, now carrying a forgery payload because GCM&apos;s integrity also leans on the nonce. Second, resist the tempting overstatement.&lt;strong&gt;Precision lock.&lt;/strong&gt; One nonce reuse is &lt;em&gt;already&lt;/em&gt; a break: it immediately leaks $C_1 \oplus C_2 = P_1 \oplus P_2$ and gives one root-finding equation for $H$. But &lt;em&gt;uniquely pinning&lt;/em&gt; $H$ for reliable universal forgery generally needs at least two collisions. Say &quot;one reuse is already catastrophic, and more reuse pins the subkey&quot; -- never &quot;one reuse recovers the key&quot; [@joux-2006]. The evidence for live reuse is the Böck et al. scan, five authors, 184 servers -- not the frequently miscited IBM Domino CVE [@nonce-disrespecting-2016].&lt;/p&gt;
&lt;p&gt;The fixes, once again, changed the &lt;em&gt;usage&lt;/em&gt; and left the cipher alone: nonce-misuse-resistant AES-GCM-SIV, where a repeat leaks only whether two messages were equal [@rfc-8452], and TLS 1.3&apos;s deterministic per-record nonce, which deletes the implementation-chosen &quot;explicit nonce&quot; that RFC 5288 had exposed [@rfc-8446]. As the mode hardened, the frontier moved one final ring outward -- to the protocol.&lt;/p&gt;
&lt;h3&gt;Generation 3: the protocol reused the nonce (2017)&lt;/h3&gt;
&lt;p&gt;WPA2&apos;s 4-way handshake exists to install a fresh key on both sides. The client installs its Pairwise Transient Key after message 3, and AES-CCMP then encrypts every frame with a nonce built from a packet number that only counts up. For reliability, the standard lets message 3 be retransmitted -- and there the trap was set. In 2017, Mathy Vanhoef and Frank Piessens showed that an attacker who captures and &lt;em&gt;replays message 3&lt;/em&gt; forces the client to reinstall a key it is already using, resetting the CCMP packet number and replay counter to their starting values [@krack-2017]. The nonce rewinds. The keystream repeats. This is KRACK: Key Reinstallation Attack.&lt;/p&gt;

Installing a key that is already in use. Because installing a key also initializes its associated nonce or packet-number counter, reinstalling an in-use key *rewinds* that counter to its starting value -- forcing the same (key, nonce) pairs, and therefore the same keystream, to be used again. KRACK triggers this by replaying a handshake message the protocol was willing to accept twice.

sequenceDiagram
    participant C as Client
    participant A as Access Point
    participant M as Attacker
    A-&amp;gt;&amp;gt;C: Message 1 (ANonce)
    C-&amp;gt;&amp;gt;A: Message 2 (SNonce)
    A-&amp;gt;&amp;gt;C: Message 3 (install key)
    Note over C: Installs PTK, packet number starts counting up
    C-&amp;gt;&amp;gt;A: Message 4 (acknowledge)
    M-&amp;gt;&amp;gt;C: Replay Message 3
    Note over C: Reinstalls the same key, packet number resets to start
    Note over C,A: Nonce reused, keystream repeats, frames become decryptable
&lt;p&gt;The insight is the same shape as before, delivered one layer further out: AES-CCMP did &lt;em&gt;exactly what it was told&lt;/em&gt;. The permutation was flawless; the state machine told it to reuse a nonce, and it obeyed. The consequence is keystream reuse -- identical (key, nonce) yields $C_1 \oplus C_2 = P_1 \oplus P_2$ -- so a known-plaintext frame yields the keystream and decrypts the colliding frame.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Scope lock.&lt;/strong&gt; Against AES-CCMP specifically, KRACK forces nonce-reuse &lt;em&gt;decryption and replay&lt;/em&gt; -- not forgery and not AES key recovery. Forgery arises for the TKIP and GCMP cases, not CCMP. The especially devastating all-zero-key variant was an Android and Linux &lt;code&gt;wpa_supplicant&lt;/code&gt; implementation bug that reinstalled an all-zero key, still not a break of AES [@krack-2017].&lt;/p&gt;
&lt;p&gt;The fix was a backwards-compatible patch to the handshake state machine -- refuse to reinstall an in-use key -- shipped across Android, Linux, Apple, Windows, and OpenBSD in 2017 [@krack-2017]. Structurally, the Wi-Fi Alliance announced WPA3 in 2018 [@wifi-wpa3-2018]; its Personal mode swaps WPA2&apos;s pre-shared-key authentication for the SAE (Dragonfly) key exchange and mandates anti-reinstallation checks plus management-frame protection. The 4-way handshake still installs the pairwise key, so KRACK immunity comes from that mandatory hardening -- the same defense WPA2 received as a patch -- not from SAE removing the handshake [@dragonblood-2019]. The protocol changed. AES did not.&lt;/p&gt;
&lt;h3&gt;The pattern, seen all at once&lt;/h3&gt;
&lt;p&gt;Put the three side by side and the shape is unmistakable. Same violated contract in three costumes; same untouched block every time.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Incident&lt;/th&gt;
&lt;th&gt;Year&lt;/th&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Mechanism&lt;/th&gt;
&lt;th&gt;Root cause&lt;/th&gt;
&lt;th&gt;Fix (usage, not cipher)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Bernstein; Osvik-Shamir-Tromer cache timing [@bernstein-2005; @osvik-shamir-tromer-2006]&lt;/td&gt;
&lt;td&gt;2005-2006&lt;/td&gt;
&lt;td&gt;Implementation&lt;/td&gt;
&lt;td&gt;Secret-dependent T-table indices leak via cache/timing&lt;/td&gt;
&lt;td&gt;A data-dependent lookup leaks the data&lt;/td&gt;
&lt;td&gt;Constant-time bitslicing; AES-NI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Joux forbidden attack; Böck et al. scan [@joux-2006; @nonce-disrespecting-2016]&lt;/td&gt;
&lt;td&gt;2006, 2016&lt;/td&gt;
&lt;td&gt;Mode&lt;/td&gt;
&lt;td&gt;Repeated GCM nonce reuses keystream and exposes $H$&lt;/td&gt;
&lt;td&gt;Buggy nonce generators break uniqueness&lt;/td&gt;
&lt;td&gt;AES-GCM-SIV; TLS 1.3 derived nonces&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;KRACK [@krack-2017]&lt;/td&gt;
&lt;td&gt;2017&lt;/td&gt;
&lt;td&gt;Protocol&lt;/td&gt;
&lt;td&gt;Replayed message 3 rewinds the CCMP nonce&lt;/td&gt;
&lt;td&gt;State machine reinstalls an in-use key&lt;/td&gt;
&lt;td&gt;Handshake patch; WPA3-SAE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Biclique baseline [@biclique-2011]&lt;/td&gt;
&lt;td&gt;2011&lt;/td&gt;
&lt;td&gt;The cipher itself&lt;/td&gt;
&lt;td&gt;Best single-key attack: $2^{126.1}$ for AES-128&lt;/td&gt;
&lt;td&gt;--&lt;/td&gt;
&lt;td&gt;None needed -- &quot;no practical impact&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Seen one at a time, these look like three unrelated bugs -- a cache thing, a TLS thing, a Wi-Fi thing. Seen together, they are a single pattern: every time, a contract &lt;em&gt;around&lt;/em&gt; the permutation was violated, real traffic or keys fell, and the 128-bit block math did not move. That pattern is the whole point, and it is worth naming out loud.&lt;/p&gt;
&lt;h2&gt;5. The Fixes Changed How AES Is Used, Never AES&lt;/h2&gt;
&lt;p&gt;Stop treating the three incidents as separate stories. Line them up and one realization collapses the subject: &lt;em&gt;every&lt;/em&gt; field break attacked a layer around the permutation, and &lt;em&gt;every&lt;/em&gt; fix changed how AES is &lt;em&gt;used&lt;/em&gt; -- never AES itself.&lt;/p&gt;
&lt;p&gt;This is not a eureka discovery. It is an engineering discipline, and it is visible only because the same shape repeats three times across 2005, 2016, and 2017. Look at what each fix actually touched:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Implementation.&lt;/strong&gt; Constant-time bitsliced code and hardware AES-NI compute the round with no data-dependent memory access [@kasper-schwabe-2009; @intel-aes-ni]. The tables are gone; the permutation they computed is unchanged.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mode.&lt;/strong&gt; AES-GCM-SIV makes a repeated nonce merely detectable rather than catastrophic -- a repeat leaks only whether two messages were equal, never the subkey $H$ [@rfc-8452]. TLS 1.3 derives each nonce deterministically from the record sequence number, deleting the footgun RFC 5288 had exposed [@rfc-8446]. The nonce plumbing changed; AES did not.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Protocol.&lt;/strong&gt; The KRACK patch forbids reinstalling an in-use key, and WPA3 makes that anti-reinstallation defense mandatory (alongside management-frame protection) while swapping WPA2&apos;s pre-shared-key authentication for the SAE key exchange; the 4-way handshake persists, hardened rather than removed [@krack-2017; @wifi-wpa3-2018; @dragonblood-2019]. The state machine changed; AES did not.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Not one of these altered the block permutation. They hardened wrappers.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The cipher is the fixed point around which everything else evolved. Every field break attacked a layer around the permutation, and every remedy -- constant-time and AES-NI, misuse-resistant AEAD and derived nonces, patched handshakes and WPA3 -- hardened a &lt;em&gt;wrapper&lt;/em&gt;. Soundness requires the weakest of the three layers to hold, and hardening any one of them is an exercise in &lt;em&gt;usage&lt;/em&gt;, not cryptanalysis.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There is a dynamic hiding in the chronology, and it is no coincidence. As AES-NI closed the implementation gap around 2010, the weakest remaining link -- the attacker&apos;s frontier -- moved to the mode, where the 2016 scan found it. As misuse-resistant modes and derived nonces closed that, the frontier moved to the protocol, where KRACK found it in 2017. The layers did not take turns being weak; the attacker simply always works the &lt;em&gt;current&lt;/em&gt; weakest one. That is why &quot;we use a strong cipher&quot; was never the right unit of analysis. The right unit is the weakest wrapper you are still running.&lt;/p&gt;

This article is the *did-break-in-the-field* story. Its companion, *How AES Would Break*, is the *would-break-in-theory* one: the key schedule, related-key attacks such as the Biryukov-Khovratovich results on AES-256 that only exist in a related-key model correct deployments never create [@biryukov-khovratovich-2009], and the slow erosion of the security margin. Different question, different article. And the general craft of constant-time code, fault resistance, and key custody belongs to a third sibling on secure implementation. This piece links out to both rather than re-teaching them, because the point here is narrow and sharp: the wrappers broke, and the wrappers were fixed.
&lt;p&gt;If every fix is a species of &quot;use AES correctly,&quot; then the state of the art is just the catalog of what &quot;correctly&quot; means at each layer in 2026 -- and, tellingly, where even correct-by-the-book still is not quite enough.&lt;/p&gt;
&lt;h2&gt;6. What Correct AES Deployment Looks Like in 2026&lt;/h2&gt;
&lt;p&gt;The modern answer is unglamorous, and that is exactly the point: be sound at all three layers at once, because a hardened mode does nothing for a leaky implementation, and a constant-time implementation does nothing for a protocol that rewinds its nonce. Here is the correct-deployment endpoint, keyed to the three failure loci.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Implementation.&lt;/strong&gt; Use hardware AES -- Intel and AMD AES-NI, or ARMv8&apos;s cryptographic extension -- which runs each round in silicon with no lookup tables and data-independent latency [@intel-aes-ni]. Where the CPU lacks AES instructions, fall back to a &lt;strong&gt;constant-time bitsliced&lt;/strong&gt; software implementation that never lets a secret index memory [@kasper-schwabe-2009]. Mainstream libraries typically make this selection at runtime, preferring hardware AES with a constant-time fallback.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mode.&lt;/strong&gt; Use a &lt;a href=&quot;https://paragmali.com/blog/the-aead-decision-matrix-seven-ciphers-three-edges-one-choic/&quot; rel=&quot;noopener&quot;&gt;vetted AEAD&lt;/a&gt;, never a hand-rolled chain of primitives. AES-GCM is the performance leader when you can &lt;em&gt;guarantee&lt;/em&gt; nonce uniqueness -- either random 96-bit nonces kept under the NIST budget of fewer than $2^{32}$ invocations per key [@sp-800-38d], or TLS 1.3&apos;s deterministic per-record nonce derived from the sequence number [@rfc-8446]. Where uniqueness cannot be guaranteed, use &lt;strong&gt;AES-GCM-SIV&lt;/strong&gt;, which survives a repeat gracefully [@rfc-8452].&lt;/p&gt;

An authenticated-encryption scheme that does not fail catastrophically when a nonce repeats. In an MRAE scheme such as AES-GCM-SIV, a repeated (nonce, message) pair leaks only the fact that the two plaintexts were identical -- never the keystream across distinct messages, never the subkey $H$. It is the provably strongest guarantee achievable once you admit that nonces sometimes repeat.
&lt;p&gt;&lt;strong&gt;Protocol.&lt;/strong&gt; At the link layer, patch WPA2 against key reinstallation or move to WPA3, which mandates anti-reinstallation checks and management-frame protection to close the defect while still running a 4-way handshake to install the pairwise key [@krack-2017; @wifi-wpa3-2018; @dragonblood-2019]. At the transport layer, prefer TLS 1.3 over 1.2: it deletes the explicit-nonce footgun and the downgrade and renegotiation hazards that made 1.2 fragile [@rfc-8446].&lt;/p&gt;
&lt;p&gt;There is one caveat that keeps this from being a victory lap, and it is a good illustration of how deep the &quot;usage&quot; story goes.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &quot;AES-NI is constant-time by construction&quot; is true by &lt;em&gt;design intent&lt;/em&gt;, but on Ice Lake and later Intel cores, and Armv8.4-A and later, data-operand-independent timing -- including for AES instructions -- is only &lt;em&gt;guaranteed&lt;/em&gt; when the processor&apos;s data-independent-timing mode is explicitly enabled [@intel-doit; @biggers-2023]. A constant-time algorithm is necessary but not sufficient for constant-time execution; part of the guarantee lives below your software, in a mode you now have to request.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The practical upshot is that &quot;constant-time&quot; has quietly become a setting rather than an assumption.On recent Intel cores the mode is called DOITM (Data Operand Independent Timing Mode); on Arm it is the DIT (Data-Independent Timing) processor-state bit. Eric Biggers raised the cross-vendor issue publicly in 2023, and it is the reason security-sensitive code on the newest silicon must ask for timing guarantees rather than inherit them [@biggers-2023; @intel-doit].&lt;/p&gt;
&lt;p&gt;&quot;Use a vetted AEAD, use hardware AES, patch your handshake&quot; is the whole answer for greenfield code. But engineers inherit constraints -- a fixed nonce source, a distributed system that cannot coordinate a counter, a CPU with no AES instructions. So the real question is rarely &quot;what is best.&quot; It is &quot;what are my options, ranked, and exactly when does each one apply?&quot;&lt;/p&gt;
&lt;h2&gt;7. Closing Each Gap: The Competing Defenses&lt;/h2&gt;
&lt;p&gt;At two of the three layers a practitioner actually has a &lt;em&gt;choice&lt;/em&gt;, and the honest framing is a set of trade-offs, not a single winner. Take the two design spaces in turn.&lt;/p&gt;
&lt;h3&gt;The side channel: hardware AES-NI versus software bitslicing&lt;/h3&gt;
&lt;p&gt;These two coexist because they optimize different constraints. Where the CPU has AES instructions, AES-NI is the fastest option and constant-time by construction (subject to the DOIT/DIT caveat from the previous section) [@intel-aes-ni]. Where it does not -- older cores, small embedded parts -- constant-time bitsliced software gives a verifiable timing guarantee at the cost of speed and implementation effort [@kasper-schwabe-2009]. The one option that is never acceptable in security code is the original T-table implementation.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;T-table AES (broken)&lt;/th&gt;
&lt;th&gt;Bitsliced constant-time software&lt;/th&gt;
&lt;th&gt;Hardware AES-NI / ARMv8&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Secret-dependent memory access&lt;/td&gt;
&lt;td&gt;Yes (about 4 KB of tables)&lt;/td&gt;
&lt;td&gt;None (boolean logic)&lt;/td&gt;
&lt;td&gt;None (silicon datapath)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Timing side-channel resistance&lt;/td&gt;
&lt;td&gt;Fails [@bernstein-2005; @osvik-shamir-tromer-2006]&lt;/td&gt;
&lt;td&gt;Constant-time by construction&lt;/td&gt;
&lt;td&gt;Data-independent by design; DOIT/DIT mode needed on Ice Lake+/Armv8.4+ [@intel-doit]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Throughput&lt;/td&gt;
&lt;td&gt;Fast (pre-attack)&lt;/td&gt;
&lt;td&gt;Good when blocks are batched&lt;/td&gt;
&lt;td&gt;Fastest; line-rate AEAD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Block-parallelism needed&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes (weak for a single block)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hardware requirement&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;CPU AES instructions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best suited for&lt;/td&gt;
&lt;td&gt;Nothing security-sensitive&lt;/td&gt;
&lt;td&gt;No-AES-NI or verifiable software&lt;/td&gt;
&lt;td&gt;Everything with the instruction&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;The nonce: four live strategies&lt;/h3&gt;
&lt;p&gt;This is the design space where the 2016 scan drew blood, so it deserves the careful table. The four options trade nonce size, streaming ability, and misuse tolerance against each other.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;AES-GCM, random 96-bit nonce&lt;/th&gt;
&lt;th&gt;AES-GCM, TLS 1.3 counter nonce&lt;/th&gt;
&lt;th&gt;AES-GCM-SIV (MRAE)&lt;/th&gt;
&lt;th&gt;XChaCha20-Poly1305&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Nonce size&lt;/td&gt;
&lt;td&gt;96-bit&lt;/td&gt;
&lt;td&gt;96-bit (derived)&lt;/td&gt;
&lt;td&gt;96-bit&lt;/td&gt;
&lt;td&gt;192-bit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Passes&lt;/td&gt;
&lt;td&gt;1 (streaming)&lt;/td&gt;
&lt;td&gt;1 (streaming)&lt;/td&gt;
&lt;td&gt;2 (buffered)&lt;/td&gt;
&lt;td&gt;1 (streaming)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;On accidental repeat&lt;/td&gt;
&lt;td&gt;Catastrophic (leaks $P_1 \oplus P_2$; two collisions give $H$ and forgery)&lt;/td&gt;
&lt;td&gt;Structurally prevented per connection&lt;/td&gt;
&lt;td&gt;Graceful (leaks only message equality)&lt;/td&gt;
&lt;td&gt;Catastrophic on a true repeat, but essentially never collides at random&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Safe budget per key&lt;/td&gt;
&lt;td&gt;Under $2^{32}$ messages [@sp-800-38d]&lt;/td&gt;
&lt;td&gt;Per-connection sequence, no reuse if the counter is sound&lt;/td&gt;
&lt;td&gt;Effectively unbounded against misuse&lt;/td&gt;
&lt;td&gt;About $2^{96}$ random nonces before collision risk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Relative speed&lt;/td&gt;
&lt;td&gt;Fastest (line rate)&lt;/td&gt;
&lt;td&gt;Fastest&lt;/td&gt;
&lt;td&gt;About 0.92 cpb on Broadwell, 14-19% slower than OpenSSL GCM [@gueron-lindell-2015]&lt;/td&gt;
&lt;td&gt;Fast in constant-time software, no AES-NI needed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Primitive&lt;/td&gt;
&lt;td&gt;AES&lt;/td&gt;
&lt;td&gt;AES&lt;/td&gt;
&lt;td&gt;AES&lt;/td&gt;
&lt;td&gt;ChaCha20 (not AES)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Read the table as a decision, not a ranking. If you own a reliable per-connection counter, deterministic-nonce AES-GCM is both fastest and safe -- that is what TLS 1.3 does [@rfc-8446]. If you &lt;em&gt;cannot&lt;/em&gt; guarantee uniqueness -- distributed writers, stateless functions, restart- or clone-prone systems -- AES-GCM-SIV is the provably strongest answer under misuse, at the price of a second pass and a buffered message [@rfc-8452; @rogaway-shrimpton-2006]. And if AES is not mandated and you just want &quot;a random nonce is always safe,&quot; XChaCha20-Poly1305&apos;s 192-bit nonce makes accidental collision astronomically unlikely [@xchacha-draft] -- a different primitive, included as the most common answer to the nonce footgun rather than as an AES deployment.&lt;/p&gt;
&lt;p&gt;Every option here changes &lt;em&gt;how AES is used&lt;/em&gt; -- or swaps AES out entirely -- and each buys its safety with a specific cost: a pass, a throughput hit, a hardware dependency, a different primitive. Which makes the honest way to close the technical arc a question about limits: how little does the attacker actually need, and how much can the defender actually guarantee?&lt;/p&gt;
&lt;h2&gt;8. Theoretical Limits: What Is Provably True on Both Sides&lt;/h2&gt;
&lt;p&gt;The thesis has two sides, and each has its own provable frontier. The surprise is the asymmetry: the cipher side is essentially closed, and all the hard, unavoidable limits live in the deployment.&lt;/p&gt;
&lt;h3&gt;The cipher side: the math that did not break&lt;/h3&gt;
&lt;p&gt;Biclique cryptanalysis is the &lt;em&gt;entire&lt;/em&gt; published erosion of the full-cipher security margin. Bogdanov, Khovratovich, and Rechberger reported the first single-key attacks on the full cipher at $2^{126.1}$, $2^{189.7}$, and $2^{254.4}$ for AES-128, AES-192, and AES-256 -- with no related-key assumption [@biclique-2011]. Against brute force at $2^{128}$, $2^{192}$, and $2^{256}$, that is a gain of at most roughly 1.6 to 2.3 bits: a factor of a few, not a factor that matters.A &quot;bit&quot; of security is a doubling of attacker work, so shaving 2 bits makes the attack about four times faster than brute force -- still astronomically far from feasible.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;AES-128&lt;/th&gt;
&lt;th&gt;AES-192&lt;/th&gt;
&lt;th&gt;AES-256&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Brute-force cost&lt;/td&gt;
&lt;td&gt;$2^{128}$&lt;/td&gt;
&lt;td&gt;$2^{192}$&lt;/td&gt;
&lt;td&gt;$2^{256}$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best known single-key attack (biclique)&lt;/td&gt;
&lt;td&gt;$2^{126.1}$&lt;/td&gt;
&lt;td&gt;$2^{189.7}$&lt;/td&gt;
&lt;td&gt;$2^{254.4}$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Margin removed&lt;/td&gt;
&lt;td&gt;about 1.9 bits&lt;/td&gt;
&lt;td&gt;about 2.3 bits&lt;/td&gt;
&lt;td&gt;about 1.6 bits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Practical threat&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Relevance to the field breaks above&lt;/td&gt;
&lt;td&gt;Zero&lt;/td&gt;
&lt;td&gt;Zero&lt;/td&gt;
&lt;td&gt;Zero&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;There is no proof that any attack on AES &lt;em&gt;must&lt;/em&gt; cost as much as exhaustive search -- concrete block ciphers essentially never come with such a theorem -- so confidence rests on more than two decades of open cryptanalysis since the competition, not on an impossibility result [@fips-197]. But the reading is unambiguous, and the authors said it themselves.&lt;/p&gt;

The best known attacks on the full AES &quot;do not threaten the practical use of AES in any way.&quot; -- Bogdanov, Khovratovich, and Rechberger, 2011 [@biclique-2011]
&lt;p&gt;Notice the defender&apos;s column in the table never moves, and key size is irrelevant to every operational break in the sections above. The cipher side is, for practical purposes, a closed question.&lt;/p&gt;
&lt;h3&gt;The deployment side: where the real limits live&lt;/h3&gt;
&lt;p&gt;Now the asymmetry. Three &lt;em&gt;provable&lt;/em&gt; boundaries constrain real systems, and none of them is about AES&apos;s strength:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;The GCM birthday bound.&lt;/strong&gt; With random 96-bit nonces, collision risk grows by the birthday bound, so NIST caps a single key at fewer than $2^{32}$ invocations [@sp-800-38d]. This is a structural limit of random-nonce GCM, independent of the cipher -- the mathematical reason &quot;just use random nonces at massive scale&quot; eventually fails.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The AEAD trilemma.&lt;/strong&gt; No single scheme is simultaneously single-pass and line-rate, fully nonce-misuse-resistant, &lt;em&gt;and&lt;/em&gt; large-nonce. GCM gives you the first, GCM-SIV the second, XChaCha the third-and-a-half; you cannot have all three at once [@rfc-8452]. And misuse-resistant AE is provably the &lt;em&gt;strongest possible&lt;/em&gt; guarantee once nonces may repeat -- an attacker can always at least detect that the same message was encrypted, and a well-designed SIV scheme leaks nothing more [@rogaway-shrimpton-2006].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ISA-guaranteed whole-machine constant time is impossible in general.&lt;/strong&gt; The instruction set does not, in general, promise data-independent instruction timing, so even AES and XOR instructions may be data-dependent on recent cores unless the timing mode is enabled [@intel-doit; @biggers-2023]. A constant-time &lt;em&gt;algorithm&lt;/em&gt; cannot by itself guarantee constant-time &lt;em&gt;execution&lt;/em&gt;; part of the guarantee lives below the software, and the general craft of getting it right is the subject of the &lt;a href=&quot;https://paragmali.com/blog/correct-constant-time-and-still-owned-a-field-guide-to-side-/&quot; rel=&quot;noopener&quot;&gt;secure-implementation sibling&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The cipher-secure and system-secure claims are different, and the gap between them is &lt;em&gt;inherent&lt;/em&gt;, not accidental. The cipher side has a negligible margin nibble -- under two bits. The deployment side has the real, provable limits: the GCM birthday bound, the single-pass / misuse-resistant / large-nonce trilemma, and the structural impossibility of ISA-guaranteed constant time. Key size buys nothing against any of them.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If the cipher side is closed and the deployment side has hard limits, then the live frontier is wherever those deployment limits are still being hit in the wild. That is not a solved problem. It is an active one.&lt;/p&gt;
&lt;h2&gt;9. Open Problems: Where AES Still Breaks in the Field&lt;/h2&gt;
&lt;p&gt;The cipher side is closed; the deployment side is not. Here are the places the same three-layer pattern is still live -- each an &lt;em&gt;operational&lt;/em&gt; frontier, consistent with the thesis that the weakest link is the wrapper, not the block.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Guaranteeing nonce uniqueness in distributed, multi-writer, restart-prone systems.&lt;/strong&gt; This is the exact gap that produced Generation 2: buggy counters and generators on 184 live servers repeated GCM nonces [@nonce-disrespecting-2016]. The best partial answer, MRAE via AES-GCM-SIV, makes a repeat &lt;em&gt;detectable&lt;/em&gt; rather than catastrophic [@rfc-8452] -- but the single-pass, fully misuse-resistant, large-nonce scheme the trilemma forbids remains unrealized. In a world of stateless functions, cloned VMs, and shared keys across a fleet, &quot;just keep a counter&quot; is still an unsolved systems problem, not a solved one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cross-VM cache side channels in multi-tenant clouds.&lt;/strong&gt; The 2005-2006 threat model assumed a shared physical machine; virtualization brought it back at scale. Irazoqui, Inci, Eisenbarth, and Sunar recovered AES keys &lt;em&gt;across virtual-machine boundaries&lt;/em&gt; using Flush+Reload with memory deduplication [@irazoqui-2014]. Hardware AES removes the &lt;em&gt;table&lt;/em&gt; channel, which is why AES-NI and constant-time code remain load-bearing in 2026.Even instruction timing can be data-dependent on recent cores unless the timing mode is enabled, so cloud tenancy keeps the Generation-1 question open even for hardware AES [@biggers-2023].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fault and differential-fault attacks.&lt;/strong&gt; Inducing a computation fault -- through voltage glitching, a laser, or rowhammer-style effects -- can recover an AES key from a handful of faulty ciphertexts [@piret-quisquater-2003]. This is again an implementation and hardware failure, not a cipher failure; the depth belongs to the secure-implementation sibling, but it is a live operational locus wherever an attacker has physical or near-physical access.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The long tail of devices without hardware AES.&lt;/strong&gt; Constant-time software is slower than AES-NI, and the performance gap quietly tempts developers back toward leaky tables on the smallest parts [@kasper-schwabe-2009]. On many of those devices the pragmatic answer is to ship a constant-time stream cipher such as ChaCha20 instead of fighting AES&apos;s software side channels [@xchacha-draft].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Formal verification of protocol state machines,&lt;/strong&gt; so the next KRACK is caught before it ships. TLS 1.3 was co-designed with formal analysis and has verified component implementations, such as those in the HACL* library [@hacl-2017]. Wi-Fi&apos;s SAE was &lt;em&gt;not&lt;/em&gt; fully immunized: Dragonblood found downgrade, denial-of-service, and side-channel leaks the authors argue are &quot;inherent to Dragonfly,&quot; and even patched software remained affected by a novel leak [@dragonblood-2019]. The state of the art at the protocol layer is &lt;em&gt;better&lt;/em&gt;, not &lt;em&gt;finished&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Every open problem here is the same sentence in new clothes: a contract around the permutation is hard to keep in the real world. Which means the practical guide almost writes itself -- it is the thesis made operational, each rule routed to the incident it prevents.&lt;/p&gt;
&lt;h2&gt;10. What to Do on Monday&lt;/h2&gt;
&lt;p&gt;Everything above collapses into a short decision procedure and a shorter list of nevers, each rule tied to the incident it prevents.&lt;/p&gt;

flowchart TD
    S[&quot;Deploying AES&quot;] --&amp;gt; Q1{&quot;CPU has AES instructions?&quot;}
    Q1 --&amp;gt;|Yes| HW[&quot;Use AES-NI or ARMv8 crypto, enable timing mode on newest cores&quot;]
    Q1 --&amp;gt;|No| CT[&quot;Use constant-time bitsliced software&quot;]
    HW --&amp;gt; Q2{&quot;Can you guarantee nonce uniqueness?&quot;}
    CT --&amp;gt; Q2
    Q2 --&amp;gt;|Yes| GCM[&quot;AES-GCM with deterministic nonces, TLS 1.3 style&quot;]
    Q2 --&amp;gt;|No| Q3{&quot;Is AES mandated?&quot;}
    Q3 --&amp;gt;|Yes| SIV[&quot;AES-GCM-SIV, misuse-resistant&quot;]
    Q3 --&amp;gt;|No| XC[&quot;XChaCha20-Poly1305, 192-bit nonce&quot;]
&lt;p&gt;The rules behind the tree:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Implementation.&lt;/strong&gt; Use a library that selects AES-NI or ARMv8 crypto at runtime and falls back to constant-time software; never table-based AES in security code; on the newest cores, be aware the data-independent-timing mode may need to be requested [@intel-aes-ni; @intel-doit]. &lt;em&gt;Prevents Generation 1: cache-timing key recovery.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mode and nonce.&lt;/strong&gt; Reliable per-connection counter, as in TLS or QUIC? Use AES-GCM with deterministic nonces [@rfc-8446]. Cannot &lt;em&gt;guarantee&lt;/em&gt; uniqueness across restarts, threads, or clones? Use AES-GCM-SIV [@rfc-8452]. Want &quot;a random nonce is always safe&quot; and AES is not mandated? Use XChaCha20-Poly1305 [@xchacha-draft]. Never hand-roll a mode, and never choose your own explicit GCM nonce. &lt;em&gt;Prevents Generation 2: nonce reuse and forgery.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Protocol.&lt;/strong&gt; Patch WPA2 against key reinstallation or move to WPA3, keep clients updated, and prefer TLS 1.3 over 1.2 [@krack-2017; @rfc-8446]. &lt;em&gt;Prevents Generation 3: handshake-driven nonce rewind.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The single highest-value check you can add to code review is a nonce-reuse detector. It is the exact contract the 184 servers violated, and it fits in a few lines.&lt;/p&gt;
&lt;p&gt;{`
// Scan a stream of (key, nonce) pairs and flag the first repeat.
function findNonceReuse(records) {
  const seen = new Set();
  for (const r of records) {
    const tag = r.key + &quot;|&quot; + r.nonce;
    if (seen.has(tag)) return { reused: true, key: r.key, nonce: r.nonce };
    seen.add(tag);
  }
  return { reused: false };
}&lt;/p&gt;
&lt;p&gt;const stream = [
  { key: &quot;k1&quot;, nonce: &quot;00000001&quot; },
  { key: &quot;k1&quot;, nonce: &quot;00000002&quot; },
  { key: &quot;k1&quot;, nonce: &quot;00000001&quot; },   // counter reset after a restart -- the bug
];&lt;/p&gt;
&lt;p&gt;console.log(findNonceReuse(stream));
// { reused: true, key: &apos;k1&apos;, nonce: &apos;00000001&apos; } -- catch it in review, not in an incident.
`}&lt;/p&gt;
&lt;p&gt;Now hold each pitfall up to the mirror. Every one of these confident sentences reproduces a specific, named incident.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;The confident mistake&lt;/th&gt;
&lt;th&gt;The incident it reproduces&lt;/th&gt;
&lt;th&gt;The fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Table-based AES is fine in security code&lt;/td&gt;
&lt;td&gt;Bernstein; Osvik-Shamir-Tromer cache timing [@bernstein-2005; @osvik-shamir-tromer-2006]&lt;/td&gt;
&lt;td&gt;AES-NI or constant-time software&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repeating a nonce across restarts, threads, or clones is unlikely to matter&lt;/td&gt;
&lt;td&gt;The 184-server GCM forgery scan [@nonce-disrespecting-2016]&lt;/td&gt;
&lt;td&gt;AES-GCM-SIV or a disciplined counter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-256 is safer against these attacks&lt;/td&gt;
&lt;td&gt;Every break here -- key size is irrelevant [@nonce-disrespecting-2016]&lt;/td&gt;
&lt;td&gt;Fix the wrapper, not the key size&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Constant-time source means constant-time execution&lt;/td&gt;
&lt;td&gt;The DOIT/DIT timing caveat [@intel-doit; @biggers-2023]&lt;/td&gt;
&lt;td&gt;Enable the timing mode where required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;An unpatched WPA2 handshake is good enough&lt;/td&gt;
&lt;td&gt;KRACK [@krack-2017]&lt;/td&gt;
&lt;td&gt;Patch WPA2 or deploy WPA3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

When you review encryption code, find where the nonce comes from and ask exactly one question: can this value repeat across a restart, a fork, a thread, or a clone? If you cannot prove it never repeats, you are reading a latent Generation-2 incident. Reach for AES-GCM-SIV or a 192-bit-nonce AEAD instead of arguing about how improbable a collision seems.
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; 1. AES-NI or ARMv8 crypto, with a constant-time software fallback. 2. A vetted AEAD -- deterministic-nonce AES-GCM where a per-connection counter is reliable, AES-GCM-SIV where uniqueness is hard, XChaCha20-Poly1305 where AES is not mandated. 3. Patched WPA2 or WPA3, and TLS 1.3 over 1.2.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The checklist is short because the lesson is one sentence. Before restating it, clear the handful of confident, wrong sentences that keep this bug alive in design meetings.&lt;/p&gt;
&lt;h2&gt;11. Frequently Asked Questions&lt;/h2&gt;


No. The best publicly known attack on the full cipher, biclique cryptanalysis, costs about $2^{126}$ operations for AES-128 -- a fraction-of-a-bit improvement over brute force with zero practical impact, and its authors say it does &quot;not threaten the practical use of AES in any way&quot; [@biclique-2011]. Every break in this article happened in a layer around the cipher, not in the cipher.


Yes -- via cache-timing side channels [@bernstein-2005; @osvik-shamir-tromer-2006]. But that is *not* a break of the cipher. The T-table implementation&apos;s memory-access pattern leaked the key; the block permutation did not. Swap the leaky tables for a constant-time implementation and the key stops leaking while AES stays byte-for-byte identical. &quot;Unbroken cipher&quot; and &quot;stolen key&quot; are both true at once.


Be precise here. One reuse immediately leaks $P_1 \oplus P_2$ through keystream reuse, and it gives one equation for the GHASH subkey $H$. But *pinning* $H$ for reliable universal forgery generally needs at least two collisions [@joux-2006]. One reuse is already catastrophic -- do not understate it -- but do not say &quot;one reuse recovers the key&quot; either.


No. Every break here is implementation, mode, or protocol; key size provides no protection against cache timing, nonce reuse, or a reinstalled handshake key [@nonce-disrespecting-2016]. For the nonce-reuse and handshake breaks AES-256 fails exactly as fast as AES-128; for cache timing it is just as vulnerable, though a longer key takes proportionally more leakage to extract. If someone proposes AES-256 as the fix for any incident in this article, they have misdiagnosed the layer.


No. Against AES-CCMP, KRACK forces nonce-reuse decryption and replay, not AES key recovery [@krack-2017]. The especially damaging all-zero-key case was an Android and Linux `wpa_supplicant` implementation bug, not a weakness in AES. No block-math weakness is involved, and no AES key is recovered by the attack itself.


No. A padding oracle is a mode-and-validation failure in CBC deployments -- the receiver leaks whether decrypted padding was valid -- and it never touches the AES permutation. It is the same moral as this article (a wrapper broke), in a different deployment, and it is covered in a dedicated padding-oracle sibling. AES itself is not the weak link there either.

&lt;p&gt;Every correction points at the same root: the cipher was never the weak link. Time to say the sentence the whole article was built to earn.&lt;/p&gt;
&lt;h2&gt;12. To Break AES in the Field, You Never Touch AES&lt;/h2&gt;
&lt;p&gt;Return to the paradox we opened with, now resolved. The best attack on the full cipher is a fraction-of-a-bit shave with no practical impact [@biclique-2011] -- and yet Wi-Fi sessions were decrypted, HTTPS connections forged, and keys lifted from running servers, because every one of those breaks happened in a wrapper the cipher knows nothing about. The implementation leaked through cache timing [@bernstein-2005; @osvik-shamir-tromer-2006]. The mode&apos;s nonce contract was violated on 184 live servers, weaponizing Joux&apos;s decade-old forbidden attack into forgery [@nonce-disrespecting-2016; @joux-2006]. The protocol rewound its nonce when a replayed handshake reinstalled a key [@krack-2017]. Three layers, three field breaks, and the 128-bit block math untouched in all three.&lt;/p&gt;
&lt;p&gt;And every fix changed how AES is &lt;em&gt;used&lt;/em&gt;, never AES: constant-time code and AES-NI at the implementation, misuse-resistant AEAD and derived nonces at the mode, patched handshakes and WPA3 at the protocol [@kasper-schwabe-2009; @rfc-8452; @rfc-8446; @wifi-wpa3-2018]. The cipher is the fixed point; the engineering happened all around it.&lt;/p&gt;

A cipher is not a cryptosystem. When your traffic falls, do not ask whether AES broke -- ask which wrapper did: the implementation, the mode, or the protocol.
&lt;p&gt;One last honesty, because the series depends on it. The claim is &quot;almost never,&quot; not &quot;never.&quot; Scoped to AES, the split is pristine -- the block math never fell in deployment. But some deployed primitives genuinely broke as &lt;em&gt;math&lt;/em&gt;: DES&apos;s 56-bit key, RC4&apos;s keystream biases [@alfardan-2013], and the &lt;a href=&quot;https://paragmali.com/blog/the-fingerprint-two-files-shared-a-field-guide-to-cryptograp/&quot; rel=&quot;noopener&quot;&gt;MD5 and SHA-1 collisions&lt;/a&gt; [@shattered-2017]. AES has not joined them, and naming the cases where cryptanalysis won is what keeps the thesis honest rather than triumphant.&lt;/p&gt;
&lt;p&gt;The cipher was never the weak link -- and no bigger key would have saved a single one of these systems. That is why this is Part 1 of a series about how things break &lt;em&gt;in real life&lt;/em&gt;, not a chapter on block-cipher cryptanalysis. The companion piece, &lt;em&gt;How AES Would Break&lt;/em&gt;, takes up the other question: what it would take to move the block itself. This one answered the question that actually decrypts traffic. It was never the cipher. It was the wrapper, every time.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;how-aes-breaks-in-real-life&quot; keyTerms={[
  { term: &quot;Block cipher vs. mode of operation&quot;, definition: &quot;AES is a keyed permutation on one 16-byte block; a mode (CTR, GCM, CCM) chains it across a whole message and turns it into a cryptosystem.&quot; },
  { term: &quot;Nonce / IV&quot;, definition: &quot;A number used once. Counter-based modes require the (key, nonce) pair to be unique per encryption, or the keystream repeats.&quot; },
  { term: &quot;AEAD&quot;, definition: &quot;Authenticated Encryption with Associated Data: confidentiality and integrity together, with headers authenticated but not encrypted. GCM and CCM are AEAD modes.&quot; },
  { term: &quot;Keystream reuse&quot;, definition: &quot;Identical (key, nonce) yields identical keystream, so the XOR of two ciphertexts equals the XOR of their plaintexts. The key is never touched.&quot; },
  { term: &quot;T-table&quot;, definition: &quot;Precomputed lookup tables that fold an AES round into a few reads. A speed optimization whose secret-dependent indices leak through the cache.&quot; },
  { term: &quot;Cache-timing attack&quot;, definition: &quot;Recovering a secret from the timing or cache footprint of data-dependent memory access, not from the algorithm output.&quot; },
  { term: &quot;GHASH subkey H&quot;, definition: &quot;GCM&apos;s authentication secret, the encryption of an all-zero block under the key. A repeated nonce turns tag differences into equations that reveal it.&quot; },
  { term: &quot;Key reinstallation&quot;, definition: &quot;Installing an already-in-use key, which rewinds its nonce or packet-number counter and forces keystream reuse. The mechanism KRACK exploits.&quot; },
  { term: &quot;MRAE&quot;, definition: &quot;Nonce-misuse-resistant authenticated encryption, such as AES-GCM-SIV, where a repeated nonce leaks only message equality, never the subkey.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>cryptography</category><category>aes</category><category>aes-gcm</category><category>nonce-reuse</category><category>krack</category><category>side-channel-attack</category><category>authenticated-encryption</category><category>tls</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>The Tag Verified, the Cipher Held, the Forgery Went Through: A Field Guide to Message Authentication and Safe Composition</title><link>https://paragmali.com/blog/the-tag-verified-the-cipher-held-the-forgery-went-through-a-/</link><guid isPermaLink="true">https://paragmali.com/blog/the-tag-verified-the-cipher-held-the-forgery-went-through-a-/</guid><description>Why HMAC, KMAC, GMAC, and Poly1305 never broke -- but Flickr, Lucky Thirteen, and 184 GCM servers did. A field guide to MACs and Encrypt-then-MAC.</description><pubDate>Sat, 11 Jul 2026 01:12:01 GMT</pubDate><content:encoded>
A MAC makes forgery hard; three deployment assumptions keep it hard, and every famous break -- Flickr [@flickr-advisory], Lucky Thirteen [@cve-2013-0169], POODLE [@cve-2014-3566], the SSH plaintext-recovery attack [@apw-2009], and 184 nonce-repeating HTTPS servers [@woot16-bock] -- broke one of those assumptions, not the math. Pick the right family (PRF-based HMAC and KMAC take a reusable key and need no nonce; Wegman-Carter GMAC and Poly1305 run at line rate but demand a one-time key [@wc-1981]), verify in constant time, and always Encrypt-then-MAC over the ciphertext with an independent key and a strongly unforgeable tag [@bn-2000]. This guide traces the primitive from Carter-Wegman universal hashing in 1979 [@cw-1979] to committing AEAD in 2025 [@rfc-9771], names every failure by root cause, and ends with a decision tree and a paste-in review checklist. The one rule underneath all of it: authenticate the ciphertext, the length, and the context -- not just the message.
&lt;h2&gt;1. A Forgery Without a Broken Cipher&lt;/h2&gt;
&lt;p&gt;In 2009, two researchers forged valid Flickr API signatures without knowing Flickr&apos;s secret key, without finding a single MD5 collision, and without touching a cipher [@flickr-advisory]. Flickr had done what feels obviously correct -- prepend a secret to each request and hash the result -- and that one instinct silently handed signing power to anyone who had ever seen a single signed URL. The hash worked exactly as designed. The way Flickr &lt;em&gt;used&lt;/em&gt; it was the vulnerability.&lt;/p&gt;
&lt;p&gt;That gap -- between a primitive that is sound and a deployment that is not -- is the subject of this article, and it is worth stating as a claim you can test against every page that follows.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; A message authentication code makes forgery hard; keeping it hard is the surrounding protocol&apos;s job. Every deployed MAC ships a proof, and every proof quietly assumes three things the deployment must supply: (1) the right &lt;strong&gt;key discipline&lt;/strong&gt; for its family, (2) a &lt;strong&gt;constant-time verify&lt;/strong&gt;, and (3) &lt;strong&gt;composition over the right bytes, in the right order, binding the right context&lt;/strong&gt;. Read that way, the entire failure catalogue is one sentence repeated -- the math never broke; a deployment broke one of these three assumptions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Before we can prove that thesis, we need the object it is about. Informally, a MAC is a small tag you attach to a message so the receiver can tell the message came from someone who holds the shared secret key, and that nobody altered it in transit.&lt;/p&gt;

A MAC is a keyed algorithm that takes a secret key and a message and produces a short fixed-size tag. Anyone holding the same key can recompute the tag to verify that the message is authentic and unmodified. Unlike a plain hash, a MAC is keyed, so an attacker without the key cannot produce a valid tag; unlike a digital signature, the same secret both makes and checks the tag, so there is no public verifiability and no non-repudiation.
&lt;p&gt;Now pair Flickr with a second break that fails a &lt;em&gt;different&lt;/em&gt; assumption. In 2013, Lucky Thirteen recovered plaintext from TLS connections that used a perfectly correct HMAC -- the attack timed &lt;em&gt;how&lt;/em&gt; the MAC was checked, not whether the MAC was strong [@cve-2013-0169]. Two production systems, two respected primitives, two failures -- and in neither case did the cryptography break. Flickr fed the hash the wrong bytes in the wrong construction; TLS checked a correct tag on a timing-leaky path.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; MD5 is badly broken for collision resistance, yet the Flickr forgery did not use a collision. HMAC was and is unbroken, yet Lucky Thirteen still bled plaintext. In both cases the primitive met its specification and the deployment violated an assumption the specification silently depended on. Hold onto that pattern -- it is the whole catalogue in miniature.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;By the end of this field guide you will have a decision procedure and a review checklist that catch every failure in this article before it ships.The original Flickr advisory by Duong and Rizzo is no longer served from its source host; the citation here points to a 2009 Wayback Machine snapshot, which is the durable primary record [@flickr-advisory]. But a checklist without the underlying model is just cargo-culting. So start with the model. If the hash was not broken, what exactly is a MAC supposed to promise, and against whom?&lt;/p&gt;
&lt;h2&gt;2. What a MAC Actually Is&lt;/h2&gt;
&lt;p&gt;Strip away the mystique and a MAC is three algorithms and one game.&lt;/p&gt;
&lt;p&gt;The three algorithms are &lt;code&gt;KeyGen&lt;/code&gt;, &lt;code&gt;Tag&lt;/code&gt;, and &lt;code&gt;Verify&lt;/code&gt;. &lt;code&gt;KeyGen&lt;/code&gt; samples a secret key $k$. &lt;code&gt;Tag&lt;/code&gt; maps a key and a message $m$ to a tag $t$. &lt;code&gt;Verify&lt;/code&gt; takes $k$, $m$, and a candidate $t$ and returns accept or reject. The whole design question is: how hard is it for someone without $k$ to make &lt;code&gt;Verify&lt;/code&gt; say accept on a message the key-holder never authorized?&lt;/p&gt;
&lt;p&gt;&quot;How hard&quot; was made precise in 1988. Shafi Goldwasser, Silvio Micali, and Ronald Rivest gave the first rigorous adversarial definition of authentication -- existential unforgeability under adaptive chosen-message attack -- while analyzing digital signatures, and MACs inherit it directly [@gmr-1988]. The game is deliberately generous to the attacker.&lt;/p&gt;

The adversary may ask for tags on any messages it likes, adaptively, as many as it wants. It wins if it then outputs a valid tag on any *new* message it never queried. A MAC is EUF-CMA secure if every efficient adversary wins only with negligible probability. The name is exact: &quot;existential&quot; means the forgery can be on any message the attacker chooses, and &quot;adaptive chosen-message&quot; means it sees each answer before picking its next query.
&lt;p&gt;EUF-CMA is the usual bar, but composition needs a slightly stronger one, and the difference will decide whether a whole protocol stands or falls in Section 6.&lt;/p&gt;

SUF-CMA forbids even a *new tag on an old message*. The adversary wins if it outputs any message-tag pair that verifies and was not itself the result of a tag query -- including a second, different valid tag on a message it already asked about. Every SUF-CMA MAC is EUF-CMA, but not conversely: a MAC with malleable tags can be existentially unforgeable yet still let an attacker maul a valid tag into another valid tag.
&lt;p&gt;Formally, if we write the tag oracle as $\mathsf{Tag}_k(\cdot)$ and let $Q$ be the set of message-tag pairs it returned, the strong-forgery advantage is&lt;/p&gt;
&lt;p&gt;$$\mathsf{Adv}^{\text{suf-cma}}_{\mathsf{MAC}}(\mathcal{A}) ;=; \Pr!\left[,(m,t) \leftarrow \mathcal{A}^{\mathsf{Tag}_k(\cdot)} : \mathsf{Verify}_k(m,t)=\text{accept} ;\wedge; (m,t)\notin Q,\right].$$&lt;/p&gt;
&lt;p&gt;A MAC is good when this probability stays negligible for every efficient $\mathcal{A}$. That single inequality is the promise Flickr&apos;s construction could not keep -- an attacker produced an accepted tag on a message that was never in $Q$.&lt;/p&gt;
&lt;p&gt;Four primitives live near this definition, and confusing them is the source of real bugs. An &lt;strong&gt;unkeyed hash&lt;/strong&gt; has no $k$, so anyone can recompute it -- it detects accidental corruption, never a motivated forger; this series covers hashes and their length-extension quirk in Part 10.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;MAC&lt;/strong&gt; is symmetric: the same secret makes and checks the tag. A &lt;strong&gt;digital signature&lt;/strong&gt; is asymmetric -- a private key signs, a public key verifies -- which buys public verifiability and non-repudiation that a MAC deliberately does not provide (Part 3 develops &lt;a href=&quot;https://paragmali.com/blog/the-signature-was-valid-the-message-was-forged-a-field-guide/&quot; rel=&quot;noopener&quot;&gt;what the authenticated bytes must actually cover&lt;/a&gt;). An &lt;strong&gt;AEAD&lt;/strong&gt; bundles a MAC together with encryption so one call delivers secrecy and integrity at once; Part 7 is &lt;a href=&quot;https://paragmali.com/blog/the-aead-decision-matrix-seven-ciphers-three-edges-one-choic/&quot; rel=&quot;noopener&quot;&gt;the decision matrix for choosing among AEADs&lt;/a&gt;, and this article is the authentication half underneath it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Because a MAC key both signs and verifies, a valid tag proves only that &lt;em&gt;someone holding the shared key&lt;/em&gt; produced it -- it cannot tell you &lt;em&gt;which&lt;/em&gt; party, and it cannot be shown to a third party as proof. If you need &quot;Alice, and only Alice, provably sent this,&quot; you need a signature, not a MAC. Reaching for a MAC where you needed non-repudiation is a design error no amount of key length fixes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The definitions say a good MAC is unforgeable. Yet the very first keyed MACs people built were forgeable in ways the definition had not yet been written to outlaw. Stranger still, the airtight, provably unforgeable answer arrived &lt;em&gt;before&lt;/em&gt; the practical, broken ones. Where did the idea come from?&lt;/p&gt;
&lt;h2&gt;3. Origins: Universal Hashing and One-Time Authentication&lt;/h2&gt;
&lt;p&gt;Here is the twist that reorders the whole story. The provably secure MAC was invented first, in 1979 and 1981, and then the field spent two decades shipping forgeable ones anyway. Keep that inversion in mind as the arc unfolds.&lt;/p&gt;

timeline
    title Message authentication, 1979 to 2025
    1979 : Carter-Wegman universal hashing
    1981 : One-time authentication, tag is hash plus one-time pad
    1985 : CBC-MAC standardized in FIPS 113
    1996 : HMAC nests the hash to stop length extension
    2000 : Encrypt-then-MAC formalized by Bellare and Namprempre
    2001 : Krawczyk indicts the SSL and SSH orderings
    2004 : GMAC revives Wegman-Carter at line speed
    2005 : Poly1305 brings it to fast software
    2006 : HMAC proven a PRF without collision resistance
    2009 : Flickr forgery and the SSH plaintext recovery
    2013 : Lucky Thirteen timing oracle
    2016 : KMAC keyed sponge and 184 nonce-repeating servers
    2018 : TLS 1.3 record layer becomes AEAD-only
    2023 : Terrapin breaks a correct channel
    2025 : RFC 9771 standardizes commitment vocabulary
&lt;p&gt;The starting point is a purely combinatorial object. Larry Carter and Mark Wegman, at IBM Research, asked what happens if you pick a hash function at random from a carefully built family, rather than fixing one function everyone knows [@cw-1979].&lt;/p&gt;

A universal family of hash functions has the property that, for any two fixed distinct inputs, a function drawn uniformly at random from the family maps them to the same output with only small, bounded probability. The bound comes from counting the functions in the family, not from any assumption about how much computing power an attacker has. It is combinatorial security, not cryptographic security -- which is exactly why it needs no unproven hardness conjecture.
&lt;p&gt;Two years later, Wegman and Carter turned that object into an authenticator [@wc-1981]. The construction is startlingly small: draw a secret hash $h$ from a strongly universal family, draw a secret one-time pad $s$, and send&lt;/p&gt;
&lt;p&gt;$$t ;=; h(m) ,\oplus, s.$$&lt;/p&gt;
&lt;p&gt;The pad $s$ hides the value $h(m)$ completely, like a one-time pad hides a plaintext, and the universal property bounds an attacker&apos;s chance of guessing a valid tag for a &lt;em&gt;different&lt;/em&gt; message. The result is unconditional: it holds against an adversary with unlimited computing power, assuming nothing about factoring, discrete logs, or the strength of any cipher.&lt;/p&gt;

Authenticate a message as the exclusive-or of a universal hash of the message and a fresh secret pad: the tag reveals nothing about the hash key, and forging a tag on a new message requires guessing a value the universal bound keeps small. The security is information-theoretic and tight -- but the pad must be used exactly once. Authenticate a second message under the same pad and the guarantee evaporates.
&lt;p&gt;Take the smallest instance. Fix a prime $p$, keep a secret pair $(a, b)$, and tag a message $m$ as $t = (a\cdot m + b) \bmod p$. An attacker who sees one pair $(m_1, t_1)$ learns one linear equation in two unknowns; every candidate slope $a$ has exactly one consistent $b$, so the tag on any different $m_2$ stays uniform over all $p$ values. The best forgery succeeds with probability $1/p$. Beautiful, and useless twice: a second pair $(m_2, t_2)$ gives a second equation, the line is pinned, and every future tag is computable.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &quot;One-time&quot; is not a restriction bolted onto Wegman-Carter authentication -- it &lt;em&gt;is&lt;/em&gt; the security proof. The pad&apos;s single use is what buys the information-theoretic guarantee. That makes it a feature in 1981 and a landmine in 2004, when the same construction is revived at network line speed and a fast deployment reuses the pad. Every GMAC and Poly1305 nonce rule you will ever read is this 1981 constraint wearing modern clothes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So the airtight answer existed. Yet it authenticates only one message per key, which is impractical for a general-purpose MAC.The two ideas are separate papers: the 1979 work introduced universal classes of hash functions as a combinatorial tool [@cw-1979]; the 1981 follow-up applied them to authentication and set equality [@wc-1981]. Universal hashing came first; authentication was the application. If the unconditional construction was this good but this restrictive, what did engineers reach for instead -- and why did the &quot;obvious&quot; keyed hashes they built break?&lt;/p&gt;
&lt;h2&gt;4. Early Approaches and Why They Broke&lt;/h2&gt;
&lt;p&gt;When engineers needed a keyed MAC in the 1990s, most reached for the hash they already had and glued a secret to it. The most natural glue is to put the key in front: compute &lt;code&gt;H(secret || message)&lt;/code&gt; and ship the digest as the tag. It looks unforgeable -- you cannot compute the hash without the secret. It is also exactly what Flickr shipped, and it is broken by a property of the hash that has nothing to do with its collision resistance.&lt;/p&gt;
&lt;p&gt;The property is length extension, and it is a direct consequence of how Merkle-Damgard hashes -- MD5, SHA-1, and most of SHA-2 -- are built [@length-ext-wiki]. Such a hash absorbs the message block by block into an internal state, and it emits &lt;em&gt;that entire internal state&lt;/em&gt; as the digest. The digest is therefore a complete, resumable snapshot: given &lt;code&gt;H(secret || message)&lt;/code&gt;, you can set a fresh hash&apos;s state to that value and keep absorbing more bytes, as if you had known the secret all along.&lt;/p&gt;

Given the digest of `secret || message` and the length of the secret, an attacker can compute the digest of `secret || message || padding || extra` for attacker-chosen `extra`, without knowing the secret. The attack works because a Merkle-Damgard digest is the hash&apos;s full internal state, so it can be resumed. The only wrinkle is the glue `padding` the original hash appended internally, whose bytes are fully determined by the known lengths.
&lt;p&gt;The forgery is mechanical once you see the state as resumable.&lt;/p&gt;

sequenceDiagram
    participant A as Attacker
    participant V as Verifier
    A-&amp;gt;&amp;gt;V: Observe one signed request, message m and tag t
    Note over A: The tag t is the full hash state after absorbing key and m
    A-&amp;gt;&amp;gt;A: Resume from t, append glue padding then chosen extra bytes
    A-&amp;gt;&amp;gt;A: Keep hashing to get t2 for the extended message, no key used
    A-&amp;gt;&amp;gt;V: Submit extended message with tag t2
    Note over V: Verifier recomputes over key plus the extended message
    V--&amp;gt;&amp;gt;A: State matches, forged request accepted
&lt;p&gt;The demonstration below builds a toy Merkle-Damgard hash whose digest is its internal state -- the essential property -- and forges a secret-prefix tag with no secret, then shows that nesting the hash (the HMAC idea) shuts the door.&lt;/p&gt;
&lt;p&gt;{`&lt;/p&gt;
Toy Merkle-Damgard hash: absorb one byte at a time; the digest IS the state.
(The mixer is illustrative, not secure -- the STRUCTURE is the point.)
&lt;p&gt;def compress(state, byte):
    return ((state * 1000003) ^ byte) &amp;amp; 0xFFFFFFFFFFFF   # 48-bit toy state&lt;/p&gt;
&lt;p&gt;def toy_hash(data, iv=0xA5A5A5A5A5A5):
    state = iv
    for byte in data:
        state = compress(state, byte)
    return state                      # digest == resumable internal state&lt;/p&gt;
&lt;p&gt;secret = b&quot;opensesame&quot;                # attacker does NOT know this...
def prefix_mac(msg):                  # ...but does know len(secret) == 10
    return toy_hash(secret + msg)&lt;/p&gt;
1) Attacker observes ONE legitimate (message, tag) pair:
&lt;p&gt;seen = b&quot;amount=10&quot;
tag  = prefix_mac(seen)&lt;/p&gt;
2) Attacker resumes from the tag and appends -- the secret is never touched:
&lt;p&gt;extra = b&quot;&amp;amp;amount=1000000&quot;
forged = tag
for byte in extra:
    forged = compress(forged, byte)&lt;/p&gt;
3) The verifier recomputes over secret + (seen + extra):
&lt;p&gt;print(&quot;secret-prefix forgery accepted:&quot;, forged == prefix_mac(seen + extra))&lt;/p&gt;
The HMAC-style fix: nest, so the outer pass re-absorbs the inner digest.
&lt;p&gt;def nested_mac(msg):
    inner = toy_hash(secret + msg)
    return toy_hash(secret + inner.to_bytes(6, &quot;big&quot;))&lt;/p&gt;
&lt;p&gt;resumed = nested_mac(seen)
for byte in extra:
    resumed = compress(resumed, byte)
print(&quot;nested (HMAC-style) forgery accepted:&quot;, resumed == nested_mac(seen + extra))
`}&lt;/p&gt;
&lt;p&gt;The first line prints &lt;code&gt;True&lt;/code&gt;, the second &lt;code&gt;False&lt;/code&gt;. That single flip is the difference between the Flickr construction and HMAC, and it is Aha number one for this article.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;code&gt;H(secret || message)&lt;/code&gt; over any Merkle-Damgard hash is not a MAC. It authenticates nothing an attacker who has seen one tag cannot forge, regardless of how strong the underlying hash is. MD5&apos;s collision weakness is irrelevant here -- the Flickr forgery used no collision at all [@flickr-advisory]. If you find &lt;code&gt;md5(secret + data)&lt;/code&gt; or &lt;code&gt;sha256(secret + data)&lt;/code&gt; in a code review, you have found a length-extension forgery waiting to happen.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The mirror construction, secret-suffix &lt;code&gt;H(message || secret)&lt;/code&gt;, resists length extension because the secret is absorbed last.Secret-suffix is not safe either: since an attacker who finds two messages colliding under the raw hash gets a tag collision for free, &lt;code&gt;H(m || k)&lt;/code&gt; reduces to the hash&apos;s collision resistance, so it dies with MD5 and SHA-1 -- the opposite failure mode from secret-prefix, same verdict [@length-ext-wiki]. Neither ad-hoc glue is a MAC.&lt;/p&gt;
&lt;p&gt;The block-cipher world made a parallel mistake. CBC-MAC, standardized as FIPS 113 in 1985, runs a block cipher in CBC mode with a zero IV and keeps the final ciphertext block as the tag [@fips-113]. It carries an unstated assumption: every message is the same fixed length. Bellare, Kilian, and Rogaway turned the failure of that assumption into a theorem in 1994 -- secure for fixed-length messages, trivially forgeable once lengths vary [@bkr-1994].&lt;/p&gt;
&lt;p&gt;The splice is mechanical. Query the tag of a one-block message $m_1$ to get $t_1 = E_k(m_1)$; then the two-block message $m_1 ,\Vert, (m_1 \oplus t_1)$ has tag $E_k\big((m_1 \oplus t_1)\oplus t_1\big) = E_k(m_1) = t_1$ -- a valid tag on a message never queried, produced with no key.&lt;/p&gt;
&lt;p&gt;Both failures teach the same lesson, and it organizes the rest of this guide: &lt;em&gt;a raw hash is not a MAC, and raw CBC-MAC is not a MAC for variable-length messages.&lt;/em&gt; Both fixes point the same direction -- stop exposing resumable internal state, and make the tag depend on length. From here the field split into two lineages. Which one wins?&lt;/p&gt;
&lt;h2&gt;5. The Evolution: Two Lineages Diverge&lt;/h2&gt;
&lt;p&gt;The field did not pick one winner. It split into two families that both survive today, and choosing between them is still the single most consequential decision a practitioner makes about authentication. One family keeps a computational assumption and buys a reusable key; the other keeps the 1981 one-time pad and buys blazing speed.&lt;/p&gt;
&lt;h3&gt;The PRF lineage: HMAC and CMAC&lt;/h3&gt;
&lt;p&gt;Bellare, Canetti, and Krawczyk fixed the secret-prefix disaster in 1996 by nesting the hash so the attacker never sees a resumable inner state [@bck-1996]. Standardized a year later as RFC 2104, HMAC computes two keyed passes [@rfc-2104]:&lt;/p&gt;
&lt;p&gt;$$\mathsf{HMAC}(k, m) ;=; H\big((k \oplus \text{opad}) ,\Vert, H((k \oplus \text{ipad}) ,\Vert, m)\big).$$&lt;/p&gt;
&lt;p&gt;The outer hash re-absorbs the inner digest, so a resumed inner state is useless -- length extension cannot reach the output.&lt;/p&gt;

RFC 2104 also fixes how the key becomes block-sized before those two XORs: a key longer than the hash&apos;s block size is first hashed down to a digest, and a shorter key is zero-padded up to the block size [@rfc-2104]. That is why HMAC accepts a key of any length -- it normalizes every key to exactly one block before mixing in `ipad` and `opad`.

flowchart TD
    K[Secret key k] --&amp;gt; IP[k XOR ipad]
    M[Message m] --&amp;gt; INNER[Inner hash of ipad key then message]
    IP --&amp;gt; INNER
    INNER --&amp;gt; ID[Inner digest, never emitted directly]
    K --&amp;gt; OP[k XOR opad]
    ID --&amp;gt; OUTER[Outer hash of opad key then inner digest]
    OP --&amp;gt; OUTER
    OUTER --&amp;gt; T[HMAC tag]
&lt;p&gt;The deepest fact about HMAC is also the most misunderstood, and it took another decade to prove. In 2006 Bellare showed HMAC is a pseudorandom function under the &lt;em&gt;sole&lt;/em&gt; assumption that the hash&apos;s compression function is a PRF -- collision resistance is not required at all [@bellare-2006].&lt;/p&gt;

A keyed function is a PRF if no efficient adversary, allowed to query it on inputs of its choice, can distinguish its outputs from those of a truly random function. A PRF makes an immediate MAC: to forge a tag on a fresh message is to predict a value that, by assumption, looks uniformly random, which succeeds only with negligible probability. Unforgeability falls out of pseudorandomness.
&lt;p&gt;This is why the collision breaks of MD5 and SHA-1 never touched HMAC-MD5 or HMAC-SHA-1. Collisions attack collision resistance; HMAC never needed it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The folklore &quot;HMAC needs a collision-resistant hash&quot; is false, and it has been false since 2006 [@bellare-2006]. HMAC needs the compression function to behave like a PRF -- a different, and for MD5 and SHA-1 still-standing, assumption. This is not a licence to use MD5 in new systems, but it is why the practical world did not catch fire when SHA-1 collisions arrived.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The block-cipher branch got the same repair. CMAC, from Iwata and Kurosawa&apos;s OMAC and standardized as NIST SP 800-38B, derives two subkeys from the block cipher and mixes one into the final block, killing the variable-length splice that sank raw CBC-MAC while keeping a single key [@omac-2003] [@sp-800-38b]. It is the block-cipher PRF-MAC, useful where a device already has AES hardware but no hash.&lt;/p&gt;
&lt;p&gt;The survival of HMAC-SHA-1 is the cleanest real-world confirmation of the 2006 proof: SHA-1&apos;s collision resistance collapsed publicly, yet no HMAC-SHA-1 forgery followed, because the security reduction never invoked collision resistance in the first place [@bellare-2006].&lt;/p&gt;
&lt;h3&gt;The sponge refinement: KMAC&lt;/h3&gt;
&lt;p&gt;SHA-3 changed the substrate. A Keccak sponge splits its state into a public rate and a secret capacity, and it never emits the capacity [@fips-202]. That single property makes the HMAC nesting trick unnecessary: you can key a sponge by simply absorbing the key first.&lt;/p&gt;

A sponge function absorbs input into a large internal state divided into a public &quot;rate&quot; (the bytes that interact with input and output) and a secret &quot;capacity&quot; (bytes never revealed). Because the capacity is never output, prepending a key and absorbing it yields a keyed authenticator with no length-extension surface and no double hashing -- the key is protected by the same hidden capacity that protects the hash.
&lt;p&gt;NIST SP 800-185 builds KMAC on cSHAKE this way: prepend the key, absorb, squeeze [@sp-800-185]. Keying is native, domain separation is built in through customization strings, and the tag length is a free parameter because the sponge is an extendable-output function. It is, conceptually, the cleanest MAC in the standard catalogue -- but conceptual cleanliness is not deployment.&lt;/p&gt;

KMAC is a real, standardized primitive [@sp-800-185], implemented in OpenSSL 3.0 and later (as the `KMAC-128`/`KMAC-256` EVP_MAC) [@openssl-kmac], as well as BouncyCastle [@bouncycastle-kmac] and Botan [@botan-kmac]. It is not academic-only. But its production footprint is thin next to HMAC, GMAC, and Poly1305, for reasons that are historical inertia rather than cryptography: SHA-2 and HMAC are welded into TLS, IPsec, JWT, HKDF, and hardware everywhere, and SHA-3 adoption trails. This guide gives KMAC full conceptual treatment and makes no claim about its market share -- no reliable quantitative figure exists in a primary source.
&lt;p&gt;Both HMAC and KMAC share a decisive operational property: a reusable key, no nonce, an unbounded stream of messages under one secret. That is the easy side of assumption one. The other lineage trades it away for speed.&lt;/p&gt;
&lt;h3&gt;The Wegman-Carter lineage: GMAC and Poly1305&lt;/h3&gt;
&lt;p&gt;In 2004 and 2005, two designs dragged the 1981 one-time construction into high-speed networking. Both keep the pattern &lt;code&gt;tag = universal_hash(m) + one_time_pad&lt;/code&gt;, and both solve the &quot;fresh pad per message&quot; problem the same way -- derive the pad from a cipher keystream instead of shipping new randomness.&lt;/p&gt;
&lt;p&gt;GHASH, the core of GCM, is a polynomial universal hash over the finite field $\mathrm{GF}(2^{128})$: it evaluates $\sum_i m_i \cdot H^{,L-i+1}$ at a secret point $H = E_k(0)$, then masks the result with an AES-encrypted counter block [@mcgrew-viega-2004]. Run GCM with an empty plaintext and you get GMAC, an authentication-only MAC over associated data, standardized in NIST SP 800-38D [@sp-800-38d]. Poly1305 evaluates a message polynomial modulo the prime $2^{130}-5$ under a secret $r$, then adds a one-time pad $s$; deployed as ChaCha20-Poly1305, it draws a fresh $(r, s)$ from the cipher keystream for every message [@rfc-8439].&lt;/p&gt;

flowchart TD
    N[Nonce and key] --&amp;gt; KS[Cipher keystream block]
    KS --&amp;gt; R[One-time hash key r]
    KS --&amp;gt; S[One-time pad s]
    M[Message m] --&amp;gt; P[Polynomial hash of m under r]
    R --&amp;gt; P
    P --&amp;gt; ADD[Add the one-time pad s]
    S --&amp;gt; ADD
    ADD --&amp;gt; T[Authentication tag]
    T -.reuse the same nonce.-&amp;gt; LEAK[Two tags cancel the pad, leaking hash of m1 minus hash of m2]
&lt;p&gt;This is where the 1981 constraint re-enters as a deployment contract. The pad is safe only if the $(key, nonce)$ pair never repeats. Reuse it and the pad cancels out of the difference of two tags, exactly as the toy line did in Section 3 -- except now the &quot;hash&quot; is a polynomial an attacker can then start solving.&lt;/p&gt;
&lt;p&gt;{`&lt;/p&gt;
A one-time Wegman-Carter MAC: tag = poly_hash(m, r) + s (mod p). Use (r, s) ONCE.
&lt;p&gt;p = (1 &amp;lt;&amp;lt; 130) - 5                          # the Poly1305 prime, 2**130 - 5&lt;/p&gt;
&lt;p&gt;def poly_hash(msg, r):
    acc = 0
    for i in range(0, len(msg), 16):
        chunk = msg[i:i+16]
        limb  = int.from_bytes(chunk, &quot;little&quot;) + (1 &amp;lt;&amp;lt; (8 * len(chunk)))
        acc   = ((acc + limb) * r) % p
    return acc&lt;/p&gt;
In ChaCha20-Poly1305 both r and s come fresh from the keystream, per message.
&lt;p&gt;r = 0x1bf54941aff6bf4afdb1f2a3c4d5e6f7
s = 0x0102030405060708090a0b0c0d0e0f10&lt;/p&gt;
&lt;p&gt;def one_time_tag(msg):
    return (poly_hash(msg, r) + s) % p&lt;/p&gt;
THE MISTAKE: two messages under the SAME (r, s).
&lt;p&gt;m1, m2 = b&quot;transfer 10 dollars now&quot;, b&quot;transfer 9999 bucks now&quot;
t1, t2 = one_time_tag(m1), one_time_tag(m2)&lt;/p&gt;
The pad s cancels in the difference -- a relation that does not depend on s at all:
&lt;p&gt;lhs = (t1 - t2) % p
rhs = (poly_hash(m1, r) - poly_hash(m2, r)) % p
print(&quot;pad cancelled, tag difference is key-independent:&quot;, lhs == rhs)
`}&lt;/p&gt;
&lt;p&gt;It prints &lt;code&gt;True&lt;/code&gt;: subtract two tags produced under the same one-time key and the secret pad vanishes, handing the attacker a clean algebraic relation in the hash key. That is the first step of the &quot;forbidden attack&quot; the failure catalogue will name -- and it is why the distinction below is not pedantry.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;master key versus one-time key&lt;/strong&gt; split is the heart of the fork. HMAC and KMAC take a &lt;em&gt;master&lt;/em&gt; key and authenticate forever under it. GMAC and Poly1305 take a &lt;em&gt;one-time&lt;/em&gt; key per message; the ChaCha20-Poly1305 keystream manufactures that one-time key so the master key stays put, but the per-message pad is still strictly single-use. Confuse the two and you get a catastrophe, not a slow degradation.&lt;/p&gt;
&lt;p&gt;The whole construction catalogue, side by side:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Table 1 -- MAC constructions, and what each one assumes.&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Construction&lt;/th&gt;
&lt;th&gt;Year&lt;/th&gt;
&lt;th&gt;Core idea&lt;/th&gt;
&lt;th&gt;Key model&lt;/th&gt;
&lt;th&gt;Strength&lt;/th&gt;
&lt;th&gt;Weakness&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Carter-Wegman one-time [@wc-1981]&lt;/td&gt;
&lt;td&gt;1981&lt;/td&gt;
&lt;td&gt;$\mathsf{UH}(m) \oplus \text{pad}$&lt;/td&gt;
&lt;td&gt;One-time pad per message&lt;/td&gt;
&lt;td&gt;Information-theoretic, no hardness assumption&lt;/td&gt;
&lt;td&gt;Pad is strictly single-use&lt;/td&gt;
&lt;td&gt;Foundational, revived&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secret-prefix $H(k \Vert m)$ [@length-ext-wiki]&lt;/td&gt;
&lt;td&gt;1990s&lt;/td&gt;
&lt;td&gt;Prepend key, hash&lt;/td&gt;
&lt;td&gt;Reusable&lt;/td&gt;
&lt;td&gt;Trivial to build&lt;/td&gt;
&lt;td&gt;Length-extension forgeable&lt;/td&gt;
&lt;td&gt;Superseded, insecure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secret-suffix $H(m \Vert k)$ [@length-ext-wiki]&lt;/td&gt;
&lt;td&gt;1990s&lt;/td&gt;
&lt;td&gt;Append key, hash&lt;/td&gt;
&lt;td&gt;Reusable&lt;/td&gt;
&lt;td&gt;No length extension&lt;/td&gt;
&lt;td&gt;Reduces to a hash collision&lt;/td&gt;
&lt;td&gt;Superseded, insecure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CBC-MAC [@fips-113]&lt;/td&gt;
&lt;td&gt;1985&lt;/td&gt;
&lt;td&gt;CBC chain, keep last block&lt;/td&gt;
&lt;td&gt;Reusable&lt;/td&gt;
&lt;td&gt;First standardized block-cipher MAC&lt;/td&gt;
&lt;td&gt;Variable-length splicing forgery&lt;/td&gt;
&lt;td&gt;Historical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HMAC [@rfc-2104]&lt;/td&gt;
&lt;td&gt;1996&lt;/td&gt;
&lt;td&gt;Nested keyed hash&lt;/td&gt;
&lt;td&gt;Reusable, no nonce&lt;/td&gt;
&lt;td&gt;PRF not collision resistance, length-ext immune&lt;/td&gt;
&lt;td&gt;Serial, no line-rate shortcut&lt;/td&gt;
&lt;td&gt;Active, default PRF-MAC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CMAC [@sp-800-38b]&lt;/td&gt;
&lt;td&gt;2005&lt;/td&gt;
&lt;td&gt;CBC-MAC plus final subkey&lt;/td&gt;
&lt;td&gt;Reusable, no nonce&lt;/td&gt;
&lt;td&gt;Fixes CBC-MAC with one key&lt;/td&gt;
&lt;td&gt;Block-cipher birthday ceiling&lt;/td&gt;
&lt;td&gt;Active, niche&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GMAC / GHASH [@sp-800-38d]&lt;/td&gt;
&lt;td&gt;2004&lt;/td&gt;
&lt;td&gt;Polynomial hash over $\mathrm{GF}(2^{128})$&lt;/td&gt;
&lt;td&gt;One-time pad per message&lt;/td&gt;
&lt;td&gt;Carry-less-multiply hardware (PCLMULQDQ/PMULL)&lt;/td&gt;
&lt;td&gt;Nonce reuse is fatal&lt;/td&gt;
&lt;td&gt;Active, inside GCM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Poly1305 [@rfc-8439]&lt;/td&gt;
&lt;td&gt;2005&lt;/td&gt;
&lt;td&gt;Polynomial hash mod $2^{130}-5$&lt;/td&gt;
&lt;td&gt;One-time key per message&lt;/td&gt;
&lt;td&gt;Fast in pure software, cipher-agnostic&lt;/td&gt;
&lt;td&gt;One-time key per message&lt;/td&gt;
&lt;td&gt;Active, inside ChaCha20-Poly1305&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;KMAC [@sp-800-185]&lt;/td&gt;
&lt;td&gt;2016&lt;/td&gt;
&lt;td&gt;Keyed sponge, cSHAKE&lt;/td&gt;
&lt;td&gt;Reusable, no nonce&lt;/td&gt;
&lt;td&gt;Native keying, domain separation, XOF tag&lt;/td&gt;
&lt;td&gt;Lightly deployed&lt;/td&gt;
&lt;td&gt;Active, niche&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;You can now build an unforgeable tag two ways: a reusable-key PRF or a one-time-key universal hash. But a perfect tag attached in the wrong place, in the wrong order, or over the wrong bytes is still useless. How do you &lt;em&gt;combine&lt;/em&gt; a MAC with a cipher without reopening the door you just closed?&lt;/p&gt;
&lt;h2&gt;6. Composition Done Right, and the Verification Contract&lt;/h2&gt;
&lt;p&gt;SSL chose one order for combining its cipher and its MAC. SSH chose another. Both were quietly indicted by a theorem years before either was broken in the field. This section is where the second aha moment lands: strength was never the variable -- discipline and order were.&lt;/p&gt;
&lt;p&gt;Bellare and Namprempre formalized the question in 2000 by splitting integrity into two notions [@bn-2000]. Integrity of plaintexts (INT-PTXT) says an attacker cannot make the receiver accept a plaintext the sender never sent. Integrity of ciphertexts (INT-CTXT) is stronger: the attacker cannot even produce a &lt;em&gt;new ciphertext&lt;/em&gt; the receiver will accept. Their result is the load-bearing one: applying the MAC to the ciphertext -- Encrypt-then-MAC -- yields both IND-CCA confidentiality and INT-CTXT, and it is the only one of the three generic orders that reaches those strong notions.&lt;/p&gt;

Encrypt the plaintext, then compute the MAC over the resulting *ciphertext* (plus any associated data and length), and send ciphertext and tag together. On receipt, verify the tag *before* touching the ciphertext; if it fails, discard without decrypting. EtM is the only generic composition order that provably delivers integrity of ciphertexts, and it does so only under two preconditions: the MAC must be strongly unforgeable and the encryption and MAC keys must be independent.
&lt;p&gt;Those two preconditions are not decoration. If the MAC is only EUF-CMA rather than SUF-CMA, the guarantee weakens from INT-CTXT down to INT-PTXT, because a malleable tag lets an attacker produce a different valid ciphertext for the same plaintext [@bn-2000]. And the keys must be independent -- reusing one key for both encryption and authentication voids the proof.&lt;/p&gt;
&lt;p&gt;A year later Krawczyk sharpened the verdict [@krawczyk-2001]. He proved that any secure-channel protocol required to work with &lt;em&gt;any&lt;/em&gt; secure cipher and &lt;em&gt;any&lt;/em&gt; secure MAC must use Encrypt-then-MAC, and he built a perfectly secret cipher that becomes totally insecure under MAC-then-Encrypt -- SSL&apos;s order -- and under Encrypt-and-MAC -- SSH&apos;s order.&lt;/p&gt;

&quot;[A]ny secure channels protocol designed to work with any combination of secure encryption ... and secure MAC must use the encrypt-then-authenticate method.&quot; -- Hugo Krawczyk, The Order of Encryption and Authentication for Protecting Communications, 2001 [@krawczyk-2001]
&lt;p&gt;Here is the precision that separates an expert from a slogan-repeater: Krawczyk &lt;em&gt;also&lt;/em&gt; proved that MAC-then-Encrypt is secure for specific cipher modes, namely &lt;a href=&quot;https://paragmali.com/blog/the-ciphertext-was-unbreakable-the-attacker-rewrote-it-anyw/&quot; rel=&quot;noopener&quot;&gt;CBC and CTR&lt;/a&gt; [@krawczyk-2001]. MtE is therefore &lt;em&gt;fragile&lt;/em&gt; and &lt;em&gt;not generically secure&lt;/em&gt; -- it holds only when you can prove something extra about the exact cipher -- but it was never unconditionally &quot;broken.&quot; Say &quot;MtE is broken&quot; in an interview and you are wrong; say &quot;MtE is not generically secure, so do not use it in new designs&quot; and you are exactly right.&lt;/p&gt;

flowchart TD
    subgraph EtM[&quot;Encrypt-then-MAC, generically secure&quot;]
        E1[Plaintext] --&amp;gt; E2[Encrypt]
        E2 --&amp;gt; E3[Ciphertext] --&amp;gt; E4[MAC the ciphertext]
        E4 --&amp;gt; E5[Receiver verifies tag first, then decrypts]
    end
    subgraph MtE[&quot;MAC-then-Encrypt, fragile&quot;]
        M1[Plaintext] --&amp;gt; M2[MAC the plaintext]
        M2 --&amp;gt; M3[Encrypt plaintext and tag together]
        M3 --&amp;gt; M4[Receiver decrypts first, only then verifies]
    end
    subgraph EM[&quot;Encrypt-and-MAC, fragile&quot;]
        A1[Plaintext] --&amp;gt; A2[Encrypt]
        A1 --&amp;gt; A3[MAC the plaintext, tag sent in the clear]
        A2 --&amp;gt; A4[Receiver decrypts, and the tag leaks plaintext]
    end
&lt;p&gt;The diagram shows the mechanism behind every &lt;a href=&quot;https://paragmali.com/blog/they-read-your-plaintext-without-breaking-your-cipher-a-fiel/&quot; rel=&quot;noopener&quot;&gt;padding-oracle&lt;/a&gt; and SSH break at once: in the two fragile orders, the receiver must &lt;em&gt;decrypt or parse before it can verify&lt;/em&gt;, so the very act of processing attacker-chosen bytes leaks information. Encrypt-then-MAC verifies first and refuses to decrypt a single byte of an unauthenticated ciphertext.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Authenticate the ciphertext, not the plaintext. Encrypt-then-MAC over the ciphertext -- with an independent key, a strongly unforgeable tag, and coverage of the associated data and length -- is the only generic order that lets the receiver reject a forgery before it decrypts anything. Every composition break in the catalogue is a system that decrypted or parsed before it verified.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Table 2 -- Composition orders, ranked by what they generically guarantee.&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Order&lt;/th&gt;
&lt;th&gt;Idea&lt;/th&gt;
&lt;th&gt;Generic security&lt;/th&gt;
&lt;th&gt;Weakness&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;MAC-then-Encrypt [@krawczyk-2001]&lt;/td&gt;
&lt;td&gt;MAC the plaintext, then encrypt both&lt;/td&gt;
&lt;td&gt;Not generic, secure only for CBC or CTR&lt;/td&gt;
&lt;td&gt;Decrypt-before-verify padding and timing oracles&lt;/td&gt;
&lt;td&gt;Superseded, fragile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Encrypt-and-MAC [@apw-2009]&lt;/td&gt;
&lt;td&gt;Encrypt, and MAC the plaintext separately&lt;/td&gt;
&lt;td&gt;Not generic&lt;/td&gt;
&lt;td&gt;Tag over plaintext leaks, MAC-covered length field abused&lt;/td&gt;
&lt;td&gt;Superseded, fragile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Encrypt-then-MAC [@bn-2000]&lt;/td&gt;
&lt;td&gt;MAC the ciphertext&lt;/td&gt;
&lt;td&gt;IND-CCA plus INT-CTXT&lt;/td&gt;
&lt;td&gt;Needs SUF-CMA, independent keys, constant-time verify&lt;/td&gt;
&lt;td&gt;Active, canonical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AEAD [@rfc-8446]&lt;/td&gt;
&lt;td&gt;EtM internalized plus nonce management&lt;/td&gt;
&lt;td&gt;IND-CCA plus INT-CTXT by construction&lt;/td&gt;
&lt;td&gt;Key-commitment gap&lt;/td&gt;
&lt;td&gt;Active, default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Committing AEAD [@rfc-9771]&lt;/td&gt;
&lt;td&gt;AEAD plus key and context commitment&lt;/td&gt;
&lt;td&gt;Adds commitment&lt;/td&gt;
&lt;td&gt;Still standardizing, cost profiling&lt;/td&gt;
&lt;td&gt;Frontier&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The order is only half of correct composition. The other half arrived not from a theorem but from a field disclosure. In 2009 Nate Lawson found that Google&apos;s Keyczar library compared HMAC tags byte by byte and returned as soon as two bytes differed [@keyczar-2009]. That early exit turns verification time into a side channel: a forged tag that matches more leading bytes takes measurably longer to reject, so an attacker can recover the correct tag one byte at a time by timing responses.&lt;/p&gt;
&lt;p&gt;{`&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Q0 -- Yes --&amp;gt; ASCON[Ascon, SP 800-232]
Q0 -- No --&amp;gt; Q1&amp;amp;#123;&quot;Is there a ciphertext to authenticate?&quot;&amp;amp;#125;
Q1 -- No --&amp;gt; HMAC[HMAC-SHA-256, reusable key, no nonce]
Q1 -- Yes --&amp;gt; Q2&amp;amp;#123;&quot;Can you guarantee a unique nonce per key?&quot;&amp;amp;#125;
Q2 -- No --&amp;gt; SIV[AES-GCM-SIV, misuse-resistant]
Q2 -- Yes --&amp;gt; Q3&amp;amp;#123;&quot;Is AES-NI hardware available?&quot;&amp;amp;#125;
Q3 -- Yes --&amp;gt; GCM[AES-GCM, rekey before the per-key ceiling]
Q3 -- No --&amp;gt; CHACHA[ChaCha20-Poly1305]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Read the tree as the three assumptions in order. If there is no ciphertext to bind -- key derivation, a token, a one-time password -- use HMAC-SHA-256 with a key of at least 128 bits, a full-length tag, and a constant-time verify; there is no nonce to mismanage, so assumption one is nearly free. This is the right tool for HKDF [@rfc-5869], JWT&apos;s &lt;code&gt;HS256&lt;/code&gt; [@rfc-7518], TOTP, HOTP, and PBKDF2.&lt;/p&gt;
&lt;p&gt;If there &lt;em&gt;is&lt;/em&gt; a ciphertext, do not hand-roll a MAC plus cipher -- reach for an AEAD, which internalizes Encrypt-then-MAC so you cannot mis-order it. Pick ChaCha20-Poly1305 when you lack AES hardware acceleration, especially on mobile and embedded targets, where its per-key budget is effectively unbounded [@rfc-8439]. Pick AES-GCM when you have AES-NI, and rekey before the $2^{23}$-packet ceiling on high-volume links [@rfc-9001]. If you cannot &lt;em&gt;guarantee&lt;/em&gt; nonce uniqueness at scale, step down to AES-GCM-SIV, which degrades gracefully instead of catastrophically on reuse [@rfc-8452].&lt;/p&gt;
&lt;p&gt;Two niche branches sit off the main tree. Use GMAC for authentication-only data, such as MACsec framing, with a guaranteed-unique nonce [@sp-800-38d] [@ieee-802-1ae]. Use KMAC when you are already in a Keccak or SHA-3 stack, or when you need domain separation or variable-length tags [@sp-800-185]. And on constrained or side-channel-sensitive hardware, use Ascon [@sp-800-232].&lt;/p&gt;
&lt;p&gt;Then there are the rules that apply &lt;em&gt;always&lt;/em&gt;, regardless of which box the tree lands in: Encrypt-then-MAC or an AEAD that internalizes it; independent encryption and MAC keys; a constant-time compare; a tag of at least 128 bits with documented truncation floors [@rfc-4868]; authentication that covers the associated data, the length, the version, and the session context; a committing AEAD when one ciphertext might be opened under multiple keys [@bellare-hoang-2022]; and a misuse-resistant AEAD when nonce uniqueness cannot be guaranteed [@rfc-8452].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Review authentication code against the checklist &lt;em&gt;and its negation&lt;/em&gt;. The checklist tells you what a correct design does; the misuse list tells you what every named CVE did instead. Run any authentication path past both -- if it matches even one line of the misuse list, you have found your next vulnerability before an attacker does.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The negation is the misuse catalogue -- each row is a line of the checklist inverted, and it maps one-to-one onto a named break from Section 7.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Table 6 -- Common misuse, the break it produced, and the fix.&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Misuse in real code&lt;/th&gt;
&lt;th&gt;Named break it caused&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Secret-prefix $H(k \Vert m)$ MAC&lt;/td&gt;
&lt;td&gt;Flickr length extension [@flickr-advisory]&lt;/td&gt;
&lt;td&gt;Use HMAC or KMAC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reusing a GCM nonce or Poly1305 one-time key&lt;/td&gt;
&lt;td&gt;Joux, Nonce-Disrespecting [@woot16-bock]&lt;/td&gt;
&lt;td&gt;Guarantee uniqueness or use AES-GCM-SIV&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;==&lt;/code&gt; or &lt;code&gt;memcmp&lt;/code&gt; tag comparison&lt;/td&gt;
&lt;td&gt;Keyczar timing leak [@keyczar-2009]&lt;/td&gt;
&lt;td&gt;Use a constant-time compare&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MAC-then-Encrypt or Encrypt-and-MAC in new code&lt;/td&gt;
&lt;td&gt;Lucky Thirteen, POODLE, SSH recovery [@cve-2013-0169]&lt;/td&gt;
&lt;td&gt;Use an AEAD (Encrypt-then-MAC)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Over-truncated tags&lt;/td&gt;
&lt;td&gt;Forgery near the $2^{-t}$ floor [@rfc-4868]&lt;/td&gt;
&lt;td&gt;Keep the tag at least 128 bits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One shared key for encryption and MAC&lt;/td&gt;
&lt;td&gt;Voids the Encrypt-then-MAC proof [@bn-2000]&lt;/td&gt;
&lt;td&gt;Derive independent keys&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MACing the plaintext instead of the ciphertext&lt;/td&gt;
&lt;td&gt;Padding oracles [@vaudenay-2002]&lt;/td&gt;
&lt;td&gt;MAC the ciphertext&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Forgetting AD, length, version, context&lt;/td&gt;
&lt;td&gt;Terrapin [@terrapin-site]&lt;/td&gt;
&lt;td&gt;Bind the full context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Treating &quot;MAC verified&quot; as &quot;key committed&quot;&lt;/td&gt;
&lt;td&gt;Invisible salamanders [@bellare-hoang-2022]&lt;/td&gt;
&lt;td&gt;Use a committing AEAD&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Run every authentication path past these ten lines: - Is the tag over the &lt;strong&gt;ciphertext&lt;/strong&gt; (Encrypt-then-MAC), never the plaintext? - Are the encryption and MAC keys &lt;strong&gt;independent&lt;/strong&gt;? - Is the MAC &lt;strong&gt;strongly unforgeable&lt;/strong&gt; (SUF-CMA), not merely EUF-CMA? - Is the tag comparison &lt;strong&gt;constant-time&lt;/strong&gt; (&lt;code&gt;compare_digest&lt;/code&gt;, &lt;code&gt;timingSafeEqual&lt;/code&gt;, &lt;code&gt;ConstantTimeCompare&lt;/code&gt;)? - Is the &lt;strong&gt;whole&lt;/strong&gt; decrypt-and-verify path constant-time, not just the compare? - Is the tag at least &lt;strong&gt;128 bits&lt;/strong&gt;, with any truncation documented against the birthday bound? - For a one-time-key MAC (GMAC, Poly1305), is nonce uniqueness &lt;strong&gt;guaranteed&lt;/strong&gt;, or are you on a misuse-resistant mode? - Does the authenticated data cover &lt;strong&gt;length, version, ordering, and session context&lt;/strong&gt;? - Is there any &lt;strong&gt;&lt;code&gt;H(secret || message)&lt;/code&gt;&lt;/strong&gt; secret-prefix construction? (Replace with HMAC or KMAC.) - Could one ciphertext open under &lt;strong&gt;two keys&lt;/strong&gt;? If so, use a committing AEAD. Any single failure here is a plausible next CVE.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That checklist and its negation are the working payoff of the whole field guide. Before the conclusion ties them back to the thesis, seven specific beliefs produce most of the remaining real-world authentication bugs -- and each is a corollary of the same one sentence.&lt;/p&gt;
&lt;h2&gt;13. Frequently Corrected Misconceptions&lt;/h2&gt;


No. As Section 5 established, Bellare&apos;s 2006 proof rests HMAC&apos;s security on a single property of the underlying compression function -- that it is itself a PRF -- and not on collision resistance [@bellare-2006]. Since a collision attack targets a property the proof never relies on, HMAC-SHA-1 and HMAC-MD5 kept standing when the SHA-1 and MD5 collision breaks landed. Use HMAC-SHA-256 in new systems for margin, but understand that the reason is prudence, not a collision threat.


No, and the difference is the most dangerous one to miss. HMAC takes a reusable key with no nonce. GMAC and Poly1305 are Wegman-Carter one-time-key MACs [@wc-1981]: they need a fresh, unique per-message key, and reusing it is catastrophic, not a gentle degradation. The 184 HTTPS servers caught repeating GCM nonces were forgeable precisely because a one-time construction was treated like a reusable one [@woot16-bock]. Same tag length, completely different key contract.


No. HMAC exists to defeat length extension on Merkle-Damgard hashes, but a Keccak sponge never emits its capacity, so it has no length-extension surface and keys natively -- just use KMAC [@sp-800-185]. In fact you cannot build HMAC on a SHAKE extendable-output function anyway; Python&apos;s `hmac` module notes that XOFs such as SHAKE-128 and SHAKE-256 cannot be used with HMAC [@python-hmac]. KMAC is the SHA-3-native answer.


No -- it is fragile, which is a different and more precise claim. Krawczyk proved MAC-then-Encrypt is *not generically secure*, yet also proved it *is* secure for CBC and CTR modes specifically [@krawczyk-2001]. So it was never unconditionally broken; it is simply deprecated for new designs, where a modern AEAD or Encrypt-then-MAC removes the cipher-specific precondition it depends on. Reach for one of those instead, but do not call MtE &quot;broken.&quot;


Not by itself, and the overstatement matters. A single $(key, nonce)$ reuse immediately leaks a tag relation and the XOR of the two plaintexts [@joux-2006]. Recovering the subkey $H$ outright is a taller order: a single reuse leaves a root-finding equation with several possible solutions for $H$, so narrowing them to the one true value takes at least a second collision, and usually more. So &quot;one reuse recovers the key&quot; is wrong; &quot;one reuse is already a break, and more reuse recovers the key&quot; is right.


No -- there is a real-world counterexample. In 2009 Google&apos;s Keyczar library did a byte-wise tag comparison with an early exit, and that timing difference let an attacker recover valid tags one byte at a time [@keyczar-2009]. The comparison time leaked the secret the MAC existed to protect. Constant-time compare is a correctness requirement, not an optimization, and every major platform ships a named primitive for it.


No. AEAD handles the encrypted channel, but plenty of jobs have no ciphertext to bind and still need authentication. HKDF key derivation [@rfc-5869], JWT&apos;s `HS256` [@rfc-7518], TOTP and HOTP one-time passwords, and PBKDF2 are all standalone HMAC. The standalone MAC did not disappear with AEAD; it moved to the places where you are authenticating keys, tokens, or messages rather than protecting a ciphertext.

&lt;p&gt;Every myth here is a corollary of one sentence, which the conclusion now restates with the whole catalogue behind it.&lt;/p&gt;
&lt;h2&gt;14. The Math Never Broke&lt;/h2&gt;
&lt;p&gt;Return to Flickr, now fully understood. Two researchers forged valid API signatures with no key, no collision, and no cipher work, because Flickr&apos;s secret-prefix &lt;code&gt;H(secret || params)&lt;/code&gt; construction handed out its resumable hash state as the tag [@flickr-advisory]. The hash met its specification exactly. The deployment broke assumption three -- the wrong construction over the wrong bytes -- and that was enough.&lt;/p&gt;
&lt;p&gt;Line up the rest of the catalogue and the pattern is total. Lucky Thirteen and POODLE broke order and timing, decrypting before verifying [@cve-2013-0169] [@cve-2014-3566]. The SSH plaintext-recovery attack broke order, authenticating the plaintext and acting on a MAC-covered length field [@apw-2009]. The 184 nonce-repeating GCM servers broke key discipline, reusing a one-time pad [@woot16-bock]. Terrapin broke context, leaving the transcript and sequence numbers unbound even though the cipher, the MAC, and the order were all correct [@terrapin-site]. Not one of them broke AES, SHA-2, or a polynomial hash. Every single failure broke the contract around the primitive.&lt;/p&gt;
&lt;p&gt;That is the whole thesis, proven by the evidence rather than asserted: a MAC makes forgery hard, and three deployment assumptions -- the right key discipline, a constant-time verify, and composition over the right bytes in the right order binding the right context -- are what keep it hard. The decision tree and the checklist in Section 12 are simply those three assumptions made executable. Carry them, and their negation, into every review.&lt;/p&gt;
&lt;p&gt;The frontier moves the bar again: soon &quot;the tag verified&quot; should also mean &quot;this ciphertext commits to one key and one context,&quot; the committing-AEAD work this series develops further in Part 7. And the deeper machinery lives in the siblings -- &lt;a href=&quot;https://paragmali.com/blog/secure-against-whom-the-security-definitions-every-protocol-/&quot; rel=&quot;noopener&quot;&gt;the security definitions&lt;/a&gt; of Part 1, &lt;a href=&quot;https://paragmali.com/blog/predictable-or-repeated-the-only-two-ways-cryptographic-rand/&quot; rel=&quot;noopener&quot;&gt;the one-time-key generation&lt;/a&gt; of Part 2, the canonicalization discipline of Part 3, the block modes of Part 5, the padding oracles of Part 6, and the AEAD decision matrix of Part 7. This part is the authentication spine that runs through all of them.&lt;/p&gt;

The math never broke; a deployment broke one of three assumptions. Authenticate the ciphertext, the length, and the context -- not just the message.
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;message-authentication-and-safe-composition&quot; keyTerms={[
  { term: &quot;Message Authentication Code (MAC)&quot;, definition: &quot;A keyed algorithm producing a short tag so a shared-key holder can verify a message is authentic and unmodified&quot; },
  { term: &quot;EUF-CMA&quot;, definition: &quot;Existential unforgeability under adaptive chosen-message attack; no forgery on a fresh message after querying tags&quot; },
  { term: &quot;SUF-CMA&quot;, definition: &quot;Strong unforgeability; not even a new valid tag on a previously queried message, the notion Encrypt-then-MAC requires&quot; },
  { term: &quot;Universal hash function&quot;, definition: &quot;A family whose random member collides any fixed pair with small, provable probability, with no hardness assumption&quot; },
  { term: &quot;Pseudorandom function (PRF)&quot;, definition: &quot;A keyed function indistinguishable from random; the sole assumption HMAC&apos;s security rests on&quot; },
  { term: &quot;Keyed sponge&quot;, definition: &quot;A sponge keyed by absorbing the key first; its hidden capacity gives native keying with no length extension, as in KMAC&quot; },
  { term: &quot;Encrypt-then-MAC&quot;, definition: &quot;Compute the tag over the ciphertext and verify before decrypting; the only generically secure composition order&quot; },
  { term: &quot;One-time key&quot;, definition: &quot;The per-message key of a Wegman-Carter MAC (GMAC, Poly1305); reuse is catastrophic, not a slow leak&quot; },
  { term: &quot;Key commitment&quot;, definition: &quot;The property that a ciphertext decrypts validly under only one key; standard AEAD does not provide it&quot; }
]} questions={[
  { q: &quot;What are the three deployment assumptions every MAC relies on?&quot;, a: &quot;Right key discipline for its family, a constant-time verify, and composition over the right bytes and order binding the right context.&quot; },
  { q: &quot;Why did HMAC-SHA-1 survive SHA-1 collisions?&quot;, a: &quot;HMAC&apos;s security reduces to the compression function being a PRF, not to collision resistance, as Bellare proved in 2006.&quot; },
  { q: &quot;Why is reusing a Poly1305 or GMAC nonce catastrophic?&quot;, a: &quot;The one-time pad cancels in the difference of two tags, leaking a key-independent relation that enables forgery.&quot; },
  { q: &quot;Is MAC-then-Encrypt broken?&quot;, a: &quot;No; it is fragile and not generically secure, though Krawczyk proved it secure for CBC and CTR. Avoid it in new designs.&quot; },
  { q: &quot;What does Encrypt-then-MAC require to be secure?&quot;, a: &quot;A strongly unforgeable (SUF-CMA) MAC, independent encryption and MAC keys, a constant-time verify path, and coverage of associated data and length.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>message-authentication</category><category>hmac</category><category>poly1305</category><category>gmac</category><category>authenticated-encryption</category><category>encrypt-then-mac</category><category>applied-cryptography</category><category>aead</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>The AEAD Decision Matrix: Seven Ciphers, Three Edges, One Choice</title><link>https://paragmali.com/blog/the-aead-decision-matrix-seven-ciphers-three-edges-one-choic/</link><guid isPermaLink="true">https://paragmali.com/blog/the-aead-decision-matrix-seven-ciphers-three-edges-one-choic/</guid><description>AES-GCM, ChaCha20-Poly1305, CCM, OCB3, GCM-SIV, AEGIS, and Ascon, compared by the three sharp edges that decide every deployment: nonce, hardware, commitment.</description><pubDate>Thu, 09 Jul 2026 15:04:00 GMT</pubDate><content:encoded>
Every modern AEAD makes the same three promises, and they differ only at the sharp edges where those promises stop. Three edges decide a real deployment: the **nonce contract** (catastrophic on reuse, or misuse-resistant), the **performance and hardware profile** (AES-NI plus CLMUL, constant-time software, or a few thousand gates), and **commitment** (does one ciphertext bind to exactly one key?). &quot;Which AEAD should I use?&quot; is not a ranking from worst to best. It is a function: default to AES-GCM or ChaCha20-Poly1305, and escalate to AES-GCM-SIV, AES-CCM, Ascon, OCB3, or AEGIS only when a specific edge demands it. Every famous break -- invisible salamanders, nonce reuse on live TLS, `CCM_8` forgeries -- was a deployment stepping on an edge, not a broken cipher.
&lt;h2&gt;1. Two Failures That Should Have Been Impossible&lt;/h2&gt;
&lt;p&gt;In 2018, a team of cryptographers handed Facebook a single encrypted file that decrypted to two completely different, perfectly meaningful images, and whose authentication tag verified correctly for &lt;em&gt;both&lt;/em&gt;, under two different keys [@dodis2018-salamander]. The cipher was AES-GCM, the internet&apos;s default authenticated encryption. Nothing about it was broken. That is the unsettling part: AES-GCM did &lt;em&gt;exactly&lt;/em&gt; what it promised. It had just never promised the thing everyone assumed it did.&lt;/p&gt;
&lt;p&gt;The result defeated Facebook Messenger&apos;s abuse-reporting scheme, which relied on the encrypted attachment being &lt;em&gt;bound&lt;/em&gt; to the key that produced it. The authors called their construction &quot;invisible salamanders&quot; [@dodis2018-salamander]. Your reflex on reading this -- &quot;but it is &lt;em&gt;authenticated&lt;/em&gt;, so how did the tag pass?&quot; -- is the entire subject of this article. The word &quot;authenticated&quot; carries less than you think.&lt;/p&gt;
&lt;p&gt;Now the second failure, because one break only shows one edge. In 2016, researchers scanning the live internet found 184 HTTPS servers reusing a &lt;code&gt;(key, nonce)&lt;/code&gt; pair under AES-GCM [@bock2016]. A repeated nonce in GCM is not a hygiene slip that costs you a little margin. It instantly leaks the XOR of the two plaintexts, and -- via an attack Antoine Joux had described to NIST a decade earlier, in 2006 -- it lets an attacker forge arbitrary messages [@joux2006]. The confidentiality half of that failure is easy to see for yourself.&lt;/p&gt;
&lt;p&gt;{`
// A stream-cipher-style AEAD (GCM, ChaCha20-Poly1305) turns the key+nonce
// into a keystream, then XORs it with the plaintext. Reuse the nonce and
// you reuse the keystream -- so it cancels out of the XOR of two ciphertexts.
const keystream = [0x9e, 0x37, 0xb1, 0xf2, 0x4a];   // same (key, nonce) =&amp;gt; same keystream
const xor = (a, b) =&amp;gt; a.map((x, i) =&amp;gt; x ^ b[i]);&lt;/p&gt;
&lt;p&gt;const p1 = [...&apos;HELLO&apos;].map(c =&amp;gt; c.charCodeAt(0));
const p2 = [...&apos;WORLD&apos;].map(c =&amp;gt; c.charCodeAt(0));&lt;/p&gt;
&lt;p&gt;const c1 = xor(p1, keystream);   // ciphertext 1
const c2 = xor(p2, keystream);   // ciphertext 2, SAME nonce&lt;/p&gt;
&lt;p&gt;// Attacker sees only c1 and c2, never the key or keystream:
const leaked = xor(c1, c2);      // == p1 XOR p2, the keystream is gone
const recovered = xor(leaked, p2);  // and if p2 is ever guessed, p1 falls out
console.log(&apos;c1 XOR c2 leaks P1 XOR P2:&apos;, leaked.join(&apos;,&apos;));
console.log(&apos;recovered P1:&apos;, String.fromCharCode(...recovered));
`}&lt;/p&gt;
&lt;p&gt;Neither of these was a broken cipher. AES-GCM met its specification in both cases. The salamander bound nothing to a key because AES-GCM was never designed to; the TLS servers leaked plaintext because they violated the one contract GCM cannot survive. Both failures were the same shape: a deployment reached for an AEAD and then stepped on the one sharp edge its designers had moved somewhere the deployment could not avoid.&lt;/p&gt;
&lt;p&gt;That is the thesis of this field guide. Authenticated encryption with associated data (AEAD) fused confidentiality and integrity so completely that composing them by hand became a solved problem. The remaining hard problem is choosing &lt;em&gt;among&lt;/em&gt; AEADs, and that choice turns on three edges: the &lt;strong&gt;nonce contract&lt;/strong&gt;, the &lt;strong&gt;performance and hardware profile&lt;/strong&gt;, and the &lt;strong&gt;commitment&lt;/strong&gt; axis.&lt;/p&gt;
&lt;p&gt;Part 1 of this series defined an AEAD&apos;s guarantees as &lt;a href=&quot;https://paragmali.com/blog/secure-against-whom-the-security-definitions-every-protocol-/&quot; rel=&quot;noopener&quot;&gt;IND-CPA plus INT-CTXT&lt;/a&gt;; commitment is a robustness property &lt;em&gt;beyond&lt;/em&gt; both. Part 6 showed the padding-oracle cost of the botched integrity AEAD was built to remove.The nonce-reuse breaks are widely mis-cited to CVE-2016-0270. That CVE actually names IBM Domino, and the NVD entry itself warns it has been &quot;incorrectly used for GCM nonce reuse issues in other products&quot; [@cve-2016-0270].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; &quot;Which AEAD should I use?&quot; is not a ranking. It is a function over three edges: pick the construction whose failure mode your deployment can &lt;em&gt;guarantee&lt;/em&gt; it will never trigger. The salamander triggered the commitment edge; the TLS servers triggered the nonce edge. Same lesson, two edges.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If &quot;authenticated&quot; does not mean &quot;bound to one key,&quot; and &quot;encrypted&quot; does not survive a repeated nonce, then what &lt;em&gt;exactly&lt;/em&gt; does an AEAD promise, and where does each promise stop? To answer that, we have to go back to the moment when &quot;encrypt&quot; and &quot;authenticate&quot; were still two separate calls.&lt;/p&gt;
&lt;h2&gt;2. From Two Calls to One&lt;/h2&gt;
&lt;p&gt;Here is a question that sounds trivial and is not: you have a cipher and you have a message authentication code (MAC). In which order do you apply them? Most engineers guess. The wrong guess shipped in SSL, IPsec, and SSH, and it took the field a decade of theory to sort out which guess was which.&lt;/p&gt;
&lt;p&gt;There are three orderings. &lt;strong&gt;Encrypt-and-MAC&lt;/strong&gt; authenticates the plaintext and appends the tag beside the ciphertext (SSH). &lt;strong&gt;MAC-then-Encrypt&lt;/strong&gt; authenticates the plaintext, then encrypts plaintext and tag together (SSL and, for years, TLS). &lt;strong&gt;Encrypt-then-MAC&lt;/strong&gt; encrypts, then authenticates the &lt;em&gt;ciphertext&lt;/em&gt; (IPsec).&lt;/p&gt;
&lt;p&gt;In 2000, Mihir Bellare and Chanathip Namprempre proved these are not interchangeable: only Encrypt-then-MAC generically preserves both privacy and integrity for &lt;em&gt;any&lt;/em&gt; secure cipher and &lt;em&gt;any&lt;/em&gt; secure MAC [@bn2000]. A year later, Hugo Krawczyk showed the authenticate-then-encrypt method used in SSL is not generically secure while Encrypt-then-MAC is [@krawczyk2001]. Part 6 is the sequel: MAC-then-encrypt is exactly the door a &lt;a href=&quot;https://paragmali.com/blog/they-read-your-plaintext-without-breaking-your-cipher-a-fiel/&quot; rel=&quot;noopener&quot;&gt;padding oracle&lt;/a&gt; walks through.&lt;/p&gt;

One keyed call that provides confidentiality of the plaintext, integrity of the plaintext, and integrity (but not secrecy) of an extra header called the associated data. The uniform interface was standardized in RFC 5116 [@rfc5116].
&lt;p&gt;The lesson cut deeper than &quot;pick Encrypt-then-MAC.&quot; If two correct primitives can combine into an &lt;em&gt;insecure&lt;/em&gt; whole, hand-composition is a footgun no matter how good the parts are. The fix was to make a &lt;em&gt;single&lt;/em&gt; primitive own both goals, so no protocol designer could botch the join.&lt;/p&gt;
&lt;p&gt;Charanjit Jutla showed the way in 2001 with IAPM and IACBC, modes that delivered message integrity in essentially one pass, almost for free [@jutla2001]. The same year, Phillip Rogaway and coauthors published OCB, a one-pass block-cipher mode built for exactly this [@ocb2001]. Then, in 2002, Rogaway named the primitive: real messages carry a header -- routing bytes, version numbers, sequence counters -- that must be &lt;em&gt;authenticated&lt;/em&gt; but not &lt;em&gt;encrypted&lt;/em&gt;, because intermediaries need to read it. His &quot;Authenticated-Encryption with Associated-Data&quot; formalized that extra input [@rogaway2002-ad].&lt;/p&gt;

The header bytes an AEAD authenticates but does not encrypt: routing information, protocol versions, sequence numbers. Tampering with the associated data makes tag verification fail, but the associated data itself travels in the clear [@rogaway2002-ad].
&lt;p&gt;By 2008, David McGrew closed the loop with RFC 5116, which defined the universal interface every construction in this article implements: &lt;code&gt;AEAD-Encrypt(key, nonce, associated_data, plaintext)&lt;/code&gt; returns &lt;code&gt;ciphertext || tag&lt;/code&gt;, and the matching decrypt either returns the plaintext or a single, uninformative failure [@rfc5116]. One call in, one call out, no way to reverse the order of two primitives because there is only one primitive.&lt;/p&gt;

A value that must be unique for every encryption under a given key. The mode, not the label, sets the exact requirement: some AEADs tolerate only uniqueness, others tolerate randomness, and a few tolerate repetition. Nonce generation is the subject of Part 2 of this series.

timeline
    title The road to the AEAD portfolio
    2000 : Encrypt-then-MAC proven the safe order
    2001 : IAPM and OCB, single-pass native AE
    2002 : Rogaway names AEAD and adds associated data
    2003 : CCM standardized in RFC 3610
    2004 : GCM published by McGrew and Viega
    2006 : Joux forbidden attack, SIV misuse-resistance
    2008 : RFC 5116 fixes the universal interface
    2013 : CAESAR opens, AEGIS announced
    2016 : Nonce reuse found on live TLS servers
    2018 : Invisible salamanders break message franking
    2019 : CAESAR portfolio chosen, OCB2 broken
    2021 : Partitioning oracles weaponize non-commitment
    2025 : NIST standardizes Ascon-AEAD128
&lt;p&gt;The interface was settled by 2008. But an interface is a promise about &lt;em&gt;shape&lt;/em&gt;, not about &lt;em&gt;sharp edges&lt;/em&gt;. Two constructions that satisfy &lt;code&gt;AEAD-Encrypt&lt;/code&gt; to the letter can fail in completely different ways, and the very first AEADs to ship proved it. The one that reached the most devices did not even win on technical merit. It won because of a patent.&lt;/p&gt;
&lt;h2&gt;3. The Welded Modes: CCM and GCM&lt;/h2&gt;
&lt;p&gt;The first AEAD to reach a billion devices was not chosen by a cryptographer. It was chosen, in effect, by a patent lawyer. When IEEE 802.11i (the security amendment that became WPA2) needed an authenticated mode, the elegant candidate was OCB -- but OCB was patent-encumbered, and the working group would not build a wireless standard on it. So 802.11i standardized the plodding, unpatented alternative: &lt;strong&gt;AES-CCM&lt;/strong&gt;. By device count, that decision made CCM one of the most widely deployed AEADs in the world.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AES-CCM = Counter mode + CBC-MAC.&lt;/strong&gt; Doug Whiting, Russ Housley, and Niels Ferguson specified it in RFC 3610 in 2003, and NIST blessed it as SP 800-38C the next year [@rfc3610][@sp80038c]. It runs the message through CBC-MAC for the tag, then encrypts with &lt;a href=&quot;https://paragmali.com/blog/the-ciphertext-was-unbreakable-the-attacker-rewrote-it-anyw/&quot; rel=&quot;noopener&quot;&gt;counter (CTR) mode&lt;/a&gt;: two passes, a strictly serial MAC, and the message length needed up front, which makes streaming awkward. What that price buys is frugality -- nothing but AES, a tiny code footprint, no second primitive to implement.&lt;/p&gt;
&lt;p&gt;That profile is why CCM owns the constrained niche -- Bluetooth Low Energy [@bluetooth-core], Zigbee [@ieee802154], and the TLS &lt;code&gt;CCM_8&lt;/code&gt; ciphersuites. IEEE 802.11i also made CCMP the mandatory data-confidentiality protocol for WPA2 [@ieee80211i], and CCM rode WPA2/CCMP into the overwhelming majority of Wi-Fi hardware over the following decade.Zigbee and 802.15.4 use a variant called CCM*, which additionally permits integrity-only or encryption-only operation, unlike the strict RFC 3610 CCM that always does both. So the same plodding, all-AES mode anchors two very different worlds: the smallest constrained devices and the Wi-Fi layer that WPA2 secures. These are the building blocks from Part 5, welded to a MAC.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AES-GCM = Counter mode + GHASH.&lt;/strong&gt; David McGrew and John Viega published Galois/Counter Mode in 2004, and NIST standardized it as SP 800-38D in 2007 [@mcgrew2004-gcm][@sp80038d]. GCM is everything CCM is not: one pass, fully parallelizable, and, on any CPU with AES-NI and CLMUL, blisteringly fast. It is the internet default, and AES-128-GCM is the single mandatory-to-implement (MUST) AEAD cipher suite in TLS 1.3, per RFC 8446 Section 9.1 -- a status the spec grants to no other AEAD [@rfc8446]. To understand every later failure, you need one fact about how its tag works.&lt;/p&gt;

An authenticator of the form $\text{tag} = H_k(\text{message}) + s$, where $H_k$ is a fast keyed universal hash and $s$ is a **one-time** secret mask. It is unforgeable only if $s$ is never reused. Repeat the mask and the algebraic structure of $H_k$ leaks. This is the shared root of both GHASH (AES-GCM) and Poly1305 (ChaCha20-Poly1305) [@bernstein-poly1305].
&lt;p&gt;GCM&apos;s tag is a one-time Wegman-Carter MAC. GHASH evaluates a polynomial over the finite field $\mathrm{GF}(2^{128})$, with the ciphertext and associated-data blocks as coefficients, at a single secret point $H = \operatorname{AES}_k(0^{128})$. It then masks the result with a per-nonce keystream block:&lt;/p&gt;
&lt;p&gt;$$T = \operatorname{GHASH}_H(A, C) \oplus \operatorname{AES}_k(J_0), \qquad H = \operatorname{AES}_k(0^{128})$$&lt;/p&gt;
&lt;p&gt;where $J_0$ is the initial counter block derived from the nonce. The mask $\operatorname{AES}_k(J_0)$ is the one-time secret $s$. It is one-time &lt;em&gt;only because the nonce is unique&lt;/em&gt;. Repeat the nonce and you repeat $J_0$, so you repeat the mask, and now two tags share it -- which turns GHASH&apos;s linear structure into a system of polynomial equations an attacker can solve.&lt;/p&gt;

The universal hash inside AES-GCM: a polynomial in the secret point $H = \operatorname{AES}_k(0^{128})$ evaluated over $\mathrm{GF}(2^{128})$. Because the polynomial is linear in its coefficients, recovering $H$ lets an attacker forge tags for chosen messages [@joux2006].

flowchart LR
    N[&quot;Nonce and counter&quot;] --&amp;gt; CTR[&quot;AES counter mode&quot;]
    K[&quot;Key&quot;] --&amp;gt; CTR
    CTR --&amp;gt; KS[&quot;Keystream&quot;]
    P[&quot;Plaintext&quot;] --&amp;gt; X((&quot;XOR&quot;))
    KS --&amp;gt; X
    X --&amp;gt; C[&quot;Ciphertext&quot;]
    C --&amp;gt; GH[&quot;GHASH polynomial at secret point H&quot;]
    AD[&quot;Associated data&quot;] --&amp;gt; GH
    K --&amp;gt; H[&quot;H is AES of the zero block&quot;]
    H --&amp;gt; GH
    GH --&amp;gt; M((&quot;XOR one-time mask&quot;))
    K --&amp;gt; J[&quot;AES of the first counter block&quot;]
    J --&amp;gt; M
    M --&amp;gt; T[&quot;Authentication tag&quot;]
&lt;p&gt;That single design choice hands GCM two sharp edges the rest of this article pays for. The first is the &lt;strong&gt;nonce contract&lt;/strong&gt;: reuse is not a weakness, it is a detonator.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; For every nonce-respecting AEAD -- AES-GCM, ChaCha20-Poly1305, AES-CCM, OCB3, AEGIS, and Ascon -- one repeated &lt;code&gt;(key, nonce)&lt;/code&gt; pair is an immediate, total break of confidentiality for those two messages, and, with a second collision, of authenticity for the whole key [@joux2006].One nonce collision leaks $P_1 \oplus P_2$ right away. Uniquely pinning the secret point $H$ for universal forgery generally needs at least two collisions, since a single pair of equations leaves multiple candidate roots. &quot;One repeat is game over for those messages&quot; is correct; &quot;one repeat exposes $H$&quot; is not quite [@bock2016].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The second edge is quieter and just as dangerous, because it is two different numbers people constantly merge into one.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; SP 800-38D fixes a &lt;strong&gt;per-message&lt;/strong&gt; plaintext limit of $2^{39}-256$ bits (about 64 GiB), set by 32-bit counter-mode block-space exhaustion, and, separately, a &lt;strong&gt;per-key&lt;/strong&gt; invocation cap of roughly $2^{32}$ messages when nonces are random 96-bit values, driven by the birthday bound on nonce collision [@sp80038d]. These are two different mechanisms, not two readings of one bound (the full derivation is in Section 8). The multi-user bounds that justify TLS 1.3&apos;s nonce randomization are tight [@htt2018-gcm]. Enforce both limits. Conflating them is the single most common accuracy error on this primitive.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;GCM gave the internet a one-pass, hardware-fast AEAD, and in the same stroke handed it a mode where one repeated nonce is not a bug but a catastrophe. This is the same GCM negotiated inside shipping Windows protocols such as &lt;a href=&quot;https://paragmali.com/blog/rotating-every-cipher-schannel-and-the-twenty-year-algorithm/&quot; rel=&quot;noopener&quot;&gt;Schannel TLS&lt;/a&gt; and SMB 3 encryption [@ms-schannel-tls][@ms-smb-encryption]. Antoine Joux saw the danger in 2006 [@joux2006]. It took the rest of the world ten years, and a scan of the live internet, to believe him.&lt;/p&gt;
&lt;h2&gt;4. A Trunk With Branches&lt;/h2&gt;
&lt;p&gt;The family tree of AEAD is not a ladder from worst to best. Draw it that way and none of the modern constructions make sense, because none of them strictly dominates GCM. Draw it correctly and the whole field snaps into focus: it is a &lt;strong&gt;trunk with branches&lt;/strong&gt;. The trunk is linear -- generic composition, then single-pass native AE, then the welded deployed modes CCM and GCM. Then, at GCM, the tree &lt;em&gt;splits&lt;/em&gt;, because GCM&apos;s edges each forced a &lt;em&gt;separate&lt;/em&gt; successor. No later generation wins. That is the entire point.&lt;/p&gt;

flowchart TD
    G0[&quot;Generic composition, Encrypt-then-MAC&quot;] --&amp;gt; G1[&quot;Single-pass native AE, IAPM and OCB&quot;]
    G1 --&amp;gt; G2[&quot;Welded deployed modes, CCM and GCM&quot;]
    G2 --&amp;gt; E1[&quot;Nonce edge&quot;]
    G2 --&amp;gt; E2[&quot;Hardware edge&quot;]
    G2 --&amp;gt; E3[&quot;Commitment edge&quot;]
    E1 --&amp;gt; S1[&quot;SIV and AES-GCM-SIV, misuse-resistant&quot;]
    E2 --&amp;gt; S2[&quot;ChaCha20-Poly1305, constant-time in software&quot;]
    E2 --&amp;gt; S4[&quot;AEGIS and Ascon, hardware and footprint co-design&quot;]
    E3 --&amp;gt; S3[&quot;Committing transforms, added on top&quot;]
&lt;h3&gt;The hardware edge: ChaCha20-Poly1305&lt;/h3&gt;
&lt;p&gt;GHASH is hard to make constant-time without the CLMUL instruction, and table-based AES is both slow and timing-leaky without AES-NI. Around 2013, that was the reality on most phones and ARM chips: no AES hardware, so GCM was either slow or a cache-timing side channel. Daniel Bernstein&apos;s answer kept GCM&apos;s exact nonce-respecting contract but threw out the parts that needed special silicon.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ChaCha20&lt;/strong&gt; is an ARX cipher -- addition, rotation, XOR -- with no S-box tables to leak timing, so it is constant-time by construction [@bernstein-chacha]. &lt;strong&gt;Poly1305&lt;/strong&gt; is a one-time Wegman-Carter MAC over a prime field rather than $\mathrm{GF}(2^{128})$, and its one-time key is derived from a ChaCha keystream block [@bernstein-poly1305].Poly1305&apos;s one-time key comes from a ChaCha-derived block, not from AES. ChaCha20-Poly1305 never calls AES at all -- a common misconception, since GCM&apos;s mask does use AES.&lt;/p&gt;
&lt;p&gt;The IETF standardized the pair as an AEAD in RFC 8439 [@rfc8439], and it now protects TLS 1.3, WireGuard, OpenSSH, and the &lt;code&gt;age&lt;/code&gt; file-encryption tool [@wireguard-protocol][@openssh-chacha][@age-spec]. Its normative status is widely overstated: in TLS 1.3, ChaCha20-Poly1305 is a &lt;em&gt;recommended&lt;/em&gt; (SHOULD) cipher suite, not mandatory-to-implement, per RFC 8446 Section 9.1 -- a default by adoption, not by requirement [@rfc8446]. It is not weaker than GCM; it is the same nonce contract on a different, table-free engine.XChaCha20-Poly1305 extends the nonce to 192 bits, large enough that random nonces essentially never collide. That is a &lt;em&gt;mitigation&lt;/em&gt; of nonce-collision anxiety, not misuse-resistance -- reuse the full 192-bit nonce and it fails exactly like GCM.&lt;/p&gt;
&lt;h3&gt;The nonce edge: misuse-resistance and SIV&lt;/h3&gt;
&lt;p&gt;Every mode so far detonates on a repeated nonce, and reuse keeps happening in the real world: cloned virtual machines that resume with identical RNG state, counters reset by a crash, embedded devices with weak entropy at first boot. If the operator cannot guarantee uniqueness, the fix is a mode that &lt;em&gt;survives&lt;/em&gt; the operator&apos;s mistake. In 2006, Phillip Rogaway and Thomas Shrimpton formalized exactly that goal and built the first construction for it [@rs2006].&lt;/p&gt;

An AEAD whose failure under a repeated nonce is graceful, not catastrophic. Repeating a `(key, nonce, associated_data, plaintext)` tuple leaks only whether two encryptions were of the *same* message -- message equality -- and nothing else. It never leaks a plaintext XOR and never hands over the authentication subkey [@rs2006][@rfc8452].
&lt;p&gt;The mechanism is a single clean idea: derive the initialization vector &lt;em&gt;synthetically&lt;/em&gt;, as a pseudorandom function of the entire message, rather than accepting it from the caller. The tag &lt;em&gt;is&lt;/em&gt; the IV.&lt;/p&gt;

A construction in which the initialization vector is computed as a MAC over the associated data and the full plaintext, then reused as the authentication tag. Two different messages under a repeated nonce produce different synthetic IVs, so their keystreams differ and nothing leaks [@rs2006].

flowchart TD
    K[&quot;Key&quot;] --&amp;gt; MAC[&quot;MAC over associated data and full plaintext&quot;]
    AD[&quot;Associated data&quot;] --&amp;gt; MAC
    N[&quot;Nonce&quot;] --&amp;gt; MAC
    P[&quot;Plaintext&quot;] --&amp;gt; MAC
    MAC --&amp;gt; IV[&quot;Synthetic IV, which is also the tag&quot;]
    IV --&amp;gt; CTR[&quot;Counter-mode encryption&quot;]
    K --&amp;gt; CTR
    P --&amp;gt; CTR
    CTR --&amp;gt; C[&quot;Ciphertext&quot;]
    IV --&amp;gt; T[&quot;Tag sent alongside ciphertext&quot;]
&lt;p&gt;That picture also explains the price, which returns as a theorem in Section 8: to compute the IV you must read the whole message first, so SIV cannot emit its first ciphertext byte until it has seen the last plaintext byte. It is inherently two-pass.&lt;/p&gt;
&lt;p&gt;Two deployable forms exist. &lt;strong&gt;AES-SIV&lt;/strong&gt;, standardized by Dan Harkins in RFC 5297, targets deterministic authenticated encryption and key wrapping [@rfc5297]. &lt;strong&gt;AES-GCM-SIV&lt;/strong&gt;, from Shay Gueron, Adam Langley, and Yehuda Lindell in RFC 8452, keeps AES-NI and CLMUL speed while adding misuse-resistance, building on the Gueron-Lindell GCM-SIV design [@rfc8452][@gl2015-gcmsiv].AES-GCM-SIV hashes with POLYVAL, a little-endian sibling of GHASH, and derives a fresh message-authentication and encryption key per nonce -- a structure whose tight multi-user bounds were later established by Bose, Hoang, and Tessaro [@bht2018].&lt;/p&gt;

&quot;...two authenticated encryption algorithms that are nonce misuse resistant -- that is, they do not fail catastrophically if a nonce is repeated.&quot; -- RFC 8452 [@rfc8452]
&lt;p&gt;Read that phrasing carefully, because it is the most misquoted sentence about SIV. &quot;Do not fail catastrophically&quot; is not &quot;do not fail.&quot; A repeated nonce in AES-GCM-SIV still leaks message equality: an attacker learns that two ciphertexts encrypt the same plaintext, which is a real and sometimes serious leak. SIV makes reuse &lt;em&gt;survivable&lt;/em&gt;, never &lt;em&gt;free&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;The elegance detour: OCB3 and the patent that chose a standard&lt;/h3&gt;
&lt;p&gt;Two edges now had answers, each on its own branch. A third construction sits off to the side -- not because it is worse, but because history was unkind to it. &lt;strong&gt;OCB3&lt;/strong&gt;, finalized by Ted Krovetz and Phillip Rogaway in 2011 and standardized as RFC 7253, is arguably the most elegant AEAD ever standardized: one block-cipher key, one pass, fully parallel, roughly one cipher call per block [@kr2011-ocb3][@rfc7253].&lt;/p&gt;
&lt;p&gt;Its mechanism is where the elegance lives. Each block is masked by a key-derived offset -- $\text{Offset}&lt;em&gt;i = \text{Offset}&lt;/em&gt;{i-1} \oplus L_{\text{ntz}(i)}$, a Gray-code walk over precomputed $L$ values -- and wrapped as $C_i = \text{Offset}_i \oplus \operatorname{ENCIPHER}(K, P_i \oplus \text{Offset}_i)$, while a &lt;em&gt;single&lt;/em&gt; running plaintext checksum, $\text{Checksum} = P_1 \oplus P_2 \oplus \cdots$, produces the tag in the &lt;em&gt;same pass&lt;/em&gt; [@rfc7253]. No second key, no separate MAC. It matches or beats GCM in software. And it lost anyway -- not for a technical reason.A widely repeated claim is that OCB3 is &lt;em&gt;inverse-free&lt;/em&gt;. It is not. OCB-DECRYPT recovers each block as $P_i = \text{Offset}_i \oplus \operatorname{DECIPHER}(K, C_i \oplus \text{Offset}_i)$, calling the block-cipher inverse $E_K^{-1}$ (RFC 7253 Section 4.3), so a hardware implementation needs both the AES encrypt &lt;em&gt;and&lt;/em&gt; decrypt circuits [@rfc7253]. Inverse-free is the property of the CTR, stream, and sponge modes -- AES-GCM, AES-CCM, ChaCha20-Poly1305, AEGIS, and Ascon -- and OCB is precisely the lineage that trades it away for single-primitive elegance.&lt;/p&gt;

OCB was patented from birth. When the 802.11i working group picked WPA2&apos;s cipher in 2003, it passed over OCB precisely because of those patents and chose the unencumbered CCM instead. Rogaway later granted free licenses for open-source and non-military use, but the damage was done: every major protocol had already standardized on GCM and ChaCha20-Poly1305 in the years the patents were live. In 2021 Rogaway released OCB into the public domain outright -- too late to matter [@kr2021-ocb]. The honest answer to &quot;when should I reach for OCB3 in 2026?&quot; is &quot;almost never, and the reason is a patent grave, not a design flaw.&quot;
&lt;h3&gt;The dead end: OCB2 and the limits of &quot;provably secure&quot;&lt;/h3&gt;
&lt;p&gt;There is one more branch, and it is a warning. Between OCB1 and OCB3 sat OCB2, an ISO-standardized refinement with a security proof. In 2019, Akiko Inoue, Tetsu Iwata, Kazuhiko Minematsu, and Bertram Poettering broke it outright: universal forgery &lt;em&gt;and&lt;/em&gt; full plaintext recovery, because OCB2 used the XEX* tweakable cipher outside the regime its proof actually covered [@inoue2019-ocb2].&lt;/p&gt;

The OCB2 break is the cautionary counterpoint to every &quot;but it has a proof&quot; argument. OCB2 was standardized by ISO/IEC and carried a published security proof, and it was still broken end to end. A proof secures a *model*; if the construction steps outside the model&apos;s assumptions, the proof guarantees nothing. Tellingly, the same attack left OCB1 and OCB3 untouched [@inoue2019-ocb2] -- a dead-end twig on a branch whose siblings survived.
&lt;p&gt;Two of GCM&apos;s three edges now had dedicated successors, and the family tree looked complete. But every construction so far -- GCM, ChaCha20-Poly1305, even the misuse-resistant SIV family -- quietly shared a third assumption nobody had thought to check: that &quot;authenticated&quot; meant &quot;bound to one key.&quot; In 2018, that assumption broke in production, on the desk of a Facebook security engineer holding a single file with two faces.&lt;/p&gt;
&lt;h2&gt;5. The Commitment Reckoning and the CAESAR Crucible&lt;/h2&gt;
&lt;p&gt;Now we can explain the salamanders. Recall the mechanism from Section 3: a GCM tag is a one-time Wegman-Carter value, $\operatorname{GHASH}_H(A,C) \oplus \operatorname{AES}_k(J_0)$, and GHASH is &lt;em&gt;linear&lt;/em&gt; in its coefficients. An attacker who gets to pick two keys, $k_1$ and $k_2$, can treat &quot;make the tag verify under both&quot; as a system of linear equations over $\mathrm{GF}(2^{128})$ and simply solve it, producing one ciphertext that decrypts to two chosen, meaningful plaintexts and passes verification under each key [@dodis2018-salamander].&lt;/p&gt;
&lt;p&gt;Nothing is broken. GCM guarantees confidentiality and integrity; it never promised that a ciphertext binds to a single key. That promise has a name, and until 2018 almost nobody was asking for it.&lt;/p&gt;

A graded robustness property beyond confidentiality and integrity. CMT-1 means a ciphertext binds to exactly one *key*; CMT-4 means it binds to the full *context* -- key, nonce, associated data, and message. Bellare and Hoang proved that CMT-1 does not imply CMT-4: committing to the key is strictly weaker than committing to everything [@bh2022-commit]. RFC 9771 standardized the vocabulary [@rfc9771].
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; &quot;Authenticated&quot; never meant &quot;committed.&quot; An AEAD&apos;s guarantees -- IND-CPA plus INT-CTXT -- say nothing about binding a ciphertext to one key. Commitment is a third, orthogonal axis. That is why every default AEAD was non-committing and nobody noticed for fifteen years: the property was simply outside the definition everyone was proving.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Two ideas define the modern state of the art, and both come from &lt;em&gt;refusing&lt;/em&gt; to treat &quot;cipher plus separate hash&quot; as the end of the design space.&lt;/p&gt;
&lt;p&gt;The first is &lt;strong&gt;robustness as an explicit goal&lt;/strong&gt; -- against the operator and against the adversary who supplies the key. The operator side is MRAE from Section 4, elevated from a mode into a principle. The adversary side is committing AEAD, and its timeline is a tidy example of a theoretical curiosity becoming an operational threat.&lt;/p&gt;
&lt;p&gt;Invisible salamanders (2018) showed a non-committing AEAD could defeat message franking [@dodis2018-salamander]. Then, in 2021, Julia Len, Paul Grubbs, and Thomas Ristenpart turned it into a weapon: &lt;strong&gt;partitioning oracle attacks&lt;/strong&gt; use the missing commitment to recover passwords and other low-entropy keys, crafting one ciphertext that decrypts under many candidate keys and using each success or failure to bisect the key space [@len2021-partition].&lt;/p&gt;
&lt;p&gt;Mihir Bellare and Viet Tung Hoang then built the graded CMT-1 through CMT-4 theory and cheap transforms that add full commitment with no ciphertext-size increase [@bh2022-commit]; Ange Albertini and coauthors independently catalogued the abuses and a padding-based fix [@albertini2022], with further theory from John Chan and Phillip Rogaway [@chan2022]. Sanketh Menda and coauthors then showed the gap is portfolio-wide, with context-discovery attacks against CCM, EAX, SIV, GCM, and OCB3 [@menda2023]. RFC 9771 (2025) finally fixed the vocabulary the field had been improvising [@rfc9771].&lt;/p&gt;

A vetted AEAD gives you confidentiality and integrity and stops there. Commitment is a third axis nobody put in the definition -- which is exactly why one ciphertext could wear two faces.
&lt;p&gt;The second idea is &lt;strong&gt;native co-design&lt;/strong&gt;: stop bolting a cipher to a hash and instead build the AEAD &lt;em&gt;around&lt;/em&gt; the hardware or footprint you actually have. Hongjun Wu and Bart Preneel&apos;s AEGIS (2013) is the AES-hardware extreme [@wu2013-aegis].&lt;/p&gt;
&lt;p&gt;It keeps a large internal state -- eight 128-bit words in AEGIS-128L -- seeded directly from the key and nonce; the &lt;strong&gt;AES round function&lt;/strong&gt; updates that state as it absorbs associated data and plaintext, encryption &lt;em&gt;squeezes&lt;/em&gt; a keystream out of the state, and the tag comes from the &lt;em&gt;finalized&lt;/em&gt; state. One primitive, one pass, no separate hash, and the IETF draft records that all variants are inverse-free and built from the AES encryption round [@aegis-draft18].&lt;/p&gt;
&lt;p&gt;That structure is &lt;em&gt;why&lt;/em&gt; AEGIS outruns GCM on AES silicon, and &lt;em&gt;why&lt;/em&gt; nonce reuse is catastrophic: the whole state is a function of &lt;code&gt;(key, nonce)&lt;/code&gt;, so a repeat lets an attacker unwind it. Its commitment story is a nuance, not a headline -- a 128-bit AEGIS tag delivers only about 64-bit committing security, while a 256-bit tag pushes cross-key collisions out of reach, so AEGIS is &lt;em&gt;partially&lt;/em&gt; committing by tag length, neither fully committing nor flatly broken [@aegis-draft18].&lt;/p&gt;
&lt;p&gt;At the other extreme, Ascon -- by Christoph Dobraunig, Maria Eichlseder, Florian Mendel, and Martin Schläffer -- uses a single lightweight permutation in a sponge, giving a tiny gate count and a side-channel-friendly structure for constrained hardware [@ascon2021].&lt;/p&gt;

flowchart LR
    KN[&quot;Key and nonce&quot;] --&amp;gt; ST[&quot;Large internal state, eight 128-bit words&quot;]
    ST --&amp;gt; UP[&quot;AES round function update&quot;]
    AD[&quot;Associated data&quot;] --&amp;gt; UP
    P[&quot;Plaintext&quot;] --&amp;gt; UP
    UP --&amp;gt; KS[&quot;Squeezed keystream&quot;]
    P --&amp;gt; X((&quot;XOR&quot;))
    KS --&amp;gt; X
    X --&amp;gt; C[&quot;Ciphertext&quot;]
    UP --&amp;gt; FIN[&quot;Finalized state&quot;]
    FIN --&amp;gt; T[&quot;Authentication tag&quot;]

A mode built from one public permutation whose state is split into a &quot;rate&quot; (absorbs input and is squeezed for output) and a &quot;capacity&quot; (the hidden security margin). A single permutation absorbs the key, nonce, associated data, and plaintext, then squeezes keystream and a tag -- no separate cipher and hash. Ascon is a sponge [@ascon2021].
&lt;p&gt;What forced this whole portfolio into existence was a contest. The &lt;strong&gt;CAESAR competition&lt;/strong&gt; (2013-2019), organized by Daniel Bernstein, was a public, multi-year, break-it-in-the-open bake-off [@caesar-home]. Its most important decision was structural: rather than crown a single winner, it selected a &lt;em&gt;portfolio across three use cases&lt;/em&gt; -- itself the thesis of this article. The winners were Ascon and ACORN for lightweight use, AEGIS-128 and OCB for high-performance use, and Deoxys-II (first choice) and COLM for defense in depth [@caesar-portfolio].Deoxys-II is built on the TWEAKEY framework for tweakable block ciphers, by Jérémy Jean, Ivica Nikolić, Thomas Peyrin, and Yannick Seurin [@caesar-portfolio].&lt;/p&gt;
&lt;p&gt;Note carefully: &lt;strong&gt;Deoxys-II is a CAESAR winner, not an also-ran&lt;/strong&gt; -- it simply was never deployed at scale. The real also-rans are the candidates eliminated during the competition, including MORUS, which took a certificational break from Tomer Ashur, Maria Eichlseder, and coauthors and did not make the final portfolio [@morus2018].&lt;/p&gt;
&lt;p&gt;The competition ended in 2019 with no single champion, on purpose. So where does that leave a working engineer in 2026, staring at seven names in a crypto library&apos;s documentation? To choose well, you need the current map: exactly what each construction is, where it wins, and where it bites.&lt;/p&gt;
&lt;h2&gt;6. The 2026 Portfolio, Precisely&lt;/h2&gt;
&lt;p&gt;The current portfolio has a stable shape: two defaults and five specialists. By deployment, the two internet defaults are AES-GCM and ChaCha20-Poly1305 -- but normatively they are not equals. In TLS 1.3 only AES-128-GCM is mandatory-to-implement (MUST); AES-256-GCM and ChaCha20-Poly1305 are both &lt;em&gt;recommended&lt;/em&gt; (SHOULD), the same normative level as each other, per RFC 8446 Section 9.1 [@rfc8446]. Everything else is a deliberate escalation. Here is each construction on its edges.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AES-GCM.&lt;/strong&gt; Counter mode plus a one-time GHASH tag; one pass, parallel, &lt;code&gt;O(1)&lt;/code&gt; online state [@mcgrew2004-gcm]. Excels on any CPU with AES-NI and CLMUL, which is every server and most modern clients. Struggles on hardware without those instructions and, above all, on nonce discipline: reuse is fatal and the two ceilings are easy to breach [@sp80038d]. Adoption: the internet default.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ChaCha20-Poly1305.&lt;/strong&gt; ARX stream cipher plus a prime-field one-time MAC; constant-time in pure software with no lookup tables [@rfc8439]. Excels precisely where GCM struggles -- phones, embedded ARM, any target without AES hardware. Same nonce contract as GCM, so it struggles on the exact same reuse cliff. Adoption: TLS 1.3, WireGuard, OpenSSH [@wireguard-protocol][@openssh-chacha].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AES-CCM.&lt;/strong&gt; Counter mode plus CBC-MAC; two passes, serial, needs the length up front, but all-AES and tiny [@rfc3610]. Excels in constrained stacks (BLE [@bluetooth-core], Zigbee [@ieee802154]) and inside WPA2 [@ieee80211i]. Struggles on throughput and streaming, and the truncated &lt;code&gt;CCM_8&lt;/code&gt; tag trades a real forgery budget for eight bytes [@rfc3610]. Adoption: enormous by device count.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AES-GCM-SIV and AES-SIV.&lt;/strong&gt; Synthetic-IV misuse-resistant modes; two-pass by necessity [@rfc8452][@rfc5297]. Excel when nonce uniqueness cannot be guaranteed: reuse degrades to leaking message equality rather than catastrophe. Struggle on streaming (they must buffer) and still leak equality, so they are survivable, not free. AES-GCM-SIV runs near AES-GCM speed on server hardware, around 0.92 cycles per byte on Broadwell in the original design [@gl2015-gcmsiv]. Adoption: growing where reuse risk is real.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OCB3.&lt;/strong&gt; One block-cipher key, one pass, fully parallel, roughly one cipher call per block -- technically superb [@kr2011-ocb3][@rfc7253]. Excels on elegance and software speed. Struggles on adoption, for the patent reasons in Section 4; it is nonce-respecting like GCM; and, unlike the CTR and stream modes, it is &lt;strong&gt;not&lt;/strong&gt; inverse-free -- decryption calls the AES inverse circuit (RFC 7253 Section 4.3), a genuine hardware cost [@rfc7253]. Adoption: minimal, despite standardization.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AEGIS.&lt;/strong&gt; Keystream and authentication driven straight from the AES round function over a large nonce-seeded state; the throughput frontier, around 0.48 cycles per byte for AEGIS-128L on 4 KB messages, faster than CCM, GCM, and OCB [@wu2013-aegis][@aegis-v11]. Excels on raw speed when you control both endpoints. Struggles on maturity and contract: nonce-respecting (catastrophic on reuse, since its whole state is nonce-seeded) and only &lt;em&gt;partially&lt;/em&gt; committing -- about 64-bit committing security at a 128-bit tag, stronger at a 256-bit tag [@aegis-draft18].&lt;/p&gt;
&lt;p&gt;Critically, &lt;strong&gt;AEGIS is still an active Internet-Draft, &lt;code&gt;draft-irtf-cfrg-aegis-aead-18&lt;/code&gt; from October 2025, not an RFC&lt;/strong&gt; -- it states plainly that it &quot;is not an IETF product and is not a standard,&quot; and it expires on 8 April 2026 [@aegis-draft18].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ascon-AEAD128.&lt;/strong&gt; A single 320-bit lightweight permutation in a sponge; tiny state, side-channel-friendly [@ascon2021]. Excels on constrained hardware and gate count. Struggles on server throughput, where AEGIS and GCM win. It is nonce-respecting, but -- unlike the CTR and stream modes -- it commits to its inputs &lt;em&gt;without&lt;/em&gt; any added transform: the tag is squeezed from the sponge&apos;s large hidden capacity after that capacity has already absorbed the key, so one ciphertext binds natively to the key it was produced under. RFC 9771 lists Ascon-AEAD128 as both key-committing and full-committing as-is, not merely as a candidate for a bolt-on fix [@rfc9771]. The currency fact matters here: &lt;strong&gt;NIST SP 800-232 is final (August 2025) and standardizes Ascon-AEAD128&lt;/strong&gt;, a &lt;em&gt;tweaked&lt;/em&gt; variant of CAESAR Ascon-128 using a larger data-absorption rate -- widely reported as 128-bit, up from the CAESAR design&apos;s 64-bit, with the exact parameter in the SP 800-232 body [@sp800232][@nist-ascon-2023]. It is not byte-identical to CAESAR Ascon [@ascon-site].&lt;/p&gt;
&lt;p&gt;A profile only helps if you can actually call the construction, so here is where each one ships as of mid-2026, with each cell cited to that project&apos;s official documentation.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Construction&lt;/th&gt;
&lt;th&gt;Where it ships (libraries and frameworks)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;AES-GCM&lt;/td&gt;
&lt;td&gt;OpenSSL/BoringSSL [@openssl-aes][@boringssl-aead], Go &lt;code&gt;crypto/cipher&lt;/code&gt; [@go-cipher], Java JCA [@java-jca], .NET CNG [@dotnet-aesgcm], WebCrypto (the only AEAD in the browser) [@webcrypto], libsodium (hardware-gated) [@libsodium-aegis]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ChaCha20-Poly1305 / XChaCha20&lt;/td&gt;
&lt;td&gt;OpenSSL/BoringSSL [@openssl-chacha][@boringssl-aead], libsodium (default for random-nonce APIs) [@libsodium-aegis], Go &lt;code&gt;x/crypto&lt;/code&gt; [@go-chacha], WireGuard [@wireguard-protocol], OpenSSH [@openssh-chacha], &lt;code&gt;age&lt;/code&gt; [@age-spec]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-CCM&lt;/td&gt;
&lt;td&gt;mbedTLS [@mbedtls-ccm], wolfSSL [@wolfssl-ccm], Wi-Fi [@ieee80211i] / BLE [@bluetooth-core] / Zigbee [@ieee802154] firmware&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-GCM-SIV&lt;/td&gt;
&lt;td&gt;BoringSSL/OpenSSL [@boringssl-aead][@openssl-aes] and several bindings; less universal than the defaults&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-SIV&lt;/td&gt;
&lt;td&gt;&lt;code&gt;miscreant&lt;/code&gt;-lineage (deterministic / key-wrap) libraries [@miscreant]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OCB3&lt;/td&gt;
&lt;td&gt;some libraries (public domain since 2021 [@kr2021-ocb]); rarely a default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AEGIS&lt;/td&gt;
&lt;td&gt;libsodium (&lt;code&gt;crypto_aead_aegis128l&lt;/code&gt; / &lt;code&gt;aegis256&lt;/code&gt;) [@libsodium-aegis] and a growing set of high-performance libraries; not a TLS suite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ascon-AEAD128&lt;/td&gt;
&lt;td&gt;reference and third-party implementations [@ascon-site]; adoption ramping since SP 800-232 [@sp800232]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Two entries on that map decide real architectures. &lt;strong&gt;In the browser, AES-GCM is the only AEAD you can call.&lt;/strong&gt;WebCrypto&apos;s &lt;code&gt;SubtleCrypto.encrypt&lt;/code&gt; recognizes RSA-OAEP, AES-CTR, AES-CBC, and AES-GCM, and AES-GCM is the only one of those that authenticates. Browser JavaScript that needs an AEAD without bundling a crypto library therefore has exactly one option [@webcrypto]. And AEGIS, still pre-RFC, is nonetheless callable in production today through libsodium&apos;s &lt;code&gt;crypto_aead_aegis128l&lt;/code&gt; and &lt;code&gt;crypto_aead_aegis256&lt;/code&gt; APIs -- deployability and standardization are not the same axis [@libsodium-aegis].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Eight constructions -- the seven cipher families, with the SIV line counted in its two deployable forms (AES-GCM-SIV and AES-SIV) -- all linear-time, all vetted, and not one strictly dominates the others. CAESAR chose a portfolio across three use cases on purpose, and NIST added Ascon for the constrained end. There is no &quot;best AEAD,&quot; and any article or vendor that names one is hiding an assumption about your deployment [@caesar-portfolio].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Two more items complete the 2026 map. The CAESAR defense-in-depth winners, Deoxys-II and COLM, remain excellent and essentially undeployed [@caesar-portfolio]. And committing transforms -- the fix for the commitment edge -- exist and are cheap, but as of mid-2026 none is &lt;em&gt;mandated&lt;/em&gt; in a shipping standard; RFC 9771 supplies vocabulary, not a required construction [@rfc9771][@bh2022-commit].&lt;/p&gt;
&lt;p&gt;Laid side by side, those eight look interchangeable. They are not, and the tool that makes the difference legible is a single table built on the three edges.&lt;/p&gt;
&lt;h2&gt;7. The Decision Matrix&lt;/h2&gt;
&lt;p&gt;This is the one screen to memorize. Everything in the previous six sections collapses into two tables and a flowchart, all built on the same three edges.&lt;/p&gt;
&lt;p&gt;The first table answers the only question that matters at selection time: for each construction, what happens on the &lt;em&gt;first repeated nonce&lt;/em&gt;, what hardware does it want, and does one ciphertext bind to one key?&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Construction&lt;/th&gt;
&lt;th&gt;First repeated nonce&lt;/th&gt;
&lt;th&gt;Hardware profile&lt;/th&gt;
&lt;th&gt;Commitment&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;AES-GCM&lt;/td&gt;
&lt;td&gt;Catastrophic: leaks P1 XOR P2, enables forgery&lt;/td&gt;
&lt;td&gt;AES-NI + CLMUL fast&lt;/td&gt;
&lt;td&gt;Not committing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ChaCha20-Poly1305&lt;/td&gt;
&lt;td&gt;Catastrophic: same one-time-MAC cliff&lt;/td&gt;
&lt;td&gt;Constant-time in software&lt;/td&gt;
&lt;td&gt;Not committing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-CCM&lt;/td&gt;
&lt;td&gt;Catastrophic&lt;/td&gt;
&lt;td&gt;All-AES, tiny footprint&lt;/td&gt;
&lt;td&gt;Not committing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-GCM-SIV&lt;/td&gt;
&lt;td&gt;Graceful: leaks message equality only&lt;/td&gt;
&lt;td&gt;AES-NI + CLMUL&lt;/td&gt;
&lt;td&gt;Not committing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-SIV&lt;/td&gt;
&lt;td&gt;Graceful: leaks message equality only&lt;/td&gt;
&lt;td&gt;All-AES, two-pass&lt;/td&gt;
&lt;td&gt;Not committing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OCB3&lt;/td&gt;
&lt;td&gt;Catastrophic&lt;/td&gt;
&lt;td&gt;Fast one-pass software&lt;/td&gt;
&lt;td&gt;Not committing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AEGIS&lt;/td&gt;
&lt;td&gt;Catastrophic&lt;/td&gt;
&lt;td&gt;AES round function, fastest&lt;/td&gt;
&lt;td&gt;Not fully committing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ascon-AEAD128&lt;/td&gt;
&lt;td&gt;Catastrophic&lt;/td&gt;
&lt;td&gt;A few thousand gates&lt;/td&gt;
&lt;td&gt;Committing from the sponge, no transform&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Read down the commitment column and the reckoning of Section 5 gets sharper than a flat &quot;nobody commits.&quot; Every deployed CTR, stream, and welded construction -- AES-GCM, ChaCha20-Poly1305, AES-CCM, the SIV family, and OCB3 -- is non-committing by default, which is exactly what the salamander and the portfolio-wide context-discovery attacks exploit [@dodis2018-salamander][@menda2023]. Two constructions break the pattern, and it is no accident that both fuse the tag with the cipher state instead of bolting on a separate hash: AEGIS partially commits through tag length, and Ascon commits natively from its sponge [@aegis-draft18][@rfc9771]. So commitment is not a uniform failure across the portfolio -- the commitment edge is a real axis of variation, with Ascon at the strong end, AEGIS in between, and the CTR, stream, and welded modes needing a bolt-on transform. Read the nonce column and only the SIV family survives a repeat, and only by leaking equality [@rfc8452]. The second table adds the structural and performance facts you need once the edges are settled.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Construction&lt;/th&gt;
&lt;th&gt;Passes / parallel&lt;/th&gt;
&lt;th&gt;Online state&lt;/th&gt;
&lt;th&gt;Nonce&lt;/th&gt;
&lt;th&gt;Tag&lt;/th&gt;
&lt;th&gt;Reported speed&lt;/th&gt;
&lt;th&gt;Inverse-free?&lt;/th&gt;
&lt;th&gt;Best suited for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;AES-GCM&lt;/td&gt;
&lt;td&gt;1 pass, parallel&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(1)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;96-bit&lt;/td&gt;
&lt;td&gt;128-bit&lt;/td&gt;
&lt;td&gt;~1 cpb with AES-NI&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;The default, server and client&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ChaCha20-Poly1305&lt;/td&gt;
&lt;td&gt;1 pass&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(1)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;96-bit&lt;/td&gt;
&lt;td&gt;128-bit&lt;/td&gt;
&lt;td&gt;Fast in pure software&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Targets without AES hardware&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-CCM&lt;/td&gt;
&lt;td&gt;2 pass, serial&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(1)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;7 to 13 byte&lt;/td&gt;
&lt;td&gt;128-bit (&lt;code&gt;CCM_8&lt;/code&gt;: 64)&lt;/td&gt;
&lt;td&gt;Modest&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Constrained stacks, WPA2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-GCM-SIV&lt;/td&gt;
&lt;td&gt;2 pass&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(n)&lt;/code&gt; buffered&lt;/td&gt;
&lt;td&gt;96-bit&lt;/td&gt;
&lt;td&gt;128-bit&lt;/td&gt;
&lt;td&gt;~0.92 cpb on Broadwell&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Nonce-reuse risk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-SIV&lt;/td&gt;
&lt;td&gt;2 pass&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(n)&lt;/code&gt; buffered&lt;/td&gt;
&lt;td&gt;None or supplied&lt;/td&gt;
&lt;td&gt;128-bit&lt;/td&gt;
&lt;td&gt;Modest&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Key wrap, deterministic AE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OCB3&lt;/td&gt;
&lt;td&gt;1 pass, parallel&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(1)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;up to 120-bit&lt;/td&gt;
&lt;td&gt;up to 128-bit&lt;/td&gt;
&lt;td&gt;Fast in software&lt;/td&gt;
&lt;td&gt;No (needs AES decrypt)&lt;/td&gt;
&lt;td&gt;Elegance (now patent-clear)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AEGIS&lt;/td&gt;
&lt;td&gt;1 pass, parallel&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(1)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;128 or 256-bit&lt;/td&gt;
&lt;td&gt;128 or 256-bit&lt;/td&gt;
&lt;td&gt;~0.48 cpb (AEGIS-128L)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Maximum throughput, both endpoints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ascon-AEAD128&lt;/td&gt;
&lt;td&gt;1 pass&lt;/td&gt;
&lt;td&gt;&lt;code&gt;O(1)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;128-bit&lt;/td&gt;
&lt;td&gt;128-bit&lt;/td&gt;
&lt;td&gt;Small, not server-fast&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;New constrained designs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Reported speeds are platform-dependent and should be read against live cross-platform benchmarks rather than a single headline number; the AEGIS and GCM-SIV figures come from their design papers, and the ECRYPT benchmarking project tracks the rest across many CPUs [@wu2013-aegis][@gl2015-gcmsiv][@bench-aead]. One column earns a second look: OCB3 is the only full-treatment construction that is &lt;em&gt;not&lt;/em&gt; inverse-free, so it alone needs the AES decrypt circuit in hardware -- the honest cost behind its elegance [@rfc7253].&lt;/p&gt;
&lt;p&gt;The tables classify. To &lt;em&gt;choose&lt;/em&gt;, turn them into a procedure. The flowchart below is the thesis rendered as a decision tree: branch on the nonce guarantee first (it is the edge that fails hardest), then on hardware, and treat commitment as an orthogonal final step because no default provides it.&lt;/p&gt;

flowchart TD
    Q1{&quot;Can you guarantee a unique nonce per key?&quot;}
    Q1 --&amp;gt;|No| SIV[&quot;AES-GCM-SIV: move on the nonce edge&quot;]
    Q1 --&amp;gt;|Yes| Q2{&quot;AES-NI and CLMUL on both endpoints?&quot;}
    Q2 --&amp;gt;|Yes| GCM[&quot;AES-GCM&quot;]
    Q2 --&amp;gt;|No| Q2b{&quot;Server or mobile software, or a constrained device?&quot;}
    Q2b --&amp;gt;|Software| CC[&quot;ChaCha20-Poly1305&quot;]
    Q2b --&amp;gt;|Constrained| ASC[&quot;Ascon-AEAD128&quot;]
    SIV --&amp;gt; Q3{&quot;Must one ciphertext bind to exactly one key?&quot;}
    GCM --&amp;gt; Q3
    CC --&amp;gt; Q3
    ASC --&amp;gt; Q3
    Q3 --&amp;gt;|Yes| ADD[&quot;Add a key-commitment transform, unless it already commits like Ascon&quot;]
    Q3 --&amp;gt;|No| DONE[&quot;Ship it&quot;]
&lt;p&gt;The argument is now explicit and testable. &quot;Which AEAD?&quot; reduces to &quot;which edge can your deployment &lt;em&gt;guarantee&lt;/em&gt; it never triggers?&quot; If you cannot guarantee nonce uniqueness, move right on the nonce edge to the SIV family. If you have no AES hardware, move on the hardware edge to ChaCha20-Poly1305 or, for a constrained device, Ascon. If a ciphertext must bind to exactly one key, you must &lt;em&gt;add&lt;/em&gt; something on the commitment edge, because none of the defaults gives it to you. You can even write the function down.&lt;/p&gt;
&lt;p&gt;{`
// &quot;Which AEAD?&quot; is a function of three edges, not a ranking.
function chooseAEAD({ nonceUnique, hasAesHardware, constrained, mustCommitToKey }) {
  let pick;
  if (!nonceUnique) {
    pick = &apos;AES-GCM-SIV&apos;;        // edge 1: cannot guarantee unique nonces
  } else if (hasAesHardware) {
    pick = &apos;AES-GCM&apos;;            // the internet default when AES-NI + CLMUL are present
  } else if (constrained) {
    pick = &apos;Ascon-AEAD128&apos;;      // edge 2: no AES hardware, only a few thousand gates
  } else {
    pick = &apos;ChaCha20-Poly1305&apos;;  // edge 2: no AES hardware, constant-time in software
  }
  // edge 3 is orthogonal: most picks do not commit, so you must ADD a transform --
  // except Ascon, which already commits natively from its sponge (RFC 9771).
  const alreadyCommits = pick === &apos;Ascon-AEAD128&apos;;
  return (mustCommitToKey &amp;amp;&amp;amp; !alreadyCommits)
    ? pick + &apos; + key-commitment transform (this construction does not bind to one key)&apos;
    : pick;
}&lt;/p&gt;
&lt;p&gt;console.log(chooseAEAD({ nonceUnique: true,  hasAesHardware: true,  constrained: false, mustCommitToKey: false }));
console.log(chooseAEAD({ nonceUnique: false, hasAesHardware: true,  constrained: false, mustCommitToKey: false }));
console.log(chooseAEAD({ nonceUnique: true,  hasAesHardware: false, constrained: false, mustCommitToKey: false }));
console.log(chooseAEAD({ nonceUnique: true,  hasAesHardware: true,  constrained: false, mustCommitToKey: true  }));
`}&lt;/p&gt;

&quot;Which AEAD should I use?&quot; is not a ranking from worst to best. It is a function: pick the one whose failure mode your deployment can guarantee it will never trigger.
&lt;p&gt;The table tells you which edge to move. It does not tell you why you sometimes &lt;em&gt;cannot&lt;/em&gt; move all of them at once -- why there is no row that is graceful on reuse &lt;em&gt;and&lt;/em&gt; single-pass &lt;em&gt;and&lt;/em&gt; fully committing &lt;em&gt;and&lt;/em&gt; fastest. That absence is not a gap in the engineering. It is a theorem.&lt;/p&gt;
&lt;h2&gt;8. The Limits Are Theorems&lt;/h2&gt;
&lt;p&gt;Everything so far has been a design choice: move an edge here, pay for it there. Now the hard walls -- the places where no cleverness helps, because a proof says so. There are four, and each maps to an edge; the standard graduate references develop these bounds in full [@boneh-shoup][@katz-lindell].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;GCM&apos;s two ceilings, correctly attributed (the nonce edge).&lt;/strong&gt; GCM&apos;s two limits from SP 800-38D are not conservative engineering guesses; they are where the security proof runs out -- and they come from two &lt;em&gt;different&lt;/em&gt; mechanisms people constantly merge into one.&lt;/p&gt;
&lt;p&gt;The per-message limit of $2^{39}-256$ bits (about 64 GiB) is &lt;strong&gt;32-bit counter-mode block-space exhaustion&lt;/strong&gt;, not a GHASH property: with a 96-bit nonce GCM forms the initial counter block $J_0 = \mathrm{IV} \parallel 0^{31} \parallel 1$, the increment function advances only the low 32 bits, so counter mode emits at most $2^{32}-2$ keystream blocks, and $(2^{32}-2)\times 128$ bits $= 2^{39}-256$ bits; exceed it and the counter wraps, repeating a keystream block -- a two-time pad (SP 800-38D Section 5.2.1.1) [@sp80038d].&lt;/p&gt;
&lt;p&gt;The per-key cap of roughly $2^{32}$ messages under random 96-bit nonces is a different quantity entirely: the birthday bound on nonce collision, where with $q$ messages the probability of a repeat scales as $q^2 / 2^{96}$, so $q \approx 2^{32}$ keeps it negligible (SP 800-38D Section 8.3) [@sp80038d]. Hoang, Tessaro, and Thiruvengadam proved these multi-user bounds tight, validating the nonce-randomization mechanism TLS 1.3 uses [@htt2018-gcm].&lt;/p&gt;
&lt;p&gt;Tag length obeys its own bound: for a one-time Wegman-Carter MAC, forgery probability grows with the number of attempts and shrinks with tag length -- exactly why a 64-bit &lt;code&gt;CCM_8&lt;/code&gt; tag is a genuine, quantifiable forgery budget rather than a free optimization [@rfc3610].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Misuse-resistance cannot be online (the nonce edge, again).&lt;/strong&gt; This is the deepest limit in the article, and it explains a design decision that otherwise looks like laziness. Rogaway and Shrimpton proved that a deterministic, nonce-misuse-resistant AEAD &lt;em&gt;cannot&lt;/em&gt; be online or single-pass [@rs2006]. The reason is forced by the definition: to be misuse-resistant, the ciphertext must depend on the &lt;em&gt;entire&lt;/em&gt; plaintext (otherwise two messages sharing a prefix under a repeated nonce would leak that prefix), so the encryptor cannot emit even the first ciphertext byte until it has read the last plaintext byte. There is no implementation trick around it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; You cannot have both streaming and misuse-resistance. It is a theorem, not a missing feature: a misuse-resistant AEAD must read the whole message before it can output any ciphertext. That single impossibility is &lt;em&gt;why&lt;/em&gt; AES-GCM-SIV is two-pass, and why &quot;just make GCM misuse-resistant without slowing it down&quot; is a request for something that provably does not exist [@rs2006].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Commitment is an orthogonal axis (the commitment edge).&lt;/strong&gt; A conventional CTR-based AEAD like GCM is provably not key-committing -- the property is simply absent from &lt;a href=&quot;https://paragmali.com/blog/secure-against-whom-the-security-definitions-every-protocol-/&quot; rel=&quot;noopener&quot;&gt;IND-CPA and INT-CTXT&lt;/a&gt;, so no amount of using GCM &quot;correctly&quot; produces it. Worse, commitment is not one property but a lattice: Bellare and Hoang proved CMT-1 (bind to the key) does not imply CMT-4 (bind to the full context), a separation RFC 9771 later codified [@bh2022-commit][@rfc9771].&lt;/p&gt;
&lt;p&gt;And the attacks are cheaper than the naive birthday intuition suggests: Menda and coauthors found context-discovery attacks against CCM, EAX, SIV, GCM, and OCB3, including an $O(2^{n/3})$ attack on SIV using Wagner&apos;s k-tree algorithm -- well below the $2^{n/2}$ a birthday bound would suggest [@menda2023].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Releasing plaintext early is a strictly weaker world (all edges).&lt;/strong&gt; The fourth limit is about what your decrypt function is allowed to do before it finishes.&lt;/p&gt;

What an implementation exposes if it emits decrypted plaintext before checking the authentication tag. The formal integrity notion for this setting, INT-RUP, is codified in RFC 9771 Section 4.3.10; security that survives releasing unverified plaintext is strictly stronger than standard AEAD security, and most fast one-pass modes satisfy it only weakly -- which is why the safe API contract is verify-then-release: never act on plaintext until the tag checks out [@rfc9771].
&lt;p&gt;Now assemble the thought experiment. Imagine the ideal AEAD: graceful on nonce reuse &lt;em&gt;and&lt;/em&gt; fully committing &lt;em&gt;and&lt;/em&gt; online/single-pass &lt;em&gt;and&lt;/em&gt; fastest at both the server and constrained extremes. The second limit rules out &quot;misuse-resistant and online&quot; together. The third makes commitment an add-on that the CTR, stream, and welded defaults lack -- Ascon, uniquely, commits natively. The performance extremes pull in opposite directions -- AES round function for servers, a few thousand gates for sensors. You cannot have all of it in one construction, and this is not because nobody has been clever enough. It is because the properties provably conflict.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; No single construction closes all three edges at once. That is not a temporary state of the art -- it is a set of theorems about online-ness, commitment, and hardware. The portfolio is not a failure to converge on a winner; it is the mathematically necessary shape of the solution [@rs2006][@bh2022-commit].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So that is settled, provably. Which turns the interesting question inside out. Not &quot;which mode wins?&quot; but &quot;can we make the &lt;em&gt;robustness&lt;/em&gt; the default instead of the expert&apos;s opt-in?&quot; That is exactly where the field is fighting right now.&lt;/p&gt;
&lt;h2&gt;9. Where AEAD Still Bites&lt;/h2&gt;
&lt;p&gt;The classical problem is closed. For confidentiality and integrity, the bounds are tight and the constructions are vetted. The entire live frontier is about robustness: turning the properties nobody used to ask for into defaults nobody has to remember. Six problems are open, and every one of them has the same shape.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Committing AEAD by default.&lt;/strong&gt; Salamanders and partitioning oracles still bite wherever a committing transform is omitted, which today means almost everywhere [@dodis2018-salamander][@len2021-partition]. The frustrating part is that the fix is cheap: Bellare and Hoang give transforms that add full commitment with no ciphertext-size increase, and Albertini and coauthors give a padding-based alternative [@bh2022-commit][@albertini2022]. Yet as of mid-2026, none is &lt;em&gt;mandated&lt;/em&gt; by a shipping standard. RFC 9771 gives the field a shared vocabulary for the property but does not require any construction to have it [@rfc9771]. The open question is not &quot;how?&quot; but &quot;why is it still opt-in?&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Misuse-resistance by default.&lt;/strong&gt; If nonce reuse is a recurring operational reality, why is the misuse-resistant mode the escalation rather than the default? The answer is the theorem from Section 8: defaulting to SIV means defaulting to two-pass, non-streaming encryption, and a great deal of infrastructure assumes it can encrypt a stream as it arrives [@rs2006]. Whether that trade is worth making by default is an active argument, not a settled one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The release-of-unverified-plaintext trade space.&lt;/strong&gt; Between &quot;buffer everything and verify first&quot; and &quot;stream plaintext out immediately&quot; is a design space that streaming media, large-file transfer, and constrained receivers all care about, and the security definitions there -- INT-RUP and its relatives -- are still maturing [@rfc9771].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hardware co-design versus conservative margin.&lt;/strong&gt; AEGIS already beats AES-GCM on AES-NI hardware, and the appetite for line-rate encryption keeps growing [@wu2013-aegis]. Newer AES-round designs push the throughput frontier even higher, but they trade cryptanalytic maturity for speed, and their standardization status is unsettled -- AEGIS itself is still only an Internet-Draft, not an RFC [@aegis-draft18]. How much margin to spend for how much throughput is an open judgment call.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://paragmali.com/blog/post-quantum-cryptography-on-windows-the-thirty-year-migrati/&quot; rel=&quot;noopener&quot;&gt;Post-quantum reality&lt;/a&gt;, minus the myth.&lt;/strong&gt; This one is mostly a matter of correcting a widespread misconception.&lt;/p&gt;

For symmetric authenticated encryption the honest answer is: no, and you mostly need to change nothing. Grover&apos;s algorithm offers at most a square-root speedup on key search, which halves the effective key length [@grover1996], so a 128-bit key gives about 64 bits of margin against a hypothetical quantum attacker. The remedy is simply to prefer 256-bit keys -- ChaCha20 already uses one, and AES-256 is a configuration flag -- and to size tags with a margin. The post-quantum upheaval lives in key exchange and signatures, not the AEAD record layer, as developed in the post-quantum-cryptography-on-Windows post in this collection. Your record encryption survives the transition largely intact.
&lt;p&gt;&lt;strong&gt;Constant-time without special hardware.&lt;/strong&gt; GHASH is hard to implement in constant time without CLMUL, and table-based AES leaks timing without AES-NI -- the exact side-channel pressure that motivated both ChaCha20-Poly1305 and Ascon [@bernstein-chacha][@ascon2021]. On the smallest devices, where neither special instruction exists and power analysis is a live threat, side-channel-resistant AEAD is still an open engineering problem, and it is much of the reason NIST ran a lightweight competition at all.&lt;/p&gt;
&lt;p&gt;None of these has a finished answer. But notice the shape of every one: they are all attempts to move an &lt;em&gt;edge&lt;/em&gt; to a place where the deployer cannot step on it by mistake -- misuse-resistance you do not have to remember, commitment you do not have to add, side-channel safety you do not have to hand-tune. Which brings us back to the only rule that actually travels.&lt;/p&gt;
&lt;h2&gt;10. The Field Guide: Rules and Parameters&lt;/h2&gt;
&lt;p&gt;Everything above collapses into one default and a short list of deliberate escalations. Follow the ladder and you will never again pick an AEAD by folklore.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Default to &lt;strong&gt;AES-GCM&lt;/strong&gt; with a 96-bit nonce that is unique per key (prefer a counter over a random value), a hard cap well under $2^{32}$ messages per key, at most 64 GiB per message, and a full 128-bit tag. Use &lt;strong&gt;ChaCha20-Poly1305&lt;/strong&gt; under the same contract when you lack AES hardware. Leave the default only when a specific edge forces you, and only in the direction that edge points [@sp80038d][@rfc8439].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The escalation ladder, each rung mapped to the edge it moves:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cannot guarantee a unique nonce?&lt;/strong&gt; Escalate on the nonce edge to &lt;strong&gt;AES-GCM-SIV&lt;/strong&gt; [@rfc8452]. Cloned VMs, counters that reset on crash, weak first-boot entropy -- if any of these is in your threat model, the graceful failure is worth the second pass.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A stack mandates it, or the device is tiny?&lt;/strong&gt; Use &lt;strong&gt;AES-CCM&lt;/strong&gt; where WPA2, BLE, or Zigbee require it [@rfc3610], and &lt;strong&gt;Ascon-AEAD128&lt;/strong&gt; for &lt;em&gt;new&lt;/em&gt; constrained designs, now that it is a NIST standard [@sp800232].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deterministic encryption or key wrapping?&lt;/strong&gt; Use &lt;strong&gt;AES-SIV&lt;/strong&gt;, which needs no nonce at all and is built for exactly this [@rfc5297].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You want one-pass, single-primitive elegance?&lt;/strong&gt; &lt;strong&gt;OCB3&lt;/strong&gt; is now patent-clear, though rarely the right call given how entrenched the defaults are [@rfc7253][@kr2021-ocb].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You control both endpoints and need maximum throughput?&lt;/strong&gt; &lt;strong&gt;AEGIS&lt;/strong&gt; is the fastest option, if you can accept a pre-RFC specification [@aegis-draft18][@wu2013-aegis].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Must a ciphertext bind to exactly one key?&lt;/strong&gt; &lt;em&gt;Add&lt;/em&gt; a key-commitment transform -- for password-based encryption, key rotation, message franking, or multi-recipient encryption -- because no default provides it [@bh2022-commit].&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://paragmali.com/blog/predictable-or-repeated-the-only-two-ways-cryptographic-rand/&quot; rel=&quot;noopener&quot;&gt;Nonce generation&lt;/a&gt; itself is the subject of Part 2 of this series; do not re-derive it here, but do treat &quot;unique per key&quot; as a hard contract, not a hope. On Windows, the &lt;a href=&quot;https://paragmali.com/blog/cng-architecture-bcrypt-ncrypt-ksps/&quot; rel=&quot;noopener&quot;&gt;CNG architecture&lt;/a&gt; post in this collection shows AES-GCM exposed through the &lt;code&gt;BCryptEncrypt&lt;/code&gt; API with an authenticated-cipher-mode information structure -- a concrete example of the parameters below appearing in a real API.&lt;/p&gt;
&lt;p&gt;Pair the ladder with the support map from Section 6 when you check feasibility: browser JavaScript means AES-GCM through WebCrypto, and a target with no AES hardware means ChaCha20-Poly1305 or, if it is also tiny, Ascon-AEAD128 [@webcrypto].&lt;/p&gt;
&lt;p&gt;The exact operational contract, per construction:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Construction&lt;/th&gt;
&lt;th&gt;Nonce&lt;/th&gt;
&lt;th&gt;Tag&lt;/th&gt;
&lt;th&gt;Per-key limit&lt;/th&gt;
&lt;th&gt;Per-message limit&lt;/th&gt;
&lt;th&gt;On nonce reuse&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;AES-GCM&lt;/td&gt;
&lt;td&gt;96-bit, unique&lt;/td&gt;
&lt;td&gt;128-bit&lt;/td&gt;
&lt;td&gt;~`2^32` msgs (random nonce)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;2^39 - 256&lt;/code&gt; bits, ~64 GiB&lt;/td&gt;
&lt;td&gt;Catastrophic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ChaCha20-Poly1305&lt;/td&gt;
&lt;td&gt;96-bit, unique&lt;/td&gt;
&lt;td&gt;128-bit&lt;/td&gt;
&lt;td&gt;~`2^32` msgs (random nonce)&lt;/td&gt;
&lt;td&gt;~256 GiB&lt;/td&gt;
&lt;td&gt;Catastrophic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-CCM&lt;/td&gt;
&lt;td&gt;7 to 13 byte&lt;/td&gt;
&lt;td&gt;up to 128-bit (&lt;code&gt;CCM_8&lt;/code&gt;: 64)&lt;/td&gt;
&lt;td&gt;Set by nonce length&lt;/td&gt;
&lt;td&gt;Set by length field&lt;/td&gt;
&lt;td&gt;Catastrophic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-GCM-SIV&lt;/td&gt;
&lt;td&gt;96-bit&lt;/td&gt;
&lt;td&gt;128-bit&lt;/td&gt;
&lt;td&gt;Improved (per-nonce derived keys)&lt;/td&gt;
&lt;td&gt;~64 GiB&lt;/td&gt;
&lt;td&gt;Graceful: message equality&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-SIV&lt;/td&gt;
&lt;td&gt;None or supplied&lt;/td&gt;
&lt;td&gt;128-bit&lt;/td&gt;
&lt;td&gt;Large&lt;/td&gt;
&lt;td&gt;Large&lt;/td&gt;
&lt;td&gt;Graceful: message equality&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OCB3&lt;/td&gt;
&lt;td&gt;up to 120-bit&lt;/td&gt;
&lt;td&gt;up to 128-bit&lt;/td&gt;
&lt;td&gt;Large&lt;/td&gt;
&lt;td&gt;Large&lt;/td&gt;
&lt;td&gt;Catastrophic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AEGIS&lt;/td&gt;
&lt;td&gt;128 or 256-bit&lt;/td&gt;
&lt;td&gt;128 or 256-bit&lt;/td&gt;
&lt;td&gt;Large (wide nonce)&lt;/td&gt;
&lt;td&gt;Large&lt;/td&gt;
&lt;td&gt;Catastrophic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ascon-AEAD128&lt;/td&gt;
&lt;td&gt;128-bit&lt;/td&gt;
&lt;td&gt;128-bit&lt;/td&gt;
&lt;td&gt;Per SP 800-232&lt;/td&gt;
&lt;td&gt;Per SP 800-232&lt;/td&gt;
&lt;td&gt;Catastrophic&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The only two numeric limits you must hard-code are GCM&apos;s, because they are the ones people breach silently: cap messages per key well under $2^{32}$ and messages under 64 GiB each [@sp80038d]. ChaCha20-Poly1305&apos;s own ~256 GiB per-message ceiling comes the same way, from its 32-bit block counter over 64-byte blocks ($2^{32}\times 64$ bytes $= 2^{38}$ bytes), per RFC 8439 [@rfc8439]. AES-GCM-SIV&apos;s per-nonce key derivation buys better multi-user bounds, which is the whole reason RFC 8452 derives fresh keys rather than reusing one [@bht2018][@rfc8452].&lt;/p&gt;
&lt;p&gt;Every rung of that ladder has a mirror image: a misuse pattern that punishes the deployment for stepping on the edge it ignored. Each row below maps a real-code mistake to the named break that catches it.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Misuse seen in real code&lt;/th&gt;
&lt;th&gt;Edge it triggers&lt;/th&gt;
&lt;th&gt;Named break&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Reusing a &lt;code&gt;(key, nonce)&lt;/code&gt; in GCM or AEGIS&lt;/td&gt;
&lt;td&gt;Nonce&lt;/td&gt;
&lt;td&gt;Nonce-Disrespecting Adversaries, 2016&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Assuming an AEAD binds a ciphertext to one key&lt;/td&gt;
&lt;td&gt;Commitment&lt;/td&gt;
&lt;td&gt;Invisible salamanders; partitioning oracles&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Truncating the tag to save bytes (&lt;code&gt;CCM_8&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Integrity budget&lt;/td&gt;
&lt;td&gt;Wegman-Carter forgery bound&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Treating AES-GCM-SIV reuse as &quot;free&quot;&lt;/td&gt;
&lt;td&gt;Nonce&lt;/td&gt;
&lt;td&gt;SIV leaks message equality&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hand-rolling Encrypt-and-MAC&lt;/td&gt;
&lt;td&gt;Composition&lt;/td&gt;
&lt;td&gt;Bellare-Namprempre; Krawczyk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Conflating GCM&apos;s two ceilings&lt;/td&gt;
&lt;td&gt;Nonce&lt;/td&gt;
&lt;td&gt;The two SP 800-38D limits&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The evidence for each is in the sections above: nonce reuse on live servers [@bock2016], the salamander and its weaponization [@dodis2018-salamander][@len2021-partition], the tag-length forgery budget [@rfc3610], the SIV equality leak [@rfc8452], the composition theorems [@bn2000][@krawczyk2001], and the two ceilings [@sp80038d]. One extra caution on attribution: the live-TLS nonce-reuse break is repeatedly mis-cited to CVE-2016-0270, which actually names IBM Domino and which the NVD itself flags as commonly misapplied to other products [@cve-2016-0270].&lt;/p&gt;

Search your codebase for any AEAD decryption that runs under an attacker-influenced key: password-based encryption, key wrapping, token decryption, or multi-recipient envelopes. If a decrypt path lets the caller supply or guess the key and then branches on whether decryption succeeded, you are exposed to a partitioning oracle and need a key-commitment transform on top of the AEAD [@len2021-partition][@bh2022-commit].
&lt;p&gt;That ladder is your inoculation against folklore. But folklore is sticky, so let us take the most common misconceptions head-on.&lt;/p&gt;
&lt;h2&gt;11. Seven Beliefs That Get Deployments Broken&lt;/h2&gt;


No. For every nonce-respecting mode -- AES-GCM, ChaCha20-Poly1305, AES-CCM, OCB3, AEGIS, and Ascon -- a single repeated `(key, nonce)` is an immediate, total break: it leaks the XOR of the two plaintexts, and a second collision hands over the authentication subkey for universal forgery [@joux2006][@bock2016]. Only the SIV family degrades gracefully, and only to leaking message equality [@rfc8452].


No. It makes reuse *survivable*, not free. A repeated nonce still leaks message equality -- an attacker learns that two ciphertexts encrypt the same plaintext -- which can matter a great deal in the right context. Use it as a safety net, not a license to stop managing nonces [@rfc8452][@rs2006].


No to both misreadings. It is a different trade-off on the hardware edge, not a weaker cipher: constant-time in pure software with no lookup tables, which makes it the *stronger* choice on hardware without AES-NI, where table-based AES leaks timing. And it is not mandatory-to-implement in TLS 1.3 -- it is a *recommended* (SHOULD) cipher suite, while only AES-128-GCM is the MUST, per RFC 8446 Section 9.1 [@rfc8446]. Recommended, not weaker, not mandatory.


No. Random 96-bit nonces are collision-safe only up to roughly $2^{32}$ messages per key, by the birthday bound. That per-key invocation cap is a different number from the per-message limit of about 64 GiB; enforce both, and prefer a counter over a random nonce when you can [@sp80038d][@htt2018-gcm].


No. Most AEADs are not key-committing. One AES-GCM ciphertext can be built to decrypt to two different meaningful plaintexts under two different keys, with the tag valid both times -- the invisible-salamanders result. If a ciphertext must bind to one key, add a commitment transform [@dodis2018-salamander][@bh2022-commit].


No. AEGIS leads on raw throughput, but it is nonce-respecting (catastrophic on reuse), not fully key-committing, and still an active Internet-Draft rather than an RFC -- it states plainly that it &quot;is not a standard&quot; and expires on 8 April 2026. Fastest is not the same as best for your deployment [@aegis-draft18][@wu2013-aegis].


No. Symmetric authenticated encryption survives the quantum transition. Grover&apos;s algorithm only halves effective key length [@grover1996], so prefer 256-bit keys and size tags with margin. The post-quantum upheaval is in key exchange and signatures, not the AEAD record layer. Separately, note that NIST&apos;s Ascon-AEAD128 is a tweaked variant of the CAESAR Ascon-128, not byte-identical [@sp800232].

&lt;h2&gt;The Function, Not the Ranking&lt;/h2&gt;
&lt;p&gt;Seven ciphers, one interface, three edges. Every break here was a deployment triggering an edge its designers deliberately moved elsewhere. The invisible salamanders triggered the commitment edge that AEAD never promised to close [@dodis2018-salamander]. The 184 TLS servers triggered the nonce edge that GHASH cannot survive [@bock2016]. The &lt;code&gt;CCM_8&lt;/code&gt; forgery budget is the tag-length edge priced in bits [@rfc3610]. The SIV equality leak is the residue of the one edge SIV &lt;em&gt;does&lt;/em&gt; close -- even the fix has a seam [@rfc8452]. And OCB3&apos;s near-total absence is the patent grave, an edge that was never technical at all [@kr2021-ocb].&lt;/p&gt;
&lt;p&gt;Put them together and the thesis is earned rather than asserted. &quot;Which AEAD should I use?&quot; is not a ranking from worst to best, because Section 8 proved there is no best -- no single construction can be misuse-resistant &lt;em&gt;and&lt;/em&gt; single-pass &lt;em&gt;and&lt;/em&gt; fully committing &lt;em&gt;and&lt;/em&gt; fastest at once. It is a function: pick the construction whose failure mode your deployment can &lt;em&gt;guarantee&lt;/em&gt; it will never trigger.&lt;/p&gt;
&lt;p&gt;Master the three edges and you can place any construction on the map, predict any misuse before it ships, and evaluate whatever the next competition invents -- key-derivation-bound AEADs, the TLS record layer&apos;s next mode, or a lightweight winner that does not exist yet. The names will change. The edges will not.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;the-aead-decision-matrix&quot; keyTerms={[
  { term: &quot;AEAD&quot;, definition: &quot;One keyed call giving confidentiality, plaintext integrity, and associated-data integrity&quot; },
  { term: &quot;Associated Data&quot;, definition: &quot;Header bytes authenticated but not encrypted, travelling in the clear&quot; },
  { term: &quot;Nonce&quot;, definition: &quot;A value that must be unique per key for a nonce-respecting mode&quot; },
  { term: &quot;MRAE&quot;, definition: &quot;Misuse-resistant AE, where nonce reuse leaks only message equality&quot; },
  { term: &quot;Wegman-Carter one-time MAC&quot;, definition: &quot;A tag of the form keyed-hash plus one-time mask, the shared root of GHASH and Poly1305&quot; },
  { term: &quot;GHASH&quot;, definition: &quot;GCM&apos;s linear universal hash at a secret point, recovering which forges tags&quot; },
  { term: &quot;Synthetic IV (SIV)&quot;, definition: &quot;An IV derived as a MAC of the whole message, so the tag is the IV&quot; },
  { term: &quot;Key commitment&quot;, definition: &quot;Binding a ciphertext to one key (CMT-1) up to the full context (CMT-4)&quot; },
  { term: &quot;Sponge&quot;, definition: &quot;One permutation that absorbs input and squeezes keystream and tag, as in Ascon&quot; },
  { term: &quot;Inverse-free&quot;, definition: &quot;A decryption path that never calls the block-cipher inverse, true of the CTR, stream, and sponge modes but not OCB3&quot; },
  { term: &quot;RUP&quot;, definition: &quot;Release of Unverified Plaintext, emitting plaintext before the tag is checked&quot; }
]} questions={[
  { q: &quot;What are the three edges that decide an AEAD choice?&quot;, a: &quot;The nonce contract, the performance and hardware profile, and commitment.&quot; },
  { q: &quot;Why is a repeated nonce catastrophic in AES-GCM?&quot;, a: &quot;It reuses the one-time Wegman-Carter mask, leaking the plaintext XOR and, with a second collision, the GHASH subkey for forgery.&quot; },
  { q: &quot;Why can a misuse-resistant AEAD not be single-pass?&quot;, a: &quot;Its ciphertext must depend on the whole message, so it must read the last plaintext byte before emitting any ciphertext, a Rogaway-Shrimpton theorem.&quot; },
  { q: &quot;Does authenticated mean a ciphertext binds to one key?&quot;, a: &quot;No. Commitment is an orthogonal axis, and most AEADs are not key-committing by default.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>aead</category><category>authenticated-encryption</category><category>aes-gcm</category><category>chacha20-poly1305</category><category>nonce-misuse</category><category>key-commitment</category><category>applied-cryptography</category><category>cryptography</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>The Ciphertext Was Unbreakable. The Attacker Rewrote It Anyway: A Field Guide to Block Cipher Modes</title><link>https://paragmali.com/blog/the-ciphertext-was-unbreakable-the-attacker-rewrote-it-anyw/</link><guid isPermaLink="true">https://paragmali.com/blog/the-ciphertext-was-unbreakable-the-attacker-rewrote-it-anyw/</guid><description>Every block cipher mode -- ECB, CBC, CFB, OFB, CTR -- answers only confidentiality, never integrity. A field guide to why, the famous breaks, and the AEAD fix.</description><pubDate>Wed, 08 Jul 2026 21:51:08 GMT</pubDate><content:encoded>
A block cipher only enciphers one fixed-size block. A &quot;mode of operation&quot; is the wrapper that turns it into a scheme for real messages -- and every mode answers only one of two questions: can the attacker *read* it (confidentiality), or can the attacker *change* it (integrity)? The five SP 800-38A modes -- ECB, CBC, CFB, OFB, CTR -- are all malleable, so an attacker who cannot decrypt your ciphertext can still predictably edit the plaintext, and ECB additionally leaks structure outright (the penguin, Adobe&apos;s 153 million passwords). This field guide hands you one lens -- *which question did this mode answer, and was its IV/nonce contract honored?* -- and uses it to walk each mode&apos;s exact contract, a named failure catalog (Vaudenay, BEAST, Lucky Thirteen, POODLE, Sweet32, Efail, GCM nonce reuse), and the fix: authenticated encryption, whose dominant AES instances (GCM equals CTR plus GHASH, CCM equals CTR plus CBC-MAC) are literally these modes plus a MAC. It closes with the 2024-2026 state of the art (IR 8459, the ECB sunset, Ascon, nonce-misuse-resistant AES-GCM-SIV) and a decision guide for using these primitives correctly.
&lt;h2&gt;1. Two Lines of Code&lt;/h2&gt;
&lt;p&gt;A bank encrypts the message &quot;transfer $9&quot; with AES and a 256-bit key and sends the ciphertext across a network an attacker completely controls. He cannot read a single byte of it. AES is unbroken and will stay unbroken. Yet by flipping a few bits he cannot even decrypt, he turns the message into &quot;transfer $9,000,000,&quot; and the receiver accepts the change as authentic. The encryption was never broken. It simply answered the wrong question.&lt;/p&gt;
&lt;p&gt;How can a ciphertext be unreadable and freely editable at once? The trick is not a flaw in AES but a property of the &lt;em&gt;mode&lt;/em&gt; -- the wrapper that stretches a one-block cipher across a longer message. Many modes turn the cipher into a keystream generator and combine it with the plaintext by XOR, so $C = P \oplus \text{keystream}$. Rearrange the algebra: $P = C \oplus \text{keystream}$. An attacker who XORs a chosen delta into the ciphertext XORs exactly that delta into the recovered plaintext. He needs no key, reads nothing, and the receiver decrypts a perfectly well-formed forgery. That is one half of the story: the integrity question was never answered.&lt;/p&gt;
&lt;p&gt;The other half is uglier, because it fails the &lt;em&gt;first&lt;/em&gt; question too. In 2013, attackers exposed roughly 153 million Adobe account records. The passwords were not hashed. They were &lt;em&gt;encrypted&lt;/em&gt;, with 3DES in ECB mode and no salt [@troyhunt-adobe-2013]. ECB enciphers each block independently, so identical passwords produced identical ciphertext. Combined with the unencrypted password hints Adobe stored beside them, enormous numbers of passwords were reconstructed without anyone ever breaking 3DES [@troyhunt-adobe-2013]. The cipher was fine. The mode leaked the plaintext.&lt;/p&gt;
&lt;p&gt;Two stories, one shape. In each, the cipher did exactly what it promised and the attacker still won. That is because a mode of operation answers up to two independent questions, and the five most famous modes answer only one:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Can the attacker read it?&lt;/strong&gt; That is &lt;em&gt;confidentiality&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Can the attacker change it?&lt;/strong&gt; That is &lt;em&gt;integrity&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The five modes standardized for decades -- ECB, CBC, CFB, OFB, CTR -- answer only the first question. ECB answers even that one wrongly. Every named break in this field, past or future, reduces to one diagnostic sentence: &lt;em&gt;which of the two questions did this mode answer, and was its IV/nonce contract honored?&lt;/em&gt; Hold that sentence in your head and the whole subject becomes legible.&lt;/p&gt;

flowchart TD
    Mode[&quot;A block cipher mode of operation&quot;]
    Mode --&amp;gt; C[&quot;Question 1: can the attacker READ it? (confidentiality)&quot;]
    Mode --&amp;gt; I[&quot;Question 2: can the attacker CHANGE it? (integrity)&quot;]
    C --&amp;gt; Cans[&quot;Answered only if the IV or nonce contract is honored&quot;]
    I --&amp;gt; Ians[&quot;Never answered by the five SP 800-38A modes&quot;]
    Cans --&amp;gt; BreakA[&quot;Break type A: violated IV/nonce contract (BEAST, GCM nonce reuse)&quot;]
    Ians --&amp;gt; BreakB[&quot;Break type B: missing integrity answer (Efail, bit-flipping, truncation)&quot;]
&lt;p&gt;This is Part 5 of a field guide for protocol designers. It leans on two earlier parts without re-deriving them: &lt;a href=&quot;https://paragmali.com/blog/secure-against-whom-the-security-definitions-every-protocol-&quot; rel=&quot;noopener&quot;&gt;Part 1&lt;/a&gt; gave us the security definitions this article keeps invoking -- IND-CPA, IND-CCA2, INT-CTXT -- and Part 2 gave us the discipline of generating initialization vectors and nonces. Here we spend those definitions on a single primitive: the block cipher mode.&lt;/p&gt;
&lt;p&gt;If AES was never broken in either story, what actually failed? To answer, you first have to know what a block cipher can and cannot do on its own, and why a mode was mandatory from the very first day it shipped.&lt;/p&gt;
&lt;h2&gt;2. A Cipher That Only Speaks in Blocks&lt;/h2&gt;
&lt;p&gt;A block cipher is smaller than you think. DES (1977) enciphers exactly 64 bits at a time. AES (2001) enciphers exactly 128. Feed it more and it simply refuses. It is a keyed permutation on one fixed-size block and physically cannot accept a message longer than that.&lt;/p&gt;

A keyed, invertible permutation on one fixed-size block of bits, written $E_k : \{0,1\}^n \to \{0,1\}^n$ for a key $k$ and block size $n$ (64 bits for DES, 128 for AES). It maps one $n$-bit input to one $n$-bit output and back. It has no notion of a message, a length, or a stream.
&lt;p&gt;Because real messages are almost never exactly one block long, every use of a block cipher needs a wrapper: a rule for chopping the message into blocks, deciding what each block&apos;s input should be, and stitching the outputs back together. That wrapper is the mode of operation.&lt;/p&gt;

The algorithm that lifts a one-block cipher to messages of arbitrary length. It specifies how plaintext is partitioned, what feeds into each block cipher call, and how the results combine into a ciphertext. The mode -- not the cipher -- decides whether identical plaintext leaks, whether the scheme is parallel, and what the initialization-vector or nonce rule is.
&lt;p&gt;The primitive came first. Horst Feistel&apos;s work at IBM in the early 1970s produced the Feistel network that became DES, a 64-bit keyed permutation blessed as a federal standard in 1977 [@feistel-1973][@fips-46-3]. The 64-bit block chosen here is the exact quantity that dies, 39 years later, to the Sweet32 attack.&lt;/p&gt;
&lt;p&gt;The first wrapper followed almost immediately. In 1976, William Ehrsam, Carl Meyer, John Smith, and Walter Tuchman at IBM filed the patent on Cipher Block Chaining -- the idea of feeding each plaintext block the previous ciphertext block before encryption, so that identical plaintext blocks stop producing identical ciphertext (US Patent 4,074,066, granted 1978) [@cbc-patent-4074066].The patent&apos;s actual title is &quot;Message verification and transmission error detection by block chaining&quot; [@cbc-patent-4074066]. That is historically ironic: CBC as a confidentiality mode provides no message verification -- no integrity -- at all, which is the very gap this article is about.&lt;/p&gt;
&lt;p&gt;Counter mode arrived on paper three years later. Whitfield Diffie and Martin Hellman described encrypting a counter to make a keystream in their 1979 survey &quot;Privacy and Authentication,&quot; turning a block cipher into a parallelizable stream cipher [@diffie-hellman-1979][@rogaway-modes-2011].Counter mode was described &quot;just as early as the basic-four modes,&quot; in Rogaway&apos;s words, &quot;yet for some reason it was not included in the initial batch&quot; [@rogaway-modes-2011]. It waited 22 years for a federal standard. The exact page in Proc. IEEE 67(3) is gated behind IEEE Xplore, so the DOI is the stable handle and Rogaway&apos;s 2011 survey carries the attribution [@diffie-hellman-1979][@rogaway-modes-2011].&lt;/p&gt;
&lt;p&gt;Then the standard fixed the toolkit. In December 1980 the National Bureau of Standards published FIPS 81, &lt;em&gt;DES Modes of Operation&lt;/em&gt;, sanctioning four ways to stretch DES across real traffic: ECB, CBC, CFB, and OFB [@fips-81]. Counter mode was left out. It did not enter a NIST standard until Morris Dworkin&apos;s SP 800-38A re-specified all five modes for the AES era in December 2001, finally adding CTR as the fifth -- 22 years after Diffie and Hellman [@nist-sp-800-38a].&lt;/p&gt;

flowchart LR
    A[&quot;1976: CBC invented at IBM&quot;] --&amp;gt; B[&quot;1979: Counter mode, Diffie-Hellman&quot;]
    B --&amp;gt; C[&quot;1980: FIPS 81 standardizes ECB, CBC, CFB, OFB&quot;]
    C --&amp;gt; D[&quot;1997: BDJR concrete-security proofs&quot;]
    D --&amp;gt; E[&quot;2000-2001: Encrypt-then-MAC proven, SP 800-38A adds CTR&quot;]
    E --&amp;gt; F[&quot;2004-2007: GCM and CCM, CTR plus a MAC&quot;]
    F --&amp;gt; G[&quot;2011-2018: BEAST, Lucky Thirteen, POODLE, Sweet32, Efail&quot;]
    G --&amp;gt; H[&quot;2024-2025: NIST IR 8459, Ascon&quot;]
&lt;p&gt;Here is the load-bearing historical fact. Every one of these five modes is a &lt;em&gt;confidentiality&lt;/em&gt; construction. Integrity -- the second question, &quot;can the attacker change it?&quot; -- was filed under a separate heading called a message authentication code, and in practice it was usually forgotten. FIPS 81 and SP 800-38A specify no integrity mechanism for any of the five [@fips-81][@nist-sp-800-38a]. That separation of concerns, confidentiality here and integrity somewhere else, is the original sin the rest of this story pays for.&lt;/p&gt;
&lt;p&gt;So the toolkit was frozen by 1980 (four modes) and completed by 2001 (a fifth), every one a way to hide data and none a way to protect it from change. The most obvious of the four is also the most broken, and seeing exactly why is the fastest route into the whole subject.&lt;/p&gt;
&lt;h2&gt;3. ECB, and Why &quot;Just Encrypt Each Block&quot; Fails&lt;/h2&gt;
&lt;p&gt;The most obvious wrapper is to apply the one-block permutation to each block on its own: $C_i = E_k(P_i)$. This is Electronic Codebook mode, and it is the design every beginner reinvents in an afternoon. It is also broken in a way you can see with your eyes.&lt;/p&gt;
&lt;p&gt;The flaw is that ECB is &lt;em&gt;deterministic&lt;/em&gt;. It has no initialization vector, no chaining, and no state, so the same plaintext block always encrypts to the same ciphertext block: $P_i = P_j \Rightarrow C_i = C_j$. The plaintext&apos;s block-level structure survives encryption intact. Rogaway&apos;s survey states it flatly: ECB &quot;leak[s] equality of blocks across both block positions and time&quot; and &quot;does not achieve any generally desirable security goal in its own right&quot; [@rogaway-modes-2011].&lt;/p&gt;

flowchart TD
    P1[&quot;Block A: LOVE&quot;] --&amp;gt; C1[&quot;Ciphertext 7a3f&quot;]
    P2[&quot;Block B: HATE&quot;] --&amp;gt; C2[&quot;Ciphertext 9b2e&quot;]
    P3[&quot;Block C: LOVE&quot;] --&amp;gt; C3[&quot;Ciphertext 7a3f&quot;]
    C1 -.-&amp;gt;|&quot;equal blocks leak&quot;| C3
&lt;p&gt;That leak is not a metaphor.The famous &quot;ECB penguin&quot; -- an image of Tux encrypted block-by-block whose outline stays perfectly visible -- is community folklore (the Tux image is by Larry Ewing, 1996) with no research primary. The load-bearing evidence for ECB&apos;s failure is the Adobe 2013 breach and the BDJR theorem, not the meme. In 2013, roughly 153 million Adobe records showed it at scale: passwords encrypted with 3DES in ECB, no salt, so identical passwords produced identical ciphertext and the plaintext structure reconstructed itself without 3DES ever being broken [@troyhunt-adobe-2013].&lt;/p&gt;
&lt;p&gt;Underneath the meme is a theorem. ECB is not IND-CPA.&lt;/p&gt;

The baseline security goal for encryption. An adversary who may request encryptions of any plaintexts it chooses still cannot tell which of two equal-length messages a challenge ciphertext hides. Bellare, Desai, Jokipii, and Rogaway (1997) proved the consequence: any IND-CPA scheme must be randomized or stateful, so a deterministic mode like ECB cannot qualify [@bdjr-1997][@katz-lindell-2020].
&lt;p&gt;The proof is a one-line adversary. Ask the challenger to encrypt a pair of equal blocks $(X, X)$ versus an unequal pair $(X, Y)$ and simply look for a repeated ciphertext block; ECB gives itself away every time [@bdjr-1997]. This is the same reasoning &lt;a href=&quot;https://paragmali.com/blog/secure-against-whom-the-security-definitions-every-protocol-&quot; rel=&quot;noopener&quot;&gt;Part 1&lt;/a&gt; develops in general. ECB is also malleable at block granularity: because blocks are independent, an attacker can cut, paste, and reorder them undetected. It fails both questions at once.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; ECB is deterministic, so identical plaintext blocks become identical ciphertext blocks and structured or repeated data leaks through untouched -- the ECB penguin, and Adobe&apos;s roughly 153 million exposed passwords [@troyhunt-adobe-2013]. Reach for ECB only as a raw one-block building block, never to encrypt a message.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That &quot;never&quot; needs one careful qualifier -- it is easy to overstate.&lt;/p&gt;

The rule is *never ECB for messages* -- multi-block, structured, or low-entropy plaintext. The raw single-block permutation is still a legitimate building block: it is the block operation every other mode calls, and it sits at the core of NIST AES Key Wrap and of CMAC/CBC-MAC. NIST&apos;s SP 800-131A Revision 3, the initial public draft published on October 21, 2024, formalizes this by moving ECB to &quot;legacy use&quot; and disallowing it for encrypting secret data, with legacy (decrypt-only) use retained -- a demotion, not a claim that ECB has no valid use anywhere [@nist-sp-800-131a-r3].
&lt;p&gt;You can watch the determinism happen. The toy below is not a real cipher, but like ECB it transforms each block with the same deterministic function, so a repeated plaintext block produces a repeated ciphertext block:&lt;/p&gt;
&lt;p&gt;{`
// A toy deterministic block transform. Not a real cipher -- the point is
// only that the same input block always yields the same output block.
function toyBlockCipher(block) {
  return block.split(&apos;&apos;).reverse().map(function (c) {
    return String.fromCharCode((c.charCodeAt(0) + 7) % 128);
  }).join(&apos;&apos;);
}&lt;/p&gt;
&lt;p&gt;// ECB: split into 4-char blocks and transform each one independently.
function ecb(message) {
  var out = [];
  for (var i = 0; i &amp;lt; message.length; i += 4) {
    out.push(toyBlockCipher(message.slice(i, i + 4)));
  }
  return out;
}&lt;/p&gt;
&lt;p&gt;var blocks = ecb(&apos;LOVEHATELOVE&apos;); // block 1 and block 3 are identical
console.log(blocks);
console.log(&apos;Block 1 equals block 3? &apos; + (blocks[0] === blocks[2]));
// True. The repeated plaintext block leaks as a repeated ciphertext block,
// with no key required to notice the pattern.
`}&lt;/p&gt;
&lt;p&gt;One clarification before moving on.These five are the SP 800-38A &lt;em&gt;confidentiality-only&lt;/em&gt; modes, not &quot;all block cipher modes.&quot; Disk encryption (XTS-AES, SP 800-38E), authentication (CMAC, SP 800-38B), and authenticated encryption (GCM in SP 800-38D, CCM in SP 800-38C) live in separate NIST publications because they pursue different goals. ECB is the degenerate member of the family, and its failure points straight at the fix.&lt;/p&gt;
&lt;p&gt;BDJR&apos;s theorem is also the cure. To be IND-CPA, encryption must be randomized or stateful. So add an initialization vector, and make each block&apos;s encryption depend on the previous one, so that identical plaintext diverges. That is Cipher Block Chaining -- and the start of a forty-year evolution that improves everything except the one thing that matters.&lt;/p&gt;
&lt;h2&gt;4. From CBC to CTR, Generation by Generation&lt;/h2&gt;
&lt;p&gt;Four modes remain, and they line up as a sequence of fixes -- each one repairing the previous mode&apos;s &lt;em&gt;limitation&lt;/em&gt;, and none of them repairing the missing integrity answer. The field got faster, more flexible, and better specified. It stayed exactly as forgeable as the day it started.&lt;/p&gt;
&lt;h3&gt;CBC: chain the blocks&lt;/h3&gt;
&lt;p&gt;CBC seeds the chain with an initialization vector and feeds each plaintext block the previous ciphertext block before encryption: $C_i = E_k(P_i \oplus C_{i-1})$, with $C_0 = \text{IV}$. Decryption runs $P_i = D_k(C_i) \oplus C_{i-1}$. Because every ciphertext block now depends on all plaintext before it, identical plaintext blocks diverge, and ECB&apos;s pattern leak is gone. With an unpredictable IV, CBC is provably IND-CPA [@bdjr-1997].&lt;/p&gt;

The per-message starting value a mode mixes in so that encrypting the same plaintext twice yields different ciphertext. For CBC and CFB the IV must be *unpredictable* -- indistinguishable from random to an attacker -- not merely fresh, because it is the first value fed into the chain [@nist-sp-800-38a]. Part 2 of this series covers how to generate one.
&lt;p&gt;CBC answered the first question correctly and left the second blank, and even its confidentiality carries three sharp contract edges. This one mode seeded most of the Failure Catalog. It is malleable: a controlled flip in ciphertext block $C_i$ deterministically flips the corresponding bits of plaintext block $P_{i+1}$ while randomizing $P_i$ -- the &quot;flip-and-garble&quot; gadget, an attacker editing a later block without the key [@rogaway-modes-2011].&lt;/p&gt;
&lt;p&gt;The three contract edges follow. It needs padding, and a receiver that reveals whether decrypted padding is valid turns that check into a plaintext-recovering oracle. Its IV must be unpredictable, or a chosen-plaintext attacker can distinguish messages. And with a 64-bit block, its ciphertext blocks start colliding after about $2^{32}$ blocks, leaking $P_i \oplus P_j$. Rogaway&apos;s performance verdict is blunt: CBC encryption is &quot;inherently serial,&quot; and he can &quot;identify no important advantages over CTR mode&quot; [@rogaway-modes-2011].Ciphertext stealing (CBC-CS, standardized in an addendum to SP 800-38A) is the no-expansion variant that avoids padding by borrowing bits from the penultimate block. It is a useful trick, not a new security property -- CBC-CS is still malleable and still needs an unpredictable IV.&lt;/p&gt;
&lt;h3&gt;CFB: a self-synchronizing stream&lt;/h3&gt;
&lt;p&gt;CFB turns the block cipher into a stream by encrypting the &lt;em&gt;previous ciphertext&lt;/em&gt; to produce a keystream, then XORing it with the plaintext: $C_i = P_i \oplus E_k(C_{i-1})$. The cipher never touches the plaintext directly, so there is no padding, the mode can operate on sub-block segments (one byte or even one bit at a time), and it self-synchronizes after lost or inserted segments -- a genuinely useful property for noisy character-oriented links [@rogaway-modes-2011].&lt;/p&gt;
&lt;p&gt;The costs are real. Encryption is still serial, and for a segment size $s \lt n$ the mode makes many more block cipher calls per byte -- Rogaway notes $s = 8$ means &quot;16 times the number of blockcipher calls as CBC,&quot; and $s = 1$ means 128 times [@rogaway-modes-2011].Folklore (and even the loose version of this article&apos;s own scope) sometimes says CFB needs only a &lt;em&gt;unique&lt;/em&gt; IV. The primary source is stricter: SP 800-38A Section 5.3 requires the IV for both CBC and CFB to be &lt;em&gt;unpredictable&lt;/em&gt; [@nist-sp-800-38a]. Treat CFB&apos;s IV exactly like CBC&apos;s.&lt;/p&gt;
&lt;p&gt;CFB&apos;s malleability is the middle case, not a pure bit-flip. Because $P_i = C_i \oplus E_k(C_{i-1})$, flipping a ciphertext bit flips exactly the aligned plaintext bit in the &lt;em&gt;current&lt;/em&gt; block -- but that same altered block is the cipher&apos;s input for the next one, so the &lt;em&gt;following&lt;/em&gt; block decrypts to garbage. Efail (2018) weaponized precisely this: Damian Poddebniak and co-authors built malleability &quot;gadgets&quot; in CFB (OpenPGP&apos;s mode), engineered to absorb the garbled block while keeping the surgical edit, that turned an encrypted email into a plaintext-exfiltration channel with no key recovery and no padding oracle [@efail-2018][@efail-site].&lt;/p&gt;
&lt;h3&gt;OFB: a pre-computable stream&lt;/h3&gt;
&lt;p&gt;OFB makes the keystream independent of the message by feeding back the cipher&apos;s &lt;em&gt;own output&lt;/em&gt; instead of the ciphertext: $O_i = E_k(O_{i-1})$, then $C_i = P_i \oplus O_i$. Because the pad depends only on the key and IV, you can compute it before the plaintext arrives, and a single flipped ciphertext bit corrupts only the corresponding plaintext bit, with no error propagation -- attractive for satellite links and digitized voice [@rogaway-modes-2011].&lt;/p&gt;

A number used once: a value that must never repeat under a given key. OFB and CTR need their nonce only to be *unique*, not unpredictable, so a simple counter is a perfectly good nonce [@nist-sp-800-38a]. Reusing one under the same key is catastrophic for every keystream mode, because it reproduces the exact same pad. Part 2 covers how to source these values safely.
&lt;p&gt;That last point is OFB&apos;s undoing. If a $(\text{key}, \text{IV})$ pair ever repeats, the pad repeats, and $C \oplus C&apos; = P \oplus P&apos;$ leaks the XOR of two plaintexts with no key -- a two-time pad [@rogaway-modes-2011]. OFB is also serial in &lt;em&gt;both&lt;/em&gt; directions, so it cannot use hardware parallelism at all, a strictly worse profile than CTR for the same &quot;stream&quot; benefit. And the original FIPS 81 reduced-feedback variants shortened the keystream cycle dangerously, a hazard SP 800-38A removed by defining OFB with full-block feedback only [@fips-81][@nist-sp-800-38a].&lt;/p&gt;
&lt;h3&gt;CTR: the parallel stream that wins&lt;/h3&gt;
&lt;p&gt;CTR keeps OFB&apos;s &quot;encrypt something to make a pad&quot; idea but replaces the serial feedback chain with an &lt;em&gt;independent&lt;/em&gt; per-block counter: $C_i = P_i \oplus E_k(\text{nonce} ,|, i)$. Because each pad block is a standalone function of its counter, the blocks have no data dependency on one another. CTR is fully parallel on both encryption and decryption, random-access (decrypt block $i$ alone), precomputable, inverse-free, and needs no padding. Rogaway estimates it &quot;encrypting at more than 10 times the speed of CBC&quot; in hardware [@rogaway-modes-2011]. Its contract is the simplest of all: the counter must be &lt;em&gt;unique&lt;/em&gt; per key, and unpredictability is explicitly not required [@bdjr-1997][@rogaway-modes-2011].&lt;/p&gt;

Counter mode is &quot;the best and most modern way to achieve privacy-only encryption&quot; and &quot;an important building block for authenticated-encryption schemes.&quot; -- Phillip Rogaway, 2011
&lt;p&gt;And here is the cliff. CTR is the best answer to the &lt;em&gt;first&lt;/em&gt; question, which is exactly what makes its failure the point of the whole story. It is still malleable, and more transparently so than any other mode: $P = C \oplus \text{keystream}$, so flipping any ciphertext bit flips exactly the corresponding plaintext bit, with no key. The &quot;transfer $9&quot; to &quot;transfer $9,000,000&quot; edit from the opening is a single XOR, and the receiver decrypts a perfectly well-formed message. CTR removed every other excuse -- it is fast, parallel, and clean -- so the blank where integrity should be is the only thing left to see.&lt;/p&gt;

flowchart TD
    subgraph CBC[&quot;CBC: serial chaining&quot;]
        cIV[&quot;IV&quot;] --&amp;gt; cx1[&quot;XOR&quot;]
        cP1[&quot;P1&quot;] --&amp;gt; cx1
        cx1 --&amp;gt; cE1[&quot;E_k&quot;] --&amp;gt; cC1[&quot;C1&quot;]
        cC1 --&amp;gt; cx2[&quot;XOR&quot;]
        cP2[&quot;P2&quot;] --&amp;gt; cx2
        cx2 --&amp;gt; cE2[&quot;E_k&quot;] --&amp;gt; cC2[&quot;C2&quot;]
    end
    subgraph CTR[&quot;CTR: independent counters&quot;]
        tK1[&quot;E_k(nonce, 1)&quot;] --&amp;gt; tx1[&quot;XOR&quot;]
        tP1[&quot;P1&quot;] --&amp;gt; tx1
        tx1 --&amp;gt; tC1[&quot;C1&quot;]
        tK2[&quot;E_k(nonce, 2)&quot;] --&amp;gt; tx2[&quot;XOR&quot;]
        tP2[&quot;P2&quot;] --&amp;gt; tx2
        tx2 --&amp;gt; tC2[&quot;C2&quot;]
    end
&lt;p&gt;Lined up as a reference grid, the five modes and their exact contracts look like this:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Relation&lt;/th&gt;
&lt;th&gt;IV / nonce contract&lt;/th&gt;
&lt;th&gt;Parallelism&lt;/th&gt;
&lt;th&gt;Malleability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;ECB&lt;/td&gt;
&lt;td&gt;&lt;code&gt;C_i = E_k(P_i)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;none (the flaw)&lt;/td&gt;
&lt;td&gt;encrypt and decrypt parallel&lt;/td&gt;
&lt;td&gt;block-level: cut, paste, reorder&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CBC&lt;/td&gt;
&lt;td&gt;&lt;code&gt;C_i = E_k(P_i XOR C_{i-1})&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;unpredictable IV&lt;/td&gt;
&lt;td&gt;encrypt serial, decrypt parallel&lt;/td&gt;
&lt;td&gt;flip-and-garble (block-coupled)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CFB&lt;/td&gt;
&lt;td&gt;&lt;code&gt;C_i = P_i XOR E_k(C_{i-1})&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;unpredictable IV&lt;/td&gt;
&lt;td&gt;encrypt serial, decrypt parallel&lt;/td&gt;
&lt;td&gt;surgical bit, next block garbled (middle)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OFB&lt;/td&gt;
&lt;td&gt;&lt;code&gt;C_i = P_i XOR E_k(O_{i-1})&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;unique nonce&lt;/td&gt;
&lt;td&gt;serial both ways&lt;/td&gt;
&lt;td&gt;surgical bitwise&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CTR&lt;/td&gt;
&lt;td&gt;&lt;code&gt;C_i = P_i XOR E_k(counter_i)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;unique nonce (not unpredictable)&lt;/td&gt;
&lt;td&gt;encrypt and decrypt parallel&lt;/td&gt;
&lt;td&gt;surgical bitwise&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The IV and nonce contracts are SP 800-38A&apos;s; the parallelism and malleability columns follow Rogaway&apos;s summary tables [@nist-sp-800-38a][@rogaway-modes-2011].&lt;/p&gt;
&lt;p&gt;That last column deserves its own magnification, because &quot;malleable&quot; is not one behavior. It runs from surgical (edit one plaintext bit and touch nothing else), through a middle case (edit one bit, but wreck the neighboring block), to block-coupled (your controlled edit lands a block &lt;em&gt;later&lt;/em&gt;):&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Malleability class&lt;/th&gt;
&lt;th&gt;What one flipped ciphertext bit does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;CTR, OFB&lt;/td&gt;
&lt;td&gt;surgical&lt;/td&gt;
&lt;td&gt;flips exactly the aligned plaintext bit, with zero collateral&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CFB&lt;/td&gt;
&lt;td&gt;middle case&lt;/td&gt;
&lt;td&gt;flips the aligned bit in the current block, and fully garbles the next block&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CBC&lt;/td&gt;
&lt;td&gt;block-coupled&lt;/td&gt;
&lt;td&gt;garbles the current block, and flips the aligned bit in the next block&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ECB&lt;/td&gt;
&lt;td&gt;block-level&lt;/td&gt;
&lt;td&gt;no sub-block control, but whole blocks can be cut, pasted, and reordered&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The distinction is operational, not academic: CTR&apos;s surgical malleability is what makes the opening bit-flip a one-line edit, while CFB&apos;s &quot;flip here, garble there&quot; is the exact structure Efail&apos;s exfiltration gadgets were built around [@rogaway-modes-2011][@efail-2018]. Read as an evolution, the same five tell a story of steady improvement on every axis but one:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Year&lt;/th&gt;
&lt;th&gt;Key idea&lt;/th&gt;
&lt;th&gt;Limitation that drove the next step&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;ECB&lt;/td&gt;
&lt;td&gt;1980&lt;/td&gt;
&lt;td&gt;encrypt each block independently&lt;/td&gt;
&lt;td&gt;deterministic; leaks block equality (not IND-CPA)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CBC&lt;/td&gt;
&lt;td&gt;1976 / 1980&lt;/td&gt;
&lt;td&gt;chain each block with the previous ciphertext&lt;/td&gt;
&lt;td&gt;serial; needs padding; unpredictable IV; 64-bit birthday&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CFB&lt;/td&gt;
&lt;td&gt;1980&lt;/td&gt;
&lt;td&gt;encrypt the previous ciphertext into a keystream&lt;/td&gt;
&lt;td&gt;serial; sub-block sizes multiply cipher calls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OFB&lt;/td&gt;
&lt;td&gt;1980&lt;/td&gt;
&lt;td&gt;encrypt the feedback into a message-independent pad&lt;/td&gt;
&lt;td&gt;serial both ways; reuse is a two-time pad&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CTR&lt;/td&gt;
&lt;td&gt;1979 / 2001&lt;/td&gt;
&lt;td&gt;encrypt an independent counter&lt;/td&gt;
&lt;td&gt;the best confidentiality mode, yet still no integrity&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Not one of the four evolutions from ECB added integrity. CBC, CFB, OFB, and CTR each improved chaining, padding, error behavior, or parallelism. Every one of them left the second question -- can the attacker change it? -- completely blank.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;One honest caveat: CFB, OFB, and CTR are not a strict quality ladder. They are three parallel answers to CBC&apos;s &quot;turn the block cipher into a stream,&quot; standardized together, with CTR the clear winner [@rogaway-modes-2011]. The linear arrow is a teaching device.&lt;/p&gt;
&lt;p&gt;Line the four up and the pattern is undeniable. The bug was never &quot;which chaining?&quot; It was the blank where the second answer should be. Naming that blank correctly is the pivot the whole field turned on.&lt;/p&gt;
&lt;h2&gt;5. Malleability Is the Real Bug&lt;/h2&gt;
&lt;p&gt;Here is the reframe that organizes the entire subject: confidentiality is not security. A mode that perfectly hides your message while letting an attacker predictably rewrite it has not handed you a weaker guarantee. It has handed you a &lt;em&gt;different&lt;/em&gt; one, and mistaking the two is the single most repeated error in applied cryptography.&lt;/p&gt;

The property that an attacker can transform a ciphertext into a predictable transformation of the underlying plaintext, without knowing the key or the plaintext. A malleable scheme may be perfectly confidential and still let an attacker edit the message. All five SP 800-38A modes are malleable.
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Every one of the five modes answers only confidentiality. The missing integrity answer &lt;em&gt;is&lt;/em&gt; malleability, and malleability is the real bug. The fix is authenticated encryption -- not a faster or cleverer confidentiality mode.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is a provable statement, not a mood. A confidentiality-only mode is not IND-CCA2 and not non-malleable; IND-CPA says nothing about an active attacker who edits ciphertext in transit [@bdjr-1997].&lt;/p&gt;
&lt;p&gt;The mechanism differs per mode, and that difference is your diagnostic. In the pure keystream modes (CTR and OFB) the relation is $P = C \oplus \text{keystream}$, so flipping ciphertext bit $i$ flips plaintext bit $i$ exactly, with no collateral. CFB is the middle case: the flip lands surgically in the current block but garbles the &lt;em&gt;next&lt;/em&gt; one, because CFB feeds each ciphertext block back through the cipher. In CBC the coupling runs the other way -- a flip in $C_i$ predictably edits $P_{i+1}$ while randomizing $P_i$. &lt;a href=&quot;https://paragmali.com/blog/secure-against-whom-the-security-definitions-every-protocol-&quot; rel=&quot;noopener&quot;&gt;Part 1&lt;/a&gt; develops why this is a failure of the &lt;em&gt;goal&lt;/em&gt;, not the construction.&lt;/p&gt;

The stronger targets a confidentiality-only mode provably fails. IND-CCA2 (indistinguishability under adaptive chosen-ciphertext attack) hands the adversary a decryption oracle for any ciphertext but the challenge; non-malleability forbids turning one ciphertext into a predictably related one. Because all five SP 800-38A modes are malleable, none is IND-CCA2. Part 1 of this series formalizes both goals -- here they are exactly what a MAC restores.
&lt;p&gt;You can run the attack from the opening. The demo below encrypts a payment instruction with a toy keystream, then, knowing only the message format, rewrites the amount by XORing a delta into the ciphertext. No key is ever touched:&lt;/p&gt;
&lt;p&gt;{`
// Toy CTR: P = C XOR keystream. Editing C edits P, with no key. NOT real crypto.
function xorBytes(a, b) { return a.map(function (x, i) { return x ^ b[i]; }); }
function toBytes(s) { return Array.from(s).map(function (c) { return c.charCodeAt(0); }); }
function toStr(b) { return b.map(function (x) { return String.fromCharCode(x); }).join(&apos;&apos;); }&lt;/p&gt;
&lt;p&gt;var plaintext = &apos;amount:0000009&apos;;                 // the honest instruction
var keystream = toBytes(&apos;SECRETPADSECRET&apos;).slice(0, plaintext.length);&lt;/p&gt;
&lt;p&gt;// Sender encrypts. The attacker sees only C -- never the key, never the keystream.
var C = xorBytes(toBytes(plaintext), keystream);&lt;/p&gt;
&lt;p&gt;// The attacker knows the fixed message FORMAT and wants this instead:
var target = &apos;amount:9000000&apos;;                    // same length, this is the &quot;9 -&amp;gt; 9,000,000&quot; edit
var delta = xorBytes(toBytes(plaintext), toBytes(target));  // computable from the format alone&lt;/p&gt;
&lt;p&gt;// He XORs the delta straight into the ciphertext.
var forged = xorBytes(C, delta);&lt;/p&gt;
&lt;p&gt;// The receiver decrypts with the real keystream and sees the forgery.
console.log(&apos;Receiver reads: &apos; + toStr(xorBytes(forged, keystream)));  // amount:9000000
console.log(&apos;Keys or keystream used by the attacker: none.&apos;);
`}&lt;/p&gt;
&lt;p&gt;The same edit, drawn as it happens on the wire:&lt;/p&gt;

sequenceDiagram
    participant S as Sender
    participant A as Attacker
    participant R as Receiver
    S-&amp;gt;&amp;gt;A: Ciphertext of a nine-dollar transfer
    Note over A: Cannot read it, AES is unbroken
    Note over A: But P is C XOR keystream, so flipping ciphertext bit i flips plaintext bit i
    A-&amp;gt;&amp;gt;A: XOR a chosen delta into the amount bytes
    A-&amp;gt;&amp;gt;R: Modified ciphertext
    Note over R: Decrypts to a nine-million transfer, perfectly well-formed
    R-&amp;gt;&amp;gt;R: Accepts the forgery as authentic

Confidentiality without integrity is not weaker encryption. It is a different, largely illusory guarantee.
&lt;p&gt;Now turn the lens on the historical record. Every famous break of these modes is one of two diagnoses -- a missing integrity answer, or a violated IV/nonce contract:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Break&lt;/th&gt;
&lt;th&gt;Year&lt;/th&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Root cause&lt;/th&gt;
&lt;th&gt;Lesson&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Adobe [@troyhunt-adobe-2013]&lt;/td&gt;
&lt;td&gt;2013&lt;/td&gt;
&lt;td&gt;ECB&lt;/td&gt;
&lt;td&gt;confidentiality answered wrongly (determinism)&lt;/td&gt;
&lt;td&gt;never ECB for messages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Padding oracle, Vaudenay [@vaudenay-2002]&lt;/td&gt;
&lt;td&gt;2002&lt;/td&gt;
&lt;td&gt;CBC&lt;/td&gt;
&lt;td&gt;no integrity plus a distinguishable padding check&lt;/td&gt;
&lt;td&gt;verify before decrypting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BEAST [@bard-2004][@cve-2011-3389]&lt;/td&gt;
&lt;td&gt;2011&lt;/td&gt;
&lt;td&gt;CBC&lt;/td&gt;
&lt;td&gt;violated IV contract (predictable IV)&lt;/td&gt;
&lt;td&gt;IVs must be unpredictable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lucky Thirteen [@lucky-thirteen-2013]&lt;/td&gt;
&lt;td&gt;2013&lt;/td&gt;
&lt;td&gt;CBC&lt;/td&gt;
&lt;td&gt;wrong composition order plus a timing leak&lt;/td&gt;
&lt;td&gt;Encrypt-then-MAC, constant time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;POODLE [@poodle-2014][@cve-2014-3566]&lt;/td&gt;
&lt;td&gt;2014&lt;/td&gt;
&lt;td&gt;CBC (SSL 3.0)&lt;/td&gt;
&lt;td&gt;padding oracle after a downgrade&lt;/td&gt;
&lt;td&gt;retire the mode and the fallback&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sweet32 [@sweet32-2016][@cve-2016-2183]&lt;/td&gt;
&lt;td&gt;2016&lt;/td&gt;
&lt;td&gt;CBC (64-bit)&lt;/td&gt;
&lt;td&gt;block-size birthday bound&lt;/td&gt;
&lt;td&gt;no 64-bit ciphers for bulk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Efail [@efail-2018]&lt;/td&gt;
&lt;td&gt;2018&lt;/td&gt;
&lt;td&gt;CBC / CFB&lt;/td&gt;
&lt;td&gt;missing integrity (malleability gadget)&lt;/td&gt;
&lt;td&gt;authenticate the ciphertext&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Truncation, Smyth-Pironti [@smyth-pironti-2013]&lt;/td&gt;
&lt;td&gt;2013&lt;/td&gt;
&lt;td&gt;TLS record (any mode)&lt;/td&gt;
&lt;td&gt;missing integrity of length and framing (omission)&lt;/td&gt;
&lt;td&gt;authenticate the end, not just the bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GCM nonce reuse [@joux-2006][@nonce-disrespecting-2016]&lt;/td&gt;
&lt;td&gt;2016&lt;/td&gt;
&lt;td&gt;CTR / GCM&lt;/td&gt;
&lt;td&gt;violated nonce contract&lt;/td&gt;
&lt;td&gt;never repeat a (key, nonce)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Most of these breaks edit or leak bytes, but the subtlest one deletes them. Ben Smyth and Alfredo Pironti showed at WOOT 2013 that silently &lt;em&gt;truncating&lt;/em&gt; a TLS stream -- cutting it short at an attacker-chosen point -- changes the meaning a web application infers from a &quot;complete&quot; response, because the record layer authenticated the bytes it carried but never the fact that the message had &lt;em&gt;ended&lt;/em&gt; [@smyth-pironti-2013]. That is an integrity failure of omission, and it is why the fix in Section 10 authenticates length and end-of-stream, not just content. Most of the rest are TLS history, which the &lt;a href=&quot;https://paragmali.com/blog/rotating-every-cipher-schannel-and-the-twenty-year-algorithm&quot; rel=&quot;noopener&quot;&gt;SChannel post&lt;/a&gt; tells from the deployment side.Precision on GCM nonce reuse: one repeated $(\text{key}, \text{nonce})$ &lt;em&gt;immediately&lt;/em&gt; leaks $P_1 \oplus P_2$, but uniquely recovering the GHASH subkey $H$ generally needs two or more collisions. Never say &quot;one reuse leaks $H$&quot; [@joux-2006].The routinely mis-cited CVE-2016-0270 actually names IBM Domino, not OpenSSL, and NVD warns it &quot;has been incorrectly used for GCM nonce reuse issues in other products.&quot; The deployed GCM-nonce forgery is the Nonce-Disrespecting Adversaries paper, whose byline is exactly five authors: Boeck, Zauner, Devlin, Somorovsky, and Jovanovic [@cve-2016-0270][@nonce-disrespecting-2016].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; A bare confidentiality mode lets an attacker edit your plaintext undetected -- bit-for-bit in CTR and OFB, a surgical bit plus a garbled next block in CFB, and block-coupled in CBC. Use an AEAD, or Encrypt-then-MAC and verify the tag &lt;em&gt;before&lt;/em&gt; you decrypt a single byte.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The fix is to add the missing answer, and the order in which you add it turns out to matter. Bellare and Namprempre (2000) and Krawczyk (2001) proved that &lt;strong&gt;Encrypt-then-MAC&lt;/strong&gt; -- encrypt, then MAC the ciphertext, and verify the tag before decrypting -- generically yields both IND-CPA and INT-CTXT, a scheme that is confidential &lt;em&gt;and&lt;/em&gt; unforgeable, while MAC-then-encrypt and encrypt-and-MAC are fragile [@bellare-namprempre-2000][@krawczyk-2001].&lt;/p&gt;

A keyed tag that proves a message was not altered and came from someone holding the key. Anyone with the key can compute the tag over a message; without it, forging a valid tag is infeasible. HMAC, CMAC, and CBC-MAC are common constructions. A MAC supplies the integrity answer a confidentiality mode leaves blank.

SSL and early TLS shipped MAC-then-encrypt. The theory said Encrypt-then-MAC was the safe generic choice. That debate was not settled by proof alone -- it was settled by a decade of breaks (BEAST, Lucky Thirteen, POODLE) that all exploited the MAC-then-encrypt-plus-CBC-padding surface, until TLS 1.3 removed CBC outright and mandated authenticated encryption [@krawczyk-2001][@rfc-8446-tls13].
&lt;p&gt;Better still, fuse the two answers into one primitive.&lt;/p&gt;

A single primitive that provides confidentiality *and* integrity at once, and can also authenticate unencrypted &quot;associated data&quot; such as headers. It answers both questions in one object, so a modified ciphertext is rejected before any plaintext is released.
&lt;p&gt;The punchline binds this whole article together: the dominant &lt;em&gt;AES&lt;/em&gt; AEADs are literally these modes plus a MAC. &lt;strong&gt;GCM equals CTR plus GHASH&lt;/strong&gt;, a polynomial hash over $GF(2^{128})$ [@mcgrew-viega-2004][@nist-sp-800-38d]. &lt;strong&gt;CCM equals CTR plus CBC-MAC&lt;/strong&gt; [@rfc-3610-ccm][@nist-sp-800-38c]. The 1979 counter idea and the 1976 chaining idea, welded into a primitive that finally answers both questions -- the &lt;a href=&quot;https://paragmali.com/blog/the-connection-that-refused-to-downgrade-twenty-five-years-o&quot; rel=&quot;noopener&quot;&gt;SMB 3.1.1 post&lt;/a&gt; shows GCM and CCM running in a real protocol.&lt;/p&gt;

flowchart TD
    P[&quot;Plaintext&quot;] --&amp;gt; CTR[&quot;CTR encryption&quot;]
    CTR --&amp;gt; C[&quot;Ciphertext&quot;]
    C --&amp;gt; M[&quot;MAC over ciphertext and associated data&quot;]
    M --&amp;gt; T[&quot;Authentication tag&quot;]
    C --&amp;gt; W[&quot;Transmit ciphertext plus tag&quot;]
    T --&amp;gt; W
    W --&amp;gt; V{&quot;Tag valid?&quot;}
    V --&amp;gt;|&quot;no&quot;| X[&quot;Reject, decrypt nothing&quot;]
    V --&amp;gt;|&quot;yes&quot;| D[&quot;Decrypt and release plaintext&quot;]
&lt;p&gt;One boundary to keep honest: not every modern AEAD is built from these modes. ChaCha20-Poly1305 (a stream cipher plus Poly1305) and Ascon (a sponge permutation) are first-class AEADs that are deliberately &lt;em&gt;not&lt;/em&gt; SP 800-38A constructions [@rfc-8439-chacha20][@nist-sp-800-232]. The lineage claim is bounded to the AES AEADs.&lt;/p&gt;
&lt;p&gt;With integrity finally bolted on, every entry in the catalog retroactively dies -- a modified ciphertext fails the tag before a byte is decrypted. So the field declared victory and shipped AEAD everywhere. Then it discovered that AEAD did not repeal the IV/nonce contract. It &lt;em&gt;sharpened&lt;/em&gt; it -- which is exactly where the state of the art picks up.&lt;/p&gt;
&lt;h2&gt;6. The Field Is Retiring Confidentiality-Only Modes&lt;/h2&gt;
&lt;p&gt;The modern answer to &quot;which block cipher mode should I use?&quot; is &lt;em&gt;no bare confidentiality mode at all.&lt;/em&gt; It is a choice of AEAD, and between 2024 and 2026 that answer stopped being folklore and became written policy. The tell is what the standards bodies did &lt;em&gt;not&lt;/em&gt; do. Faced with four decades of breaks, nobody proposed a sixth confidentiality mode. Every document below reaches instead for authentication.&lt;/p&gt;
&lt;p&gt;Start with the audit. NIST IR 8459, published in September 2024 by Nicky Mouha and Morris Dworkin, is the first formal review of the entire SP 800-38 series, and it reads less like a specification than a post-mortem: it works through the family mode by mode, documenting why each keeps failing, and its recommendations point at authenticated encryption rather than a patched mode -- down to disallowing ECB for the very job it keeps losing at, encrypting secrets [@nist-ir-8459]. An audit whose answer to &quot;which new mode?&quot; is &quot;stop adding modes&quot; is this whole section in miniature.&lt;/p&gt;
&lt;p&gt;The policy machinery had already started turning. In April 2023 NIST&apos;s Crypto Publication Review Board published its decision to revise SP 800-38A itself, with goals that read like a confession: to &quot;limit the approval of the Electronic Codebook (ECB) mode,&quot; to &quot;provide guidance on the importance of incorporating authentication, where feasible,&quot; to fold in &quot;three variations of ciphertext stealing for Cipher Block Chaining mode,&quot; and -- once a stronger technique exists -- to &quot;consider deprecating the modes in SP 800-38A&quot; [@csrc-sp38a-revision-2023]. The document that defines the five modes is contemplating its own retirement, and names authenticated encryption as the successor it is waiting on.&lt;/p&gt;
&lt;p&gt;SP 800-131A Revision 3 supplies the compliance lever. Its initial public draft of October 21, 2024 disallows ECB for encrypting secret data and relegates it to legacy (decrypt-only) use; the draft&apos;s own phrase is &quot;the retirement of ECB as a confidentiality mode of operation&quot; [@nist-sp-800-131a-r3]. For a FIPS-bound product that is an effective-on-finalization change, not a suggestion.&lt;/p&gt;
&lt;p&gt;Where the field is heading is just as clear from what it &lt;em&gt;standardized&lt;/em&gt;. Ascon, finalized as NIST SP 800-232 in August 2025, is the new AEAD for the constrained, low-power class for which earlier standards specified AES-CCM -- and it is a sponge permutation, pointedly &lt;em&gt;not&lt;/em&gt; an SP 800-38A block cipher mode [@nist-sp-800-232]. &quot;Migrate to AEAD&quot; does not mean &quot;migrate to a mode.&quot; And for the one contract even AEADs still impose, AES-GCM-SIV (RFC 8452, 2019) is the standardized hedge: a nonce-misuse-resistant scheme that degrades gracefully instead of catastrophically when a nonce repeats [@rfc-8452-gcm-siv].&lt;/p&gt;

An AEAD that stays secure even when a nonce is accidentally reused, leaking at most whether two identical messages were sent under the same nonce, instead of collapsing into a two-time pad and forgery. AES-GCM-SIV reaches this by deriving its internal counter from a MAC of the whole message, so a repeat is a mild, bounded leak rather than a catastrophe [@rfc-8452-gcm-siv][@gcm-siv-spec-2017].

AES-GCM-SIV is engineered to be &quot;nonce misuse resistant -- that is, [it does] not fail catastrophically if a nonce is repeated.&quot; -- RFC 8452
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Document&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;NIST IR 8459 [@nist-ir-8459]&lt;/td&gt;
&lt;td&gt;audits the whole SP 800-38 series; steers ECB and secrets toward AEAD&lt;/td&gt;
&lt;td&gt;published, Sept 2024&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decision to revise SP 800-38A [@csrc-sp38a-revision-2023]&lt;/td&gt;
&lt;td&gt;limit ECB, add CBC ciphertext stealing, urge authentication, weigh deprecation&lt;/td&gt;
&lt;td&gt;published, Apr 2023&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SP 800-131A Rev. 3 [@nist-sp-800-131a-r3]&lt;/td&gt;
&lt;td&gt;moves ECB to legacy (decrypt-only) use; disallowed for encrypting secrets on publication&lt;/td&gt;
&lt;td&gt;draft (Oct 21, 2024 IPD)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ascon (SP 800-232) [@nist-sp-800-232]&lt;/td&gt;
&lt;td&gt;a permutation AEAD for constrained devices, deliberately not a 38A mode&lt;/td&gt;
&lt;td&gt;final, Aug 2025&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-GCM-SIV (RFC 8452) [@rfc-8452-gcm-siv]&lt;/td&gt;
&lt;td&gt;a nonce-misuse-resistant AEAD hedge&lt;/td&gt;
&lt;td&gt;published, 2019&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The migration is credible &lt;em&gt;now&lt;/em&gt;, rather than merely aspirational, because the substrate already moved. TLS 1.3 (RFC 8446, 2018) removed every CBC-mode cipher suite and makes AES-GCM its mandatory-to-implement AEAD [@rfc-8446-tls13]; QUIC protects every packet with an AEAD, binding the packet number directly into the AEAD nonce, with no unauthenticated-confidentiality option at all [@rfc-9001-quic-tls].&lt;/p&gt;
&lt;p&gt;The performance objection that once favored CBC also evaporated: with AES-NI and the carry-less multiply instruction PCLMULQDQ, AES-GCM fell from roughly 3.7 cycles per byte in optimized software toward about 1, so the fast path and the safe path are now the same path [@krovetz-rogaway-ae-2011][@gcm-siv-spec-2017]. The 2024-2026 standards are simply retiring the confidentiality-only modes to match a deployment reality that migrated years earlier.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The modern &quot;which mode?&quot; question is really &quot;which AEAD?&quot; The five SP 800-38A confidentiality-only modes now survive as &lt;em&gt;internals&lt;/em&gt; of authenticated encryption and as legacy interoperability options -- not as something you deploy on purpose.&lt;/p&gt;
&lt;/blockquote&gt;

Not every SP 800-38 sibling is a confidentiality mode. SP 800-38G defines FF1 and FF3, *format-preserving* encryption that turns a 16-digit card number into another 16-digit string so it still fits a legacy database column [@nist-sp-800-38g]. Different goal, and it came with its own break: Durak and Vaudenay gave a practical total recovery of FF3 over small domains, a slide attack exploiting the design&apos;s &quot;bad domain separation&quot; in roughly $O(N^{11/6})$ chosen plaintexts [@durak-vaudenay-2017]. NIST responded with FF3-1, shrinking the tweak from 64 to 56 bits and raising the minimum domain to one million [@nist-sp-800-38g-r1]. Signposted here, not surveyed -- it is not one of the five.
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Reach for a vetted AEAD -- AES-GCM or ChaCha20-Poly1305 -- give it a unique nonce per key, cap your messages under the nonce limit, and drop to a raw confidentiality mode only as an Encrypt-then-MAC building block when an AEAD is genuinely unavailable.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The cross-references write themselves: the CBC-to-GCM migration is the story the &lt;a href=&quot;https://paragmali.com/blog/rotating-every-cipher-schannel-and-the-twenty-year-algorithm&quot; rel=&quot;noopener&quot;&gt;SChannel post&lt;/a&gt; tells for Windows TLS, and GCM and CCM running in a shipping protocol is what the &lt;a href=&quot;https://paragmali.com/blog/the-connection-that-refused-to-downgrade-twenty-five-years-o&quot; rel=&quot;noopener&quot;&gt;SMB 3.1.1 post&lt;/a&gt; shows. So the strategic direction is settled: move to AEAD. But &quot;AEAD&quot; is not one thing. The moment you have to &lt;em&gt;ship&lt;/em&gt;, the question sharpens from &quot;which mode?&quot; to &quot;which AEAD, with which parameters, for which platform?&quot; -- and that has a real, defensible answer.&lt;/p&gt;
&lt;h2&gt;7. When You Must Pick a Mode, and Which AEAD&lt;/h2&gt;
&lt;p&gt;Two comparisons matter in practice. The first is the intra-family one folklore gets wrong. The second is the one you actually face when you ship.&lt;/p&gt;
&lt;h3&gt;CBC versus CTR: a choice that changes nothing that matters&lt;/h3&gt;
&lt;p&gt;Both are confidentiality-only, both are malleable, and both are still everywhere. On the merits CTR is superior: fully parallel on encryption and decryption, random-access, and governed by the simplest contract (a unique nonce). CBC survives on forty years of deployment inertia, not on technical advantage -- Rogaway, having surveyed all five modes, reports &quot;no important advantages over CTR mode&quot; for CBC [@rogaway-modes-2011].&lt;/p&gt;
&lt;p&gt;But here is the point most tuning guides miss: swapping CBC for CTR fixes nothing that matters, because neither answers the second question. You trade a serial mode with padding for a parallel mode without it, and you keep every bit of the malleability. If your reason for the swap is security, you are solving the wrong problem.&lt;/p&gt;
&lt;h3&gt;Which AEAD&lt;/h3&gt;
&lt;p&gt;This is the comparison with real stakes, and every option is a defensible answer to a different constraint. AES-GCM is the throughput default on modern CPUs, hardware-accelerated by AES-NI and CLMUL, and brittle exactly where humans err -- a single reused nonce is catastrophic [@nist-sp-800-38d]. ChaCha20-Poly1305 is the software default: constant-time by construction, with no AES hardware and no cache-timing hazard [@rfc-8439-chacha20]. AES-CCM is CTR plus CBC-MAC, two-pass and small-footprint [@rfc-3610-ccm][@nist-sp-800-38c]; those documents define CCM, and its compact profile is why the IEEE wireless standards adopt it -- WPA2 (802.11i) [@krovetz-rogaway-ae-2011] and IEEE 802.15.4 low-power wireless [@rfc-4944][@rfc-9031] both build their link-layer security on it. AES-GCM-SIV is the nonce-misuse-resistant hedge [@rfc-8452-gcm-siv]. Ascon is the lightweight standard for microcontrollers [@nist-sp-800-232].&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;AEAD&lt;/th&gt;
&lt;th&gt;Built from&lt;/th&gt;
&lt;th&gt;Passes&lt;/th&gt;
&lt;th&gt;Constant-time&lt;/th&gt;
&lt;th&gt;Nonce-reuse penalty&lt;/th&gt;
&lt;th&gt;Best fit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;AES-GCM [@nist-sp-800-38d]&lt;/td&gt;
&lt;td&gt;CTR + GHASH&lt;/td&gt;
&lt;td&gt;1, online&lt;/td&gt;
&lt;td&gt;needs AES-NI, CLMUL&lt;/td&gt;
&lt;td&gt;catastrophic (forgery)&lt;/td&gt;
&lt;td&gt;server bulk, TLS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ChaCha20-Poly1305 [@rfc-8439-chacha20]&lt;/td&gt;
&lt;td&gt;stream + Poly1305&lt;/td&gt;
&lt;td&gt;1, online&lt;/td&gt;
&lt;td&gt;by construction (software)&lt;/td&gt;
&lt;td&gt;catastrophic&lt;/td&gt;
&lt;td&gt;mobile, no AES hardware&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-CCM [@rfc-3610-ccm]&lt;/td&gt;
&lt;td&gt;CTR + CBC-MAC&lt;/td&gt;
&lt;td&gt;2, not online&lt;/td&gt;
&lt;td&gt;needs AES-NI&lt;/td&gt;
&lt;td&gt;catastrophic&lt;/td&gt;
&lt;td&gt;WPA2, IoT, small code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-GCM-SIV [@rfc-8452-gcm-siv]&lt;/td&gt;
&lt;td&gt;POLYVAL-SIV + CTR&lt;/td&gt;
&lt;td&gt;2, not online&lt;/td&gt;
&lt;td&gt;needs AES-NI, CLMUL&lt;/td&gt;
&lt;td&gt;graceful (leak equality)&lt;/td&gt;
&lt;td&gt;nonce-uncertain systems&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ascon [@nist-sp-800-232]&lt;/td&gt;
&lt;td&gt;sponge permutation&lt;/td&gt;
&lt;td&gt;1 (duplex)&lt;/td&gt;
&lt;td&gt;easy to protect&lt;/td&gt;
&lt;td&gt;catastrophic&lt;/td&gt;
&lt;td&gt;microcontrollers, IoT&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The performance folklore is worth correcting too. The cleanest apples-to-apples software measurement, Krovetz and Rogaway at FSE 2011 on an Intel i5 &quot;Clarkdale,&quot; found CCM near 4.2 cycles per byte, GCM near 3.7, OCB near 1.5, and raw CTR near 1.3 [@krovetz-rogaway-ae-2011]. Read that as an &lt;em&gt;ordering&lt;/em&gt; under fixed effort, not a modern absolute: with mature AES-NI and CLMUL, AES-GCM reaches roughly 1 cycle per byte on current x86 [@gcm-siv-spec-2017]. The durable lesson is that hardware, not algorithm choice, moved GCM from 3.7 to 1 -- which is the whole reason CTR-based AEADs won.&lt;/p&gt;

The two non-38A AEADs from Section 5, ChaCha20-Poly1305 and Ascon, sit within a broader research lineage -- OCB, EAX, SIV/AES-SIV, IACBC/IAPM, McOE -- that is real but out of scope here; OCB is the elegant one-pass design that patents kept out of deployment for years [@rfc-7253-ocb].
&lt;p&gt;Every column wins on some axis and loses on another; none is unconditionally best. And the reasons &lt;em&gt;why&lt;/em&gt; no single scheme dominates are not engineering accidents. They are theorems. To use any of these correctly, you have to know the walls they are all pressed against.&lt;/p&gt;
&lt;h2&gt;8. You Cannot Get Integrity From a Confidentiality Mode&lt;/h2&gt;
&lt;p&gt;The two-question frame is not merely good advice. It is a theorem, and it draws a hard line no amount of clever engineering crosses.&lt;/p&gt;
&lt;p&gt;Start with the central impossibility. IND-CPA does not imply IND-CCA2 or non-malleability; BDJR proved ECB is not even IND-CPA and that CBC and CTR &lt;em&gt;are&lt;/em&gt; IND-CPA with proper IVs and nonces, but IND-CPA says nothing about an active attacker editing ciphertext [@bdjr-1997]. Bellare and Namprempre sharpened the target, separating INT-PTXT from INT-CTXT and proving that only Encrypt-then-MAC generically delivers IND-CPA plus INT-CTXT [@bellare-namprempre-2000][@krawczyk-2001].&lt;/p&gt;
&lt;p&gt;The consequence is a lower bound, not a tip: you cannot patch integrity into a bare CTR, CBC, CFB, or OFB mode, because malleability is a property of the confidentiality &lt;em&gt;goal&lt;/em&gt;, not a bug in any &lt;em&gt;construction&lt;/em&gt;. This is the reasoning &lt;a href=&quot;https://paragmali.com/blog/secure-against-whom-the-security-definitions-every-protocol-&quot; rel=&quot;noopener&quot;&gt;Part 1&lt;/a&gt; sets up in full.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; &quot;Confidentiality does not imply integrity&quot; is a theorem, not advice. IND-CPA does not imply IND-CCA2 or non-malleability, so you cannot patch integrity into a bare CTR, CBC, CFB, or OFB mode. It is a property of the goal, not a bug in the construction.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The second wall is the block size.&lt;/p&gt;

The threshold at which collisions among random $n$-bit values become likely: around $2^{n/2}$ of them. For a block cipher it means ciphertext blocks start repeating -- and leaking $P_i \oplus P_j$ -- after roughly $2^{n/2}$ blocks, regardless of key length. This is the ceiling behind Sweet32 and the GCM nonce cap.
&lt;p&gt;Ciphertext-collision leakage grows like $q^2 / 2^n$ in the number of blocks $q$, so security degrades at about $q \approx 2^{n/2}$ blocks: roughly $2^{32}$ blocks (about 32 GiB) for a 64-bit cipher, which is the Sweet32 ceiling, and $2^{64}$ blocks for AES [@bdjr-1997][@sweet32-2016]. A provable ceiling, independent of key size -- doubling the key does not move it.&lt;/p&gt;
&lt;p&gt;GCM inherits its own two ceilings, and conflating them is a common error. Per SP 800-38D, a single message is capped at $2^{39} - 256$ bits (about 64 GiB), and, under random 96-bit nonces, the number of invocations per key must stay below about $2^{32}$ to keep the nonce-collision probability negligible [@nist-sp-800-38d]. One is a length limit; the other is a count limit. They are different numbers that both bite.&lt;/p&gt;
&lt;p&gt;The last wall is the sharpest, because no computational assumption stands behind it. Reusing a $(\text{key}, \text{nonce})$ in any keystream mode leaks $C_1 \oplus C_2 = P_1 \oplus P_2$ -- a two-time pad. You can watch it recover a plaintext with nothing but XOR:&lt;/p&gt;
&lt;p&gt;{`
// Reusing a (key, nonce) reproduces the SAME keystream. That is a two-time pad.
function xorBytes(a, b) { return a.map(function (x, i) { return x ^ b[i]; }); }
function toBytes(s) { return Array.from(s).map(function (c) { return c.charCodeAt(0); }); }
function toStr(b) { return b.map(function (x) { return String.fromCharCode(x); }).join(&apos;&apos;); }&lt;/p&gt;
&lt;p&gt;var p1 = &apos;attack at dawn&apos;;
var p2 = &apos;defend the fort&apos;;
var n = Math.min(p1.length, p2.length);
var ks = toBytes(&apos;REUSEDPADREUSEDPAD&apos;).slice(0, n);   // the SAME pad used twice -- the bug&lt;/p&gt;
&lt;p&gt;var c1 = xorBytes(toBytes(p1).slice(0, n), ks);
var c2 = xorBytes(toBytes(p2).slice(0, n), ks);&lt;/p&gt;
&lt;p&gt;// The attacker never has the key. He XORs the two ciphertexts; the pad cancels:
var leaked = xorBytes(c1, c2);                         // equals p1 XOR p2&lt;/p&gt;
&lt;p&gt;// With a crib -- a good guess at p1 -- he recovers p2 outright:
var crib = toBytes(&apos;attack at dawn&apos;).slice(0, n);
console.log(&apos;Recovered from a crib: &apos; + toStr(xorBytes(leaked, crib)));  // defend the for
`}&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Reusing a $(\text{key}, \text{nonce})$ leaks $P_1 \oplus P_2$ with no computational assumption to fall back on -- no key length saves you. In GCM it is worse: repeated nonces also expose the GHASH subkey $H$ -- uniquely, once two or more collisions accumulate -- enabling universal forgery [@joux-2006][@nist-sp-800-38d].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The core science, then, is closed. &quot;Confidentiality does not imply integrity&quot; is settled, reuse is an information-theoretic floor, and the block-size wall is provable. If the theory is finished, what is left to work on? More than you would guess -- and it is where the modes still bite.&lt;/p&gt;
&lt;h2&gt;9. Where Modes Still Bite&lt;/h2&gt;
&lt;p&gt;The confidentiality-versus-integrity fight is won. The live frontier is one level up: not &quot;is it confidential?&quot; but &quot;how &lt;em&gt;resilient&lt;/em&gt; is the authenticated scheme when humans and hardware misbehave?&quot; Four problems are genuinely open, and one popular worry is not a problem at all.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Make nonce-misuse-resistance the default, not the hedge.&lt;/strong&gt; AES-GCM fails catastrophically on nonce reuse, yet reuse -- from stateless senders, VM clones, restarted counters -- is among the most common real misuses [@nist-sp-800-38d]. AES-GCM-SIV delivers graceful degradation at roughly 1 cycle per byte and up to $2^{50}$ messages per key, &quot;well suited for real world applications that need a nonce-misuse resistant Authenticated Encryption scheme&quot; [@gcm-siv-spec-2017].&lt;/p&gt;
&lt;p&gt;But it is two-pass and offline, and it remains opt-in. The open problem is an AEAD that is online, single-pass, parallel, roughly 1 cycle per byte, &lt;em&gt;and&lt;/em&gt; misuse-resistant at once -- and, harder, getting TLS and KMS libraries to make it the default. NIST IR 8459 flags nonce management across the whole SP 800-38 series as a first-order concern [@nist-ir-8459].&lt;/p&gt;

The property that binds a ciphertext to the single key and context that produced it, so it cannot be made to decrypt validly under a second key. Standard AEAD security says nothing about it, which is why AES-GCM and ChaCha20-Poly1305 lack it -- and why a ciphertext can be crafted to open to two different valid plaintexts under two different keys.
&lt;p&gt;&lt;strong&gt;Key commitment and robustness.&lt;/strong&gt; AES-GCM and ChaCha20-Poly1305 are not key-committing: a single ciphertext can be built to decrypt to valid plaintexts under &lt;em&gt;two&lt;/em&gt; different keys [@key-commitment-2022]. Real systems assume otherwise, so this breaks password-based encryption, message franking, and envelope schemes.&lt;/p&gt;
&lt;p&gt;Partitioning-oracle attacks turned that gap into practical password recovery against Shadowsocks proxies; the same study only &lt;em&gt;surveyed&lt;/em&gt; protocols such as OPAQUE as potentially vulnerable rather than breaking them [@partitioning-oracles-2021]. The &quot;invisible salamanders&quot; attack built AES-GCM ciphertexts that decrypt to valid files under two keys, defeating message franking [@fast-franking-2018], a technique later generalized across file formats [@key-commitment-2022]. A genuine lower bound -- compactly committing AE is provably impossible at AES-GCM&apos;s exact performance profile [@fast-franking-2018] -- meets a cheap upper bound -- committing GCM and GCM-SIV variants at no ciphertext expansion [@committing-ae-2022]. The bounds nearly meet, yet the deployed default still sits on the wrong side.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Constant-time implementation.&lt;/strong&gt; CBC-decrypt-then-MAC timing gave us Lucky Thirteen, and table-based AES and GHASH leak through cache [@lucky-thirteen-2013]. This is effectively solved on hardware with AES-NI and CLMUL, and ChaCha20-Poly1305 is constant-time by design [@rfc-8439-chacha20]. It stays a live hazard on microcontrollers and throughout the legacy CBC base.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The forty-year migration.&lt;/strong&gt; A vast deployed base still runs CBC and 64-bit block ciphers, keeping Sweet32 and padding oracles alive. TLS 1.3 removed CBC-mode cipher suites and mandates AEAD [@rfc-8446-tls13], and IR 8459 audits the whole series [@nist-ir-8459], but embedded firmware, file-format crypto, database encryption, and private protocols lag by years. This is an engineering and logistics problem, not a mathematical one -- and it is the one that keeps the Failure Catalog growing.&lt;/p&gt;

A widespread belief holds that quantum computers break block cipher modes. To first order they do not: Grover&apos;s algorithm gives only a quadratic speedup on key search, so doubling the key (AES-256) restores the margin. The post-quantum churn is in key exchange and signatures, not in symmetric modes or AEADs [@nist-ir-8105].
&lt;p&gt;None of these is a hole in the confidentiality-versus-integrity theory. All are the gap between the ideal AEAD and the one you can install today -- which is exactly the gap a practitioner has to bridge. So here are the rules that bridge it.&lt;/p&gt;
&lt;h2&gt;10. Use X With These Params In Case Y&lt;/h2&gt;
&lt;p&gt;Everything so far collapses into one rule and a short decision tree you can apply without re-deriving a theorem. The rule: use a vetted AEAD, not a raw confidentiality mode [@ferguson-schneier-kohno-2010].&lt;/p&gt;
&lt;p&gt;The decision guide, in priority order:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Default:&lt;/strong&gt; AES-GCM with a 96-bit nonce, unique per key -- prefer a deterministic counter -- and a hard cap of fewer than $2^{32}$ messages per key [@nist-sp-800-38d].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cannot guarantee unique nonces:&lt;/strong&gt; AES-GCM-SIV [@rfc-8452-gcm-siv], or XChaCha20-Poly1305, which widens the RFC 8439 ChaCha20-Poly1305 construction to a 192-bit random nonce [@rfc-8439-chacha20].The 192-bit-nonce XChaCha20 variant is specified in the IRTF draft draft-irtf-cfrg-xchacha, not in RFC 8439, which standardizes only the 96-bit ChaCha20-Poly1305 [@rfc-8439-chacha20]. The wider nonce is exactly what lets you pick nonces at random without tracking a counter.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No fast AES hardware, or you need constant-time software:&lt;/strong&gt; ChaCha20-Poly1305 [@rfc-8439-chacha20].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Constrained or IoT, small code budget:&lt;/strong&gt; Ascon-AEAD128 [@nist-sp-800-232] or AES-CCM [@rfc-3610-ccm].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Need key or context commitment&lt;/strong&gt; (password-based encryption, franking, envelope, rotation): a committing AEAD [@committing-ae-2022].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Must drop to a raw mode&lt;/strong&gt; (interoperability or a FIPS boundary): CTR plus Encrypt-then-MAC (CMAC or HMAC) with a unique nonce, or CBC only with a fresh &lt;em&gt;unpredictable&lt;/em&gt; IV plus Encrypt-then-MAC plus constant-time padding [@nist-sp-800-38a][@bellare-namprempre-2000].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Streaming or large objects:&lt;/strong&gt; do not ship one monolithic AEAD blob you cannot buffer. Split the stream into records, give each a unique per-chunk nonce, and authenticate a sequence number plus an explicit end-of-stream marker, so a dropped, reordered, or truncated record is caught rather than silently accepted. This is the record-protocol pattern DTLS 1.3 uses -- rejecting duplicates through &quot;a sliding receive window&quot; -- and that QUIC uses by binding each packet number into its AEAD nonce; together they close truncation and replay, the two integrity gaps a bare mode cannot see [@smyth-pironti-2013][@rfc-9147-dtls13][@rfc-9001-quic-tls].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Never:&lt;/strong&gt; ECB for messages, a 64-bit block cipher for bulk data, a reused nonce, or &quot;encryption&quot; with no integrity tag.&lt;/li&gt;
&lt;/ol&gt;

flowchart TD
    Start[&quot;Need to encrypt a message&quot;] --&amp;gt; Q1{&quot;Is a vetted AEAD available?&quot;}
    Q1 --&amp;gt;|&quot;no&quot;| Raw[&quot;CTR or CBC plus Encrypt-then-MAC, verify tag first&quot;]
    Q1 --&amp;gt;|&quot;yes&quot;| Q2{&quot;Can you guarantee unique nonces?&quot;}
    Q2 --&amp;gt;|&quot;no&quot;| NMR[&quot;AES-GCM-SIV or XChaCha20-Poly1305 (192-bit nonce)&quot;]
    Q2 --&amp;gt;|&quot;yes&quot;| Q3{&quot;Fast AES hardware present?&quot;}
    Q3 --&amp;gt;|&quot;no&quot;| Chacha[&quot;ChaCha20-Poly1305&quot;]
    Q3 --&amp;gt;|&quot;yes&quot;| Q4{&quot;Constrained device?&quot;}
    Q4 --&amp;gt;|&quot;yes&quot;| Small[&quot;Ascon-AEAD128 or AES-CCM&quot;]
    Q4 --&amp;gt;|&quot;no&quot;| GCM[&quot;AES-GCM, 96-bit nonce, fewer than 2^32 messages per key&quot;]
&lt;p&gt;When you do touch a raw mode, the contract is the whole game. &lt;a href=&quot;https://paragmali.com/blog/predictable-or-repeated-the-only-two-ways-cryptographic-rand&quot; rel=&quot;noopener&quot;&gt;Part 2&lt;/a&gt; covers how to &lt;em&gt;generate&lt;/em&gt; these values; this table says what each mode &lt;em&gt;requires&lt;/em&gt;:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Requirement&lt;/th&gt;
&lt;th&gt;Consequence of violation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;ECB&lt;/td&gt;
&lt;td&gt;none (and that is the flaw)&lt;/td&gt;
&lt;td&gt;determinism leaks block equality&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CBC&lt;/td&gt;
&lt;td&gt;unpredictable and unique IV&lt;/td&gt;
&lt;td&gt;a predictable IV enables BEAST&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CFB&lt;/td&gt;
&lt;td&gt;unpredictable and unique IV&lt;/td&gt;
&lt;td&gt;a predictable IV enables chosen-plaintext distinguishing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OFB&lt;/td&gt;
&lt;td&gt;unique nonce&lt;/td&gt;
&lt;td&gt;reuse is a two-time pad&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CTR&lt;/td&gt;
&lt;td&gt;unique nonce (unpredictability not required)&lt;/td&gt;
&lt;td&gt;reuse is a two-time pad&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Those requirements come straight from SP 800-38A [@nist-sp-800-38a]; the raw bytes that satisfy them come from a CSPRNG, which the &lt;a href=&quot;https://paragmali.com/blog/a-key-is-only-as-unguessable-as-the-dice-that-made-it-inside&quot; rel=&quot;noopener&quot;&gt;Windows CSPRNG post&lt;/a&gt; covers, and the real API calls that wire AES-CBC and AES-GCM together live in the &lt;a href=&quot;https://paragmali.com/blog/cng-architecture-bcrypt-ncrypt-ksps&quot; rel=&quot;noopener&quot;&gt;CNG post&lt;/a&gt;. Finally, every common misuse maps one-to-one to a named break and its fix:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Misuse&lt;/th&gt;
&lt;th&gt;Named break&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;ECB for structured data&lt;/td&gt;
&lt;td&gt;Adobe 2013 [@troyhunt-adobe-2013]&lt;/td&gt;
&lt;td&gt;AEAD over AES&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;static or predictable IV&lt;/td&gt;
&lt;td&gt;BEAST [@cve-2011-3389]&lt;/td&gt;
&lt;td&gt;fresh unpredictable IV, or an AEAD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;reused GCM nonce&lt;/td&gt;
&lt;td&gt;Nonce-Disrespecting Adversaries [@nonce-disrespecting-2016]&lt;/td&gt;
&lt;td&gt;counter nonces, or GCM-SIV / XChaCha&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MAC-then-encrypt or encrypt-and-MAC&lt;/td&gt;
&lt;td&gt;Lucky Thirteen [@lucky-thirteen-2013]&lt;/td&gt;
&lt;td&gt;Encrypt-then-MAC, verify before decrypt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;no integrity at all&lt;/td&gt;
&lt;td&gt;Efail [@efail-2018]&lt;/td&gt;
&lt;td&gt;an AEAD, or Encrypt-then-MAC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;64-bit block cipher for bulk&lt;/td&gt;
&lt;td&gt;Sweet32 [@sweet32-2016]&lt;/td&gt;
&lt;td&gt;a 128-bit-block AEAD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;truncation with no length integrity&lt;/td&gt;
&lt;td&gt;Truncation, Smyth-Pironti [@smyth-pironti-2013]&lt;/td&gt;
&lt;td&gt;authenticate length and end-of-stream&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

Run `openssl s_client -connect example.com:443 -tls1_3` and read the `Cipher` line: a modern server reports an AEAD such as `TLS_AES_128_GCM_SHA256` or `TLS_CHACHA20_POLY1305_SHA256`. If you instead see a suite with `CBC` in the name, you are looking at a legacy, malleable-mode configuration that belongs on the migration list.
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Read every mode as a building block with an exact IV/nonce contract, and read every break as a missing integrity answer or a violated contract. Default to an AEAD; touch a raw mode only under Encrypt-then-MAC discipline, and only when an AEAD is off the table.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Notice that every rule is the same rule wearing different clothes: pick the primitive that answers &lt;em&gt;both&lt;/em&gt; questions, and honor its IV/nonce contract. The folklore that gets this wrong is dense enough to deserve its own section.&lt;/p&gt;
&lt;h2&gt;11. Misconceptions, Named and Corrected&lt;/h2&gt;
&lt;p&gt;Seven half-truths cause real incidents. Each dissolves under the same two-question lens.&lt;/p&gt;


No. All five SP 800-38A modes are malleable, so an attacker who cannot read your ciphertext can still predictably edit the plaintext -- bit-for-bit in the additive keystream modes CTR and OFB, block-coupled in CBC, and a mix of the two in CFB. Confidentiality and integrity are different guarantees; you need a MAC or an AEAD to get the second one, and encryption alone does not provide it.


Only as a building block, never as a message-encryption mode. The raw single-block permutation is legitimate inside key wrap and CMAC or CBC-MAC. But ECB is deterministic, so the moment your data has any structure or repetition it leaks block equality -- which is why NIST is moving ECB to legacy use [@nist-sp-800-131a-r3]. The rule is &quot;never ECB for messages,&quot; not &quot;ECB has no use anywhere.&quot;


No. A random IV fixes ECB&apos;s determinism, but it adds no integrity -- the mode is still malleable. And the requirement is not uniform: CBC and CFB need an *unpredictable* IV, while CTR and OFB need only a *unique* nonce [@nist-sp-800-38a]. Getting that distinction wrong is exactly what BEAST exploited.


No. Under random 96-bit nonces you must stay below roughly $2^{32}$ invocations per key to keep the nonce-collision probability negligible [@nist-sp-800-38d]. Past that, a repeat becomes likely, and a repeated GCM nonce fails catastrophically. If you cannot count, use AES-GCM-SIV or XChaCha20-Poly1305 instead.


That fixes nothing that matters. Both are confidentiality-only and both are malleable; swapping one for the other trades performance characteristics, not security [@rogaway-modes-2011]. The fix is an AEAD, not a different malleable mode.


Not under nonce reuse. A single repeated $(\text{key}, \text{nonce})$ leaks $P_1 \oplus P_2$, and with two or more collisions it recovers the GHASH subkey $H$, enabling universal forgery -- Joux&apos;s &quot;forbidden attack,&quot; which was later found live on real TLS servers [@joux-2006][@nonce-disrespecting-2016]. GCM is only as strong as its nonce discipline.


Order matters. MAC-then-encrypt and encrypt-and-MAC are fragile and produced Lucky Thirteen and the padding-oracle family [@lucky-thirteen-2013]. The proven-safe generic composition is Encrypt-then-MAC: authenticate the ciphertext and verify the tag *before* you decrypt [@bellare-namprempre-2000].

&lt;p&gt;Every one dissolves into the same sentence -- which is where this started, and where it ends.&lt;/p&gt;
&lt;h2&gt;Two Questions, Forty Years&lt;/h2&gt;
&lt;p&gt;Return to the opening. A ciphertext AES kept perfectly secret, rewritten in transit by an attacker who never read a byte of it, and accepted as authentic -- because the mode answered only the first of two questions. That was not an exotic failure. It was the ordinary shape of every break in this article.&lt;/p&gt;
&lt;p&gt;Run the catalog back through the lens and the pattern is total. Adobe [@troyhunt-adobe-2013], Vaudenay&apos;s padding oracle [@vaudenay-2002], BEAST [@cve-2011-3389], Lucky Thirteen [@lucky-thirteen-2013], POODLE [@cve-2014-3566], Sweet32 [@cve-2016-2183], Efail [@efail-2018], and GCM nonce reuse [@nonce-disrespecting-2016]: in every case, AES or DES did exactly what it promised, and the variable was always &lt;em&gt;which question the design forgot&lt;/em&gt; or &lt;em&gt;which IV/nonce contract it violated&lt;/em&gt;. Not one of these was a cipher break.&lt;/p&gt;
&lt;p&gt;Read that way, the 2024-2026 state of the art is a single move. The field stopped iterating confidentiality modes and standardized the &lt;em&gt;second&lt;/em&gt; answer. Authenticated encryption is the destination -- and its dominant AES instances, GCM and CCM, are literally these very modes plus a MAC, while ChaCha20-Poly1305 and Ascon supply a parallel lineage that is not [@nist-ir-8459][@nist-sp-800-232]. The frontier moved with it: nonce-misuse resistance and key commitment are the properties the deployed defaults still lack.&lt;/p&gt;
&lt;p&gt;The payoff of the field guide is the same as its premise. Master the five not as interchangeable dropdown options but as building blocks with exact contracts, and every break -- past or future -- becomes readable on sight. You do not need to memorize the next CVE. You need one test, and you already have it: &lt;em&gt;which question did this mode answer, and was its IV/nonce contract honored?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;That lens outlives every mode, every cipher, and every standard revision. Which is why this is Part 5 of a field guide to protocol design, not a chapter on five diagrams.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;block-cipher-modes-ecb-to-ctr&quot; keyTerms={[
  { term: &quot;Block cipher&quot;, definition: &quot;A keyed, invertible permutation on one fixed-size block of bits (64 for DES, 128 for AES).&quot; },
  { term: &quot;Mode of operation&quot;, definition: &quot;The wrapper that lifts a one-block cipher to messages of arbitrary length.&quot; },
  { term: &quot;IND-CPA&quot;, definition: &quot;Indistinguishability under chosen-plaintext attack; it forces secure encryption to be randomized or stateful.&quot; },
  { term: &quot;Initialization Vector (IV)&quot;, definition: &quot;A per-message starting value; it must be unpredictable for CBC and CFB.&quot; },
  { term: &quot;Nonce&quot;, definition: &quot;A number used once per key; CTR and OFB need it unique, not unpredictable.&quot; },
  { term: &quot;Malleability&quot;, definition: &quot;An attacker can turn a ciphertext into a predictable change of the plaintext, with no key.&quot; },
  { term: &quot;Message Authentication Code (MAC)&quot;, definition: &quot;A keyed integrity tag that supplies the answer a confidentiality mode omits.&quot; },
  { term: &quot;AEAD&quot;, definition: &quot;Authenticated Encryption with Associated Data; confidentiality and integrity in one primitive.&quot; },
  { term: &quot;Birthday bound&quot;, definition: &quot;Collisions among n-bit values become likely near 2 to the n over 2; the block-size ceiling.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>block-cipher-modes</category><category>aes</category><category>authenticated-encryption</category><category>aead</category><category>cryptography</category><category>cbc</category><category>ctr</category><category>gcm</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>They Read Your Plaintext Without Breaking Your Cipher: A Field Guide to Padding Oracles</title><link>https://paragmali.com/blog/they-read-your-plaintext-without-breaking-your-cipher-a-fiel/</link><guid isPermaLink="true">https://paragmali.com/blog/they-read-your-plaintext-without-breaking-your-cipher-a-fiel/</guid><description>A padding oracle reads your plaintext without touching your key. Why CBC, Vaudenay, Lucky13, and POODLE are one bug -- and why Encrypt-then-MAC ends it.</description><pubDate>Wed, 08 Jul 2026 20:09:31 GMT</pubDate><content:encoded>
A padding oracle lets an attacker read your plaintext without ever touching your key -- and it is not a flaw in AES, in CBC, or even in PKCS#7. It is what you get whenever a receiver reveals *whether an attacker-chosen ciphertext decrypted to well-formed plaintext* before it has proven that ciphertext authentic. That one leaked bit (&quot;was the padding valid?&quot;), plus CBC&apos;s malleability, recovers plaintext one byte at a time -- about 128 guesses per byte -- as Serge Vaudenay showed in 2002 and Juliano Rizzo and Thai Duong weaponized against ASP.NET in 2010.&lt;p&gt;This field guide follows the &lt;em&gt;same&lt;/em&gt; bug leaking through progressively quieter channels: a loud error (Vaudenay), coarse timing (Canvel), statistical timing under unified errors (Lucky Thirteen), SSL 3.0&apos;s unchecked padding (POODLE), and the oracle re-created by Lucky Thirteen&apos;s own fix (CVE-2016-2107). Every point fix lost. The single structural cure is to invert the order: &lt;strong&gt;authenticate before you decrypt-and-unpad.&lt;/strong&gt; Encrypt-then-MAC proves it attains IND-CCA plus INT-CTXT; AEAD, mandated by TLS 1.3, ships it with no knob to misset. The article ends with ranked decision rules and a design-review checklist for 2026.
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
&lt;h2&gt;1. The Break That Never Touched the Key&lt;/h2&gt;
&lt;p&gt;In September 2010, two researchers pointed a few thousand malformed requests at an ordinary ASP.NET application and walked away with its authentication tickets and its &lt;code&gt;web.config&lt;/code&gt; -- the site&apos;s master secrets -- without ever attacking its AES-256 encryption or going near the key [@rizzo_duong_woot2010]. It had done nothing more than return one error when a decrypted request had bad padding and a different error when the padding was fine but the data was not. That one-bit difference is a decryption machine: the attackers never broke the cipher, they turned the server&apos;s error handling into the decryption function.&lt;/p&gt;
&lt;p&gt;Sit with the paradox, because the rest of this article lives inside it. AES-256 was, and is, intact. Nobody factored anything, guessed a key, or exploited a weakness in the block cipher&apos;s rounds. The plaintext walked out the door one byte at a time purely because the server answered a question it should never have been willing to answer: &lt;em&gt;was this ciphertext, which I did not create, well-formed after I decrypted it?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Juliano Rizzo and Thai Duong automated that question against &lt;code&gt;WebResource.axd&lt;/code&gt; and &lt;code&gt;ScriptResource.axd&lt;/code&gt; handlers and recovered Forms-authentication tickets and server files. The United States National Vulnerability Database catalogs it as CVE-2010-3332, the &quot;ASP.NET Padding Oracle Vulnerability,&quot; and Microsoft shipped an out-of-band patch to close it [@cve_2010_3332]. This was not a lab curiosity. It was, at the time, the largest deployed instance of a bug that had been sitting in plain sight for eight years.&lt;/p&gt;

A padding oracle is an attack class, not a cipher weakness. A receiver decrypts an attacker-chosen ciphertext, checks whether the recovered plaintext has valid padding, and reveals the verdict -- through an error message, a timing difference, or any observable behavior. That single accept/reject bit, repeated, becomes a plaintext-recovery oracle that never attacks the underlying cipher or key.
&lt;p&gt;The reframe is worth stating in the sharpest possible terms, because once you hold it you will see this bug everywhere.&lt;/p&gt;

The attacker never attacks the cipher. They turn the receiver&apos;s error handling into the decryption function -- &quot;decrypt, then validate&quot; becomes &quot;decrypt, then confess.&quot;
&lt;p&gt;This is Part 6 of a field guide for protocol designers. It assumes the malleability of CBC mode from Part 5 (the lever the attack pulls) and the &lt;a href=&quot;https://paragmali.com/blog/secure-against-whom-the-security-definitions-every-protocol-/&quot; rel=&quot;noopener&quot;&gt;chosen-ciphertext adversary&lt;/a&gt; from Part 1 (this &lt;em&gt;is&lt;/em&gt; that adversary, deployed and winning). By the end you will carry one diagnostic sentence and drop every named break in this article -- Vaudenay, Lucky Thirteen, POODLE, and tomorrow&apos;s application-layer oracle -- onto it on sight: &lt;em&gt;when a ciphertext you did not create arrives, what does the receiver reveal about it before it has proven the ciphertext authentic?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If AES was intact and the key was never touched, then the machine that recovered the plaintext was built entirely out of the server&apos;s own responses. That idea did not begin with CBC, or even with symmetric cryptography. To see the atom clearly, go back to the first time anyone realized that a receiver&apos;s verdict on validity is itself a decryption function.&lt;/p&gt;
&lt;h2&gt;2. A Validity Check Is a Decryption Oracle&lt;/h2&gt;
&lt;p&gt;The year is 1998, the place is Bell Labs, and Daniel Bleichenbacher is staring at an SSL server that is far too honest. When the server receives an RSA-encrypted message, it decrypts and checks whether the result has the structure that the PKCS #1 v1.5 standard demands. If the structure is wrong, it says so. Bleichenbacher realized that this single yes/no answer -- &lt;em&gt;does the decrypted message have valid PKCS #1 formatting?&lt;/em&gt; -- is enough to recover the plaintext.&lt;/p&gt;
&lt;p&gt;With roughly $2^{20}$ adaptively chosen queries, he could extract an RSA-protected session key without factoring the modulus and without ever learning the private key [@bleichenbacher1998]. The server&apos;s &quot;is this well-formed?&quot; answer &lt;em&gt;was&lt;/em&gt; the attacker&apos;s decryption function. This is the seed of everything that follows.&lt;/p&gt;
&lt;p&gt;It is also the moment to nail down a boundary that expert readers will check for. Bleichenbacher&apos;s attack is an &lt;strong&gt;RSA PKCS #1 v1.5&lt;/strong&gt; oracle -- a different primitive with different arithmetic. It is the conceptual ancestor of the CBC padding-oracle class &quot;in spirit,&quot; but it is never itself a CBC padding oracle [@bleichenbacher1998].Calling Bleichenbacher &quot;the first CBC padding oracle&quot; is a common and consequential error. His target is RSA public-key encryption; the CBC class is symmetric. The shared idea -- a structural validity verdict on attacker-chosen ciphertext leaks the plaintext -- is what makes him the ancestor, not the mechanism. The distinction matters because the family tree has two branches, and confusing them muddles the fix.&lt;/p&gt;

In an adaptive chosen-ciphertext attack, the adversary submits ciphertexts of its choosing and learns something from the receiver&apos;s reaction to each one. A scheme is IND-CCA2 secure only if those reactions leak nothing that helps distinguish or recover plaintext. A padding oracle is precisely a receiver whose reaction leaks -- so it is a live, deployed IND-CCA2 break, the security notion this series defines in Part 1.
&lt;p&gt;The whole subject lives inside that definition. If a receiver&apos;s response to a ciphertext it did not create tells the attacker anything, the game is already lost -- the only question is how expensive the win is.&lt;/p&gt;

Bleichenbacher&apos;s oracle never died; it changed clothes. **DROWN** (2016) revived it by using a server&apos;s SSLv2 support to attack modern TLS [@drown_attack2016]. **ROBOT** (2017 to 2018) found the same PKCS #1 v1.5 oracle live in load balancers and TLS stacks from major vendors, nearly two decades on [@robot_2018]. And the **Marvin Attack** (2023) showed the timing variant still breaks RSA implementations &quot;previously thought immune&quot; [@marvin_attack2023]. All three are RSA-side breaks -- a different primitive from the CBC story told here -- and they appear only as this signpost so nobody mistakes them for CBC oracles. The lesson each one re-teaches is the same: a validity verdict on attacker-chosen input is a decryption oracle, whatever the cipher.
&lt;p&gt;Four years after Bleichenbacher, Serge Vaudenay carried the idea across the aisle from public-key to symmetric cryptography. In &quot;Security Flaws Induced by CBC Padding,&quot; presented at EUROCRYPT 2002, he showed that a receiver which decrypts a CBC ciphertext and reveals whether the padding is valid becomes a plaintext-recovery oracle against SSL, IPSEC, and WTLS [@vaudenay2002]. This is the founding result of the class -- the moment &quot;confidentiality without integrity&quot; was shown to be, in the general case, a decryption oracle waiting to be asked.&lt;/p&gt;
&lt;p&gt;The object it manipulates had arrived on schedule: PKCS #7 padding, the append-&lt;code&gt;n&lt;/code&gt;-bytes-each-equal-to-&lt;code&gt;n&lt;/code&gt; scheme, was standardized as RFC 2315 in the same era, so the manipulable surface and the attack template appeared together [@rfc2315]. Vaudenay&apos;s procedure is documented in cryptography&apos;s standard texts as the canonical illustration of chosen-ciphertext insecurity [@katz_lindell_imc].&lt;/p&gt;

timeline
    title Padding oracles, 1998 to 2022
    1998 : Bleichenbacher RSA PKCS number 1 oracle
    2000 : Bellare-Namprempre composition theorem
    2002 : Vaudenay CBC padding oracle
    2003 : Canvel timing oracle vs TLS
    2010 : ASP.NET break by Rizzo and Duong
    2013 : Lucky Thirteen statistical timing
    2014 : POODLE and RFC 7366 Encrypt-then-MAC
    2016 : CVE-2016-2107, the fix re-creates the oracle
    2018 : TLS 1.3 removes CBC, mandates AEAD
    2022 : BCP 195 recommends against CBC
&lt;p&gt;Vaudenay&apos;s real contribution was noticing that CBC makes the symmetric version &lt;em&gt;cleaner&lt;/em&gt; than Bleichenbacher&apos;s RSA original: flip a byte, watch the verdict, recover a byte. To believe that -- and to earn the right to use it on every later break -- you have to see the arithmetic. It is simpler than it sounds, and once you see it you cannot un-see it in any decrypt-then-check system you review.&lt;/p&gt;
&lt;h2&gt;3. The Atom: Vaudenay&apos;s Oracle, Worked Byte by Byte&lt;/h2&gt;
&lt;p&gt;Everything in this article is one move, performed once here and then reused by every named break with only the &lt;em&gt;channel&lt;/em&gt; changed. Derive it in full and the rest of the piece can move fast. There are three steps: understand the padding, understand the lever, then watch the recovery.&lt;/p&gt;
&lt;h3&gt;Step one: three padding formats, disambiguated once&lt;/h3&gt;
&lt;p&gt;Block ciphers operate on whole blocks, so a message that does not fill the last block must be padded, and the padding must be self-describing so the receiver can strip it. PKCS #7 is the canonical scheme.&lt;/p&gt;

To pad a message to a block boundary, append `n` bytes, each equal to the value `n`. Need three bytes of padding? Append `03 03 03`. Need one? Append `01`. If the message is already block-aligned, append a *full extra block* of padding (for a 16-byte AES block, sixteen bytes of `10`). To unpad, read the final byte `n`, verify that the last `n` bytes all equal `n`, and strip them. Standardized in RFC 2315 [@rfc2315].
&lt;p&gt;Here is the trap that catches expert readers, so disambiguate it now and never again: not every named attack operates on literal PKCS #7 bytes. Three formats matter, and mitigations for one do not automatically cover another.&lt;/p&gt;
&lt;p&gt;PKCS #7 (RFC 2315) requires every pad byte to equal the pad length [@rfc2315]. TLS 1.0 through 1.2 use a PKCS #7-&lt;em&gt;like&lt;/em&gt; scheme where every pad byte equals &lt;code&gt;length - 1&lt;/code&gt;, and -- this detail will return with Lucky Thirteen -- the record is MAC&apos;d, &lt;em&gt;then&lt;/em&gt; padded, &lt;em&gt;then&lt;/em&gt; encrypted [@rfc5246]. SSL 3.0 is the dangerous outlier: its pad bytes are &lt;em&gt;arbitrary&lt;/em&gt;, and only the final length byte is constrained, so there is effectively no padding content to check at all [@rfc6101].&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Padding format&lt;/th&gt;
&lt;th&gt;Pad-byte rule&lt;/th&gt;
&lt;th&gt;What the receiver checks&lt;/th&gt;
&lt;th&gt;Break that targets it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;PKCS #7 (RFC 2315)&lt;/td&gt;
&lt;td&gt;Append &lt;code&gt;n&lt;/code&gt; bytes each equal to &lt;code&gt;n&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Length byte and every pad byte&lt;/td&gt;
&lt;td&gt;Vaudenay&apos;s canonical oracle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TLS 1.0 to 1.2 (RFC 5246)&lt;/td&gt;
&lt;td&gt;Every pad byte equals &lt;code&gt;length - 1&lt;/code&gt;; MAC then pad then encrypt&lt;/td&gt;
&lt;td&gt;Length and pad bytes, after decrypt&lt;/td&gt;
&lt;td&gt;Lucky Thirteen&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSL 3.0 (RFC 6101)&lt;/td&gt;
&lt;td&gt;Pad bytes arbitrary; only the final length byte constrained&lt;/td&gt;
&lt;td&gt;Length byte only; pad bytes unchecked&lt;/td&gt;
&lt;td&gt;POODLE&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The DES-era ancestor is PKCS #5, re-published as RFC 8018, which is the same scheme fixed at an 8-byte block; PKCS #7 generalizes it to any block size up to 255 [@rfc8018]. The two names describe one idea, which is why you see both in old code.&lt;/p&gt;
&lt;p&gt;That single table is why &quot;just make the padding check uniform&quot; was never a complete fix -- it says nothing about SSL 3.0, where there is no pad content to make uniform.&lt;/p&gt;
&lt;h3&gt;Step two: CBC malleability, the lever&lt;/h3&gt;

In CBC decryption, each plaintext block is $P_i = D_k(C_i) \oplus C_{i-1}$: decrypt the current ciphertext block with the block cipher, then XOR the previous ciphertext block. Because that XOR is the last step, an attacker who flips a bit in $C_{i-1}$ deterministically flips the *same* bit in $P_i$ -- steering the plaintext without any knowledge of the key. Part 5 derives this in full; here it is the lever the oracle pulls.

flowchart TD
    Ci[&quot;Target ciphertext block Ct&quot;] --&amp;gt; Dk[&quot;Block cipher decryption Dk&quot;]
    Dk --&amp;gt; Inter[&quot;Intermediate block, equals Dk of Ct&quot;]
    Cprev[&quot;Previous ciphertext block, attacker controls it&quot;] --&amp;gt; XORnode((&quot;XOR&quot;))
    Inter --&amp;gt; XORnode
    XORnode --&amp;gt; Pt[&quot;Recovered plaintext block Pt&quot;]
    Attacker[&quot;Attacker flips byte j of the previous block&quot;] -.-&amp;gt; Cprev
    Attacker -.-&amp;gt; Result[&quot;Byte j of Pt flips by the same amount, no key needed&quot;]
&lt;p&gt;Hold the two pieces together: the receiver will tell you whether a decrypted block has valid padding, and you can steer any byte of that decrypted block by editing the block in front of it. Those two facts are a decryption oracle.&lt;/p&gt;
&lt;h3&gt;Step three: the recovery, last byte first&lt;/h3&gt;
&lt;p&gt;Take a target ciphertext block $C_t$ whose plaintext you want. Prepend a block $C&apos;$ that you fully control, and ask the receiver to decrypt the pair. The receiver computes an intermediate block $I = D_k(C_t)$ and returns the plaintext $P = I \oplus C&apos;$, then checks its padding. You do not know $I$, but you can search for it one byte at a time.&lt;/p&gt;
&lt;p&gt;Fix your attention on the last byte. Vary $C&apos;$&apos;s last byte over all 256 possible values and watch the verdict. For exactly one value, the decrypted last byte becomes &lt;code&gt;0x01&lt;/code&gt;, which is valid single-byte padding, and the receiver accepts. At that instant you know that $I[\text{last}] \oplus C&apos;[\text{last}] = \texttt{0x01}$, so the intermediate byte is $I[\text{last}] = C&apos;[\text{last}] \oplus \texttt{0x01}$. XOR that against the &lt;em&gt;real&lt;/em&gt; previous ciphertext byte and you have recovered a true plaintext byte -- and AES was never touched.&lt;/p&gt;
&lt;p&gt;One honest wrinkle hides inside &quot;about 128 guesses.&quot; A guess can occasionally produce valid &lt;em&gt;longer&lt;/em&gt; padding by luck -- for instance if the plaintext already ended in &lt;code&gt;0x02&lt;/code&gt;, a crafted byte could yield &lt;code&gt;02 02&lt;/code&gt;. So the careful attacker perturbs the second-to-last byte to confirm the intended &lt;code&gt;01&lt;/code&gt; interpretation. That rare double-check is why the average is ~128 rather than a clean 128, and why worst-case is 256.&lt;/p&gt;
&lt;p&gt;To peel the next byte, target two-byte padding: set the known last byte to decrypt to &lt;code&gt;0x02&lt;/code&gt; (you can, because you now know its intermediate), and brute-force the second-to-last byte until the receiver sees &lt;code&gt;02 02&lt;/code&gt;. March inward -- &lt;code&gt;03 03 03&lt;/code&gt;, then &lt;code&gt;04 04 04 04&lt;/code&gt; -- and a full block falls. The cost is about &lt;strong&gt;128 guesses per byte on average and 256 in the worst case&lt;/strong&gt; [@vaudenay2002].&lt;/p&gt;

sequenceDiagram
    participant A as Attacker
    participant O as Oracle receiver
    Note over A,O: Goal, learn the last byte of target block Ct
    A-&amp;gt;&amp;gt;O: Send chosen block Cprime, then Ct
    O-&amp;gt;&amp;gt;O: Decrypt, inspect last-byte padding
    O--&amp;gt;&amp;gt;A: invalid padding
    Note over A: Increment last byte of Cprime, retry
    A-&amp;gt;&amp;gt;O: The value making the last plaintext byte 0x01
    O-&amp;gt;&amp;gt;O: Padding parses as one valid byte
    O--&amp;gt;&amp;gt;A: valid padding
    Note over A,O: Intermediate byte is that guess XOR 0x01
    Note over A: True plaintext byte is intermediate XOR real previous byte
&lt;p&gt;Run the atom yourself. The simulation below models the oracle over a fixed intermediate block -- no real cipher, so you can watch the one-in-256 accept that leaks a byte.&lt;/p&gt;
&lt;p&gt;{`
// A toy padding oracle over a fixed 16-byte &quot;intermediate&quot; block.
// No real crypto: we model I = D_k(C_t) as a known array so you can watch
// the 1-in-256 accept that leaks one plaintext byte.
const BLOCK = 16;&lt;/p&gt;
&lt;p&gt;// Pretend these are the secret intermediate bytes I = D_k(C_t).
const intermediate = [0x8a,0x2f,0x11,0x77,0x4c,0x93,0xe0,0x05,
                      0xbb,0x6d,0x19,0xa4,0x3c,0xf8,0x52,0x7e];
// The real previous-ciphertext block (known to the attacker).
const realPrev = [0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,
                  0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10];&lt;/p&gt;
&lt;p&gt;// Oracle: is the last decrypted byte valid 0x01 padding?
function oracle(cprime) {
  const lastPlain = intermediate[BLOCK-1] ^ cprime[BLOCK-1];
  return lastPlain === 0x01;   // the single leaked bit
}&lt;/p&gt;
&lt;p&gt;// Attack: brute-force the last byte of a controlled block.
let guesses = 0;
const cprime = new Array(BLOCK).fill(0);
for (let g = 0; g &amp;lt; 256; g++) {
  guesses++;
  cprime[BLOCK-1] = g;
  if (oracle(cprime)) {
    const intByte = g ^ 0x01;                    // I[last] = guess XOR 0x01
    const plainByte = intByte ^ realPrev[BLOCK-1];
    console.log(&quot;Accepted after &quot; + guesses + &quot; guesses&quot;);
    console.log(&quot;Recovered intermediate byte: 0x&quot; + intByte.toString(16));
    console.log(&quot;Recovered plaintext byte:    0x&quot; + plainByte.toString(16));
    break;
  }
}
`}&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; One reliable accept/reject bit on attacker-chosen ciphertext, plus CBC&apos;s malleability, is a complete decryption function -- about 128 guesses per byte, and the key is never touched. Every named break in the rest of this article is that same atom, with only the channel that carries the bit changed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That is Aha number one, and it dismantles the mental model most engineers start with. AES-256&apos;s strength was never the variable. The variable was what the receiver was willing to say about a ciphertext it had not authenticated. Before moving on, one point of vocabulary, because it changes how you diagnose the bug.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; A padding oracle is an &lt;em&gt;attack class&lt;/em&gt; -- a side channel against a &lt;em&gt;construction&lt;/em&gt; (CBC-mode encryption composed with a MAC), not a weakness in a primitive. The block cipher (AES) and the MAC (HMAC) are the primitives, and they are doing exactly what they promise. The oracle lives in how they are composed and in what the receiver reveals. Say &quot;attack class&quot; and &quot;construction,&quot; never &quot;the padding-oracle primitive.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The atom needs exactly one thing from the receiver: a distinguishable answer to &quot;was the padding valid?&quot; Vaudenay read that answer off a loud error message. The next fifteen years are the story of the field muffling that answer, one channel at a time -- and the same bit escaping through the next-quietest one every single time.&lt;/p&gt;
&lt;h2&gt;4. One Distinguisher, Four Quieter Channels&lt;/h2&gt;
&lt;p&gt;The atom never changes. What changes is &lt;em&gt;how the accept/reject bit is observed&lt;/em&gt; -- and each time the field silences one channel, the bit re-emerges through a quieter one. Here is the entire failure catalog as one descending staircase, with POODLE branching off to the side.&lt;/p&gt;

flowchart TD
    A[&quot;Loud padding-error message (Vaudenay, ASP.NET)&quot;] --&amp;gt;|&quot;Unify the alert&quot;| B[&quot;Coarse timing gap (Canvel)&quot;]
    B --&amp;gt;|&quot;Compute the MAC anyway&quot;| C[&quot;Statistical timing (Lucky Thirteen)&quot;]
    C --&amp;gt;|&quot;Constant-time AES-NI fast path&quot;| D[&quot;Fix re-creates the oracle (CVE-2016-2107)&quot;]
    D --&amp;gt;|&quot;Verify authenticity first&quot;| F[&quot;Encrypt-then-MAC and AEAD, no verdict to leak&quot;]
    P[&quot;Unchecked padding by spec (POODLE, SSL 3.0)&quot;] --&amp;gt;|&quot;Retire SSL 3.0 and CBC&quot;| F
&lt;p&gt;&lt;strong&gt;Channel one -- the loud error message (Vaudenay 2002, ASP.NET 2010).&lt;/strong&gt; The first receivers simply returned a distinct &quot;padding error,&quot; trivially observable. Vaudenay read it straight off the response, and eight years later Rizzo and Duong read it off differing HTTP responses from ASP.NET applications, recovering authentication tickets and &lt;code&gt;web.config&lt;/code&gt; at scale [@rizzo_duong_woot2010] [@cve_2010_3332]. The obvious countermeasure: return one indistinguishable error for both padding failures and data failures. That closes the loudest channel and opens the next.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Channel two -- coarse timing (Canvel et al. 2003).&lt;/strong&gt; Once OpenSSL returned the &lt;em&gt;same&lt;/em&gt; &lt;code&gt;bad_record_mac&lt;/code&gt; alert for padding and MAC failures, Brice Canvel, Alain Hiltgen, Serge Vaudenay, and Martin Vuagnoux showed the verdict still leaked through &lt;em&gt;when&lt;/em&gt; the alert arrived: a receiver that accepted the padding went on to compute the MAC, while one that rejected padding could bail early, and the resulting millisecond gap reconstituted the oracle [@canvel2003]. They intercepted a password over a live OpenSSL TLS channel. This is the first concrete demonstration of the pattern that organizes the whole subject. The standards response, TLS 1.1 (RFC 4346), mandated uniform alert handling and explicit per-record initialization vectors [@rfc4346]. The countermeasure: make the decryption path constant-time -- compute the MAC even on padding failure so both paths take equal time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Channel three -- statistical timing, Lucky Thirteen (AlFardan and Paterson, 2013).&lt;/strong&gt; This is the break that proved constant-time is &lt;em&gt;the&lt;/em&gt; hard problem, and it is worth binding tightly to the thesis, because it is not merely &quot;a timing attack.&quot; TLS uses MAC-then-encrypt with a specific receiver order: decrypt, &lt;em&gt;strip the padding&lt;/em&gt;, then run HMAC over what remains. The trouble is that &quot;what remains&quot; has a length that depends on how many bytes the receiver treated as padding -- and HMAC&apos;s running time depends on that length, because the hash compression function runs one extra time at certain length thresholds. So the attacker&apos;s &lt;em&gt;guess about the padding&lt;/em&gt; changes the MAC-computation time by a few tens of CPU cycles [@lucky13_2013].&lt;/p&gt;

A comparison (or, more broadly, a code path) is constant-time when its running time does not depend on secret data or on how far into the data a difference occurs. A tag check that returns early on the first mismatched byte leaks *where* the mismatch is; a constant-time check XORs all bytes and inspects the accumulated difference once. Lucky Thirteen forced constant-time unpadding-and-MAC on the whole industry, and CVE-2016-2107 shows how easily a hand-written fast path reintroduces the oracle -- there, through a missing length check that produced a distinguishable alert rather than a timing gap.
&lt;p&gt;Nadhem AlFardan and Kenneth Paterson amplified that sub-microsecond difference statistically across the network, recovering a full plaintext block in about $2^{23}$ TLS sessions, dropping to roughly $2^{13}$ sessions per byte with favorable positioning, across OpenSSL, GnuTLS, PolarSSL, and more (CVE-2013-0169) [@lucky13_2013] [@cve_2013_0169]. Bind it to the ordering: MAC-then-encrypt &lt;em&gt;forces&lt;/em&gt; a length-dependent MAC, so the timing leak is a property of the order of operations, not a stray implementation slip.The name &quot;Lucky Thirteen&quot; comes from the 13 bytes TLS feeds into the HMAC before the record body: a 5-byte TLS record header plus an 8-byte sequence number. Their alignment against the 64-byte hash-compression boundary is exactly what opens the timing gap. A number that sounds whimsical is really a byte-counting accident. The next countermeasure was obvious and genuinely hard: make the MAC and the unpadding constant-time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Channel four -- unchecked structure, POODLE (Moller, Duong, and Kotowicz 2014).&lt;/strong&gt; Here the staircase forks into a parallel branch. SSL 3.0&apos;s pad bytes are &lt;em&gt;arbitrary by specification&lt;/em&gt; -- only the final length byte is constrained -- so there is no padding check to harden, no message to unify, no timing to flatten [@rfc6101]. An attacker who maneuvers a target byte into the last position of a block learns it from &lt;em&gt;MAC pass or fail alone&lt;/em&gt;, needing neither an error message nor a timing measurement, at an expected cost of 256 SSL 3.0 requests per byte [@poodle_writeup] [@cve_2014_3566]. The name expands to Padding Oracle On Downgraded Legacy Encryption, and this is where a persistent misconception must be corrected.POODLE&apos;s downgrade is the &lt;em&gt;enabler&lt;/em&gt;, not the bug. The downgrade only forces a modern client back onto vulnerable SSL 3.0; the vulnerability is the unchecked pad. The proof is TLS-POODLE (CVE-2014-8730), which hit TLS stacks that copied SSL 3.0&apos;s lax padding check and works with &lt;em&gt;no downgrade at all&lt;/em&gt; [@cve_2014_8730]. Frame POODLE as a padding oracle first, a downgrade second. Google&apos;s write-up and the accompanying announcement documented the mechanism and effort in full [@poodle_writeup] [@google_poodle_blog]. Because there is no check to make uniform, the only fix is to remove SSL 3.0, and CBC, from the wire entirely.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Channel five -- the oracle the fix re-created (CVE-2016-2107, 2016).&lt;/strong&gt; This is the single clearest proof of the thesis. OpenSSL&apos;s AES-NI assembly fast path, written to make the Lucky Thirteen countermeasure constant-time, mishandled a length check -- and re-opened a padding oracle. It was found with the TLS-Attacker fuzzing methodology [@somorovsky_fuzzing2016], and the National Vulnerability Database records the cause in words worth quoting exactly.&lt;/p&gt;

This vulnerability [CVE-2016-2107] exists because of an incorrect fix for CVE-2013-0169.
&lt;p&gt;The constant-time patch for Lucky Thirteen re-created the very oracle it was written to close, and OpenSSL shipped the repair in 1.0.2h and 1.0.1t [@cve_2016_2107] [@openssl_secadv_20160503]. It did not travel alone. Amazon&apos;s s2n library added a Lucky Thirteen countermeasure that still leaked, revived as Lucky Microseconds by Martin Albrecht and Kenneth Paterson -- and the randomized delays s2n had added as masking were part of the problem [@lucky_microseconds2016].&lt;/p&gt;
&lt;p&gt;Then, in 2019, Craig Young&apos;s Zombie POODLE and GOLDENDOODLE and a large Internet scan by Robert Merget and colleagues found CBC padding oracles still live in 1.83% of the Alexa Top Million, distinguishable by the &lt;em&gt;content&lt;/em&gt; of server responses with no precise timing required at all [@merget2019] [@qualys_zombie_poodle2019].&lt;/p&gt;
&lt;p&gt;Zombie POODLE is an invalid-padding, valid-MAC oracle; GOLDENDOODLE is the mirror image, a valid-padding, invalid-MAC oracle. Different verdicts, same atom.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Incident&lt;/th&gt;
&lt;th&gt;Year&lt;/th&gt;
&lt;th&gt;Leak channel&lt;/th&gt;
&lt;th&gt;Root cause&lt;/th&gt;
&lt;th&gt;Primary source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Vaudenay&lt;/td&gt;
&lt;td&gt;2002&lt;/td&gt;
&lt;td&gt;Distinct padding error&lt;/td&gt;
&lt;td&gt;MtE-CBC observable branch&lt;/td&gt;
&lt;td&gt;[@vaudenay2002]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Canvel et al.&lt;/td&gt;
&lt;td&gt;2003&lt;/td&gt;
&lt;td&gt;Coarse timing&lt;/td&gt;
&lt;td&gt;MAC computed vs skipped&lt;/td&gt;
&lt;td&gt;[@canvel2003]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ASP.NET (Rizzo, Duong)&lt;/td&gt;
&lt;td&gt;2010&lt;/td&gt;
&lt;td&gt;Distinct HTTP error&lt;/td&gt;
&lt;td&gt;Padding vs data error revealed&lt;/td&gt;
&lt;td&gt;[@rizzo_duong_woot2010] [@cve_2010_3332]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lucky Thirteen&lt;/td&gt;
&lt;td&gt;2013&lt;/td&gt;
&lt;td&gt;Statistical timing&lt;/td&gt;
&lt;td&gt;Strip-then-MAC length dependence&lt;/td&gt;
&lt;td&gt;[@lucky13_2013] [@cve_2013_0169]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;POODLE&lt;/td&gt;
&lt;td&gt;2014&lt;/td&gt;
&lt;td&gt;MAC pass or fail on shifted byte&lt;/td&gt;
&lt;td&gt;SSL 3.0 unchecked padding&lt;/td&gt;
&lt;td&gt;[@poodle_writeup] [@cve_2014_3566]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TLS-POODLE&lt;/td&gt;
&lt;td&gt;2014&lt;/td&gt;
&lt;td&gt;Same, no downgrade&lt;/td&gt;
&lt;td&gt;TLS stacks copying the lax check&lt;/td&gt;
&lt;td&gt;[@cve_2014_8730]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CVE-2016-2107&lt;/td&gt;
&lt;td&gt;2016&lt;/td&gt;
&lt;td&gt;Distinguishable alert (bad_record_mac vs record_overflow)&lt;/td&gt;
&lt;td&gt;Constant-time fix slipped a length check&lt;/td&gt;
&lt;td&gt;[@cve_2016_2107]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zombie POODLE, GOLDENDOODLE&lt;/td&gt;
&lt;td&gt;2019&lt;/td&gt;
&lt;td&gt;Content differences in responses&lt;/td&gt;
&lt;td&gt;Deployed CBC-HMAC long tail, 1.83%&lt;/td&gt;
&lt;td&gt;[@merget2019] [@qualys_zombie_poodle2019]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Never return a distinct &quot;bad padding&quot; error, and never let padding validity change a branch or the timing of the response. Any distinguishable decryption outcome on attacker-chosen ciphertext -- an error string, a millisecond, a TCP reset, a difference in response content -- is a padding oracle. The channel does not matter; the observability does.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;One clarification sharpens the definition by contrast. BEAST (2011) is often filed next to these breaks, but it is &lt;em&gt;not&lt;/em&gt; a padding oracle: it is a &lt;a href=&quot;https://paragmali.com/blog/predictable-or-repeated-the-only-two-ways-cryptographic-rand/&quot; rel=&quot;noopener&quot;&gt;predictable-initialization-vector&lt;/a&gt;, chosen-plaintext attack on CBC [@beast_2011], and it belongs to the IV story of Part 2 and Part 5, not here.The tell is the direction of information flow. A padding oracle recovers &lt;em&gt;unknown&lt;/em&gt; plaintext from the receiver&apos;s verdict on the attacker&apos;s ciphertext. BEAST confirms &lt;em&gt;guessed&lt;/em&gt; plaintext by exploiting a predictable IV. Different precondition, different fix -- naming it here only sharpens what a padding oracle is.&lt;/p&gt;
&lt;p&gt;Five generations, five channels, one bit. Every fix silenced the loudest remaining leak, and every fix was beaten by the next-quietest -- including a fix that became its own oracle. Whack-a-mole is not a strategy; it is a symptom. And the symptom points at a diagnosis the field had actually proved correct two years before Vaudenay&apos;s attack, and simply had not deployed.&lt;/p&gt;
&lt;h2&gt;5. The Bug Is the Order, Not the Padding&lt;/h2&gt;
&lt;p&gt;Stop looking at the padding. A padding oracle is not a padding bug; it is the consequence of &lt;em&gt;checking padding on data you have not authenticated&lt;/em&gt;. Change what you check first, and the oracle has nothing to answer. To see why, you need the piece the attack has been quietly relying on: the MAC, and the three ways to combine it with encryption.&lt;/p&gt;

A MAC is a keyed tag that proves a message is authentic and unmodified: only a holder of the secret key can produce a tag that verifies. HMAC is the deployed instance. A valid MAC on a ciphertext means the ciphertext is genuine -- it came from someone with the key, and nothing tampered with it. Part 3 covers HMAC&apos;s structure; here the point is simply *when* you check it.
&lt;p&gt;In 2000, Mihir Bellare and Chanathip Namprempre formalized the three &quot;generic composition&quot; ways to bolt a MAC onto an encryption scheme and proved exactly what each one buys [@bellare_namprempre2000]. Each maps cleanly onto a real protocol.&lt;/p&gt;

Compute the MAC over the *plaintext*, then encrypt the plaintext, MAC, and padding together. On receipt the order is forced: decrypt, strip padding, *then* verify the MAC. Because the receiver must decrypt and unpad before it can check authenticity, the padding verdict is observable by construction. This is SSL and TLS&apos;s original choice -- and the reason SSL/TLS, and only SSL/TLS, became a fifteen-year catalog of padding oracles.

Encrypt the plaintext, then compute the MAC over the *ciphertext* (and the IV), and transmit ciphertext plus tag. On receipt, verify the tag *first*; decrypt only if it passes. A ciphertext the attacker altered fails the MAC and is discarded before any padding logic runs -- so there is no padding verdict to leak, through any channel. This is IPsec ESP&apos;s design and the shape RFC 7366 retrofits onto TLS.
&lt;p&gt;The third sibling, encrypt-and-MAC, tags the plaintext and sends the tag alongside the ciphertext; SSH chose it. It still forces decryption before verification, and because the tag is over the plaintext it can leak plaintext equality, so it is no cure [@bellare_kohno_namprempre_ssh2002].&lt;/p&gt;

flowchart TD
    subgraph MtE[&quot;MAC-then-encrypt (SSL and TLS)&quot;]
        M1[&quot;Decrypt&quot;] --&amp;gt; M2[&quot;Strip padding&quot;] --&amp;gt; M3[&quot;Verify MAC&quot;]
    end
    subgraph EnM[&quot;Encrypt-and-MAC (SSH)&quot;]
        E1[&quot;Decrypt&quot;] --&amp;gt; E2[&quot;Verify MAC over plaintext&quot;]
    end
    subgraph EtM[&quot;Encrypt-then-MAC (IPsec ESP)&quot;]
        T1[&quot;Verify MAC over IV and ciphertext&quot;] --&amp;gt; T2[&quot;Decrypt&quot;] --&amp;gt; T3[&quot;Strip padding&quot;]
    end
&lt;p&gt;Look at where the MAC check sits. In the first two, unauthenticated ciphertext reaches the decrypt-and-parse machinery &lt;em&gt;before&lt;/em&gt; anyone has proven it genuine. In the third, a forged ciphertext dies at the door.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Composition&lt;/th&gt;
&lt;th&gt;MAC covers&lt;/th&gt;
&lt;th&gt;Receiver order&lt;/th&gt;
&lt;th&gt;IND-CCA (generic)&lt;/th&gt;
&lt;th&gt;INT-CTXT (generic)&lt;/th&gt;
&lt;th&gt;Protocol&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;MAC-then-encrypt&lt;/td&gt;
&lt;td&gt;Plaintext&lt;/td&gt;
&lt;td&gt;Decrypt, unpad, verify&lt;/td&gt;
&lt;td&gt;Not guaranteed&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;SSL and TLS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Encrypt-and-MAC&lt;/td&gt;
&lt;td&gt;Plaintext&lt;/td&gt;
&lt;td&gt;Decrypt, verify&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;SSH&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Encrypt-then-MAC&lt;/td&gt;
&lt;td&gt;Ciphertext and IV&lt;/td&gt;
&lt;td&gt;Verify, decrypt, unpad&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;IPsec ESP&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Now the theorem, stated precisely. Encrypt-then-MAC, composed from an IND-CPA encryption scheme and a strongly unforgeable MAC (SUF-CMA), generically attains both IND-CCA and integrity of ciphertexts -- the strongest guarantees of the three -- while MAC-then-encrypt and encrypt-and-MAC do not generically reach integrity of ciphertexts [@bellare_namprempre2000]. Strong unforgeability is the load-bearing word: with only ordinary unforgeability, a second valid tag on the same ciphertext is a fresh accepted ciphertext, and the guarantee weakens to integrity of &lt;em&gt;plaintexts&lt;/em&gt;. In practice the qualifier is free, because HMAC is strongly unforgeable, so the deployed guarantee is exactly as stated. That is the whole game: a construction with integrity of ciphertexts rejects any forged ciphertext &lt;em&gt;before&lt;/em&gt; decryption, so a padding oracle cannot form.&lt;/p&gt;
&lt;p&gt;One honest caveat, because the sloppy version of this claim is wrong. Hugo Krawczyk proved in 2001 that MAC-then-encrypt &lt;em&gt;is&lt;/em&gt; secure when the encryption is CBC or counter mode, under stated conditions [@krawczyk2001]. So MtE is not &quot;always broken.&quot;Krawczyk&apos;s result is conditional: MtE with CBC or CTR is provably secure &lt;em&gt;in the model&lt;/em&gt;, which means Canvel, Lucky Thirteen, and POODLE are implementation, side-channel, and underspecified-padding failures -- not refutations of a theorem. The precise statement guards against the overreach &quot;MtE is broken.&quot; What is true is subtler and more useful: MtE is conditionally provable and practically fragile, because it leaves unauthenticated ciphertext reaching the parser, and holding the model&apos;s assumptions in compiled code is the hard part [@krawczyk2001]. The practitioner&apos;s takeaway is not &quot;the theorem was wrong&quot; but &quot;the theorem&apos;s assumptions are unreasonably hard to preserve in real code -- so change the order and stop needing them.&quot; The practitioner literature has said as much for years [@ferguson_schneier_kohno_ce].&lt;/p&gt;
&lt;p&gt;Watch the difference on a single tampered ciphertext. The MtE receiver leaks a distinguishable outcome; the EtM receiver returns one indistinguishable failure before it parses anything.&lt;/p&gt;
&lt;p&gt;{`
// Two toy receivers over the SAME tampered ciphertext.
// No real crypto: &quot;decrypt&quot; and &quot;macOk&quot; are stand-ins so you can see
// what each receiver reveals.
function decrypt(ct)  { return { paddingValid: false }; } // tampering broke the pad
function macOk(ct)    { return ct.tag === &quot;authentic&quot;; }  // forged tag fails&lt;/p&gt;
&lt;p&gt;const tampered = { tag: &quot;forged&quot; };&lt;/p&gt;
&lt;p&gt;// MAC-then-encrypt: decrypt and check padding BEFORE the MAC.
function mteReceive(ct) {
  const p = decrypt(ct);
  if (!p.paddingValid) return &quot;PADDING_ERROR&quot;;  // leaks the padding verdict
  if (!macOk(ct))      return &quot;MAC_ERROR&quot;;
  return &quot;OK&quot;;
}&lt;/p&gt;
&lt;p&gt;// Encrypt-then-MAC: verify the MAC FIRST; never touch padding on forgeries.
function etmReceive(ct) {
  if (!macOk(ct)) return &quot;FAIL&quot;;                // one indistinguishable outcome
  const p = decrypt(ct);
  if (!p.paddingValid) return &quot;FAIL&quot;;
  return &quot;OK&quot;;
}&lt;/p&gt;
&lt;p&gt;console.log(&quot;MtE says:&quot;, mteReceive(tampered)); // PADDING_ERROR (distinguishable)
console.log(&quot;EtM says:&quot;, etmReceive(tampered)); // FAIL (nothing to learn)
`}&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The bug is the &lt;em&gt;order&lt;/em&gt;, not the padding. Silencing channels is whack-a-mole; checking authenticity &lt;em&gt;first&lt;/em&gt; -- Encrypt-then-MAC, and its successor AEAD -- removes the precondition that unauthenticated ciphertext ever reaches a padding check, so the oracle has nothing left to answer.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That is Aha number two, and it reorganizes the entire catalog. Every generation before Encrypt-then-MAC silenced a channel while leaving the precondition intact; the last two remove the precondition itself.&lt;/p&gt;

flowchart TD
    G1[&quot;Gen 1, distinct padding error&quot;] --&amp;gt; G2[&quot;Gen 2, unified alert&quot;]
    G2 --&amp;gt; G3[&quot;Gen 3, constant-time MtE&quot;]
    G3 --&amp;gt; G4[&quot;Gen 4, Encrypt-then-MAC&quot;]
    G4 --&amp;gt; G5[&quot;Gen 5, AEAD&quot;]
    G1 -.-&amp;gt; S[&quot;Silenced a channel, precondition intact&quot;]
    G2 -.-&amp;gt; S
    G3 -.-&amp;gt; S
    G4 -.-&amp;gt; R[&quot;Removed the precondition, authenticity first&quot;]
    G5 -.-&amp;gt; R

The three compositions were not tried in sequence; they were chosen in *parallel* by different protocols and coexisted for years. MAC-then-encrypt went into SSL and TLS, encrypt-and-MAC into SSH, Encrypt-then-MAC into IPsec ESP [@bellare_namprempre2000]. Only the MtE branch became the fifteen-year catalog. IPsec&apos;s Encrypt-then-MAC branch was structurally immune from the start, which is the quiet punchline of the whole story: the fix TLS reached for in 2014 was, in effect, &quot;become IPsec&quot; -- the negotiated `encrypt_then_mac` extension of RFC 7366 [@rfc7366].
&lt;p&gt;AEAD (RFC 5116) is Encrypt-then-MAC&apos;s standardized successor: one primitive, authenticity intrinsic, no composition knob to misset [@rfc5116]. The theorem was published in 2000. Vaudenay&apos;s attack landed in 2002. And the fix did not reach the deployed TLS base until 2014 to 2018. The rest of this article is what &quot;check authenticity first&quot; looks like when it finally shipped at Internet scale -- and why, even now, the class is not entirely dead.&lt;/p&gt;
&lt;h2&gt;6. The State of the Art: Closed by Construction&lt;/h2&gt;
&lt;p&gt;The modern answer is boring, and that is exactly the point. Use a primitive where a padding oracle &lt;em&gt;cannot exist&lt;/em&gt;, because authenticity is checked first and there is no block padding at all.&lt;/p&gt;

An AEAD primitive takes a key, a nonce, a plaintext, and optional associated data, and produces a ciphertext with an integral authentication tag. Decryption verifies the tag as part of the operation and returns *nothing* -- a single indistinguishable failure -- if it does not match. There is no separate MAC to order, and for the stream-based AEADs in wide use there is no block padding to be oracular. Standardized as an interface in RFC 5116 [@rfc5116].
&lt;p&gt;Two AEADs carry nearly all modern traffic. &lt;strong&gt;AES-GCM&lt;/strong&gt; is the default where AES hardware exists: it is AES in counter mode for encryption, plus a GHASH tag over the ciphertext and associated data, verified before any plaintext is released. &lt;strong&gt;ChaCha20-Poly1305&lt;/strong&gt; is the default where AES hardware does not exist -- Google deployed it in Chrome on Android because it runs about three times faster than AES-GCM on devices without AES acceleration, and it is constant-time in portable software by design [@rfc8439] [@google_chacha_blog2014]. Both are counter-mode stream constructions, and that structural fact, not the label &quot;AEAD,&quot; is why they are immune.A stream construction has &lt;em&gt;no block padding at all&lt;/em&gt; -- the keystream is simply truncated to the plaintext length. So the object Vaudenay&apos;s atom acts on, a padded final block whose validity the receiver checks, does not exist. There is no surface. This is why &quot;GCM has a tag, could it have a padding oracle?&quot; answers itself: there is nothing to pad.&lt;/p&gt;
&lt;p&gt;Then the standards removed the choice. TLS 1.3 (RFC 8446, 2018) removes CBC cipher suites entirely and mandates AEAD, and QUIC inherits that record layer, so a conformant modern stack cannot express the padding-oracle precondition [@rfc8446].&lt;/p&gt;
&lt;p&gt;For the deployed base that could not jump straight to 1.3, RFC 7366 (2014) retrofits Encrypt-then-MAC onto TLS 1.0 through 1.2 as a negotiated extension -- extension type 22 -- citing Bellare-Namprempre and Krawczyk by name as the reason MtE &quot;is no longer regarded as secure&quot; [@rfc7366]. And BCP 195 (RFC 9325, 2022) codifies the operational rule: prefer TLS 1.3, prefer AEAD suites on 1.2, and recommend against CBC [@rfc9325].&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;How it works&lt;/th&gt;
&lt;th&gt;What it buys&lt;/th&gt;
&lt;th&gt;Status 2024 to 2026&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;AES-GCM&lt;/td&gt;
&lt;td&gt;AES-CTR plus GHASH tag, verified first&lt;/td&gt;
&lt;td&gt;No padding surface, fastest with AES hardware&lt;/td&gt;
&lt;td&gt;Default (TLS 1.3, QUIC)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ChaCha20-Poly1305&lt;/td&gt;
&lt;td&gt;ChaCha20 plus Poly1305, verified first&lt;/td&gt;
&lt;td&gt;Constant-time in software, ~3x without AES-NI&lt;/td&gt;
&lt;td&gt;Co-default, WireGuard, OpenSSH&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Encrypt-then-MAC (RFC 7366)&lt;/td&gt;
&lt;td&gt;MAC over IV and ciphertext, verified first&lt;/td&gt;
&lt;td&gt;Structural fix for legacy CBC&lt;/td&gt;
&lt;td&gt;Compose-by-hand rule&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Constant-time CBC-HMAC&lt;/td&gt;
&lt;td&gt;Harden the MtE order in place&lt;/td&gt;
&lt;td&gt;Nothing new; fragile&lt;/td&gt;
&lt;td&gt;Deprecated (BCP 195)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Misuse-resistant, committing AEAD&lt;/td&gt;
&lt;td&gt;AES-GCM-SIV, committing wrappers&lt;/td&gt;
&lt;td&gt;Nonce-repeat safety, key commitment&lt;/td&gt;
&lt;td&gt;Ascending, niche&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Padding-oracle detection&lt;/td&gt;
&lt;td&gt;TLS-Attacker, padcheck scanners&lt;/td&gt;
&lt;td&gt;Measures residual exposure&lt;/td&gt;
&lt;td&gt;Active tooling&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The honest status has two levels. At the primitive level the class is &lt;em&gt;closed&lt;/em&gt;: TLS 1.3 has no CBC-HMAC record layer, so it has no padding oracle. But CBC-HMAC survives in the long tail -- legacy TLS, VPN appliances, load balancers, IoT stacks, and home-grown application crypto -- which is why padding oracles are still discovered, in 1.83% of the top million as recently as the 2019 scan, exploitable without precise timing [@merget2019].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Treat any distinguishable decryption error on a CBC-HMAC endpoint as a reportable finding, not a performance bug to smooth over. The lesson of five generations is that the construction, not any single leak, is the problem: CBC-HMAC is the thing to &lt;em&gt;retire&lt;/em&gt;. Every hour spent hardening its constant-time behavior is an hour not spent migrating to AEAD, which needs no such hardening.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&quot;Use AEAD&quot; is the entire answer for greenfield code. But engineers inherit constraints -- a mode they cannot change, a library without AEAD, a protocol mid-migration -- so the real question is not &quot;what is best&quot; but &quot;what are my options, ranked, and exactly when does each apply?&quot;&lt;/p&gt;
&lt;h2&gt;7. How to Not Have a Padding Oracle, Ranked&lt;/h2&gt;
&lt;p&gt;There are three ways to keep a padding oracle out of your system, in strict order of durability -- and the ranking is a theorem, not a taste. The yardstick is one question: &lt;em&gt;is authenticity checked before anything parses the plaintext?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;First choice: AEAD.&lt;/strong&gt; Authenticity is intrinsic, there is no padding, and there are &lt;em&gt;zero composition knobs&lt;/em&gt; for an implementer to misset. This is the default, full stop. Its own frontier is a genuinely different problem, not a padding successor: nonce reuse under AES-GCM is catastrophic -- the &quot;forbidden attack,&quot; demonstrated against real TLS and IPMI stacks by Böck et al. (WOOT &apos;16) [@bock_nonce_woot2016] -- and standard AEAD is not key-committing, so one ciphertext can be made to open to different valid plaintexts under different keys [@albertini_committing2022]. Those are addressed by AES-GCM-SIV for nonce-misuse resistance and by committing AEAD constructions, which the CFRG&apos;s property vocabulary now names formally [@rfc8452] [@rfc9771]. Treat that as a one-line signpost, not a reason to hesitate on AEAD.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Second choice: Encrypt-then-MAC by hand.&lt;/strong&gt; Correct, but only if you get three things right -- an &lt;em&gt;independent&lt;/em&gt; MAC key (never the encryption key), coverage of &lt;em&gt;both&lt;/em&gt; the IV and the ciphertext, and a &lt;em&gt;constant-time&lt;/em&gt; tag comparison performed &lt;em&gt;before&lt;/em&gt; any decrypt or unpad. That is the RFC 7366 shape [@rfc7366]. Three knobs an implementer can misset is precisely the argument for reaching for AEAD&apos;s zero knobs whenever you can.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Third choice, and only if forced: constant-time MtE / CBC-HMAC.&lt;/strong&gt; This is the &quot;make the existing order safe in place&quot; path, and it is the cautionary option to &lt;em&gt;retire&lt;/em&gt;, not to choose. Lucky Thirteen, Lucky Microseconds, and CVE-2016-2107 are the evidence that it fights the construction: MtE keeps unauthenticated ciphertext reaching the parser, so the distinguisher re-emerges through whatever the CPU or the compiler leaves open [@lucky13_2013] [@cve_2016_2107].&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;AES-GCM&lt;/th&gt;
&lt;th&gt;ChaCha20-Poly1305&lt;/th&gt;
&lt;th&gt;Encrypt-then-MAC (CBC-HMAC)&lt;/th&gt;
&lt;th&gt;Constant-time MtE (CBC-HMAC)&lt;/th&gt;
&lt;th&gt;AES-GCM-SIV&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Authenticity checked first?&lt;/td&gt;
&lt;td&gt;Yes (intrinsic)&lt;/td&gt;
&lt;td&gt;Yes (intrinsic)&lt;/td&gt;
&lt;td&gt;Yes (verify tag first)&lt;/td&gt;
&lt;td&gt;No (decrypt and unpad first)&lt;/td&gt;
&lt;td&gt;Yes (intrinsic)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Padding-oracle surface&lt;/td&gt;
&lt;td&gt;None (stream)&lt;/td&gt;
&lt;td&gt;None (stream)&lt;/td&gt;
&lt;td&gt;None (rejected pre-unpad)&lt;/td&gt;
&lt;td&gt;Full (precondition survives)&lt;/td&gt;
&lt;td&gt;None (stream)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Composition knobs to misset&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Many&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nonce or IV reuse behavior&lt;/td&gt;
&lt;td&gt;Catastrophic&lt;/td&gt;
&lt;td&gt;Catastrophic&lt;/td&gt;
&lt;td&gt;IV must be unpredictable&lt;/td&gt;
&lt;td&gt;IV must be unpredictable&lt;/td&gt;
&lt;td&gt;Graceful (equality leak only)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Status 2024 to 2026&lt;/td&gt;
&lt;td&gt;Active default&lt;/td&gt;
&lt;td&gt;Active co-default&lt;/td&gt;
&lt;td&gt;Compose-by-hand rule&lt;/td&gt;
&lt;td&gt;Deprecated (BCP 195)&lt;/td&gt;
&lt;td&gt;Ascending, niche&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Only the first two options remove the &lt;em&gt;precondition&lt;/em&gt;; the third merely silences the loudest channel. That is the whole ranking, and it maps onto the parallel history from the last section: AEAD and Encrypt-then-MAC are what IPsec effectively had from the start, while constant-time MtE is the fifteen-year attempt to make SSL/TLS&apos;s original order safe without changing it.&lt;/p&gt;
&lt;p&gt;So the durable options all share one property: they refuse to let unauthenticated ciphertext reach a parser. That raises a deeper question a careful reader should now be asking. &lt;em&gt;Why&lt;/em&gt; is one accept/reject bit enough to be fatal in the first place -- and is Encrypt-then-MAC &lt;em&gt;provably&lt;/em&gt; enough to stop it, or just empirically better so far?&lt;/p&gt;
&lt;h2&gt;8. Why a Bit Is Enough, and Why the Fix Is a Theorem&lt;/h2&gt;
&lt;p&gt;Two boundaries frame the whole subject: how &lt;em&gt;little&lt;/em&gt; leakage the attacker needs, which is frighteningly little, and how &lt;em&gt;hard&lt;/em&gt; the defender&apos;s guarantee actually is, which is a proof rather than a hope.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The lower bound: one reliable bit suffices.&lt;/strong&gt; A single accept/reject bit per query, combined with CBC&apos;s malleability, recovers plaintext at about 128 guesses per byte, and the cipher is never attacked [@vaudenay2002]. The consequence is a hard limit on defense that every engineer should internalize: there is no &quot;leak too small to matter,&quot; only &quot;too noisy to measure cheaply.&quot; The bit is information-theoretically sufficient; the only variable is how many queries it takes to read it reliably.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Lucky Thirteen turned a difference of a few tens of CPU cycles -- invisible to a human, buried in network jitter -- into full plaintext recovery by amplifying it statistically over many sessions [@lucky13_2013]. If a one-bit distinguisher exists at all, &quot;make it quieter&quot; only raises the query count; it never reaches zero. The only defense that reduces the leak to &lt;em&gt;nothing&lt;/em&gt; is removing the precondition, so no bit is ever produced.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;The impossibility in the middle.&lt;/strong&gt; An unauthenticated, malleable mode is provably not IND-CCA2. CBC without integrity is a decryption oracle by construction, so no amount of error-message hygiene or timing equalization can rescue MAC-then-encrypt CBC against a determined side-channel adversary. The impossibility lives in the &lt;em&gt;precondition itself&lt;/em&gt; -- in letting a malleable ciphertext be decrypted before it is authenticated -- which is why the deployed padding oracle is exactly the &lt;a href=&quot;https://paragmali.com/blog/secure-against-whom-the-security-definitions-every-protocol-/&quot; rel=&quot;noopener&quot;&gt;IND-CCA2 break&lt;/a&gt; this series defines in Part 1.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The upper bound: the fix is a hard theorem.&lt;/strong&gt; The best achievable defense is a proved one.&lt;/p&gt;

A scheme has integrity of ciphertexts when an adversary, even after seeing many valid ciphertexts, cannot produce *any* new ciphertext the receiver accepts as valid. This is the property that closes the oracle: if every forged ciphertext is rejected before decryption, the receiver never reveals a padding verdict on attacker-chosen input. Encrypt-then-MAC and AEAD provide it; MAC-then-encrypt does not, generically.
&lt;p&gt;Encrypt-then-MAC with an IND-CPA cipher and a strongly unforgeable MAC (SUF-CMA) generically attains IND-CCA plus integrity of ciphertexts, so a forged ciphertext is rejected with overwhelming probability &lt;em&gt;before&lt;/em&gt; decryption -- the oracle is closed by theorem, not by patch [@bellare_namprempre2000]. Krawczyk marks the honest boundary of the alternative: MAC-then-encrypt is conditionally provable for CBC and counter mode, so the real-world MtE breaks are implementation and side-channel failures, not refutations of a theorem -- but Encrypt-then-MAC needs no such conditions [@krawczyk2001].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; At the level of construction design there is no gap. The lower bound -- any observable padding verdict yields byte-at-a-time decryption -- is &lt;em&gt;met&lt;/em&gt; by removing the precondition, and the upper bound -- reject forgeries before decryption, IND-CCA plus INT-CTXT -- is &lt;em&gt;achieved&lt;/em&gt; by Encrypt-then-MAC and AEAD. Best-possible and best-achieved coincide. Every remaining gap is implementation and deployment, not mathematics.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That is Aha number three, and it is a humbler note than it first sounds. If the design problem is provably solved, why do scanners still find these oracles in production, and why did a correct construction get re-broken by its own patch? Because &quot;solved on paper&quot; and &quot;solved in a compiled binary on a specific CPU, deployed to a billion devices&quot; are different sentences -- and the space between them is where the class still lives.&lt;/p&gt;
&lt;h2&gt;9. Where Padding Oracles Still Live&lt;/h2&gt;
&lt;p&gt;The construction-level problem is closed; the &lt;em&gt;class&lt;/em&gt; is not. Here are four places the 2002 bug remains exploitable, and one frontier that would end the whack-a-mole.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Constant-time is a moving target.&lt;/strong&gt; Even with the correct construction, a specific compiled binary on a specific CPU can reintroduce a secret-dependent timing difference through branch prediction, cache behavior, or an assembly fast path -- and the countermeasure can also slip in a plainer way. CVE-2016-2107 is the canonical evidence: OpenSSL&apos;s AES-NI fast path, written to make the fix constant-time, dropped a length check and re-created the oracle -- leaking not through timing but through a distinguishable alert (bad_record_mac versus record_overflow), which is why TLS-Attacker found it by clustering responses rather than measuring cycles [@cve_2016_2107]. The strongest partial answer is formally verified, secret-independent cryptographic code -- HACL* and EverCrypt prove memory safety, functional correctness, &lt;em&gt;and&lt;/em&gt; secret independence, and ship in Firefox and NSS [@hacl_star]. But that covers primitives, not yet whole record layers end to end, so the verification frontier is real.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The deployed CBC-HMAC long tail.&lt;/strong&gt; Legacy TLS, VPN appliances, load balancers, and IoT stacks that cannot move to TLS 1.3 keep MAC-then-encrypt CBC alive. The 2019 scan put the exposure at 1.83% of the top million, exploitable without precise timing, and the population shrinks year over year rather than vanishing -- a trend the SSL Pulse dashboard tracks [@merget2019] [@ssl_pulse].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Application-layer oracles.&lt;/strong&gt; This is the part TLS 1.3 does not reach, and it deserves its own aside because it is where the next decade of these bugs will be found.&lt;/p&gt;

Tibor Jager and Juraj Somorovsky broke the W3C XML Encryption standard with the same oracle, decrypting XML in SOAP and web-services stacks by watching how an endpoint reacted to manipulated ciphertext -- proof that the mechanism operates far outside TLS [@jager_somorovsky_xmlenc2011]. The application layer is full of the same shape: JWE and JOSE `A128CBC-HS256` tokens, encrypted cookies, and ViewState-style tokens reproduce the 2002 bug, often with no MAC at all, above TLS where network scanners cannot see them. A separate but adjacent hazard, Efail, exploited a CBC *malleability gadget* in S/MIME and a CFB gadget in OpenPGP to exfiltrate plaintext directly -- not a padding-verdict oracle, but the same &quot;unauthenticated malleable ciphertext&quot; precondition wearing different clothes [@efail2018].
&lt;p&gt;&lt;strong&gt;Format and parse oracles beyond padding.&lt;/strong&gt; Generalize once more: &lt;em&gt;any&lt;/em&gt; observable post-decryption structural verdict -- a JSON parse success, a protobuf validity check, a decompression outcome -- is a padding oracle by another name whenever it acts on unauthenticated ciphertext. The padding was only ever the first structure anyone checked. Jager and Somorovsky already proved the mechanism outside padding entirely [@jager_somorovsky_xmlenc2011], and systematic detection of &quot;decrypt-then-parse&quot; leaks is not yet automated the way TLS padding-oracle scanning now is.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AEAD&apos;s own frontier.&lt;/strong&gt; The successor primitive has two sharp edges of its own -- catastrophic nonce reuse in AES-GCM [@bock_nonce_woot2016] and the lack of key commitment [@albertini_committing2022] -- which matter most in exactly the places large systems trip: nonce management across many distributed senders, and multi-key or multi-recipient contexts like JWT and envelope encryption. Both are addressed &lt;em&gt;separately&lt;/em&gt; today, by AES-GCM-SIV for misuse resistance and by committing constructions that RFC 9771&apos;s vocabulary now specifies, but no single ubiquitous primitive yet delivers misuse-resistant &lt;em&gt;and&lt;/em&gt; committing &lt;em&gt;and&lt;/em&gt; fast &lt;em&gt;and&lt;/em&gt; online at once [@rfc8452] [@rfc9771]. That convergence is the open engineering target, and it is a different problem from the padding oracle, not a continuation of it.&lt;/p&gt;
&lt;p&gt;Every one of these is the same sentence wearing new clothes: unauthenticated, attacker-chosen input reaching a check whose verdict is observable. Which means the practical guide almost writes itself -- it is the thesis made operational.&lt;/p&gt;
&lt;h2&gt;10. Decision Rules: Use X With These Params in Case Y&lt;/h2&gt;
&lt;p&gt;Everything above collapses into a short decision procedure and a shorter list of nevers.&lt;/p&gt;

flowchart TD
    Start[&quot;Need authenticated encryption&quot;] --&amp;gt; Q1{&quot;Greenfield design?&quot;}
    Q1 --&amp;gt;|&quot;Yes&quot;| Q2{&quot;AES hardware present?&quot;}
    Q2 --&amp;gt;|&quot;Yes&quot;| GCM[&quot;AES-GCM, unique 96-bit nonce&quot;]
    Q2 --&amp;gt;|&quot;No&quot;| ChaCha[&quot;ChaCha20-Poly1305&quot;]
    Q1 --&amp;gt;|&quot;No, stuck with CBC&quot;| Q3{&quot;Can you retire CBC?&quot;}
    Q3 --&amp;gt;|&quot;Yes&quot;| GCM
    Q3 --&amp;gt;|&quot;No&quot;| EtM[&quot;Encrypt-then-MAC, RFC 7366, verify first&quot;]
    GCM --&amp;gt; Q4{&quot;Nonce uniqueness hard?&quot;}
    Q4 --&amp;gt;|&quot;Yes&quot;| SIV[&quot;AES-GCM-SIV&quot;]
    Q4 --&amp;gt;|&quot;No&quot;| Done[&quot;Ship it&quot;]
&lt;p&gt;The rules, in order:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Default to a vetted AEAD, from a library you cannot misuse.&lt;/strong&gt; Use AES-GCM with a unique 96-bit nonce and fewer than $2^{32}$ messages per key where the CPU has AES-NI; use ChaCha20-Poly1305 where there is no AES hardware, or when you want constant-time behavior from portable software [@rfc8439]. In application code, reach for libsodium&apos;s &lt;code&gt;secretbox&lt;/code&gt; or Google Tink rather than raw primitives, and prefer any API where you &lt;em&gt;cannot&lt;/em&gt; express &quot;decrypt, then check&quot; -- the safest libraries never hand you plaintext before verification.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;If nonce uniqueness is hard to guarantee&lt;/strong&gt; across many independent senders or under snapshot and rollback risk, use AES-GCM-SIV, so a nonce repeat degrades gracefully instead of catastrophically [@rfc8452].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;If a ciphertext may be opened under more than one key&lt;/strong&gt; -- JWT and JOSE, envelope encryption, abuse reporting -- use a committing AEAD [@albertini_committing2022] [@rfc9771].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;If you must compose by hand,&lt;/strong&gt; use Encrypt-then-MAC: encrypt, then compute the MAC over the IV and ciphertext with an &lt;em&gt;independent&lt;/em&gt; MAC key, and verify the tag in constant time &lt;em&gt;before&lt;/em&gt; you decrypt or unpad [@rfc7366].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;On a legacy TLS 1.2 CBC deployment you cannot yet retire,&lt;/strong&gt; negotiate RFC 7366 Encrypt-then-MAC, prefer AEAD suites, and follow BCP 195 [@rfc9325].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Never&lt;/strong&gt; return a distinct &quot;bad padding&quot; error; never branch or vary timing on padding validity; never decrypt before verifying; never reuse the encryption key as the MAC key; never leave the IV out of the MAC; and never ship SSL 3.0 or non-RFC-7366 CBC.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you are stuck at the fourth rule, the shape below is the reference. It is dependency-free and non-cryptographic on purpose: copy the &lt;em&gt;order of operations&lt;/em&gt;, not the stand-in primitives.&lt;/p&gt;
&lt;p&gt;{`
// Reference SHAPE for a correct Encrypt-then-MAC open().
// constantTimeEqual, hmac, cbcDecrypt, removePkcs7 are stand-ins, NOT real crypto.
function constantTimeEqual(a, b) {
  if (a.length !== b.length) return false;
  let diff = 0;
  for (let i = 0; i &amp;lt; a.length; i++) diff |= a[i] ^ b[i];
  return diff === 0;   // no early exit: time is independent of where they differ
}&lt;/p&gt;
&lt;p&gt;function open(kEnc, kMac, iv, ciphertext, tag) {
  // 1. Authenticate FIRST, over IV concat ciphertext, in constant time.
  const expected = hmac(kMac, iv.concat(ciphertext));
  if (!constantTimeEqual(tag, expected)) return &quot;FAIL&quot;;  // one outcome, always&lt;/p&gt;
&lt;p&gt;  // 2. Only authentic ciphertext ever reaches decryption and unpadding.
  const padded = cbcDecrypt(kEnc, iv, ciphertext);
  const plain = removePkcs7(padded);
  return plain === null ? &quot;FAIL&quot; : plain;                // same FAIL either way
}&lt;/p&gt;
&lt;p&gt;// Stand-ins so the snippet runs (NOT secure):
function hmac(k, data)          { return data.map((b) =&amp;gt; (b ^ k) &amp;amp; 0xff); }
function cbcDecrypt(k, iv, c)   { return c; }
function removePkcs7(p)         { return p; }&lt;/p&gt;
&lt;p&gt;console.log(open(1, 2, [9, 9], [4, 5, 6], [7, 7, 7])); // FAIL: forged tag rejected first
`}&lt;/p&gt;
&lt;p&gt;Every misuse in real code maps one-to-one onto a named break in the catalog. That mapping is the practical guide as a grid.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Misuse seen in code&lt;/th&gt;
&lt;th&gt;The named break it reproduces&lt;/th&gt;
&lt;th&gt;The fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Distinct &quot;bad padding&quot; error&lt;/td&gt;
&lt;td&gt;Vaudenay, ASP.NET&lt;/td&gt;
&lt;td&gt;Verify authenticity first&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Non-constant-time unpad and MAC&lt;/td&gt;
&lt;td&gt;Lucky Thirteen&lt;/td&gt;
&lt;td&gt;AEAD, or constant-time EtM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unchecked pad bytes&lt;/td&gt;
&lt;td&gt;POODLE&lt;/td&gt;
&lt;td&gt;Retire SSL 3.0 and CBC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-NI fast-path length slip&lt;/td&gt;
&lt;td&gt;CVE-2016-2107&lt;/td&gt;
&lt;td&gt;Verified constant-time, or AEAD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verifying the MAC after decrypting&lt;/td&gt;
&lt;td&gt;The whole class&lt;/td&gt;
&lt;td&gt;Encrypt-then-MAC ordering&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nonce reuse under AES-GCM&lt;/td&gt;
&lt;td&gt;The forbidden attack&lt;/td&gt;
&lt;td&gt;Unique nonces, or AES-GCM-SIV&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;App-layer encrypt with no MAC&lt;/td&gt;
&lt;td&gt;JWE and cookie oracles&lt;/td&gt;
&lt;td&gt;A committing AEAD&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Use a vetted AEAD: AES-GCM with unique 96-bit nonces and the under-$2^{32}$-messages-per-key cap where AES hardware exists, or ChaCha20-Poly1305 where it does not. If you must keep CBC, negotiate RFC 7366 Encrypt-then-MAC with an independent MAC key and a constant-time verify performed first. Never ship SSL 3.0 or non-RFC-7366 CBC. That is the entire checklist, because the lesson is a single sentence.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Detection is cheap enough to wire into a pipeline, and you should, because content-difference oracles need no timing rig to find [@merget2019].&lt;/p&gt;

Point an open-source padding-oracle scanner at your own hosts. Craig Young&apos;s `padcheck` and the TLS-Attacker project&apos;s `TLS-Padding-Oracles` both probe for the invalid-padding-versus-invalid-MAC content differences that Zombie POODLE and GOLDENDOODLE exploit, and they run without a precise timing setup [@padcheck] [@tls_padding_oracles]. A clean result on a CBC endpoint is reassuring; any distinguishable response is a reportable finding, not a tuning opportunity.
&lt;p&gt;The checklist is short because the lesson is one sentence. Before restating it, clear the confident, wrong sentences that keep this bug alive in design meetings.&lt;/p&gt;
&lt;h2&gt;11. Misconceptions, Named and Corrected&lt;/h2&gt;
&lt;p&gt;The padding oracle survives mostly because a handful of confident, wrong sentences keep getting said in design meetings. Here they are, corrected.&lt;/p&gt;


The strength of AES is irrelevant to this attack, because the key is never attacked. A padding oracle recovers plaintext from the receiver&apos;s error handling -- a distinguishable answer to &quot;was the padding valid?&quot; -- combined with CBC&apos;s malleability [@vaudenay2002]. The ASP.NET break recovered authentication tickets and `web.config` with AES-256 fully intact [@rizzo_duong_woot2010]. &quot;The cipher is strong&quot; and &quot;the system is secure&quot; are different claims.


No. The same accept/reject bit re-emerges through the next-quietest channel. Once the error message was unified, it leaked through coarse timing (Canvel et al., 2003) and then through statistical timing under unified errors (Lucky Thirteen, 2013), and through unchecked structure entirely (POODLE, 2014) [@canvel2003] [@lucky13_2013] [@poodle_writeup]. Silencing one channel just moves the leak; only removing the precondition closes it.


No -- and the overstatement matters. Krawczyk proved MAC-then-encrypt conditionally secure for CBC and counter mode, so the real-world breaks are implementation, side-channel, and underspecified-padding failures, not refutations of a theorem [@krawczyk2001]. What is true is that MtE is *fragile in practice*: it leaves unauthenticated ciphertext reaching the parser, so constant-time MtE is a fight against the construction. The fix is to change the order, not to declare a theorem false.


It is a padding oracle; the downgrade is only the enabler that forces a client onto vulnerable SSL 3.0, whose pad bytes are unchecked by specification [@poodle_writeup] [@rfc6101]. The proof is TLS-POODLE (CVE-2014-8730), the same oracle against TLS stacks that copied the lax check, with no downgrade at all [@cve_2014_8730]. Frame POODLE as a padding oracle first, a downgrade second.


No. Bleichenbacher (1998) is an RSA PKCS #1 v1.5 oracle -- a different primitive with different arithmetic [@bleichenbacher1998]. Vaudenay (2002) is the first *CBC* instance [@vaudenay2002]. Bleichenbacher is the ancestor &quot;in spirit,&quot; because he first showed that a structural validity verdict is a decryption oracle, but calling his attack a CBC padding oracle confuses two branches of the family tree.


No. AES-GCM and ChaCha20-Poly1305 are counter-mode stream constructions with no block padding, and they verify the authentication tag before releasing any plaintext, so the Vaudenay atom has no surface to act on [@rfc8439]. GCM&apos;s own hazard is nonce reuse, which is a different problem -- the &quot;forbidden attack&quot; -- not a padding oracle [@bock_nonce_woot2016].


Only if authenticity is checked *first* and the unpadding is *also* constant-time. A constant-time compare on a MAC you verify *after* decrypting still leaves the padding check reachable, which is the whole class -- and a hand-written fast path can reintroduce the oracle anyway, as CVE-2016-2107 did, through a missing length check observable as a distinguishable alert rather than a timing leak [@cve_2016_2107]. The safe pattern is verify-then-decrypt, or an AEAD that gives you no other option.

&lt;p&gt;Every correction points at the same root: the padding was never the bug. Time to say the sentence the whole article was built to earn.&lt;/p&gt;
&lt;h2&gt;Decrypt, Then Confess&lt;/h2&gt;
&lt;p&gt;Return to that ASP.NET server in September 2010. AES-256 intact. The key never touched, never even approached. And the plaintext -- authentication tickets, &lt;code&gt;web.config&lt;/code&gt;, the site&apos;s master secrets -- gone, one byte at a time, because the server answered a question it should never have been asked before it authenticated the ciphertext [@rizzo_duong_woot2010].&lt;/p&gt;
&lt;p&gt;Line up the catalog and the shape is unmistakable. Bleichenbacher, Vaudenay, Canvel, ASP.NET, Lucky Thirteen, POODLE, CVE-2016-2107, Zombie POODLE: in every case the cipher did exactly what it promised, and the variable was always the &lt;em&gt;order of operations&lt;/em&gt;, leaking through a quieter channel each time it was silenced. A loud error became coarse timing became statistical timing became unchecked structure became a fix that re-created its own oracle. Five generations chased the bit; the bit kept escaping, because the precondition -- unauthenticated, malleable ciphertext reaching a padding check -- was never removed.&lt;/p&gt;
&lt;p&gt;The resolution the field finally deployed is a single move: verify authenticity &lt;em&gt;first&lt;/em&gt;. Encrypt-then-MAC proves it -- IND-CCA plus integrity of ciphertexts, the strongest of the three generic compositions, published two years &lt;em&gt;before&lt;/em&gt; Vaudenay&apos;s attack [@bellare_namprempre2000]. AEAD ships it as one primitive with no knob to misset, and TLS 1.3 makes it the only option a conformant stack can express [@rfc8446].&lt;/p&gt;
&lt;p&gt;This mirrors the running lesson of the series: Part 1&apos;s IND-CCA2 adversary is not a chalkboard abstraction but the exact adversary that walked out of that ASP.NET server, and Part 5&apos;s warning that confidentiality is not integrity is precisely the gap a padding oracle drives through.&lt;/p&gt;

When a ciphertext you did not create arrives, what does your receiver reveal about it before it has proven the ciphertext authentic? Encrypt-then-MAC and AEAD are the discipline of making the answer nothing.
&lt;p&gt;Carry that one question into every protocol you design or review. Drop Lucky Thirteen onto it, drop POODLE onto it, drop the next application-layer JWE oracle onto it: each is a non-empty answer, and the fix is always the same shape. The cipher was never the weak link, and no future cipher will be. That is why this is Part 6 of a field guide to &lt;em&gt;protocol design&lt;/em&gt;, not a chapter on block ciphers.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;padding-oracles-field-guide&quot; keyTerms={[
  { term: &quot;Padding oracle&quot;, definition: &quot;An attack class where a receiver&apos;s observable verdict on the padding of attacker-chosen ciphertext becomes a plaintext-recovery oracle, never touching the key.&quot; },
  { term: &quot;PKCS#7 padding&quot;, definition: &quot;Append n bytes each equal to n to fill the final block; a full extra block when already aligned (RFC 2315).&quot; },
  { term: &quot;CBC malleability&quot;, definition: &quot;Because each plaintext block is D_k(C_i) XOR C_(i-1), flipping a ciphertext byte flips the same plaintext byte deterministically.&quot; },
  { term: &quot;Chosen-ciphertext attack (IND-CCA2)&quot;, definition: &quot;An adversary that submits ciphertexts and learns from the receiver&apos;s reactions; a padding oracle is a deployed instance.&quot; },
  { term: &quot;Message authentication code (MAC)&quot;, definition: &quot;A keyed tag proving a message is authentic and unmodified; HMAC is the deployed instance.&quot; },
  { term: &quot;MAC-then-encrypt (MtE)&quot;, definition: &quot;MAC the plaintext, then encrypt; the receiver decrypts and unpads before verifying, so the padding verdict is observable by construction. SSL and TLS&apos;s original choice.&quot; },
  { term: &quot;Encrypt-then-MAC (EtM)&quot;, definition: &quot;MAC the ciphertext and IV, verify first, decrypt only authentic ciphertext; attains IND-CCA plus INT-CTXT. IPsec ESP and RFC 7366.&quot; },
  { term: &quot;INT-CTXT (integrity of ciphertexts)&quot;, definition: &quot;The adversary cannot produce any new ciphertext the receiver accepts; the property that closes the oracle.&quot; },
  { term: &quot;AEAD&quot;, definition: &quot;Authenticated Encryption with Associated Data: one primitive that verifies authenticity as part of decryption and returns nothing on failure (RFC 5116).&quot; },
  { term: &quot;Constant-time comparison&quot;, definition: &quot;A check whose running time does not depend on secret data or on where a difference occurs; the countermeasure Lucky Thirteen forced, whose hand-written implementation CVE-2016-2107 later showed to be fragile.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>cryptography</category><category>padding-oracle</category><category>cbc</category><category>tls</category><category>authenticated-encryption</category><category>aead</category><category>encrypt-then-mac</category><category>lucky-thirteen</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>Secure Against Whom? The Security Definitions Every Protocol Designer Needs</title><link>https://paragmali.com/blog/secure-against-whom-the-security-definitions-every-protocol-/</link><guid isPermaLink="true">https://paragmali.com/blog/secure-against-whom-the-security-definitions-every-protocol-/</guid><description>A protocol designer&apos;s field guide to IND-CPA, IND-CCA2, EUF-CMA, AEAD, and the random oracle model, and why the wrong adversary model sinks real protocols.</description><pubDate>Sat, 04 Jul 2026 15:17:50 GMT</pubDate><content:encoded>
A security definition is a contract with two clauses: a **goal** (what the adversary must fail to do) bound to an **adversary model** (what the adversary is allowed to do). Nothing is ever &quot;secure&quot; in the abstract, only secure *relative to that contract*. Most real-world breaks are not weak math. They are a construction that met a *weaker* target than its deployment&apos;s adversary demanded: Bleichenbacher and POODLE handed attackers a decryption oracle, AES-GCM nonce reuse handed them a repeated nonce, invisible salamanders handed them a second key. This guide builds the vocabulary generation by generation, from IND-CPA and IND-CCA2 through EUF-CMA, SUF-CMA, AEAD, and committing encryption, plus the two proof settings (random oracle versus standard model) and the reduction that ties goals to hard problems. The operational lesson is one habit: **state your deployment&apos;s adversary model first, pick the matching target second, and choose the primitive last.**
&lt;h2&gt;1. The Primitive Was Fine&lt;/h2&gt;
&lt;p&gt;In 1998, Daniel Bleichenbacher did not break RSA. Factoring stayed hard, the keys stayed secret, and the math was exactly as sound the day after his attack as the day before. Yet with about a million carefully malformed messages, he could recover the secrets of an SSL session, because the server, trying to be helpful, answered one question every time it rejected a ciphertext: was the padding valid? [@bleichenbacher1998]&lt;/p&gt;
&lt;p&gt;That single leaked bit is a decryption oracle. RSA as used in SSL wrapped the session key in PKCS#1 v1.5 padding, and a server that reports &quot;bad padding&quot; differently from &quot;bad key&quot; tells the attacker, ciphertext by ciphertext, whether a chosen value decrypts into the padded structure. Bleichenbacher showed that roughly $2^{20}$ adaptive queries turn that trickle into the full plaintext [@bleichenbacher1998].&lt;/p&gt;
&lt;p&gt;The tempting reading is &quot;an RSA bug.&quot; It is not. Nineteen years later, in 2017, researchers pointed the identical attack at modern TLS stacks and load balancers, and it &lt;em&gt;still worked&lt;/em&gt; against products from several major vendors [@robot_2018] [@robot_site]. They called it ROBOT, the Return Of Bleichenbacher&apos;s Oracle Threat. The industry had spent two decades patching individual symptoms, tightening one timing difference here, one error message there, without ever changing what was actually wrong.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; ROBOT is the clearest evidence in this article that the failure is structural, not incidental. Every point fix removed one &lt;em&gt;instance&lt;/em&gt; of the oracle. None of them changed the fact that PKCS#1 v1.5 encryption was deployed where an attacker can observe decryption behavior, and it was never built to survive that. You cannot patch your way out of the wrong security target. You have to change the target [@robot_2018].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So what, exactly, does &quot;secure&quot; mean, and secure against whom? That question is not rhetorical. It is the entire discipline. A construction is secure only against a specified adversary trying to achieve a specified goal, and the moment the deployment hands that adversary a capability the specification never modeled, the guarantee evaporates no matter how sound the underlying math.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; A security definition is a contract with two clauses: a &lt;strong&gt;goal&lt;/strong&gt; (what the adversary must fail to achieve) bound to an &lt;strong&gt;adversary model&lt;/strong&gt; (what the adversary is allowed to do). &quot;Secure&quot; without a named adversary model is not a weak claim. It is not a claim at all.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This guide makes you fluent in that contract. We build the vocabulary the way the field built it, one generation at a time, and prove the thesis with evidence: a catalog of named, dated breaks in which a &lt;em&gt;provably fine&lt;/em&gt; primitive sank a real protocol because the environment granted an adversary the proof never covered. Bleichenbacher and ROBOT are the first entry.&lt;/p&gt;
&lt;p&gt;By the end you will read any construction as goal plus adversary model plus proof setting, and see why that one habit would have prevented the entire catalog. For the deployment story of how Windows TLS stacks rotated ciphers over twenty years, see &lt;a href=&quot;https://paragmali.com/blog/rotating-every-cipher-schannel-and-the-twenty-year-algorithm&quot; rel=&quot;noopener&quot;&gt;SChannel and the twenty-year algorithm&lt;/a&gt;.&lt;/p&gt;

A construction is never secure in the abstract. It is secure only relative to a named adversary model.
&lt;p&gt;To see why a correct primitive was not enough, we have to go back to a time when &quot;secure&quot; had no definition at all.&lt;/p&gt;
&lt;h2&gt;2. Before &quot;Secure&quot; Meant Anything&lt;/h2&gt;
&lt;p&gt;For most of history, a cipher was &quot;secure&quot; because nobody important had broken it yet. That is survivorship bias wearing the costume of a guarantee. It tells you nothing about the attacks nobody has tried, and it cannot distinguish a strong design from one that simply has not attracted a competent adversary. Every classical cipher, from simple substitution to Vigenère to Enigma, was &quot;secure&quot; by this standard right up until the morning it was not.&lt;/p&gt;
&lt;p&gt;The one durable gain from that era is Kerckhoffs&apos;s principle: assume the adversary knows every detail of your algorithm, and put all the secrecy in the key.Auguste Kerckhoffs stated this in 1883 [@kerckhoffs1883]. It is why &quot;security through obscurity&quot; is a slur, and why modern designs publish their algorithms and keep only keys secret. But note what it still does not supply: a definition of what the attacker must &lt;em&gt;fail&lt;/em&gt; to do. It is a rule about where to hide the secret, not a definition of success. It leaves &quot;secure&quot; undefined.&lt;/p&gt;
&lt;p&gt;That gap survived the single most important idea in the field&apos;s modern history. In 1976, Whitfield Diffie and Martin Hellman opened public-key cryptography, showing that two strangers could agree on a secret over a channel an eavesdropper fully controls, and sketching digital signatures along the way [@dh1976]. It was a genuine discontinuity. But it delivered &lt;em&gt;mechanisms&lt;/em&gt;, not a definition of what an attacker must fail to achieve. &quot;Secure&quot; still meant &quot;we tried and could not break it.&quot;&lt;/p&gt;
&lt;p&gt;You cannot prove a scheme meets a goal you never wrote down. So the founding question of modern cryptography is not &quot;how do we encrypt?&quot; It is &quot;what must the attacker fail at, and what is the attacker allowed to do while failing?&quot; Shafi Goldwasser and Silvio Micali answered it in 1982 and 1984 with &lt;em&gt;semantic security&lt;/em&gt;: a ciphertext must leak nothing computationally useful about its plaintext, not even a single predicate, to any efficient adversary who already knows partial information [@gm1984] [@gm1982stoc].&lt;/p&gt;
&lt;p&gt;They also gave an equivalent, more usable form, indistinguishability, which we meet as IND-CPA in the next section. The award committee agreed the shift mattered: Goldwasser and Micali received the 2012 Turing Award for it [@turing2012].&lt;/p&gt;
&lt;p&gt;Two words in that definition carry enormous weight. &quot;Efficient&quot; means the adversary runs in probabilistic polynomial time; we do not defend against an attacker with unbounded computation, because for public-key cryptography that is hopeless. &quot;Negligible&quot; means the adversary&apos;s edge over guessing shrinks faster than any inverse polynomial in the security parameter.Probabilistic polynomial time (PPT) and negligible functions are the two dials of computational security. A function is negligible if it eventually falls below $1/n^c$ for every constant $c$. Together they let us say &quot;no realistic adversary wins by more than a vanishing margin&quot; instead of the impossible &quot;no adversary ever wins.&quot; Security stops being a binary property of an algorithm and becomes a statement about a &lt;em&gt;game&lt;/em&gt; between a challenger and a bounded adversary.&lt;/p&gt;

This article numbers the generations of definitions by *idea*, not by calendar. Confidentiality against a passive attacker comes first, then against an active one, then integrity, then their union, then commitment. The field did not invent them in that order: unforgeability for signatures (1988) was defined *before* adaptive chosen-ciphertext security (1991). Where the dates cross, we flag it. The dependency that matters here is conceptual, not temporal.
&lt;p&gt;Before we build the first game, there is one loose end. An airtight, provably unbreakable definition of secrecy was already on the books, and it predated all of this by decades. Why did the field not simply use Shannon&apos;s?&lt;/p&gt;
&lt;h2&gt;3. The Perfect Cipher We Cannot Afford&lt;/h2&gt;
&lt;p&gt;Claude Shannon gave cryptography a mathematically perfect definition of secrecy in 1949, and the one-time pad achieves it, unconditionally, forever [@shannon1949]. Not &quot;we think it is hard to break.&quot; Provably impossible to break, even against an adversary with infinite computing power.&lt;/p&gt;

An encryption scheme has perfect secrecy if the ciphertext is statistically independent of the plaintext: observing the ciphertext leaves the adversary&apos;s probability distribution over possible messages exactly where it started. Formally, $\Pr[M = m \mid C = c] = \Pr[M = m]$ for every message and ciphertext. No amount of computation helps, because the information is simply not present in the ciphertext.
&lt;p&gt;The one-time pad reaches this bar with almost embarrassing simplicity. Take a key $k$ that is uniformly random and as long as the message $m$, and send $c = m \oplus k$. Because each key bit is a fresh coin flip, every plaintext of that length is an equally plausible explanation of the ciphertext, so the ciphertext reveals nothing. Decryption is the same XOR again.&lt;/p&gt;
&lt;p&gt;So why is the internet not built on one-time pads? Shannon proved the catch in the same paper: any perfectly secret cipher needs at least as much key entropy as message entropy, $H(K) \ge H(M)$ [@shannon1949]. The key must be as long as everything you will ever send, and it does nothing to solve the problem of getting that key to the other party in the first place. Two strangers who have never met cannot pre-share gigabytes of secret pad, which is exactly the situation every TLS handshake faces.&lt;/p&gt;
&lt;p&gt;There are two more ceilings, and they matter for the rest of this guide. The first is that the perfection is contingent on the pad being used &lt;em&gt;once&lt;/em&gt;. Reuse a pad across two messages and $c_1 \oplus c_2 = m_1 \oplus m_2$, which leaks the XOR of the plaintexts and, with a little language structure, both messages.This is not hypothetical. The VENONA project decrypted Soviet cables for years precisely because the Soviets reused one-time-pad key material under wartime production pressure [@venona]. &quot;Never reuse the key&quot; is a lesson written in decades of intercepted traffic, and it returns almost verbatim in the AES-GCM nonce story later.&lt;/p&gt;
&lt;p&gt;The second ceiling is quieter and more important for our thesis. The one-time pad offers zero integrity. It is maximally &lt;em&gt;malleable&lt;/em&gt;: flip any bit of the ciphertext and you flip exactly the corresponding bit of the plaintext, and the receiver has no way to notice. Perfect secrecy says nothing whatsoever about whether a message arrived unmodified.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This is one of the most expensive misconceptions in applied cryptography, so meet it early. Confidentiality (nobody can read it) and integrity (nobody can change it undetected) are &lt;em&gt;different goals&lt;/em&gt;. A scheme can have perfect confidentiality and no integrity at all, as the one-time pad demonstrates. Assuming encryption implies integrity is the root cause of an entire class of breaks we catalog in Generation 4.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The way out of the key-length ceiling is to relax the adversary. Shannon&apos;s model grants the attacker unlimited computation. If we instead demand only that a &lt;em&gt;computationally bounded&lt;/em&gt; adversary fail, we can hope for short keys, public keys, and eventually integrity, provided we state precisely what &quot;fail&quot; means. That relaxation is the whole computational project the previous section set up.&lt;/p&gt;
&lt;p&gt;The relaxation bites immediately, and its first bite is instructive. Consider deterministic &quot;textbook&quot; RSA, where a message always encrypts to the same ciphertext under a given public key. An adversary who suspects the plaintext is one of two values does not need to break RSA at all. The public key lets anyone encrypt, so the attacker encrypts both candidates and compares them to the challenge ciphertext. Whichever matches is the answer.&lt;/p&gt;
&lt;p&gt;Goldwasser and Micali turned this into a theorem: no deterministic public-key scheme can be semantically secure [@gm1984]. Randomization is not good hygiene; it is mandatory, a consequence of the definition itself. That randomness has to come from somewhere trustworthy, its own deep subject that a later part of this series takes up.&lt;/p&gt;
&lt;p&gt;With the passive adversary finally pinned down as a game, we can write the first modern definition precisely, and then watch an attacker walk straight through its one blind spot.&lt;/p&gt;
&lt;h2&gt;4. Five Generations, One Recurring Story&lt;/h2&gt;
&lt;p&gt;The next four decades of cryptography follow one pattern so regularly that you can predict the next entry. A definition fixes a goal and an adversary model. A deployment then hands the attacker a capability the model never granted, whether a decryption oracle, a repeated nonce, or a second valid key. A named, dated break follows. And the field responds by writing a stronger definition that pulls the new capability inside the game. Watch for that shape. By Generation 3 you will feel it coming.&lt;/p&gt;

timeline
    title From perfect secrecy to committing encryption
    1949 : Shannon perfect secrecy, unbounded adversary
    1976 : Diffie-Hellman public-key crypto, no definition of success
    1984 : Goldwasser-Micali semantic security and IND-CPA
    1988 : Goldwasser-Micali-Rivest unforgeability, EUF-CMA
    1990 to 1991 : Naor-Yung CCA1, Rackoff-Simon CCA2, Dolev-Dwork-Naor non-malleability
    1993 : Bellare-Rogaway random oracle model
    1998 : Bleichenbacher break, relations map, Cramer-Shoup, ROM uninstantiability
    2000 to 2006 : Bellare-Namprempre AE, Rogaway AEAD, SIV nonce-misuse resistance
    2018 to 2021 : Invisible salamanders and partitioning oracles, committing AE
    2024 : ML-KEM in FIPS 203, NIST Accordion effort
&lt;h3&gt;Generation 1: confidentiality against a passive adversary (IND-CPA, 1984)&lt;/h3&gt;
&lt;p&gt;Goldwasser and Micali&apos;s indistinguishability game is the founding contract of modern cryptography, and it is worth stating exactly.&lt;/p&gt;

A scheme is IND-CPA secure if no efficient adversary can tell which of two self-chosen, equal-length messages was encrypted, even while free to encrypt anything else it likes. The adversary submits $m_0$ and $m_1$; the challenger flips a secret bit $b$ and returns the challenge $\mathrm{Enc}(m_b)$; the adversary outputs a guess $b&apos;$. Its advantage is $\lvert \Pr[b&apos; = b] - \tfrac{1}{2} \rvert$, and security means that advantage stays negligible. This is the indistinguishability form of semantic security.
&lt;p&gt;In the public-key setting the adversary already holds the public key, so its chosen-plaintext power is free: it can encrypt anything it wants. That is exactly what dooms determinism. If encryption is a plain function, the adversary encrypts $m_0$ itself and checks whether the result equals the challenge.&lt;/p&gt;
&lt;p&gt;{`
// A toy &quot;deterministic&quot; encryption: the same message always maps to the same ciphertext.
function encryptDeterministic(pk, m) {
  // stand-in for textbook RSA: a fixed, public, invertible transform
  return &quot;CT[&quot; + pk + &quot;:&quot; + m + &quot;]&quot;;
}&lt;/p&gt;
&lt;p&gt;// The IND-CPA adversary, given only the public key and the challenge ciphertext.
function adversary(pk, challenge) {
  const m0 = &quot;attack at dawn&quot;;
  const m1 = &quot;retreat at dusk&quot;;
  // The public key lets the adversary encrypt candidates itself.
  const guessForM0 = encryptDeterministic(pk, m0);
  // Re-encrypt m0 and compare. No key recovery, no math broken.
  return (challenge === guessForM0) ? &quot;m0&quot; : &quot;m1&quot;;
}&lt;/p&gt;
&lt;p&gt;const pk = &quot;PUBLIC-KEY&quot;;
const challengerSecretlyChose = &quot;attack at dawn&quot;;   // this is m0
const challenge = encryptDeterministic(pk, challengerSecretlyChose);
console.log(&quot;Adversary guesses:&quot;, adversary(pk, challenge));
console.log(&quot;Advantage over guessing: 1/2, the maximum. Deterministic PKE cannot be IND-CPA.&quot;);
`}&lt;/p&gt;
&lt;p&gt;The adversary wins every time, with the maximal advantage of one half. The fix, forced by the definition rather than by taste, is randomization: a good scheme encrypts the same message to freshly random-looking ciphertexts, so re-encrypting a guess tells the attacker nothing.&lt;/p&gt;
&lt;p&gt;IND-CPA is the right target for exactly one adversary: a passive one, who watches ciphertexts go by but never learns how the receiver reacts to them. That is its blind spot. Real servers decrypt attacker-supplied ciphertexts and &lt;em&gt;do something observable&lt;/em&gt;: return an error, take a branch, spend measurable time. Each reaction is a decryption oracle the IND-CPA game never handed out.&lt;/p&gt;
&lt;p&gt;Bleichenbacher&apos;s 1998 attack, from the opening of this article, is precisely this failure: an IND-CPA-grade target deployed where the adversary can watch decryption behavior [@bleichenbacher1998]. To survive that attacker, the definition itself must give the adversary a decryption oracle.&lt;/p&gt;
&lt;h3&gt;Generation 2: confidentiality against an active adversary (IND-CCA1, IND-CCA2, non-malleability, 1990 to 1998)&lt;/h3&gt;
&lt;p&gt;The strengthening arrived in two steps. Naor and Yung (1990) gave the adversary a decryption oracle it may query only &lt;em&gt;before&lt;/em&gt; seeing the challenge, the &quot;lunchtime attack&quot; or CCA1, and built the first provably chosen-ciphertext-secure scheme using double encryption plus a zero-knowledge proof that both ciphertexts hold the same plaintext [@ny1990]. A year later Rackoff and Simon (1991) removed the timing restriction: the oracle is available before &lt;em&gt;and&lt;/em&gt; after the challenge, forbidding only a query on the challenge ciphertext itself. That is IND-CCA2, still the gold-standard confidentiality target today [@rs1991].&lt;/p&gt;

IND-CCA2 is the IND-CPA game plus a decryption oracle the adversary may call adaptively both before and after receiving the challenge $c^{*}$, with the single restriction that it may not ask for the decryption of $c^{*}$ itself. A scheme that meets it withstands exactly the padding-oracle and reaction-attack environments that sink IND-CPA-only deployments.

sequenceDiagram
    participant A as Adversary
    participant C as Challenger
    A-&amp;gt;&amp;gt;C: Two equal-length messages m0 and m1
    C-&amp;gt;&amp;gt;C: Flip secret bit b, encrypt the chosen message
    C-&amp;gt;&amp;gt;A: Challenge ciphertext c-star
    A--&amp;gt;&amp;gt;C: IND-CCA2 only, decrypt any ciphertext except c-star
    C--&amp;gt;&amp;gt;A: The corresponding plaintext
    A-&amp;gt;&amp;gt;C: Final guess b-prime
    Note over A,C: Advantage measures how far a correct guess beats one half
&lt;p&gt;Dolev, Dwork, and Naor (1991) added an orthogonal axis that turns out to matter just as much.&lt;/p&gt;

A scheme is non-malleable if, given a ciphertext of some message $m$, no efficient adversary can produce a ciphertext of a *meaningfully related* message such as $m+1$ or $2m$. Indistinguishability says the adversary learns nothing from a ciphertext; non-malleability says the adversary cannot *transform* it into a ciphertext of a related plaintext, which is a distinct, active threat such as raising a sealed bid by one dollar [@ddn1991].
&lt;p&gt;By 1998 the notions had multiplied into a zoo, and Bellare, Desai, Pointcheval, and Rogaway mapped it. They proved every implication and separation among the goals of indistinguishability and non-malleability crossed with the attacks CPA, CCA1, and CCA2, and the headline result is that IND-CCA2 and non-malleability under CCA2 are the same property [@bdpr1998]. That equivalence is the reward of definition-first thinking: hit the single target IND-CCA2 and you get non-malleability with no separate proof.&lt;/p&gt;
&lt;p&gt;Notice the chronology. Rackoff and Simon defined the adaptive oracle in 1991, seven years before Bleichenbacher showed a real SSL server &lt;em&gt;being&lt;/em&gt; that oracle. The definition did not chase the break; it predicted the entire class of break. What was missing in 1998 was not the theory but the discipline of choosing the target the deployment demanded. And yet IND-CCA2, for all its strength, guarantees only confidentiality. It promises nothing about whether a message you &lt;em&gt;can&lt;/em&gt; read arrived unmodified, or whether an attacker who cannot read it can still inject one the receiver will accept.&lt;/p&gt;
&lt;h3&gt;Generation 3: integrity as a first-class goal (EUF-CMA and SUF-CMA, 1988 onward)&lt;/h3&gt;
&lt;p&gt;Here the calendar folds back. Goldwasser, Micali, and Rivest defined unforgeability in 1988, three years before adaptive chosen-ciphertext security, by carrying the game-based, reduction-oriented definition style from secrecy to authenticity: the same challenger, oracle access, and negligible success bound, now applied to a forgery game rather than to indistinguishability [@gmr1988].&lt;/p&gt;

Give the adversary the verification key and a signing oracle it may query on any messages it chooses. The adversary wins if it outputs a valid signature on a message it never asked the oracle to sign. A signature or MAC scheme is EUF-CMA secure if every efficient adversary wins with only negligible probability. This is the target behind HMAC, RSA-PSS, ECDSA, and Ed25519.
&lt;p&gt;There is a strictly stronger sibling that the deployment reality of the decade made important.&lt;/p&gt;

SUF-CMA changes only the winning condition: the adversary wins if it produces any valid message-signature *pair* the oracle never produced, including a brand-new signature on a message that was already signed. SUF-CMA therefore forbids the signature malleability that EUF-CMA tolerates. Every SUF-CMA scheme is EUF-CMA, but not the reverse [@katzlindell].
&lt;p&gt;Why does the gap between them matter? Because EUF-CMA lets a third party take a valid signature and &lt;em&gt;maul&lt;/em&gt; it into a different valid signature on the same message. Wherever a protocol treats a signature or ciphertext as a unique identifier, that malleability bites. Early Bitcoin is the textbook case: an attacker could re-encode an ECDSA signature, changing a transaction&apos;s identifier without invalidating it, which disrupted systems that assumed the identifier was fixed. MtGox famously halted withdrawals citing malleability, though the same analysis found it did not actually account for the exchange&apos;s lost funds [@decker2014]. That is exactly the attack SUF-CMA forbids and EUF-CMA permits.&lt;/p&gt;
&lt;p&gt;A subtler cousin is verifying a signature without binding its context (which key, which algorithm, which audience), which invites cross-protocol confusion. For a real incident where a stolen signing key met permissive validation, see &lt;a href=&quot;https://paragmali.com/blog/forged-from-2016-how-storm-0558-turned-one-stolen-signing-ke&quot; rel=&quot;noopener&quot;&gt;how Storm-0558 turned one signing key into forged tokens&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A MAC or signature protects a token. It is not, by itself, a secure channel. For that we need confidentiality and integrity together, composed in a way we can prove correct.&lt;/p&gt;
&lt;h3&gt;Generation 4: authenticated encryption (AE and AEAD, 2000 to 2006)&lt;/h3&gt;
&lt;p&gt;Practitioners had been bolting encryption and MACs together by instinct, and instinct chose badly. Bellare and Namprempre (2000) settled the matter with definitions and proofs [@bn2000].&lt;/p&gt;

INT-PTXT (plaintext integrity) means the adversary cannot force decryption to accept a plaintext that was never legitimately encrypted. INT-CTXT (ciphertext integrity), strictly stronger, means the adversary cannot produce *any* valid ciphertext the encryptor never output. INT-CTXT is what real channels want, because it rejects forged ciphertexts before they are ever decrypted.
&lt;p&gt;Their verdict on the three ways to glue encryption to a MAC is one of the most consequential engineering results in the field: &lt;strong&gt;Encrypt-then-MAC&lt;/strong&gt; (encrypt, then authenticate the ciphertext) generically delivers IND-CCA together with INT-CTXT, while &lt;strong&gt;MAC-then-Encrypt&lt;/strong&gt; and &lt;strong&gt;Encrypt-and-MAC&lt;/strong&gt; do not [@bn2000]. Order is not a detail. It is the difference between a secure channel and a broken one.&lt;/p&gt;

AEAD is a single combined target: confidentiality (IND-CPA) plus ciphertext integrity (INT-CTXT) over a nonce-based interface that takes a key, a nonce, associated data, and a message, and returns a ciphertext and a tag. The associated data (packet headers, sequence numbers, routing context) is authenticated but not encrypted. Rogaway named and formalized it in 2002, and RFC 5116 turned it into the deployable interface every modern channel uses.
&lt;p&gt;Rogaway (2002) added the associated-data interface [@rogaway2002], McGrew&apos;s RFC 5116 (2008) standardized it as the API protocol designers actually call [@rfc5116], and Rogaway and Shrimpton (2006) defined the fallback for when nonces cannot be trusted [@rs2006siv].&lt;/p&gt;

A nonce-misuse-resistant scheme degrades gracefully when a nonce repeats: instead of collapsing, it leaks only whether two (nonce, associated data, message) triples were identical. The SIV construction achieves this by deriving the tag from the plaintext first, then using that tag as the encryption nonce. This is the guarantee behind AES-GCM-SIV.
&lt;p&gt;Now the breaks, and they line up with the theory exactly. TLS chose MAC-then-Encrypt with CBC, the very order Bellare and Namprempre flagged, and decrypted before verifying. That handed attackers a padding-and-timing decryption oracle twice: &lt;strong&gt;Lucky Thirteen&lt;/strong&gt; (2013) recovered plaintext from tiny timing differences in MAC and padding checks [@lucky13_2013] [@lucky13_site], and &lt;strong&gt;POODLE&lt;/strong&gt; (2014) forced a downgrade to SSL 3.0, whose CBC padding is not checkably authenticated, then peeled secrets off byte by byte [@poodle_cve]. Both are wrong-composition-order failures wearing different clothes.&lt;/p&gt;
&lt;p&gt;The second Gen-4 landmine is the nonce contract, and it is the most destructive single mistake in applied cryptography.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Reuse one (key, nonce) pair in AES-GCM and you do not lose a little security, you lose all of it. GHASH evaluates a polynomial whose coefficients are the ciphertext blocks at the secret authentication key $H$, so two messages under one nonce cancel the block-cipher mask and leave a polynomial equation in $H$. The attacker factors that polynomial to recover $H$ and can then forge a valid tag on &lt;em&gt;any&lt;/em&gt; message. This is Joux&apos;s &quot;forbidden attack,&quot; a universal forgery rather than a slow leak [@joux_gcm]. VM clones, snapshot rollbacks, and stateless senders are the usual culprits.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Even without reuse, GCM has a hard ceiling.AES-GCM&apos;s standard nonce is 96 bits. With random nonces, birthday collisions on that nonce cap a single key at about $2^{32}$ messages, the bound NIST SP 800-38D fixes in section 8.3 to keep the collision probability negligible. A separate limit, the 32-bit block counter that the 96-bit nonce leaves inside the 128-bit block, caps any one message at about $2^{32}$ blocks (roughly 64 GiB). NIST warns that exceeding either cap can compromise both confidentiality and integrity [@sp800_38d]. The proof was always conditioned on unique nonces and a bounded message count; the environment routinely violates both.&lt;/p&gt;
&lt;p&gt;Which surfaces the deepest omission of all. AE and AEAD guarantee that a ciphertext is unforgeable and hides its plaintext. They never required it to commit to the &lt;em&gt;key&lt;/em&gt; that produced it.&lt;/p&gt;
&lt;h3&gt;Generation 5: committing encryption, binding a ciphertext to its key (2018 to 2021, still open)&lt;/h3&gt;

An AEAD scheme is key-committing if a single ciphertext cannot be made to decrypt validly under two different keys. Stronger notions bind more of the input: context commitment binds the key, nonce, and associated data, while the strongest level also binds the message. Bellare and Hoang grade these from CMT-1 (key only) up to CMT-4, which commits to the entire input tuple of key, nonce, associated data, and message. It is a binding property, not a privacy property, and standard AEAD never required it.
&lt;p&gt;The break that named the goal is vivid. For AES-GCM you can craft one ciphertext that decrypts to two different, meaningful plaintexts under two chosen keys, because its GHASH tag can be made to collide across keys.Dodis, Grubbs, Ristenpart, and Woodage called the hidden second message an &quot;invisible salamander,&quot; after a test image they smuggled past Facebook&apos;s abuse-reporting checks. The playful name marks a serious result: a reported ciphertext could be made to &quot;say&quot; different things to sender, receiver, and moderator. That broke Facebook&apos;s encrypted-message franking, the mechanism that lets a recipient report abuse in a way a moderator can verify [@salamanders2018].&lt;/p&gt;
&lt;p&gt;Three years later the same missing property was weaponized for a different goal. Len, Grubbs, and Ristenpart showed that a single ciphertext valid under many keys turns password guessing into a binary search: each query rules out half the candidate key space at once. These &lt;em&gt;partitioning oracles&lt;/em&gt; sped online attacks against Shadowsocks proxies and reached into key-management and end-to-end-encrypted settings [@partitioning2021]. Bellare and Hoang formalized the graded commitment hierarchy and proved that committing to the key alone (CMT-1) does not imply committing to the full context (CMT-4), so partial fixes leave a real gap [@bh2022]; Menda and colleagues then demonstrated concrete context-discovery and commitment attacks that exploit that gap in real settings [@menda2023].&lt;/p&gt;
&lt;p&gt;Generation 5 is not superseded. It is the live frontier, being written into standards right now, and we return to it in the state of the art.&lt;/p&gt;
&lt;p&gt;That is five turns of one wheel. It is worth seeing the wheel itself.&lt;/p&gt;

flowchart TD
    A[&quot;A definition fixes a goal and an adversary model&quot;] --&amp;gt; B[&quot;A deployment hands the attacker a capability outside that model&quot;]
    B --&amp;gt; C{&quot;Does the attack win inside the old game?&quot;}
    C --&amp;gt;|&quot;No, the game never granted that capability&quot;| D[&quot;A named, dated break follows in the wild&quot;]
    D --&amp;gt; E[&quot;The field writes a stronger definition that grants the capability&quot;]
    E --&amp;gt; A
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Every arrow in that chain has the same shape. A definition names a goal and an adversary model; a deployment grants the attacker a capability outside that model; a dated break follows; a stronger definition absorbs the capability. Learning the definitions is learning to spot the next missing capability before an attacker does.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Two tables make the pattern concrete. The first is the failure catalog, where each row is a construction that met a weaker target than its environment demanded.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Break&lt;/th&gt;
&lt;th&gt;Year&lt;/th&gt;
&lt;th&gt;Construction&lt;/th&gt;
&lt;th&gt;Capability the model ignored&lt;/th&gt;
&lt;th&gt;Missing target&lt;/th&gt;
&lt;th&gt;Lesson&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Bleichenbacher, then ROBOT&lt;/td&gt;
&lt;td&gt;1998, 2017&lt;/td&gt;
&lt;td&gt;RSA PKCS#1 v1.5 encryption&lt;/td&gt;
&lt;td&gt;Decryption and padding oracle&lt;/td&gt;
&lt;td&gt;IND-CCA2&lt;/td&gt;
&lt;td&gt;You cannot patch out a missing target&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lucky Thirteen&lt;/td&gt;
&lt;td&gt;2013&lt;/td&gt;
&lt;td&gt;TLS CBC, MAC-then-Encrypt&lt;/td&gt;
&lt;td&gt;Timing decryption oracle&lt;/td&gt;
&lt;td&gt;AEAD (Encrypt-then-MAC)&lt;/td&gt;
&lt;td&gt;Composition order is provable, not a matter of taste&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;POODLE&lt;/td&gt;
&lt;td&gt;2014&lt;/td&gt;
&lt;td&gt;SSL 3.0 CBC, MAC-then-Encrypt&lt;/td&gt;
&lt;td&gt;Padding oracle via forced downgrade&lt;/td&gt;
&lt;td&gt;AEAD / IND-CCA2&lt;/td&gt;
&lt;td&gt;The adversary model must include downgrade&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AES-GCM nonce reuse&lt;/td&gt;
&lt;td&gt;ongoing&lt;/td&gt;
&lt;td&gt;AES-GCM AEAD&lt;/td&gt;
&lt;td&gt;Repeated (key, nonce) pair&lt;/td&gt;
&lt;td&gt;Nonce-misuse resistance&lt;/td&gt;
&lt;td&gt;Unique nonces are a load-bearing assumption&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Invisible salamanders&lt;/td&gt;
&lt;td&gt;2018&lt;/td&gt;
&lt;td&gt;AES-GCM message franking&lt;/td&gt;
&lt;td&gt;A second valid key&lt;/td&gt;
&lt;td&gt;Key commitment (CMT)&lt;/td&gt;
&lt;td&gt;AEAD never promised one key per ciphertext&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Partitioning oracles&lt;/td&gt;
&lt;td&gt;2021&lt;/td&gt;
&lt;td&gt;Non-committing AEAD&lt;/td&gt;
&lt;td&gt;One ciphertext valid under many keys&lt;/td&gt;
&lt;td&gt;Key commitment (CMT)&lt;/td&gt;
&lt;td&gt;Missing commitment enables key and password search&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The second table lays out the targets themselves, in order of increasing strength, so you can name any construction as a goal bound to an adversary model.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Target&lt;/th&gt;
&lt;th&gt;Goal&lt;/th&gt;
&lt;th&gt;Adversary model&lt;/th&gt;
&lt;th&gt;Strength relation&lt;/th&gt;
&lt;th&gt;Deployed instance&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;IND-CPA&lt;/td&gt;
&lt;td&gt;Confidentiality&lt;/td&gt;
&lt;td&gt;Passive, chosen-plaintext&lt;/td&gt;
&lt;td&gt;Weakest confidentiality&lt;/td&gt;
&lt;td&gt;Building block only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IND-CCA2&lt;/td&gt;
&lt;td&gt;Confidentiality&lt;/td&gt;
&lt;td&gt;Active, adaptive decryption oracle&lt;/td&gt;
&lt;td&gt;Implies IND-CPA, equals NM-CCA2&lt;/td&gt;
&lt;td&gt;ML-KEM, RSA-OAEP, Cramer-Shoup (standard-model reference)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EUF-CMA&lt;/td&gt;
&lt;td&gt;Authenticity&lt;/td&gt;
&lt;td&gt;Adaptive chosen-message&lt;/td&gt;
&lt;td&gt;Base authenticity&lt;/td&gt;
&lt;td&gt;HMAC, ECDSA, Ed25519&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SUF-CMA&lt;/td&gt;
&lt;td&gt;Authenticity&lt;/td&gt;
&lt;td&gt;Adaptive chosen-message&lt;/td&gt;
&lt;td&gt;Strictly stronger than EUF-CMA&lt;/td&gt;
&lt;td&gt;Ed25519, HMAC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AEAD&lt;/td&gt;
&lt;td&gt;Confidentiality and integrity&lt;/td&gt;
&lt;td&gt;Active, nonce-respecting&lt;/td&gt;
&lt;td&gt;Combines IND-CPA and INT-CTXT&lt;/td&gt;
&lt;td&gt;AES-GCM, ChaCha20-Poly1305&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Committing AE&lt;/td&gt;
&lt;td&gt;Binds ciphertext to key and context&lt;/td&gt;
&lt;td&gt;Active, multi-key&lt;/td&gt;
&lt;td&gt;Strictly stronger than AEAD&lt;/td&gt;
&lt;td&gt;AWS Encryption SDK, Accordion (pending)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Five times we have said a scheme &quot;meets&quot; a target. It is time to say what &lt;em&gt;meets&lt;/em&gt; actually means, and why you should believe it.&lt;/p&gt;
&lt;h2&gt;5. What &quot;Provably Secure&quot; Actually Proves&lt;/h2&gt;
&lt;p&gt;We have been defining games. A game tells you what it means to win. It does not tell you that nobody can. So how do you prove a negative, that no efficient adversary wins, without enumerating every possible attack? The answer is the single idea that unifies everything in this guide: a proof by reduction.&lt;/p&gt;

To prove a scheme meets a target, assume some problem is hard (integer factoring, the decisional Diffie-Hellman problem, Module-LWE) or that a lower-level primitive is secure. Then exhibit an efficient algorithm, the reduction, that turns *any* adversary who wins the security game into a solver for that hard problem. If the problem really is hard, no such solver exists, so no such adversary exists either. Security becomes a conditional theorem: break the scheme and you have broken the assumption.
&lt;p&gt;Read that structure carefully, because it is doing something subtle. It never claims the scheme is unbreakable. It claims something you can actually establish: that breaking the scheme is at least as hard as a problem the world&apos;s cryptanalysts have failed to crack for decades. The proof relocates all the risk onto one clearly labeled assumption, where everyone can study it. The hard problems themselves (factoring, discrete logarithms, lattice problems) are the subject of later parts of this series; here they are simply the anchors a reduction reaches for.&lt;/p&gt;

flowchart LR
    A[&quot;Efficient adversary A wins the security game&quot;] --&amp;gt; R[&quot;Reduction R runs A as a black box&quot;]
    R --&amp;gt; S[&quot;R becomes an algorithm that solves the hard problem&quot;]
    S --&amp;gt; X[&quot;But the problem is assumed hard, so no such solver exists&quot;]
    X --&amp;gt; Z[&quot;Therefore no efficient adversary A can exist&quot;]
&lt;p&gt;This is the only known way to make &quot;secure&quot; falsifiable, and it &lt;em&gt;composes&lt;/em&gt;, which is what makes it practical. Bellare and Namprempre&apos;s result that IND-CPA plus INT-CTXT implies IND-CCA is itself a reduction you can bolt onto others: prove your encryption IND-CPA and your MAC strongly unforgeable, glue them Encrypt-then-MAC, and the channel&apos;s IND-CCA security follows with no fresh from-scratch proof [@bn2000] [@bonehshoup]. Large guarantees get assembled from small proven parts.&lt;/p&gt;

A security proof does not promise that nobody can break the scheme. It promises that breaking it is as hard as a problem we have collectively failed to solve for decades.
&lt;p&gt;But a proof is only as good as two things: the assumption it rests on, and how &lt;em&gt;tightly&lt;/em&gt; it reduces.&lt;/p&gt;

A reduction is tight if the solver it builds is almost as effective as the adversary it consumes, running in similar time with similar success probability. It is loose if it loses a factor, for instance a multiple of the number of queries or users. A reduction that loses a factor $L$ means a scheme advertised at $k$-bit security actually delivers only about $k - \log_2 L$ bits at the chosen parameters. Looseness is not academic; you pay it back in larger keys and slower handshakes.
&lt;p&gt;Neal Koblitz and Alfred Menezes pressed exactly this point in their &quot;Another Look&quot; critique: many published reductions are loose, or rest on bespoke, barely-studied assumptions, and calling a scheme &quot;provably secure&quot; invites readers to hear &quot;unbreakable&quot; when the honest claim is much narrower [@km2007]. We take up their argument in full when we reach the limits. For now it is enough to know that the tightness of a proof is an operational number, not a footnote.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; &quot;Provably secure&quot; means &lt;em&gt;conditionally&lt;/em&gt; secure: secure relative to a named hardness assumption and a named adversary model, and only as tightly as the reduction allows. It converts a vague hope into a precise, falsifiable claim whose single point of failure is written on the label. That is far more than folklore offers, and far less than &quot;unbreakable.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This method is not a museum piece. It is the machine still producing the definitions that shipped last year. Here is what it built between 2024 and 2026.&lt;/p&gt;
&lt;h2&gt;6. The Definitions That Shipped: 2024 to 2026&lt;/h2&gt;
&lt;p&gt;A quantum-resistant standard published in 2024 is built directly on the 1984, 1991, and 1999 sequence: an IND-CPA scheme, upgraded to IND-CCA2, by a transform invented to plumb exactly that gap.&lt;/p&gt;
&lt;p&gt;On August 13, 2024, NIST published FIPS 203, standardizing ML-KEM, a key-encapsulation mechanism whose security rests on the hardness of Module-LWE and which is, in the standard&apos;s own words, believed to be secure even against adversaries who possess a quantum computer [@fips203].&lt;/p&gt;

A KEM is the modern shape of public-key confidentiality. Rather than encrypting a chosen message, encapsulation generates a fresh random shared secret together with a ciphertext that carries it; decapsulation recovers the secret from the ciphertext using the private key. The shared secret then keys a symmetric AEAD channel. The target you want from a KEM is IND-CCA2, because an active network attacker can submit chosen ciphertexts to decapsulation.
&lt;p&gt;ML-KEM reaches IND-CCA2 the way Fujisaki-Okamoto transforms do: start from an IND-CPA lattice scheme, then make decapsulation &lt;em&gt;recompute and compare&lt;/em&gt;. It derives the encryption randomness deterministically from the message, re-encrypts on the way in, and on any ciphertext that does not re-encrypt exactly returns a pseudorandom key instead of the real one (implicit rejection), so a decapsulation failure is invisible to the caller [@fips203] [@fo1999]. That single move strips out the malleability an adaptive attacker would exploit, turning a passive-secure scheme into an active-secure one.&lt;/p&gt;
&lt;p&gt;The transform&apos;s soundness in both the random-oracle and quantum-random-oracle settings is the subject of a careful modular analysis by Hofheinz, Hövelmanns, and Kiltz, which also shows the quantum bound is not tight [@hhk2017].The Quantum Random Oracle Model (QROM) lets the adversary query the idealized hash in superposition, which is what a real quantum attacker holding the hash&apos;s public code could do. Proving the FO transform secure in the QROM is harder than in the classical setting and currently costs a looser bound. The full story belongs to a later post-quantum installment of this series.&lt;/p&gt;
&lt;p&gt;The price of the strong target is not CPU, it is bandwidth. Google reports that an ML-KEM key exchange transmits about 1 KB per peer against 32 bytes for X25519, an over-thirty-fold increase that splits the TLS ClientHello across packets and adds roughly 4 percent to median desktop handshake latency [@chrome2024].&lt;/p&gt;
&lt;p&gt;That cost is being paid at scale regardless. Cloudflare reported that nearly 2 percent of all TLS 1.3 connections already used post-quantum key exchange in early 2024 [@cloudflare2024], Signal&apos;s PQXDH was the first large-scale deployment of post-quantum key establishment in messaging [@signal_pqxdh], and Apple&apos;s iMessage PQ3 layers ongoing ML-KEM rekeying on top for what it calls Level 3 security [@apple_pq3].&lt;/p&gt;

ML-KEM ships in *hybrid* mode, combining a classical key exchange such as X25519 with the post-quantum one so a break of either component alone is survivable. The driver is &quot;harvest now, decrypt later&quot;: an adversary recording encrypted traffic today could decrypt it once a quantum computer arrives, so confidentiality that must outlive the next decade needs the post-quantum target now. The Windows-side rollout is covered in [the thirty-year migration that ships in a pip install](/blog/the-thirty-year-migration-ships-in-a-pip-install-how-post-qu) and [post-quantum cryptography on Windows](/blog/post-quantum-cryptography-on-windows-the-thirty-year-migrati).
&lt;p&gt;The same AEAD target ships in three deployed instances that differ not in what they guarantee but in the deployment reality they suit. All three hit AEAD; the discriminating axis is how they behave when a nonce repeats [@rfc8439] [@rfc8452] [@sp800_38d].&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;AES-GCM&lt;/th&gt;
&lt;th&gt;ChaCha20-Poly1305&lt;/th&gt;
&lt;th&gt;AES-GCM-SIV&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Target met&lt;/td&gt;
&lt;td&gt;AEAD (IND-CPA + INT-CTXT)&lt;/td&gt;
&lt;td&gt;AEAD&lt;/td&gt;
&lt;td&gt;AEAD plus nonce-misuse resistance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Structure&lt;/td&gt;
&lt;td&gt;Counter mode plus GHASH&lt;/td&gt;
&lt;td&gt;ChaCha20 stream plus Poly1305&lt;/td&gt;
&lt;td&gt;Tag derived from plaintext, then counter mode, via POLYVAL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Passes&lt;/td&gt;
&lt;td&gt;One pass, online, parallelizable&lt;/td&gt;
&lt;td&gt;One pass, online&lt;/td&gt;
&lt;td&gt;Two passes, not online&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best hardware&lt;/td&gt;
&lt;td&gt;AES-NI and carryless multiply&lt;/td&gt;
&lt;td&gt;none needed, fast in software&lt;/td&gt;
&lt;td&gt;AES-NI and carryless multiply&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nonce reuse&lt;/td&gt;
&lt;td&gt;Catastrophic (Joux forgery)&lt;/td&gt;
&lt;td&gt;Catastrophic (keystream reuse)&lt;/td&gt;
&lt;td&gt;Graceful, leaks only equality of inputs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Per-key limit&lt;/td&gt;
&lt;td&gt;about $2^{32}$ invocations at a 96-bit nonce&lt;/td&gt;
&lt;td&gt;same nonce-uniqueness requirement&lt;/td&gt;
&lt;td&gt;far higher tolerance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Key-committing&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best suited for&lt;/td&gt;
&lt;td&gt;TLS and QUIC with AES hardware&lt;/td&gt;
&lt;td&gt;mobile and embedded, no AES hardware&lt;/td&gt;
&lt;td&gt;stateless senders, key wrap, uncertain nonces&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spec&lt;/td&gt;
&lt;td&gt;NIST SP 800-38D&lt;/td&gt;
&lt;td&gt;RFC 8439&lt;/td&gt;
&lt;td&gt;RFC 8452&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Pick AES-256-GCM when you have AES hardware and can guarantee unique nonces. Pick ChaCha20-Poly1305 when you cannot count on AES hardware, as on many mobile and embedded targets [@rfc8439]. Pick AES-GCM-SIV when nonce uniqueness is at risk, for example stateless senders, key wrapping, or anything that can be cloned or rolled back [@rfc8452]. None of the three commits to its key, so add that property separately if you need it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The newest target on this list, key commitment from Generation 5, is being written into standards as you read this. In May 2025 the IRTF&apos;s Crypto Forum Research Group published RFC 9771, which gives consensus, game-based names for Key Commitment and Full Commitment alongside related properties such as nonce hiding, multi-user security, and quantum security. A spec can finally &lt;em&gt;name&lt;/em&gt; the property it needs instead of gesturing at it [@rfc9771].&lt;/p&gt;
&lt;p&gt;NIST is scoping an actual mode. Its Accordion effort targets a tweakable, variable-input-length strong pseudorandom permutation with a reduction proof and key commitment as a stated requirement, laid out across NIST IR 8537 in 2024 [@ir8537], the requirements report NIST IR 8552 in April 2025 [@ir8552], and a pre-draft call for comments on SP 800-197A that proposes three modes (Acc128, Acc256, and a beyond-birthday variant) built from the HCTR2 technique [@sp800197a] [@hctr2] [@nist_news_accordion].&lt;/p&gt;
&lt;p&gt;You do not have to wait for it: the AWS Encryption SDK already enforces key commitment through a commitment policy, a production deployment that predates any standard [@aws_esdk].&lt;/p&gt;
&lt;p&gt;Why does commitment need a whole new mode rather than a bigger tag? Partly because a binding guarantee inherits the birthday bound: $n$-bit commitment security needs roughly a $2n$-bit commitment, about 256 bits for 128-bit security, so a standard 128-bit tag is undersized for the job [@bh2022]. And breaking commitment is a &lt;em&gt;binding&lt;/em&gt; problem, which the sketch below shows is a weapon rather than a curiosity.&lt;/p&gt;
&lt;p&gt;{`
// Intuition only, not a real attack. A non-committing &quot;AEAD&quot; whose verifier
// happens to accept a crafted ciphertext under MANY candidate keys.
function accepts(candidateKey, craftedCiphertext) {
  // In a committing scheme this would be true for at most one key.
  // Here the attacker built a ciphertext valid for a whole set of keys.
  return craftedCiphertext.validKeys.includes(candidateKey);
}&lt;/p&gt;
&lt;p&gt;// The attacker packs &quot;half the remaining candidates&quot; into one ciphertext.
function craftFor(keySubset) {
  return { validKeys: keySubset };
}&lt;/p&gt;
&lt;p&gt;let candidates = [];
for (let i = 0; i &amp;lt; 1024; i++) candidates.push(&quot;key#&quot; + i);&lt;/p&gt;
&lt;p&gt;let queries = 0;
while (candidates.length &amp;gt; 1) {
  const half = candidates.slice(0, Math.floor(candidates.length / 2));
  const ct = craftFor(half);
  queries++;
  // One online guess rules out half the space, committing or not.
  candidates = accepts(candidates[0], ct) ? half : candidates.slice(half.length);
}
console.log(&quot;Recovered key:&quot;, candidates[0], &quot;in&quot;, queries, &quot;online queries over 1024 candidates.&quot;);
`}&lt;/p&gt;
&lt;p&gt;Ten queries to search a thousand keys, because each ciphertext answers &quot;is your key in this set?&quot; A committing scheme makes that impossible: one ciphertext accepts under at most one key, so each guess can only ever eliminate a single candidate.&lt;/p&gt;
&lt;p&gt;All of this, classical and post-quantum, symmetric and public-key, is proven in one of two settings, under one of two styles of definition. Which one you trust changes what the proof is worth.&lt;/p&gt;
&lt;h2&gt;7. Two Styles of Definition, Two Places to Prove Them&lt;/h2&gt;
&lt;p&gt;Two long-running tensions run underneath every definition so far, and neither is resolved. The first is &lt;em&gt;how&lt;/em&gt; you state a goal. The second is &lt;em&gt;where&lt;/em&gt; you prove it.&lt;/p&gt;
&lt;p&gt;Everything up to this point has used indistinguishability games: define two worlds and demand that no efficient adversary can tell them apart. That style fits standalone primitives beautifully. But there is a second style, simulation-based (or real-versus-ideal) security, which asks a different question: is there a simulator that, with no access to the secrets, can produce a transcript indistinguishable from a real interaction? If so, the real protocol leaks nothing the ideal one would not, because anything the adversary learns it could have generated itself.&lt;/p&gt;
&lt;p&gt;Simulation is the natural language for zero-knowledge proofs, secure multiparty computation, and composable settings, where the strongest framework is Universal Composability.Universal Composability, due to Ran Canetti [@canetti2001uc], proves a protocol secure even when arbitrarily many copies of it and other protocols run concurrently, by comparing the real execution to an ideal functionality. It is the strongest simulation-based framework, and the price of that strength is that UC-secure protocols are harder to build. We only point at it here. Simulation generally implies the matching indistinguishability notion but not the reverse, so the two are complementary lenses rather than rivals [@bonehshoup]. For these simulation-based definitions in deployed systems, see &lt;a href=&quot;https://paragmali.com/blog/the-age-gate-that-doesnt-know-your-age-how-anonymous-credent&quot; rel=&quot;noopener&quot;&gt;the age gate that does not know your age&lt;/a&gt; and &lt;a href=&quot;https://paragmali.com/blog/direct-anonymous-attestation-the-zero-knowledge-proof-alread&quot; rel=&quot;noopener&quot;&gt;direct anonymous attestation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The second tension is the setting in which a proof lives, and it is the one most often misunderstood.&lt;/p&gt;

The random oracle model proves a scheme secure while treating a hash function as if it were a truly random function that everyone can query but nobody can predict. It is a *proof setting*, a modeling assumption you adopt in order to prove a goal such as IND-CCA2, and it sits beside the standard model, which assumes only that standard problems are hard. The random oracle model is emphatically **not** a security definition. It never occupies the same slot as IND-CPA or EUF-CMA; it is where you prove those goals, not what you prove.
&lt;p&gt;Bellare and Rogaway introduced it in 1993 precisely because it buys efficient, strong proofs for practical schemes: OAEP, PSS, and the FO transform behind ML-KEM all live here [@br1993]. The standard model asks for less faith and is therefore more trustworthy when you can afford it.&lt;/p&gt;
&lt;p&gt;Cramer and Shoup proved in 1998 that IND-CCA2 is achievable in the standard model, under the decisional Diffie-Hellman assumption, with no random oracle at all, settling that the strongest confidentiality target is not hostage to the heuristic [@cramershoup1998]. The two settings coexist as a trade of assurance against efficiency, and the post-quantum era stacks the quantum random oracle model on top.Beyond the deployed targets in this guide, the literature refines these notions further along both axes. RCCA (Canetti-Krawczyk-Nielsen) [@ckn2003rcca] and the related gCCA and mCCA variants relax IND-CCA2 for settings such as re-randomizable encryption. On the hash-function side, UCE is a standard-model assumption for discharging hash-based proofs without a random oracle, while indifferentiability is an ideal-model framework showing that a concrete construction built from an ideal primitive behaves like a random oracle, the tool that justifies random-oracle-style design rather than replacing it. These academic refinements are surveyed in later parts of this series; here they are pointers only.&lt;/p&gt;
&lt;p&gt;Here is the whole thing in one picture: two proof settings, the random oracle model and the standard model, with the major schemes sorted by where each one is proven.&lt;/p&gt;

flowchart TD
    subgraph ROM[&quot;Random oracle model&quot;]
        O[&quot;RSA-OAEP (IND-CCA2) and RSA-PSS (EUF-CMA), strong game-based goals proven in the ROM&quot;]
        K[&quot;ML-KEM, IND-CCA2 KEM via the FO transform in the quantum ROM&quot;]
    end
    subgraph STD[&quot;Standard model&quot;]
        CS[&quot;Cramer-Shoup, IND-CCA2 under decisional Diffie-Hellman&quot;]
        UC[&quot;Universal-composability zero knowledge, simulation based&quot;]
    end

The random oracle model and the standard model are not rival definitions of secure. They are two settings in which you prove the same goal.
&lt;p&gt;Which raises the uncomfortable question the next section confronts. If the random oracle model is only a heuristic, exactly how much is a random-oracle proof worth?&lt;/p&gt;
&lt;h2&gt;8. What a Proof Cannot Promise&lt;/h2&gt;
&lt;p&gt;Now the uncomfortable part. A scheme can be provably secure in the random oracle model and broken under &lt;em&gt;every&lt;/em&gt; real hash function you could ever plug in.&lt;/p&gt;
&lt;p&gt;That is not a worry, it is a theorem. Canetti, Goldreich, and Halevi constructed signature and encryption schemes that carry airtight proofs in the random oracle model yet become insecure the moment the oracle is replaced by any concrete, efficiently computable hash [@cgh2004]. Their construction is deliberately contrived, engineered to detect when its oracle has a short description and to misbehave when it does. But contrived is enough: it proves that a random-oracle proof cannot, in general, guarantee security once instantiated. The proof is real; the security does not always survive contact with a real hash.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Treat a random-oracle proof as strong evidence, not as a certificate. It says a scheme has no &lt;em&gt;structural&lt;/em&gt; weakness of the kind the proof rules out, which is reassuring for OAEP, PSS, and ML-KEM. It does not say that every hash instantiation is safe, because we know constructions where none is [@cgh2004]. Calibrate your trust to the setting the proof actually used.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The honest reading is not to discard random-oracle proofs. Almost everything efficient we deploy has one, and the counterexamples above are artificial rather than schemes anyone would design. The honest reading is to calibrate. That is also the spirit of Koblitz and Menezes&apos;s &quot;Another Look&quot; critique, which is often misread as an attack on provable security and is better understood as a discipline for reading proofs [@km2007].&lt;/p&gt;

Before you trust a &quot;provably secure&quot; label, ask four questions. What exactly are the goal and adversary model, stated in full? What assumption does the reduction rest on, and how well studied is it? How tight is the reduction, and what security does it actually deliver at the deployed parameters? And in which setting does the proof live, random oracle or standard model? None of these questions refutes a proof. Each tells you what the proof is worth [@km2007].
&lt;p&gt;Even celebrated proofs need repair. The original OAEP argument had a gap in its chosen-ciphertext proof that went unnoticed for years before it was found and fixed for the RSA case.Victor Shoup showed in 2001 that the original OAEP proof did not establish IND-CCA2 in the generality claimed. The result was recovered for RSA specifically, but only after the community re-examined a proof everyone had trusted [@shoup2001]. A proof is an artifact, and artifacts can contain bugs. If the proofs themselves can carry errors, &quot;it has a proof&quot; is the beginning of due diligence, not the end.&lt;/p&gt;
&lt;p&gt;Underneath all of it sits the deepest limit of the field. Essentially every computational definition in this guide rests on an &lt;em&gt;unproven&lt;/em&gt; assumption: that factoring is hard, that discrete logarithms are hard, that Module-LWE is hard. A genuine, unconditional proof that any of them is hard would resolve questions on the order of P versus NP, which nobody can do [@bonehshoup].&lt;/p&gt;
&lt;p&gt;So &quot;provably secure&quot; always means &lt;em&gt;conditionally&lt;/em&gt; secure. There is no unconditional computational security above the Shannon bound we started with. The one-time pad remains the only thing proven secure against an unbounded adversary, and it is the one thing we cannot afford to use.&lt;/p&gt;
&lt;p&gt;None of this refutes the method. It maps the edge of what is settled. And the edge is exactly where today&apos;s research is moving.&lt;/p&gt;
&lt;h2&gt;9. Where the Definitions Are Still Moving&lt;/h2&gt;
&lt;p&gt;The chain is not closed. Each open problem below is a place where the adversary model is still being enlarged, which is another way of saying the thesis is a roadmap rather than a finished map.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Standardizing committing AEAD.&lt;/strong&gt; The deployed triad commits to nothing, yet message franking, multi-recipient encryption, key rotation, key-management services, and password-based encryption all need it. The Accordion effort is scoping the mode now, but whether the default becomes key commitment (CMT-1) or full context commitment (CMT-4) is still open, and the two differ in both cost and in what they defend [@ir8537] [@sp800197a].&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tight, deployment-honest reductions.&lt;/strong&gt; Loose reductions force larger keys than the assumption alone requires, and the gap is worst in the multi-user setting, where one attacker faces millions of sessions at once. The Section 5 rule makes the cost concrete: if a reduction loses a factor equal to a billion ($2^{30}$) sessions, a headline 128-bit guarantee shrinks to about 98 bits at the deployed parameters.RFC 9771 names multi-user security as a distinct property precisely because a bound that is comfortable for one user can dissolve across a billion of them. Tight multi-user proofs are an active target, not a solved problem [@rfc9771]. How much the community should discount a loose proof remains contested rather than settled [@km2007].&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Post-quantum definitions in the quantum random oracle model.&lt;/strong&gt; What &quot;IND-CCA2 against a quantum adversary&quot; actually costs is still being pinned down. ML-KEM ships with a proof whose bound is not tight, and the right model for a superposition decryption oracle is unsettled [@hhk2017] [@rfc9771].&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The random-oracle-versus-standard-model question.&lt;/strong&gt; Canetti, Goldreich, and Halevi proved the random oracle model is in principle uninstantiable, yet the efficient schemes running the internet are proved there, and Cramer and Shoup showed the standard model can reach the same target at higher cost [@cgh2004] [@cramershoup1998]. There is no consensus on how much to trust the heuristic; the honest position is calibrated trust, not resolution.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Every entry on this list is a place where a future deployment could hand an attacker a capability no current definition names, exactly as message franking did in 2018. That is why the discipline is not &quot;memorize the acronyms.&quot; It is a habit you apply before you choose a primitive.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Which is exactly why mastery here is not the acronyms. It is a workflow, and it fits on one screen.&lt;/p&gt;
&lt;h2&gt;10. The Field Guide: Choose the Target Before the Primitive&lt;/h2&gt;
&lt;p&gt;Everything in this guide collapses into one workflow you can run in a design review this afternoon: name what the adversary is allowed to do, pick the target that survives that adversary, and only then choose a concrete mode and its parameters. The tree below is the whole method.&lt;/p&gt;

flowchart TD
    Q1{&quot;Can the adversary observe decryption or accept/reject?&quot;}
    Q1 --&amp;gt;|&quot;Yes&quot;| CCA[&quot;Require IND-CCA2, never IND-CPA-only&quot;]
    Q1 --&amp;gt;|&quot;No, just encrypting a channel&quot;| AEAD[&quot;Use AEAD by default&quot;]
    AEAD --&amp;gt; Q2{&quot;Can you guarantee unique nonces?&quot;}
    Q2 --&amp;gt;|&quot;Yes, with AES hardware&quot;| GCM[&quot;AES-256-GCM, 96-bit random nonce, cap under 2 to the 32 per key&quot;]
    Q2 --&amp;gt;|&quot;No&quot;| SIV[&quot;AES-GCM-SIV, nonce-misuse resistant&quot;]
    CCA --&amp;gt; Q3{&quot;Must one ciphertext bind to one key?&quot;}
    Q3 --&amp;gt;|&quot;Yes&quot;| CMT[&quot;Require committing AE, CMT-4 or a vetted transform&quot;]
&lt;p&gt;The decision rules, stated the way you would apply them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;If any adversary can observe decryption or accept/reject behavior, require IND-CCA2, never IND-CPA-only.&lt;/strong&gt; That is the Bleichenbacher and ROBOT lesson: a reacting server is a decryption oracle [@bleichenbacher1998].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;If you are encrypting a channel, use AEAD by default.&lt;/strong&gt; AES-256-GCM with 96-bit random nonces and a hard message cap well under $2^{32}$ per key [@sp800_38d]; ChaCha20-Poly1305 where there is no AES hardware [@rfc8439]; AES-GCM-SIV when nonce uniqueness cannot be guaranteed [@rfc8452].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;If you must use RSA encryption at all, use RSA-OAEP, never PKCS#1 v1.5,&lt;/strong&gt; or drop RSA key transport entirely as TLS 1.3 did [@br1994oaep] [@bleichenbacher1998].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;If you need authenticity only, use HMAC or Ed25519 for EUF-CMA,&lt;/strong&gt; and require SUF-CMA wherever a signature or token must be unique [@bonehshoup] [@decker2014]. Ed25519 delivers SUF-CMA only when verification enforces the RFC 8032 canonical-S range check, rejecting any scalar $S$ outside $[0, L)$; libraries that skip it stay malleable [@rfc8032].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;If a ciphertext must bind to exactly one key or context, require a committing AE:&lt;/strong&gt; a CMT-4 construction or a vetted committing transform, never the raw triad. This is the multi-recipient, key-rotation, franking, password-based, and key-management case [@rfc9771] [@aws_esdk] [@bh2022].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;If you need post-quantum key establishment, use ML-KEM (FIPS 203) in hybrid mode&lt;/strong&gt; with a classical KEM during the transition [@fips203].&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Deployment condition&lt;/th&gt;
&lt;th&gt;Required target&lt;/th&gt;
&lt;th&gt;Concrete choice and parameters&lt;/th&gt;
&lt;th&gt;Anti-pattern it prevents&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Adversary sees decryption or accept/reject&lt;/td&gt;
&lt;td&gt;IND-CCA2&lt;/td&gt;
&lt;td&gt;ML-KEM, RSA-OAEP, or an AEAD channel&lt;/td&gt;
&lt;td&gt;Bleichenbacher, ROBOT, POODLE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Channel, unique nonces, AES hardware&lt;/td&gt;
&lt;td&gt;AEAD&lt;/td&gt;
&lt;td&gt;AES-256-GCM, 96-bit random nonce, cap under $2^{32}$ per key&lt;/td&gt;
&lt;td&gt;Unauthenticated or malleable ciphertext&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Channel, no AES hardware&lt;/td&gt;
&lt;td&gt;AEAD&lt;/td&gt;
&lt;td&gt;ChaCha20-Poly1305&lt;/td&gt;
&lt;td&gt;Slow or side-channel-prone software AES&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nonce uniqueness not guaranteed&lt;/td&gt;
&lt;td&gt;AEAD plus misuse resistance&lt;/td&gt;
&lt;td&gt;AES-GCM-SIV&lt;/td&gt;
&lt;td&gt;Joux forbidden-attack forgery&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Legacy RSA encryption required&lt;/td&gt;
&lt;td&gt;IND-CCA2&lt;/td&gt;
&lt;td&gt;RSA-OAEP, never PKCS#1 v1.5&lt;/td&gt;
&lt;td&gt;Padding-oracle decryption&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Signature or token must be unique&lt;/td&gt;
&lt;td&gt;SUF-CMA&lt;/td&gt;
&lt;td&gt;Ed25519&lt;/td&gt;
&lt;td&gt;Signature-malleability confusion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One ciphertext must bind to one key&lt;/td&gt;
&lt;td&gt;Committing AE (CMT)&lt;/td&gt;
&lt;td&gt;Committing transform or Accordion mode&lt;/td&gt;
&lt;td&gt;Invisible salamanders, partitioning oracles&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Confidentiality must outlive a quantum computer&lt;/td&gt;
&lt;td&gt;IND-CCA2, post-quantum&lt;/td&gt;
&lt;td&gt;Hybrid X25519 plus ML-KEM&lt;/td&gt;
&lt;td&gt;Harvest-now-decrypt-later&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Every rule above has a mirror image, a mistake that turns up in code review after code review. Here is the misuse catalog, each entry the negation of a rule you just read.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Nonce reuse under AES-GCM or ChaCha20-Poly1305,&lt;/strong&gt; the single most destructive AEAD error, because it is a universal forgery via the Joux attack rather than a slow degradation [@joux_gcm]. Clones, snapshots, and stateless senders are the usual sources; reach for AES-GCM-SIV or a strictly managed random nonce with a per-key cap.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The wrong composition order,&lt;/strong&gt; MAC-then-Encrypt or Encrypt-and-MAC; only Encrypt-then-MAC or a dedicated AEAD is generically safe, and history already paid for this with POODLE and Lucky Thirteen [@bn2000].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Treating AES-GCM as key-committing.&lt;/strong&gt; It commits to nothing; assuming otherwise is the salamander and partitioning-oracle bug [@salamanders2018] [@partitioning2021].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unbounded messages per key,&lt;/strong&gt; silently walking past the birthday ceiling that GCM&apos;s 96-bit nonce imposes [@sp800_38d].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Verifying a signature without binding its context,&lt;/strong&gt; which EUF-CMA never promised to cover and which invites cross-protocol confusion.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Trusting a random-oracle proof as a standard-model guarantee,&lt;/strong&gt; when it is a heuristic to be calibrated rather than a certificate [@cgh2004].&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For where these targets are actually invoked as concrete API calls on Windows, from BCrypt to key storage providers, see &lt;a href=&quot;https://paragmali.com/blog/cng-architecture-bcrypt-ncrypt-ksps&quot; rel=&quot;noopener&quot;&gt;the CNG architecture behind BCrypt, NCrypt, and KSPs&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; State your deployment&apos;s adversary model first, choose the matching target second, and pick the concrete primitive and its parameters last. Every rule and every anti-pattern above is a corollary of that one habit.&lt;/p&gt;
&lt;/blockquote&gt;

Bleichenbacher and ROBOT: require IND-CCA2 and drop PKCS#1 v1.5. Lucky Thirteen and POODLE: use an AEAD with Encrypt-then-MAC, not MAC-then-Encrypt CBC. AES-GCM nonce reuse: cap messages per key and use AES-GCM-SIV where uniqueness is uncertain. Invisible salamanders and partitioning oracles: require a committing (CMT) mode. Every break in the catalog was preventable by choosing the target the environment demanded before choosing the primitive.
&lt;p&gt;One habit generated every rule and every warning on this page: name the adversary first.&lt;/p&gt;
&lt;h2&gt;11. Misconceptions, Named and Corrected&lt;/h2&gt;
&lt;p&gt;The fastest way to internalize the thesis is to correct the folklore it contradicts.&lt;/p&gt;


Only against a *passive* adversary who never sees how the receiver reacts to a ciphertext. The moment a server decrypts attacker-supplied input and behaves observably differently on success and failure, you need IND-CCA2. That gap is exactly what Bleichenbacher&apos;s attack exploited [@bleichenbacher1998].


Only under a strict nonce-uniqueness contract and a per-key message cap. Reusing a (key, nonce) pair is a universal forgery, not a minor leak [@joux_gcm]; NIST caps GCM at about $2^{32}$ invocations per key at a 96-bit nonce [@sp800_38d]; and GCM commits to no key, so it is unsafe wherever commitment is assumed [@salamanders2018].


It is strong evidence, not a guarantee. Canetti, Goldreich, and Halevi built schemes provably secure in the random oracle model that are insecure under every real hash [@cgh2004]. Trust a random-oracle proof, but calibrate that trust to the setting it used.


No. Confidentiality and integrity are different goals; a one-time pad has perfect confidentiality and zero integrity, since flipping a ciphertext bit flips the plaintext bit undetected. Use an AEAD, and compose Encrypt-then-MAC if you must build it yourself [@bn2000].


No. SUF-CMA also forbids producing a *new* valid signature on an already-signed message, which EUF-CMA permits. The gap bites whenever a signature or ciphertext is treated as a unique token, as Bitcoin transaction malleability showed [@decker2014] [@bonehshoup].


No. It means *conditionally* secure, relative to a named hardness assumption and adversary model, and only as tightly as the reduction allows. A loose reduction delivers fewer bits of security than the headline number suggests [@km2007].


No. It is a proof setting, a heuristic that idealizes a hash as a random function, and it sits beside the standard model, not beside goals like IND-CPA or EUF-CMA. Cramer and Shoup showed the strongest confidentiality target is reachable without it [@br1993] [@cramershoup1998].

&lt;h2&gt;The Contract Behind the Cipher&lt;/h2&gt;
&lt;p&gt;We began with a puzzle: Daniel Bleichenbacher decrypted SSL sessions without ever breaking RSA. The answer runs through every section since. &quot;Secure&quot; is not a property an algorithm has. It is a contract, a goal bound to an adversary model, and a construction honors that contract only against the adversary the contract names.&lt;/p&gt;
&lt;p&gt;Bleichenbacher, POODLE, Lucky Thirteen, AES-GCM nonce reuse, invisible salamanders, partitioning oracles: not one of them was weak math. Each was a construction meeting a weaker target than its deployment&apos;s adversary demanded, after the environment handed the attacker an oracle, a repeated nonce, or a second key the proof never granted.&lt;/p&gt;
&lt;p&gt;That is why the vocabulary matters. IND-CPA and IND-CCA2 name what confidentiality means against a passive versus an active adversary. EUF-CMA and SUF-CMA name authenticity with and without malleability. AEAD names their union; committing AE names what AEAD forgot. The random oracle model and the standard model name where a proof lives, and a reduction names the single assumption on which the whole guarantee rests. Learn to read a construction as goal plus adversary model plus proof setting, and the failure catalog stops being a list of surprises and becomes a list of predictions.&lt;/p&gt;
&lt;p&gt;This is Part 1 of a field guide, and it deliberately taught no primitive in depth. That was the point. The remaining parts of this series will build RSA, Diffie-Hellman, elliptic curves, lattices, and hash functions, and every one of them will be measured against exactly the targets defined here. The math will change from part to part. The contract will not.&lt;/p&gt;
&lt;p&gt;The RSA math was always fine. What the field lacked in 1998 was the habit of naming the adversary before trusting the primitive. Now you have it.&lt;/p&gt;

State the adversary model first, choose the matching target second, and pick the primitive last. That one habit would have prevented every break in this article.
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;secure-against-whom-security-definitions&quot; keyTerms={[
  { term: &quot;IND-CPA&quot;, definition: &quot;Indistinguishability under chosen-plaintext attack; confidentiality against a passive adversary.&quot; },
  { term: &quot;IND-CCA2&quot;, definition: &quot;Adaptive chosen-ciphertext security; confidentiality against an adversary with a decryption oracle before and after the challenge.&quot; },
  { term: &quot;EUF-CMA&quot;, definition: &quot;Existential unforgeability under chosen-message attack; no forgery on a new message.&quot; },
  { term: &quot;SUF-CMA&quot;, definition: &quot;Strong unforgeability; no new signature even on an already-signed message.&quot; },
  { term: &quot;AEAD&quot;, definition: &quot;Authenticated encryption with associated data; confidentiality plus ciphertext integrity over a nonce interface.&quot; },
  { term: &quot;INT-CTXT&quot;, definition: &quot;Ciphertext integrity; the adversary cannot produce any valid ciphertext the encryptor never output.&quot; },
  { term: &quot;Key commitment&quot;, definition: &quot;A ciphertext binds to exactly one key or context; graded CMT-1 through CMT-4.&quot; },
  { term: &quot;Random oracle model&quot;, definition: &quot;A proof setting that idealizes a hash as a truly random function; not a security definition.&quot; },
  { term: &quot;Reduction&quot;, definition: &quot;A proof that turns any adversary against the scheme into a solver for a hard problem.&quot; },
  { term: &quot;Nonce-misuse resistance&quot;, definition: &quot;Graceful degradation when a nonce repeats, as in AES-GCM-SIV.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>cryptography</category><category>security-definitions</category><category>authenticated-encryption</category><category>provable-security</category><category>ind-cca2</category><category>aead</category><category>post-quantum-cryptography</category><category>protocol-design</category><author>noreply@paragmali.com (Parag Mali)</author></item></channel></rss>