AES Cipher Β· 6 min read
AES-GCM vs AES-CBC: Why Authentication Mode Matters
AES-CBC encrypts but doesn't authenticate. AES-GCM does both. Here's why the difference has caused a decade of padding-oracle bugs and why GCM is the modern default.
AES is a block cipher. It encrypts exactly 16 bytes at a time. To encrypt anything longer β a file, a database field, a message β you need a mode that explains how to chain those 16-byte blocks together. CBC and GCM are two such modes, both built on the same underlying AES algorithm. The difference is whether the receiver can detect tampering. That single property has driven a decade of high-profile bugs.
How CBC Works
Cipher Block Chaining XORs each plaintext block with the previous ciphertext block before encrypting. The first block is XORed with a random initialisation vector (IV). The result is that identical plaintext blocks produce different ciphertext blocks, and a single bit-flip in the ciphertext garbles the corresponding plaintext block plus one bit of the next.
CBC is well-defined, fast on hardware without AES-NI, and was the workhorse of TLS 1.0 and 1.1. But it has one critical missing feature: it does not authenticate. There is nothing in a CBC ciphertext that lets the receiver tell whether the bytes were modified in transit.
The Padding Oracle Problem
CBC requires the plaintext to be a multiple of 16 bytes. The standard padding scheme (PKCS#7) appends bytes whose value equals the number of padding bytes β so a message needing three pad bytes ends with 03 03 03. On decryption, the receiver checks the padding and rejects malformed messages.
Vaudenay showed in 2002 that this rejection itself is a side channel. An attacker who can submit modified ciphertexts and observe whether the receiver returns "bad padding" or "bad MAC" (or just notices a timing difference) can decrypt the entire message byte by byte, without ever knowing the key. Real-world variants β POODLE, Lucky 13, BEAST β broke TLS, ASP.NET ViewState, JSF state tokens, and dozens of custom protocols. The root cause was always the same: CBC was used without a properly composed authentication step.
How GCM Works
Galois/Counter Mode runs AES in counter mode (encrypting nonce || counterblocks and XORing with plaintext) and simultaneously feeds each ciphertext block through a Galois-field multiplication to produce an authentication tag. The output is ciphertext plus a 16-byte tag. The receiver recomputes the tag during decryption and rejects anything that doesn't match β without revealing where the discrepancy was, in constant time.
GCM is an AEAD: Authenticated Encryption with Associated Data. You can include unencrypted context (a header, a user ID, a version field) in the tag computation so the receiver detects tampering on those fields too, even though they travel in plaintext.
Why GCM Won
- One primitive, two properties. Confidentiality and integrity in a single pass. No bolt-on HMAC, no chance of getting the composition order wrong.
- Hardware acceleration. Modern CPUs have AES-NI and PCLMULQDQ instructions that make GCM as fast or faster than CBC.
- Constant-time verification. The tag check doesn't leak timing information the way CBC padding checks do.
- Standard library support. Every modern crypto library β WebCrypto, OpenSSL, libsodium, Go's
crypto/cipherβ exposes AES-GCM with a sensible API.
The Nonce Trap
GCM has one footgun: nonce reuse is catastrophic. If you encrypt two different messages with the same key and the same nonce, an attacker can XOR the ciphertexts to recover the XOR of the plaintexts and forge arbitrary tags from then on. The nonce doesn't need to be secret, but it must be unique per key.
For most applications that means generating a 12-byte random nonce per message. The birthday bound says you can safely encrypt around 2^32 messages under the same key before random collisions become likely, which is plenty for almost everything but extreme high-volume systems. If you need more, derive a fresh key per session, or use AES-GCM-SIV (RFC 8452) which is misuse-resistant.
Encrypt-Then-MAC: The Other Right Answer
If you need CBC for legacy reasons, the safe pattern is "encrypt-then-MAC": encrypt with AES-CBC, then HMAC the entire ciphertext (including IV) with a separate key. On decrypt, verify the HMAC firstin constant time, and only attempt CBC decryption if it matches. This sidesteps padding oracles because attackers can't produce ciphertexts that even reach the padding-check stage. Bellare and Namprempre proved in 2000 that encrypt-then-MAC is generically secure; the other compositions (MAC-then-encrypt, encrypt-and-MAC) are not.
The Practical Recommendation
New code: AES-256-GCM with a random 12-byte nonce, or ChaCha20-Poly1305 if you want a non-AES alternative. Reach for AES-GCM-SIV if nonce uniqueness is hard to guarantee in your environment. Avoid AES-CBC unless you're working in a constrained legacy context, and if you do, always pair it with an HMAC over the ciphertext.
The high-level lesson is that "encryption" without authentication isn't useful in any modern threat model. If a mode doesn't come with a built-in tag, you have to add one yourself β and the history of CBC shows that most engineers who try, get it wrong.
References
- Dworkin, M. (2007). NIST Special Publication 800-38D: Recommendation for Block Cipher Modes of Operation: Galois/Counter Mode (GCM) and GMAC. National Institute of Standards and Technology.
- Vaudenay, S. (2002). Security Flaws Induced by CBC Padding. EUROCRYPT 2002, Lecture Notes in Computer Science vol 2332.
- Rizzo, J. & Duong, T. (2010). Practical Padding Oracle Attacks. USENIX WOOT '10.
- MΓΆller, B., Duong, T., & Kotowicz, K. (2014). This POODLE Bites: Exploiting the SSL 3.0 Fallback. Google Security Advisory.
- Bellare, M. & Namprempre, C. (2000). Authenticated Encryption: Relations among notions and analysis of the generic composition paradigm. ASIACRYPT 2000.