Chapter 16 — Hands-on: symmetric encryption with OpenSSL
Why this chapter exists
OpenSSL is the tool you will actually reach for. It is also notoriously unfriendly. This chapter is the practical drill.
Generating keys and random data
cd ~/sec-lab/scratch
openssl rand -hex 32 # 256-bit key as hex
openssl rand -base64 32 # 256-bit key as base64
openssl rand -out key.bin 32 # raw bytes to a file
# NEVER generate keys with: date, PID, rand(), or a password you made up.
# Use the OS CSPRNG -- which is what `openssl rand` does.
Password-based encryption (the common case)
echo "the launch code is 0000" > plan.txt
# ENCRYPT -- always include -pbkdf2 and a high -iter
openssl enc -aes-256-cbc -pbkdf2 -iter 600000 -salt \
-in plan.txt -out plan.enc
# DECRYPT
openssl enc -d -aes-256-cbc -pbkdf2 -iter 600000 -in plan.enc
# Base64-armour it for email/JSON transport (-a)
openssl enc -aes-256-cbc -pbkdf2 -iter 600000 -salt -a -in plan.txt -out plan.b64
cat plan.b64
What each flag does:
| Flag | Why it matters |
|---|---|
-aes-256-cbc |
The cipher and mode |
-pbkdf2 |
Use PBKDF2 for key derivation. Without it, OpenSSL uses one round of MD5. |
-iter 600000 |
PBKDF2 iterations. Higher = slower to crack. |
-salt |
Random salt (default on, but be explicit) |
-a |
Base64-encode the output |
-d |
Decrypt |
-K / -iv |
Supply a raw key/IV in hex instead of a password |
Raw key and IV (when you manage keys yourself)
KEY=$(openssl rand -hex 32) # 32 bytes = 64 hex chars for AES-256
IV=$(openssl rand -hex 16) # 16 bytes = 32 hex chars
openssl enc -aes-256-cbc -K "$KEY" -iv "$IV" -in plan.txt -out plan.raw
openssl enc -d -aes-256-cbc -K "$KEY" -iv "$IV" -in plan.raw
Dangerous: anything on a command line is visible in
psoutput and your shell history. For real work, pass keys via a file, an environment variable, or stdin — never as an argument.
Inspecting what you produced
# The OpenSSL container format starts with "Salted__" + 8 salt bytes
xxd plan.enc | head -2
# Compare sizes -- note the padding and the salt header
ls -l plan.txt plan.enc
Practice (30 min) — the drill
Do these without looking back:
- Generate a 256-bit key and save it to
mykey.hex. - Encrypt a file with AES-256-CBC using that key and a random IV. Store the IV with the ciphertext.
- Decrypt it again.
- Encrypt the same file twice with the same key but different IVs. Confirm the ciphertexts differ.
- Now encrypt twice with the same IV. Confirm they're identical — and explain why that's a leak.
- Corrupt one byte of a ciphertext and decrypt. What happens? (CBC: garbled first block, then correct. No error. That's the missing integrity.)
- Repeat step 6 with AEAD in Python. Note that it refuses to decrypt.
Step 6 vs 7 is the point of the whole Part.
The OpenSSL survival guide
openssl version -a # version and build config
openssl list -cipher-algorithms # what ciphers are available (OpenSSL 3.x)
openssl errstr 0A000086 # decode a cryptic error code
openssl enc -help # flags for a subcommand
Appendix B has the full cookbook.
Common confusions
- "
openssl encuses AES-GCM if I ask." It technically accepts the flag but cannot handle the authentication tag, so the result is not authenticated. Use a real library orage. - "The salt makes it secure." The salt prevents precomputation. The iterations make it slow. You need both.
- "I'll pipe the key in with
echo."echomay leave it in history and in process listings. Use-pass file:...or-pass env:VAR.
Check yourself
- What happens if you omit
-pbkdf2? - Why must the IV be stored alongside the ciphertext, and is it secret?
- Why is passing a key as a command-line argument dangerous?
- Why can't
openssl encdo proper AES-GCM?
Further reading
- Book: OpenSSL Cookbook — Ivan Ristić. Free. The clearest OpenSSL reference in existence; you'll use it throughout Parts 5–7.
- Docs:
openssl-enc(1)man page. - Tool:
age— for when you want file encryption that's hard to get wrong.
End of Part 4 — Milestone check
- I can state Kerckhoffs's principle and why it matters
- I know why key/nonce reuse is catastrophic, and can demonstrate it
- I have seen the ECB penguin with my own eyes
- I can explain why CBC needs a MAC and GCM doesn't
- I know the nonce rule for AEAD
- I have encrypted and decrypted files with OpenSSL
- I have watched AEAD refuse to decrypt tampered data