Symmetric Encryption for Real
Symmetric encryption uses one shared key to both encrypt and decrypt, and in practice that means AES. But how you use AES decides whether the ciphertext is actually secure — the mode of operation, and the authentication that rides with it, matters more than the cipher. AES-GCM protects confidentiality and integrity together; AES-ECB leaks the structure of your data in plain sight.
This topic moves you from "AES is the standard" to encrypting a Meridian database backup correctly, and to recognizing the two mistakes — the wrong mode and the reused nonce — that betray you no matter how strong the cipher is.
Keys, Blocks, and Modes
AES is a block cipher: it operates on fixed 128-bit blocks with a 128- or 256-bit key. A mode of operation defines how those blocks chain together to encrypt a message longer than one block, and the mode is where security is won or lost. The same AES can be unbreakable or trivially readable depending only on the mode wrapped around it.
ECB, and Why It Fails Visibly
The simplest mode, ECB, encrypts each block independently — so identical plaintext blocks produce identical ciphertext blocks, and the structure of the data survives encryption. The textbook demonstration encrypts a bitmap of a penguin in ECB mode and the penguin is still clearly visible in the ciphertext. That is the whole lesson: ECB hides values but not patterns, which for real data is no security at all.
Authenticated Encryption with GCM
Modern encryption uses an authenticated mode — AES-GCM or ChaCha20-Poly1305 — which produces, alongside the ciphertext, an authentication tag. On decryption, any tampering with the ciphertext makes the tag fail, so you learn the data was altered instead of silently decrypting garbage or, worse, attacker-chosen changes. Unauthenticated modes like CBC alone let an attacker flip bits undetected, which is why authenticated encryption is the default you should reach for.
# AES-256-GCM with a vetted library — NOT `openssl enc`, which does not support
# GCM (it silently drops the auth tag); use a high-level AEAD API instead.
# python, using the `cryptography` library
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os
key = AESGCM.generate_key(bit_length=256) # 256-bit key; store this in a KMS, not on disk
nonce = os.urandom(12) # a FRESH 96-bit nonce for EVERY encryption
data = open("meridian-db.sql", "rb").read()
ct = AESGCM(key).encrypt(nonce, data, None) # ct includes the authentication tag
# store nonce + ct together; decryption raises InvalidTag if either was tampered with:
AESGCM(key).decrypt(nonce, ct, None)
The code above encrypts the backup with a 256-bit key and a fresh 96-bit nonce. In production the key never lives in a file next to the data — it comes from a key-management service (Chapter 3) — and the nonce is generated fresh for every encryption. Get those two things right and the ciphertext is secure; get either wrong and the strongest cipher in the world will not save you.
The Nonce Contract
GCM requires a unique nonce for every encryption under a given key. Reuse a nonce — from a counter that resets, a forked process sharing state, or a weak random source that collides — and you catastrophically leak the relationship between the two plaintexts and even the ability to forge messages. Nonce reuse is the single most common real-world way to break AES, and it breaks it completely, not partially.
ECB — never use it; identical plaintext blocks leak as identical ciphertext, so patterns survive encryption.
CBC — chains blocks so patterns are hidden, but provides no integrity on its own and needs careful padding, exposing padding-oracle attacks. Not a default.
GCM (and ChaCha20-Poly1305) — authenticated encryption: confidentiality and integrity in one, the modern default — provided the nonce is never reused under a key.
- Using ECB mode — often the library's default in older code — and shipping ciphertext that visibly preserves the plaintext's structure.
- Reusing a nonce or IV with GCM, which breaks the mode completely: it exposes plaintext relationships and enables forgery, and it happens whenever a counter resets or a "random" nonce collides.
- Encrypting without authenticating (raw CBC) and being surprised when an attacker tampers with ciphertext undetected or mounts a padding-oracle attack.
- Hard-coding or reusing one key across environments, so a single leak decrypts everything everywhere.
- Rolling a custom "lightweight" scheme instead of using a vetted AEAD construction, which almost always hides a fatal flaw.
- Default to an AEAD mode — AES-GCM or ChaCha20-Poly1305 — so confidentiality and integrity come together.
- Generate a fresh, unique nonce for every encryption and never reuse one under the same key; prefer the library's nonce management over a hand-rolled counter.
- Keep keys out of code and config — fetch them from a KMS or secret store (Chapter 3), and separate keys per environment and purpose.
- Encrypt data at rest that leaves controlled storage — backups, exports — and treat the key's protection as the real security boundary.
- Use a high-level, misuse-resistant library that makes the safe choice the default rather than assembling primitives by hand.
Knowledge Check
Why does AES-ECB fail to secure a real image or document?
- Identical plaintext blocks give identical ciphertext
- It uses a key that is too short to resist brute force
- It cannot encrypt data larger than a single block
- It always reuses the same nonce for every block
What is the consequence of reusing a nonce with AES-GCM under the same key?
- It breaks the mode, leaking plaintext and allowing forgery
- Nothing at all, provided the key is 256 bits rather than 128
- It only slows down decryption slightly
- It makes the ciphertext larger but no less secure
What does an AEAD mode like GCM give you that raw CBC does not?
- Built-in integrity detection
- A longer key, which makes brute force harder
- The ability to skip generating a nonce entirely
- Compatibility with ECB-encrypted data
You got correct