cipher.ink Write a message

Learn · Technologies we use

How AES works, round by round

How the cipher under every cipher.ink message scrambles 16 bytes, with the standard's own worked numbers.

AES, the Advanced Encryption Standard, protects almost everything that's encrypted today: your Wi-Fi, your bank's website, your phone's storage and every message sealed on cipher.ink, which uses AES-256-GCM. It takes 16 bytes and a key and scrambles the bytes in ten, twelve or fourteen identical rounds of four small steps. Each step is simple enough to follow by hand, so below we walk through one real round with real numbers and then look at why those steps, repeated, are so hard to undo.

Where AES came from

By the late 1990s the old standard, DES, had a 56-bit key that specialized hardware could search in days. The US National Institute of Standards and Technology (NIST) ran an open competition to replace it, and fifteen designs from around the world were picked over in public for about five years. The winner was Rijndael, by two Belgian cryptographers, Joan Daemen and Vincent Rijmen. NIST published it, with a fixed 128-bit block, as FIPS 197 on 26 November 2001, and it became a US federal standard on 26 May 2002. Three key sizes are allowed, and the number of rounds depends on the key:

VariantKeyBlockRounds
AES-128128 bits128 bits10
AES-192192 bits128 bits12
AES-256256 bits128 bits14

The competition matters to the story. DES was designed largely out of public view, while AES was chosen after years of attack by the world's cryptographers. Two decades on, it hasn't just survived. It's one of the most heavily analyzed ciphers in history.

The state: 16 bytes in a grid

AES works on a block of 16 bytes and arranges them as a 4×4 grid called the state. The bytes go into the grid column by column, so the first four fill the first column, the next four the second, and so on.

The 16 input bytes fill the 4 x 4 state column by columnb0b1b2b3b4b5b6b7b8b9b10b11b12b13b14b15SubByteseach byte alone, through the S-boxShiftRowsrow r slides left by r placesMixColumnseach column mixed with a fixed matrixAddRoundKeyXOR with the round keyShiftRows: row 0 stays
The AES state and the four steps that act on it, in order, in every round.

Every round applies four steps to that grid: SubBytes, ShiftRows, MixColumns and AddRoundKey. One extra AddRoundKey comes before round 1, and the last round skips MixColumns. The picture below is round 1 of the worked example in FIPS 197 (the key 2b7e1516 28aed2a6 abf71588 09cf4f3c and the plaintext 3243f6a8 885a308d 313198a2 e0370734), with the real bytes after each step.

Round 1 of the FIPS 197 example: shaded bytes changed in that step19a09ae93df4c6f8e3e28d48be2b2a08startSubBytesd4e0b81e27bfb44111985d52aef1e530ShiftRowsd4e0b81ebfb441275d52119830aef1e5MixColumns04e0482866cbf8068119d326e59a7a4cAddRoundKeya4686b029c9f5b6a7f35ea50f22b4349XOR round key
Round 1 of the FIPS 197 example. You can reproduce every grid in the AES round explorer.

SubBytes: the only non-linear step

SubBytes swaps each of the 16 bytes for another byte, using a 256-entry lookup table called the S-box. The table looks arbitrary, but it isn't random. Each entry is built in two stages.

  1. Invert in a finite field. Treat the byte as a polynomial of degree 7 with coefficients 0 or 1, and take its multiplicative inverse modulo the polynomial x8 + x4 + x3 + x + 1 (zero maps to zero). Multiplication in this field is ordinary polynomial multiplication with the coefficients added by XOR, reduced whenever the degree reaches 8. The standard's own example shows 57 × 13 = fe in this field. The inverse of 53 is ca, because 53 × ca = 01.
  2. Scramble the bits. Apply a fixed linear map, then XOR with 63. The inverse ca becomes ed. So the S-box sends 53 to ed, and 00 to 63.

The inversion is what lets the cipher stand up to the two most powerful general attacks, differential and linear cryptanalysis. Inversion in this field is about as far from a linear function as a function on bytes can get. The second stage removes the fixed points and the simple algebraic description the inversion would have on its own. This site's test suite builds the whole table from that definition and checks it against the standard.

ShiftRows and MixColumns: spreading the damage

With only SubBytes, each byte would stay where it was and the cipher would amount to 16 separate lookups. ShiftRows and MixColumns spread every byte's influence across the whole grid.

ShiftRows leaves row 0 alone and rotates row 1 left by one place, row 2 by two and row 3 by three. Afterward, the four bytes that shared a column sit in four different columns.

MixColumns treats each column as four field elements and multiplies by a fixed 4×4 matrix of small numbers (2, 3, 1, 1 in a rotating pattern). Each output byte is the XOR of the column's four input bytes, each multiplied by 1, 2 or 3 in the field. For example, the column db 13 53 45 becomes 8e 4d a1 bc. After MixColumns, every output byte depends on all four bytes of its column. ShiftRows then moves those bytes to different columns, and after one more MixColumns each byte depends on all 16.

The result is diffusion. In our example, flipping one bit of the plaintext changes this many of the 128 state bits after each round: 1 after the first AddRoundKey, then 19, 70, 62, 68, 68, 61, 67, 65, 75 and 68 at the end. Within two rounds about half the bits have changed, and they keep changing. That's the avalanche property, and it's what ten rounds are for. A few rounds mix the data thoroughly, and the rest buy a wide margin over every known attack.

AddRoundKey and the key schedule

AddRoundKey XORs the state with a 16-byte round key, and it's the only place the key enters. The key schedule stretches the original key into a different round key for each round. In the example, round key 0 is the key itself, 2b7e1516 28aed2a6 abf71588 09cf4f3c, and round key 1 is a0fafe17 88542cb1 23a33939 2a6c7605. Each new 4-byte word is the XOR of the word four positions back and the previous word. Every fourth word is first rotated by a byte, passed through the S-box and XORed with a round constant. The constant keeps any two rounds from being symmetric, and the S-box makes the schedule non-linear, so knowing one round key doesn't hand you the others.

How secure is it?

No practical attack is known against AES as it's actually used. The best published attacks on the full cipher, the biclique attacks by Bogdanov, Khovratovich and Rechberger in 2011 (improved slightly in 2015), need about 2126.2 operations for AES-128, 2190.2 for AES-192 and 2254.6 for AES-256. That saves a factor of only two to four over brute force. They're academic results and no threat. Related-key attacks on AES-192 and AES-256 (2009) run faster, but they need keys related in a chosen way, which a well-designed protocol never allows.

Brute force is hopeless. 2128 is about 3.4 × 1038. A machine that tried 1018 keys a second, a billion times faster than anything that exists, would need about 1013 years, some 780 times the age of the universe. AES-256 has 2256 keys, a number with 78 digits. Quantum computers don't change this much. Grover's algorithm searches a key space in roughly the square root of the time, so AES-256 would still need about 2128 steps. That's one reason this site uses 256-bit keys (post-quantum cryptography).

What breaks AES in practice is the implementation, not the cipher. Table-lookup software can leak the key through the time it takes, because memory caches respond differently to different lookups. Daniel Bernstein demonstrated a cache-timing attack on a server in 2005, and Osvik, Shamir and Tromer recovered a full key after 800 encryptions in a lab setting the same year. Modern processors have dedicated AES instructions (AES-NI) that run in constant time and are far faster, at around 1 to 2 cycles per byte. That's why browsers use the hardware.

What AES leaves out

  • AES is a block cipher, and 16 bytes isn't a message. To encrypt more than 16 bytes you need a mode. Encrypting each block separately (ECB) leaks patterns: see the ECB picture demo. Counter mode and CBC avoid that.
  • AES doesn't check that a message is unchanged. That's the job of an authenticated mode such as GCM, which adds a tag (AES-GCM, explained).
  • AES doesn't turn a passphrase into a key. A short passphrase is a weak key whatever the cipher. cipher.ink runs your passphrase through PBKDF2 first.

How cipher.ink uses it

Every message is sealed in your browser with AES using a 256-bit key, in Galois/Counter Mode, with a fresh 12 bytes (96 bits) nonce and a 128-bit authentication tag. Our code calls the browser's built-in Web Crypto API and never touches the cipher itself, so it runs on the processor's AES instructions. You can read the exact lines on the code page. The round-by-round implementation that drives the tools here is a separate, teaching version, checked against the standard's test vectors.

Further reading

  1. FIPS 197: Advanced Encryption Standard (2001)
  2. Daemen and Rijmen: The Design of Rijndael (Springer, 2002)
  3. Bogdanov, Khovratovich, Rechberger: Biclique Cryptanalysis of the Full AES (2011)
  4. Bernstein: Cache-timing attacks on AES (2005)
  5. Osvik, Shamir, Tromer: Cache Attacks and Countermeasures: the Case of AES (2005)
  6. Biryukov and Khovratovich: Related-key Cryptanalysis of the Full AES-192 and AES-256 (2009)