Start with a common encryption misconception
"If it uses AES, it is secure"—that sentence only answers half the question. AES is a block cipher: it defines the transform for a single fixed-size block. How you split arbitrary-length plaintext into blocks, how blocks influence each other, and how you prevent tampering are answered by the mode of operation. Choose the wrong mode and AES protection drops considerably.
This article walks the three most-used modes visually and gives selection advice you can apply directly.
Understand the block first
AES processes 16-byte blocks. Longer plaintext is split into 16-byte chunks; the final short block gets PKCS7 padding.
plaintext: [12-byte region] → pad 4 bytes
actual: [12-byte region][\x04\x04\x04\x04] → 16 total
A full block always adds one extra padding block (\x10×16) so decryption can always tell real data from padding.
ECB: blocks are fully independent
block1 ──AES──▶ c1
block2 ──AES──▶ c2 (blocks do not influence each other)
block3 ──AES──▶ c3
Identical plaintext blocks → identical ciphertext blocks. That is the fatal flaw: repeated patterns survive encryption. Don't use ECB by default; it suits only a single fixed-length, unpredictable block.
CBC: chain the previous block into the next
IV(random) c1 c2
│ │ │
block1 ─┴─∈⊕────────► AES ──►┐ block2─┴─∈⊕─► AES ──►
CBC XORs each plaintext block with the previous ciphertext block before encrypting, forming a chain:
- IV's role: the random initialization vector serves as the predecessor of the first block;
- IV rules: fresh and random every time, never reused; prepend it to the ciphertext;
- Drawbacks: encryption must run serially (no parallelism), and one corrupted ciphertext block corrupts the following plaintext block too.
GCM: encrypt and authenticate together
GCM encrypts in CTR counter mode (parallel, no padding) and computes an auth tag over the output:
nonce ──▶ counter(1) ─▶ keystream ∈⊕ block1 ─▶ c1 ─┐
nonce ──▶ counter(2) ─▶ keystream ∈⊕ block2 ─▶ c2 ─┼──▶ GMAC tag
AAD ─┘
- Output =
nonce ‖ ciphertext ‖ tag; the tag detects any tampering; - The 96-bit nonce is random and unique, never reused under the same key;
- Default in TLS 1.3 and mainstream libraries (OpenSSL, WebCrypto, Go, .NET).
Mode quick reference
| Property | ECB | CBC | GCM |
|---|---|---|---|
| Confidentiality | ✔ | ✔ | ✔ |
| Integrity/anti-tamper | ✘ | ✘ (add HMAC) | ✔ (auth tag built-in) |
| Padding | PKCS7 | PKCS7 | None (stream) |
| Parallelizable | ✔ | ✘ | ✔ |
| Random IV/nonce | Not needed | Required | Required |
| Caveat | Leaks patterns | Serial; easy to botch HMAC | Use a vetted implementation |
Common pitfalls checklist
- ECB on variable-length data → leaks structure; switch to GCM.
- CBC with reused/hardcoded IV → common-prefix leak; random IV each time, prepended.
- Encryption without authentication → ciphertext can be flipped and still decrypt; GCM authenticates.
- GCM nonce reuse → keystream reuse, catastrophic; one unique nonce per key.
- Hardcoded key in source → defeats even the strongest cipher; manage keys securely and separately.
Try it yourself
Pick an encryption library (WebCrypto's AES-GCM works in the browser) and encrypt the same pattern-heavy text twice with CBC and GCM. You will see CBC yields different ciphertext due to a different IV, demonstrating its purpose. Now flip any byte in a GCM ciphertext and tag verification fails—that is the value of authenticated encryption.
Remember one line: default to AES-256-GCM; make IV/nonce random and unique; store the ciphertext together with its nonce and tag.