syndicated · dev.to / @markyu
A practical block cipher guide for developers explaining AES modes, CBC pitfalls, GCM authentication, IV rules, and what to avoid in production.
- Published
- May 4 '24
- Reading time
- 2 min read
- Reactions
- 9
securitycryptographybackendwebdev
Most crypto bugs I have seen were not caused by someone inventing a new cipher.
They were caused by using a good cipher in the wrong mode, reusing an IV, skipping authentication, or copying a Stack Overflow snippet without understanding the contract.
If you are building a normal application in 2026, my default advice is simple:
Prefer authenticated encryption like AES-GCM. Avoid raw AES-CBC unless you know exactly how you will authenticate the ciphertext.
The Quick Map
| Mode | What it gives you | Main risk |
|---|---|---|
| AES-ECB | encryption only | leaks patterns, avoid it |
| AES-CBC | encryption only | needs padding and MAC |
| AES-CTR | stream-like encryption | nonce reuse is dangerous |
| AES-GCM | encryption + authentication | nonce must be unique |
The important word is authentication.
Encryption hides content. Authentication tells you whether the ciphertext was modified.
Never Use ECB
ECB encrypts equal plaintext blocks into equal ciphertext blocks.
That means patterns can leak.
same plaintext block -> same ciphertext block
same plaintext block -> same ciphertext blockThis is why ECB is the classic "do not use this" example.
CBC Needs More Than Encryption
CBC uses an initialization vector:
plaintext + key + IV -> ciphertextThe IV must be unpredictable and unique for the message.
The bigger issue: CBC does not authenticate data by itself.
That means this is incomplete:
ciphertext = AES-CBC-Encrypt(key, iv, plaintext)You also need a MAC, usually encrypt-then-MAC:
ciphertext = AES-CBC-Encrypt(encKey, iv, plaintext)
tag = HMAC(macKey, iv + ciphertext)If you skip the MAC, attackers may be able to tamper with ciphertext and learn things from error behavior.
Why I Prefer GCM
AES-GCM gives encryption and authentication together:
plaintext + key + nonce + aad -> ciphertext + tagYou still need to manage nonces correctly, but the API nudges you toward the right model.
Node.js example:
import crypto from "node:crypto";
const key = crypto.randomBytes(32); // AES-256
const iv = crypto.randomBytes(12); // recommended GCM nonce size
const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
const ciphertext = Buffer.concat([
cipher.update("secret message", "utf8"),
cipher.final(),
]);
const tag = cipher.getAuthTag();
console.log({ iv, ciphertext, tag });Decrypt:
const decipher = crypto.createDecipheriv("aes-256-gcm", key, iv);
decipher.setAuthTag(tag);
const plaintext = Buffer.concat([
decipher.update(ciphertext),
decipher.final(),
]);
console.log(plaintext.toString("utf8"));If the ciphertext or tag is modified, decryption fails.
That is exactly what you want.
Practical Rules
- Do not use ECB.
- Do not hardcode keys.
- Do not reuse GCM nonces with the same key.
- Do not store encryption keys beside encrypted data.
- Do not invent your own padding or MAC scheme.
- Use high-level libraries when possible.
Where Block Ciphers Still Matter
You may hit this when building:
- encrypted backups
- secure tokens
- internal secrets tooling
- file encryption
- compliance-heavy backend systems
For normal password storage, do not use AES. Use a password hashing algorithm such as Argon2, bcrypt, or scrypt.
That distinction is important:
password storage -> hash
data secrecy -> encryptionFinal Thought
Crypto code should be boring. If your encryption design feels clever, slow down.
For most application work, AES-GCM or a trusted high-level library is the safer path than hand-rolling AES-CBC with padding and MAC logic.
Have you ever had to review encryption code in an application backend?
Related reading
Next.js Images Without CLS: My LQIP Blur-Up Setup
A practical Next.js image optimization guide for zero CLS layouts, blur placeholders, dimensions, remote images, and production image hygiene.
nextjs
Bad Data Quality Costs More Than a Slow Query
A practical data quality guide for engineers: validation, ownership, schema drift, observability, and fixing bad data before dashboards lie.
data
Network Address Calculation: The Subnet Math That Matters
A practical subnetting guide showing how to calculate a network address from an IP address and mask using binary math and simple examples.
networking
originally published
This post first ran on dev.to. Comments and reactions live there.
Continue on dev.to