One key, both directions
Symmetric-key cryptography uses a single secret key for both encryption and decryption. If Alice and Bob share a key, Alice can encrypt a message with it and Bob can decrypt it with the same key. The security of the whole scheme rests entirely on that key staying secret.
This is the oldest form of cryptography in continuous use, and it remains the workhorse of modern systems because it's fast — often 100-1000x faster than public-key operations on the same data.
AES: the current standard
The Advanced Encryption Standard (AES) was selected by NIST in 2001 after a public competition, replacing the older DES. AES operates on fixed-size 128-bit blocks of data and supports key sizes of 128, 192, or 256 bits.
Internally, AES applies a series of transformations — substitution (SubBytes), permutation (ShiftRows), mixing (MixColumns), and key mixing (AddRoundKey) — repeated over 10, 12, or 14 rounds depending on key size. Each round diffuses the input so thoroughly that flipping a single input bit changes roughly half the output bits (the avalanche effect).
No practical attack breaks full AES faster than brute force. AES-128 offers roughly 128 bits of security — meaning an attacker needs on the order of 2^128 operations to find the key. That number is astronomically larger than the number of atoms in the observable universe.
One AES round (repeated 10, 12, or 14 times)
- 1
SubBytes
Each byte of the 128-bit block is substituted using a fixed lookup table, adding non-linearity.
- 2
ShiftRows
Bytes are shifted across rows of the internal 4×4 state, spreading data across columns.
- 3
MixColumns
Each column is mixed via matrix multiplication over a finite field, diffusing every byte's influence.
- 4
AddRoundKey
The current round's subkey (derived from the main key) is XORed into the state.
Roughly 10 billion times more than the estimated number of stars in the observable universe.
The same four steps, as a pipeline
Laid out as a loop, it's clearer why AES needs as many rounds as it does: each pass diffuses the state a little further, and it takes several rounds before a single changed input bit has plausibly affected every output bit.
Inside a round: the state, laid out as a grid
AES doesn't treat its 128-bit block as a flat line of bytes — it arranges the 16 bytes into a 4×4 grid called the state, filled one column at a time from the input. Every transformation in a round (SubBytes, ShiftRows, MixColumns, AddRoundKey) operates on this grid shape, which is exactly why ShiftRows and MixColumns are able to spread a single input byte's influence across the entire block within a couple of rounds.
The AES state — 16 input bytes b0…b15, filled column by column
This grid, not the original byte order, is what SubBytes, ShiftRows, and MixColumns actually operate on.
ShiftRows: spreading bytes across columns
SubBytes (the step before this one) substitutes each byte independently using a fixed lookup table — it adds non-linearity, but on its own it wouldn't mix bytes together at all. ShiftRows is what starts the mixing: it cyclically shifts row r of the state left by r positions. Row 0 doesn't move; row 3 shifts by three positions. After this, a byte that started in one column is now sitting in a different column, ready for MixColumns to blend it with its new neighbors.
The state after ShiftRows
Row 1 shifted left by 1, row 2 by 2, row 3 by 3 — compare against the original layout above.
MixColumns and the key schedule
MixColumns treats each column of four bytes as a small vector and multiplies it by a fixed matrix, using arithmetic in a finite field (GF(2⁸)) rather than ordinary integer arithmetic. The output byte in each position depends on all four input bytes of that column — this is the step that actually diffuses information within a column, complementing ShiftRows' diffusion across columns.
None of this would be a secret without a key. AES's key schedule (key expansion) takes the original 128/192/256-bit key and algorithmically derives a separate round key for every round — 11, 13, or 15 round keys depending on key size — using repeated rotation, substitution (reusing the same S-box as SubBytes), and XOR with round constants. Each round's AddRoundKey step XORs one of these derived round keys into the state; without knowing the original key, an attacker can't reproduce any of them.
Modes of operation: turning a block cipher into something usable
AES itself only ever encrypts one 128-bit block at a time. A mode of operation is the algorithm that extends that single-block primitive to encrypt messages of any length — and the choice of mode matters as much as the choice of key size, because a weak mode can leak information even when the underlying cipher (AES) is unbroken.
ECB: the mode you should never use
Electronic Codebook (ECB) mode is the simplest possible approach: split the message into blocks and encrypt each one independently with the same key. It's also the classic cautionary example in cryptography teaching, because identical plaintext blocks always produce identical ciphertext blocks — patterns in the input (a repeated header, a solid-colored region of an image) remain visible as patterns in the output, even though each individual block is properly encrypted.
CBC: chaining blocks together
Cipher Block Chaining (CBC) fixes ECB's pattern leakage by XORing each plaintext block with the previous ciphertext block before encrypting it, starting with a random Initialization Vector (IV) for the first block. This makes every ciphertext block depend on everything encrypted before it, so identical plaintext blocks no longer produce identical ciphertext — but it also means CBC is inherently sequential to decrypt, and a corrupted block only affects that block and the next one, not everything after it.
CBC encryption, block by block
- 1
Block 1
P₁ is XORed with the IV, then encrypted to produce C₁.
- 2
Block 2
P₂ is XORed with C₁ (the previous ciphertext), then encrypted to produce C₂.
- 3
Block 3 and onward
Each block is XORed with the ciphertext immediately before it — one long dependency chain.
CTR: turning a block cipher into a stream cipher
Counter (CTR) mode takes a completely different approach: instead of encrypting the plaintext directly, it encrypts a counter value (combined with a nonce) to produce a keystream, then XORs that keystream with the plaintext — structurally identical to the stream-cipher pattern covered in the ChaCha20 module. This has a major practical advantage over CBC: because each block's keystream only depends on the counter, not on previous ciphertext, blocks can be encrypted and decrypted in parallel and in any order.
GCM: encryption and authentication in one pass
Galois/Counter Mode (GCM) is CTR mode plus an authentication layer: alongside encrypting with a counter-based keystream exactly like CTR, it computes an authentication tag over the ciphertext using a technique called GHASH. The result is an AEAD construction — the same category as ChaCha20-Poly1305 — that gives you confidentiality and tamper detection from a single pass over the data, which is why GCM (not CBC, not plain CTR) is the default for AES in TLS 1.3.
CTR — confidentiality only
- •Fast, parallelizable, no padding needed
- •No built-in way to detect tampering
- •A flipped ciphertext bit silently flips the corresponding plaintext bit
GCM — confidentiality + integrity
- •CTR-mode encryption plus a GHASH-computed authentication tag
- •Any tampering with the ciphertext is detected on decryption
- •The mode behind most TLS 1.3 connections today
Inside GHASH: how the tag is actually built
The encryption half of GCM is plain CTR mode: a counter block is encrypted and XORed with the plaintext. The authentication half runs in parallel — every ciphertext block is folded into a running value through multiplication in the finite field GF(2¹²⁸), keyed by a hash subkey H derived from encrypting an all-zero block. That running value is then XORed with one more encrypted counter block (using counter value J0, never reused for plaintext) to produce the final tag.
GCM: counter-mode encryption + GHASH authentication
Shown for a single plaintext block; longer messages chain more ciphertext blocks through the same GHASH multiplication before the final XOR that produces the tag.
Padding, and the oracle it can create
CBC and ECB both require the plaintext to be a multiple of the block size, so short final blocks are padded — commonly with PKCS#7 padding, which fills the remaining bytes with a value equal to the number of padding bytes added (so a decryptor can identify and strip it unambiguously). CTR and GCM, by contrast, need no padding at all, since they turn AES into a stream cipher rather than encrypting the plaintext directly.
Padding sounds like a minor bookkeeping detail, but it's exactly the mechanism behind the Bleichenbacher-style padding oracle attacks covered in the RSA padding module and the Lucky Thirteen attack covered in the side-channel module — both exploit a server that reveals, even indirectly through timing, whether decrypted padding was valid.
Nonce reuse: the catastrophic failure mode
Every mode covered here depends on never reusing the same IV/nonce with the same key for two different messages. In CBC, IV reuse leaks whether two messages start with the same block. In CTR and GCM, it's far worse: reusing a nonce produces the identical keystream twice, and XORing the two resulting ciphertexts together cancels the keystream out entirely — handing an attacker the XOR of the two plaintexts directly, which is often enough to recover both messages. For GCM specifically, nonce reuse also breaks the authentication guarantee, letting an attacker forge valid-looking ciphertexts.
This is why AES-GCM implementations are so strict about nonce generation (typically a counter or a securely random 96-bit value that's never reused for a given key) — it's the single most common way real-world AES-GCM deployments get broken, not any weakness in AES itself.
Why it matters for the PQC conversation
Symmetric-key algorithms like AES are not broken by quantum computers the way RSA and ECC are. Grover's algorithm gives a quadratic speedup against brute-force key search, which roughly halves the effective key length — so AES-256 still offers about 128 bits of quantum-resistant security. This is why PQC migration guidance focuses on replacing RSA/ECC, not AES.