AES is a block cipher — it only knows how to scramble exactly 16 bytes at a time. Real data is almost never exactly 16 bytes, so every AES implementation needs a mode of operation: an algorithm for chaining blocks together to encrypt messages of any length. That mode is not a minor implementation detail. It's the difference between a system that's provably tamper-evident and one that's quietly vulnerable to a padding oracle attack, and the two most common choices — CBC and GCM — solve the problem in fundamentally different ways.
CBC: chaining blocks, trusting nothing extra
Cipher Block Chaining takes each 16-byte plaintext block and XORs it with the previous ciphertext block before encrypting — which is why the very first block needs a random initialization vector (IV) to XOR against, since there's no previous block yet. This chaining is what makes CBC secure against pattern leakage (unlike ECB mode, where identical plaintext blocks produce identical ciphertext blocks — the famous "ECB penguin" image that's still visibly a penguin after encryption).
Two things fall out of that design:
- It needs padding. Plaintext rarely divides evenly into 16-byte blocks, so CBC pads the last block out (commonly with PKCS#7) — and the receiver strips it back off after decrypting.
- It provides no integrity check. CBC encrypts; it doesn't authenticate. Nothing stops an attacker from flipping bits in the ciphertext, and depending on how padding errors are handled, that can open a padding oracle attack — an attacker who can observe whether decryption succeeds or fails (even just from a different error message or response time) can recover plaintext byte by byte without ever knowing the key. This is a real, repeatedly-exploited class of vulnerability, not a theoretical one.
CBC is fine — even the right choice for legacy interop — but only when it's not the whole story: pair it with a separate MAC (HMAC-SHA256, applied encrypt-then-MAC) to get the integrity check it doesn't provide on its own.
GCM: encryption and integrity in one pass
Galois/Counter Mode takes a different approach. It's built on counter mode (CTR) — instead of chaining ciphertext blocks, it encrypts a counter value and XORs the result with the plaintext, which turns AES into a keystream generator. That has two immediate benefits: no padding (you XOR only as many keystream bytes as you have plaintext), and blocks can be encrypted in parallel, since each one only depends on the counter, not on the previous block's output.
The bigger win is what GCM adds on top: a Galois field hash computed alongside the encryption, producing an authentication tag. GCM is an AEAD cipher — Authenticated Encryption with Associated Data — meaning it gives you confidentiality and tamper detection from a single primitive. Flip even one bit of GCM ciphertext and the tag verification fails on decrypt; there's no padding oracle to exploit because there's no padding, and no separate MAC step to forget.
GCM's one sharp edge: the nonce (IV) must never repeat for a given key. Reuse a nonce under GCM and the security guarantees don't just weaken — they collapse, leaking the XOR of two plaintexts and potentially the authentication key itself. This is why GCM implementations lean hard on random or counter-based nonce generation and why key rotation policies matter more under GCM than under CBC.
Side by side
| | CBC | GCM | | --- | --- | --- | | Integrity check | None (needs a separate MAC) | Built in (authentication tag) | | Padding required | Yes | No | | Parallelizable | No (each block needs the previous) | Yes | | IV/nonce reuse risk | Weakens security | Catastrophic — breaks the whole scheme | | Modern default? | Legacy interop only | Yes — TLS 1.3, most new systems |
Which to reach for
Default to GCM for anything new. It's what TLS 1.3 standardized on, it's faster on hardware with AES-NI, and it removes an entire class of padding-oracle bugs by construction. Reach for CBC only when you're interoperating with an existing system that already speaks it — and if you do, always add HMAC on top rather than trusting CBC's confidentiality alone to mean "safe."
Our AES Encryption/Decryption tool implements AES-256-CBC client-side — useful for decoding legacy payloads or testing interop with systems that still speak CBC, with everything staying in your browser. Need a fresh key first? The AES Key Generator pulls random bytes from the Web Crypto API's crypto.getRandomValues() — not Math.random() — and formats them as hex or Base64 for either mode.
