Your HTTPS connection, phone storage, Wi-Fi password, and encrypted ZIP files all rely on the same algorithm: AES (Advanced Encryption Standard). Standardized by NIST in 2001, AES remains the unbroken workhorse of practical cryptography. Understanding how it works — and how to use it correctly — is essential knowledge for any developer or security engineer.
1. The Origins of AES
In 1997, NIST launched a public competition to replace DES (Data Encryption Standard), whose 56-bit key had been brute-forced in 22 hours in 1999. After five years of open global cryptanalysis, NIST selected Rijndael — designed by Belgian cryptographers Joan Daemen and Vincent Rijmen — and published it as AES (FIPS PUB 197) in 2001.
AES is symmetric: the same key encrypts and decrypts. RSA is asymmetric: a public key encrypts, a private key decrypts. HTTPS combines both — RSA or ECDH securely exchanges an AES session key, then AES handles all actual data transmission at high speed.
2. Key Sizes
AES supports three key lengths:
| Key Size | Rounds | Security Level | Typical Use |
|---|---|---|---|
| AES-128 | 10 | 128-bit | Consumer apps, TLS |
| AES-192 | 12 | 192-bit | Rarely used |
| AES-256 | 14 | 256-bit | Government secrets, high-security requirements |
AES-128 is more than sufficient for nearly all applications — brute-forcing it requires 2¹²⁸ attempts, far beyond any feasible computation. AES-256 is required by US government policy for TOP SECRET data and provides a safety margin against future quantum computers (Grover's algorithm halves effective key length, so 256-bit → 128-bit remains secure).
3. How AES Works
AES processes data in fixed 128-bit (16-byte) blocks. The key length determines the number of rounds; each round applies four transformations to a 4×4 byte state matrix:
3.1 The Four Round Operations
- SubBytes: Each byte is replaced via a fixed S-Box lookup table, providing non-linear confusion
- ShiftRows: Each row of the state matrix is cyclically shifted left by a different amount, spreading data across columns
- MixColumns: Each column is multiplied in GF(2⁸), mixing bytes so each output byte depends on all four inputs (skipped in the final round)
- AddRoundKey: The state is XORed with a round key derived from the master key via key schedule
These operations achieve two core cryptographic properties: confusion (complex relationship between key and ciphertext) and diffusion (one plaintext bit change affects many ciphertext bits — the avalanche effect).
4. Encryption Modes: The Most Important Choice
AES alone only defines how to encrypt one 128-bit block. For arbitrary-length data, you need a mode of operation. This choice matters more than key size.
4.1 ECB (Electronic Codebook) — Never Use This
ECB encrypts each block independently. Fatal flaw: identical plaintext blocks produce identical ciphertext blocks. This preserves data patterns in the ciphertext.
Encrypt a bitmap image of a penguin with ECB, and you can still see the penguin in the ciphertext — identical pixel regions produce identical encrypted blocks. ECB should never be used for any data requiring confidentiality.
4.2 CBC (Cipher Block Chaining) — Legacy Standard
CBC XORs each plaintext block with the previous ciphertext block before encrypting; the first block uses a random IV (Initialization Vector). Identical plaintexts produce different ciphertexts under different IVs.
- Requires Padding (PKCS#7 is standard) to align data to block boundaries
- Decryption is parallelizable; encryption is sequential
- Provides no integrity protection — vulnerable to Padding Oracle attacks when used without a MAC
4.3 CTR (Counter Mode) — AES as a Stream Cipher
CTR encrypts an incrementing counter value and XORs the result with plaintext. This turns AES into a stream cipher:
- No padding required
- Fully parallelizable (both encrypt and decrypt)
- No integrity protection — must be paired with a MAC (e.g., HMAC-SHA256)
4.4 GCM (Galois/Counter Mode) — The Modern Standard
GCM combines CTR encryption with GHASH authentication, producing an Authentication Tag that detects any tampering with the ciphertext.
- AEAD (Authenticated Encryption with Associated Data): confidentiality and integrity in one operation
- No padding required; fully parallelizable
- Supports AAD (Additional Authenticated Data): authenticate unencrypted headers without encrypting them
- Used in TLS 1.3 (AES-256-GCM is the primary cipher suite)
| Mode | Padding | Integrity | Parallelizable | Verdict |
|---|---|---|---|---|
| ECB | Yes | No | Yes | ❌ Never use |
| CBC | Yes | No | Decrypt only | ⚠️ Legacy compat only |
| CTR | No | No | Yes | ✅ OK with MAC |
| GCM | No | ✅ Built-in | Yes | ✅✅ Modern default |
5. IVs and Nonces: Never Reuse
CBC requires an IV; GCM requires a Nonce. This is where most real-world AES implementations go wrong:
- Every encryption operation must use a unique IV/Nonce — reuse seriously weakens security
- IVs and Nonces are not secret — transmit them alongside the ciphertext
- GCM Nonces are typically 96 bits (12 bytes); generate with a cryptographically secure RNG
- GCM Nonce reuse is catastrophic: an attacker can recover the authentication key, breaking the entire encryption scheme
Always generate IVs and Nonces randomly for each encryption operation. Never hardcode them. Use a cryptographically secure random number generator — PHP's
random_bytes(), Python's os.urandom(), or Node's crypto.randomBytes().
6. Key Derivation: Never Use a Password Directly
AES keys must be high-entropy random bytes. If your system derives keys from user passwords, never use the raw password (or its MD5/SHA hash) as an AES key. Use a KDF (Key Derivation Function):
- PBKDF2: Widely supported; use 600,000+ iterations (OWASP 2023 recommendation)
- Argon2: Modern default; resists both GPU and memory-parallel attacks
- scrypt: Memory-hard KDF; widely used in cryptocurrency wallets
7. Code Examples
# PHP (OpenSSL, AES-256-GCM)
$key = random_bytes(32); // 256-bit key
$nonce = random_bytes(12); // 96-bit Nonce
$ciphertext = openssl_encrypt(
$plaintext, 'aes-256-gcm', $key,
OPENSSL_RAW_DATA, $nonce, $tag
);
// Store/transmit: nonce + tag + ciphertext
// Decrypt
$decrypted = openssl_decrypt(
$ciphertext, 'aes-256-gcm', $key,
OPENSSL_RAW_DATA, $nonce, $tag
);
# Python (cryptography package, AES-256-GCM)
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os
key = os.urandom(32) # 256-bit key
nonce = os.urandom(12) # 96-bit Nonce
aesgcm = AESGCM(key)
ciphertext = aesgcm.encrypt(nonce, plaintext, None)
plaintext = aesgcm.decrypt(nonce, ciphertext, None)
# Node.js (built-in crypto, AES-256-GCM)
const crypto = require('crypto')
const key = crypto.randomBytes(32)
const nonce = crypto.randomBytes(12)
const cipher = crypto.createCipheriv('aes-256-gcm', key, nonce)
const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()])
const tag = cipher.getAuthTag() // 16-byte authentication tag
8. Common Questions
8.1 Has AES been broken?
No practical attack exists. The best theoretical attack (biclique, 2011) reduces AES-128 brute-force complexity by a factor of 4 — still requiring 2¹²⁶·¹ operations. AES security in practice depends almost entirely on correct key management and mode selection, not the algorithm itself.
8.2 AES-128 or AES-256?
AES-128 is sufficient for virtually all applications. Choose AES-256 for compliance requirements (FIPS, government mandates), quantum-computing defense (Grover's algorithm halves key strength, so 256-bit → 128-bit remains secure), or when the ~40% performance overhead is acceptable. Both are secure; neither has known weaknesses.
8.3 Why does HTTPS also need asymmetric encryption?
AES is symmetric — both parties need the same key. How do you securely share that key over a public network? RSA or ECDH solves this: asymmetric crypto securely exchanges a temporary AES session key, then AES handles all actual data transfer. This combination gets the security of asymmetric crypto with the performance of symmetric crypto.
8.4 Is encryption enough?
No. Encryption provides confidentiality but doesn't prevent an attacker from modifying the ciphertext. This is why modern encryption should use AEAD like AES-GCM — it provides both encryption and integrity verification in one step. Systems using AES-CBC without a MAC are vulnerable to Padding Oracle and other attacks.
9. Summary
AES is the backbone of modern cryptography: over two decades of open scrutiny and it remains unbroken. But the algorithm is only one piece — correct usage is what actually provides security. Use GCM mode (not ECB or bare CBC), generate a fresh random Nonce for every encryption operation, and derive keys with a KDF rather than using passwords directly. Get these three things right, and AES delivers industrial-grade protection for your application.