Don't like ads? Go Ad-Free Today

AES Encryption for Developers When You Need It and How It Works

Published on
AES Encryption for Developers: When You Need It and How It Works 1
ADVERTISEMENT · REMOVE?

If you’re storing sensitive data — user PII, API keys, financial records — AES encryption is the tool you reach for. It’s the industry standard for symmetric encryption at rest: fast, battle-tested, and supported natively in every major language.

But AES done wrong is worse than useless. ECB mode leaks patterns. Reusing an IV with GCM breaks its security guarantee entirely. And storing your key next to your ciphertext defeats the whole point.

Here’s what you actually need to use AES correctly in production.

What Is AES?

AES (Advanced Encryption Standard) is a symmetric block cipher. Symmetric means the same key encrypts and decrypts. Block cipher means it operates on fixed 128-bit chunks of data.

It replaced DES in 2001, and today it’s everywhere: TLS, disk encryption, password managers, database field encryption. Unlike asymmetric encryption (RSA, ECDH), AES is fast enough to encrypt large amounts of data in real time. The tradeoff: both parties need the same key, so key distribution becomes your problem.

AES-128 vs AES-256: Which Key Size?

AES comes in three key sizes: 128, 192, and 256 bits. In practice you’ll choose between 128 and 256.

AES-128AES-256
Key length128 bits256 bits
Rounds1014
PerformanceFaster~40% slower
SecurityStrong — no known practical attackStronger — future-proof against quantum
VerdictFine for most applicationsUse for high-sensitivity data or long retention

AES-128 is not broken. No practical attack exists. But if you’re encrypting data that needs to stay secure for 20+ years — or your threat model includes future quantum computers — AES-256 adds meaningful margin. For most applications encrypting database fields today, AES-128 is sufficient. When in doubt, use AES-256; the performance hit is negligible for typical workloads.

Mode of Operation: Why GCM, Not ECB

AES alone only encrypts a single 128-bit block. For real data you need a mode of operation that handles multiple blocks and sequences them correctly. This choice matters enormously.

ModeAuthenticatedIV RequiredVerdict
ECBNoNoNever use — identical plaintext produces identical ciphertext, leaks patterns
CBCNoYesOutdated — no authentication, vulnerable to padding oracle attacks
GCMYes (AEAD)Yes (nonce)Use this — encrypts and authenticates in one pass

Use GCM. GCM (Galois/Counter Mode) is an AEAD cipher — Authenticated Encryption with Associated Data. It does two things at once:

  1. Encrypts your data so it’s unreadable without the key
  2. Produces an authentication tag so any tampering is immediately detectable

Without authentication, an attacker can flip bits in your ciphertext and you’ll decrypt garbage without knowing it. With GCM, decryption fails loudly if the ciphertext was modified — before any plaintext is returned.

The IV/Nonce: Random, Never Reused

GCM requires an initialization vector (IV), also called a nonce — “number used once.” The IV doesn’t need to be secret, but it must be:

  • Random — generated with a cryptographically secure RNG
  • Unique — never reused with the same key

Reusing an IV with the same key in GCM is catastrophic. An attacker who sees two ciphertexts encrypted with the same key and IV can XOR them together and recover both plaintexts. This is not theoretical — it has happened in production systems.

Use a 96-bit (12-byte) random IV per encryption operation. Since you need it for decryption, store it alongside the ciphertext — IV prepended to the ciphertext is the conventional format.

Working Code: AES-256-GCM

Here are production-ready snippets. Both store the IV and auth tag with the ciphertext so decryption is self-contained.

Node.js

const crypto = require('crypto');

const ALGORITHM = 'aes-256-gcm';
const KEY_LENGTH = 32; // 256 bits
const IV_LENGTH  = 12; // 96 bits — recommended for GCM
const TAG_LENGTH = 16; // 128-bit auth tag

function encrypt(plaintext, key) {
  const iv = crypto.randomBytes(IV_LENGTH);
  const cipher = crypto.createCipheriv(ALGORITHM, key, iv);

  const encrypted = Buffer.concat([
    cipher.update(plaintext, 'utf8'),
    cipher.final(),
  ]);
  const tag = cipher.getAuthTag();

  // Layout: [iv (12)] + [tag (16)] + [ciphertext]
  return Buffer.concat([iv, tag, encrypted]).toString('base64');
}

function decrypt(ciphertextB64, key) {
  const data      = Buffer.from(ciphertextB64, 'base64');
  const iv        = data.subarray(0, IV_LENGTH);
  const tag       = data.subarray(IV_LENGTH, IV_LENGTH + TAG_LENGTH);
  const encrypted = data.subarray(IV_LENGTH + TAG_LENGTH);

  const decipher = crypto.createDecipheriv(ALGORITHM, key, iv);
  decipher.setAuthTag(tag);

  return Buffer.concat([decipher.update(encrypted), decipher.final()]).toString('utf8');
}

// Usage
const key        = crypto.randomBytes(KEY_LENGTH); // store this securely
const ciphertext = encrypt('sensitive data here', key);
const plaintext  = decrypt(ciphertext, key);

Python

import os, base64
from cryptography.hazmat.primitives.ciphers.aead import AESGCM

IV_LENGTH = 12  # 96 bits

def encrypt(plaintext: str, key: bytes) -> str:
    iv = os.urandom(IV_LENGTH)
    aesgcm = AESGCM(key)
    # encrypt() appends the 16-byte auth tag automatically
    ciphertext = aesgcm.encrypt(iv, plaintext.encode(), None)
    return base64.b64encode(iv + ciphertext).decode()

def decrypt(ciphertext_b64: str, key: bytes) -> str:
    data       = base64.b64decode(ciphertext_b64)
    iv         = data[:IV_LENGTH]
    ciphertext = data[IV_LENGTH:]
    aesgcm = AESGCM(key)
    return aesgcm.decrypt(iv, ciphertext, None).decode()

# Usage
key        = AESGCM.generate_key(bit_length=256)  # store this securely
ciphertext = encrypt('sensitive data here', key)
plaintext  = decrypt(ciphertext, key)

Install the dependency: pip install cryptography

You can test AES encrypt and decrypt interactively — without any setup — using the IO Tools AES Encryption/Decryption tool.

Key Management: The Hard Part

Your encryption is only as strong as your key management. The most common mistakes:

  • Key in the same database as the encrypted data — if an attacker gets your DB dump, they get both.
  • Key committed to source control — even in a gitignored .env, rotation becomes painful and history persists.
  • Key appearing in logs — application logs get shipped to aggregators. Keys should never surface there.

Where to actually store encryption keys:

  • AWS KMS / Google Cloud KMS / Azure Key Vault — managed key storage with audit trails and automatic rotation
  • HashiCorp Vault — self-hosted, good for multi-cloud environments
  • Environment variables — acceptable for low-sensitivity workloads with limited exposure surface

For database field encryption, envelope encryption is the standard pattern: generate a data encryption key (DEK) per record or column, then encrypt the DEK with a master key stored in a KMS. Your database contains only encrypted DEKs and ciphertext — the master key never touches the database.

When to Use AES — and When Not To

AES is the right tool for:

  • Encrypting fields in a database — SSNs, card numbers, health records
  • Encrypting files at rest before cloud storage
  • Secret sharing between services that share a pre-established key

AES is not the right tool when:

  • You’re transmitting data over a network — use TLS. Don’t roll your own transport layer.
  • You need asymmetric encryption — if sender and receiver can’t share a key in advance, use RSA or ECDH for key exchange.
  • You’re storing passwords — use bcrypt, scrypt, or Argon2. Encrypted passwords can be decrypted; properly hashed ones can’t.
  • A managed solution fits — AWS Secrets Manager, Vault, and similar handle rotation, access control, and audit logs out of the box. Prefer that over manual AES if it covers your use case.

The mistake most developers make is treating AES as a complete security solution. It’s a primitive — a building block. Pair it with authenticated mode (GCM), unique per-operation IVs, and proper key management, and it’s extremely effective. Skip any of those pieces and you’ve built something that looks secure but isn’t.

Want To enjoy an ad-free experience? Go Ad-Free Today

Install Our Extensions

Add IO tools to your favorite browser for instant access and faster searching

Add to Chrome Extension Add to Edge Extension Add to Firefox Extension Add to Opera Extension

Scoreboard Has Arrived!

Scoreboard is a fun way to keep track of your games, all data is stored in your browser. More features are coming soon!

ADVERTISEMENT · REMOVE?
ADVERTISEMENT · REMOVE?
ADVERTISEMENT · REMOVE?

News Corner w/ Tech Highlights

Get Involved

Help us continue providing valuable free tools

Buy me a coffee
ADVERTISEMENT · REMOVE?