<?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: side-channel-attack</title><description>Posts tagged side-channel-attack.</description><link>https://paragmali.com/</link><language>en-US</language><lastBuildDate>Sun, 19 Jul 2026 05:08:42 GMT</lastBuildDate><atom:link href="https://paragmali.com/tags/side-channel-attack/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></channel></rss>