AES — Advanced Encryption Standard Explained
- AES operates on 128-bit blocks through 10 (AES-128), 12 (AES-192), or 14 (AES-256) rounds of SubBytes, ShiftRows, MixColumns, AddRoundKey.
- Never use ECB mode — identical plaintext blocks produce identical ciphertext, leaking structure.
- Use AES-GCM (authenticated encryption) for new code — provides confidentiality AND integrity. Use a random 96-bit nonce, never reuse with the same key.
AES (Advanced Encryption Standard) became the global encryption standard in 2001 after a 5-year public competition run by NIST. The winner — Rijndael, designed by Belgian cryptographers Joan Daemen and Vincent Rijmen — beat 14 other submissions on the criteria of security, efficiency, flexibility, and simplicity. AES is today the most widely deployed symmetric cipher in existence: it is in every TLS connection, every AES-NI-accelerated processor, every encrypted storage device, and every major messaging application.
Understanding AES means understanding why it is fast (hardware acceleration), why the specific operations (SubBytes, ShiftRows, MixColumns) were chosen, and critically — why the cipher mode (ECB, CBC, GCM) can make a perfectly good cipher catastrophically insecure.
AES Structure — The Four Operations
AES operates on a 4×4 byte state matrix (128 bits). Each round applies four operations:
SubBytes: Non-linear substitution via an S-box lookup. Each byte independently mapped to another. Provides confusion — hides the key.
ShiftRows: Rotate each row of the state by a different offset. Row 0: no shift. Row 1: shift left 1. Row 2: shift left 2. Row 3: shift left 3. Provides diffusion across columns.
MixColumns: Multiply each column by a fixed matrix in GF(2^8). Ensures each byte affects every other byte in its column. Provides full diffusion.
AddRoundKey: XOR the state with the round key derived from the original key via key schedule. This is where the key is mixed in.
The final round omits MixColumns.
Using AES Correctly in Python
from cryptography.hazmat.primitives.ciphers.aead import AESGCM import os # AES-GCM: authenticated encryption — the correct choice for most applications def aes_gcm_encrypt(key: bytes, plaintext: bytes, aad: bytes = b'') -> tuple[bytes, bytes]: """Encrypt with AES-GCM. Returns (nonce, ciphertext+tag).""" nonce = os.urandom(12) # 96-bit nonce — NEVER reuse with same key aesgcm = AESGCM(key) ciphertext = aesgcm.encrypt(nonce, plaintext, aad) return nonce, ciphertext def aes_gcm_decrypt(key: bytes, nonce: bytes, ciphertext: bytes, aad: bytes = b'') -> bytes: aesgcm = AESGCM(key) return aesgcm.decrypt(nonce, ciphertext, aad) # Generate a 256-bit key key = os.urandom(32) nonce, ct = aes_gcm_encrypt(key, b'Hello, secure world!', aad=b'additional data') pt = aes_gcm_decrypt(key, nonce, ct, aad=b'additional data') print(f'Decrypted: {pt}')
Cipher Modes — Why ECB is Broken
AES encrypts exactly 128 bits at a time. For longer messages, a mode of operation specifies how to chain blocks:
ECB (Electronic Codebook): Each block encrypted independently with same key. NEVER use — identical plaintext blocks produce identical ciphertext blocks, leaking pattern information. The famous ECB penguin: encrypt a bitmap with ECB and you can still see the image's structure in the ciphertext.
CBC (Cipher Block Chaining): Each block XORed with previous ciphertext before encryption. Better, but requires padding and is vulnerable to padding oracle attacks if not authenticated.
GCM (Galois/Counter Mode): Stream mode + authentication tag. Provides both confidentiality and integrity. The standard for new code — authenticated encryption (AEAD). Use this.
AES-NI Hardware Acceleration
Modern x86 processors (Intel since 2010, AMD since 2011) include AES-NI hardware instructions that perform a full AES round in a single CPU instruction. This makes AES-128-GCM faster than SHA-256 on most modern hardware.
Python's cryptography library uses AES-NI automatically through OpenSSL. AES-256-GCM achieves >1GB/s throughput on a single core on modern hardware. This is why AES remains the default choice even when alternatives like ChaCha20 exist — when hardware acceleration is available, AES is faster.
🎯 Key Takeaways
- AES operates on 128-bit blocks through 10 (AES-128), 12 (AES-192), or 14 (AES-256) rounds of SubBytes, ShiftRows, MixColumns, AddRoundKey.
- Never use ECB mode — identical plaintext blocks produce identical ciphertext, leaking structure.
- Use AES-GCM (authenticated encryption) for new code — provides confidentiality AND integrity. Use a random 96-bit nonce, never reuse with the same key.
- AES-NI hardware instructions make AES among the fastest operations on modern CPUs — no reason to avoid it for performance.
- As of 2026, AES-128 and AES-256 are both secure. AES-256 has a wider security margin but AES-128 is not weaker in practice — no known attack comes close to breaking either.
Interview Questions on This Topic
- QWhat are the four operations in each AES round and what does each achieve?
- QWhy is ECB mode insecure? Describe the ECB penguin problem.
- QWhat is authenticated encryption and why should you use AES-GCM instead of AES-CBC?
- QWhy is nonce reuse in AES-GCM catastrophic?
Frequently Asked Questions
Should I use AES-128 or AES-256?
Both are secure. AES-128 has no known attack better than brute force, which is 2^128 operations — computationally impossible. AES-256 provides additional margin against unknown future attacks. In TLS 1.3, AES-128-GCM is the standard choice — AES-256-GCM for applications with very long-term confidentiality requirements (government, classified).
Developer and founder of TheCodeForge. I built this site because I was tired of tutorials that explain what to type without explaining why it works. Every article here is written to make concepts actually click.