AES Modes of Operation
A block cipher encrypts 16 bytes at a time; a mode of operation is the rule book for chaining those blocks into a stream of arbitrary length, and it decides whether your encryption is secure, malleable, or both. The practical menu is short: GCM, CBC (legacy), CTR (needs a MAC), and OFB/CFB (rarely chosen by hand). This chapter explains what each mode buys and what it costs, with the cryptography calls for the ones you should actually use.
GCM - Galois/Counter Mode
GCM combines counter-mode encryption with a Galois-field authentication tag. One construction gives confidentiality and integrity, and it is fast in hardware. It is the default for TLS 1.3 and for most modern protocols.
import os
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
key = AESGCM.generate_key(bit_length=256)
nonce = os.urandom(12)
ct = AESGCM(key).encrypt(nonce, b"message", b"assoc-data")
Constraints: nonce unique per key (reusing a GCM nonce with the same key breaks both confidentiality and authenticity), and authenticated data is bound to the ciphertext.
CBC - Cipher Block Chaining
CBC XORs each plaintext block with the previous ciphertext block before encrypting, using a random IV for the first block. It hides patterns, but it provides no authentication - you must add a MAC yourself (encrypt-then-MAC), and it requires PKCS#7 padding, which opens the padding-oracle attack class if you ever reject "bad padding" without checking the MAC first.
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
iv = os.urandom(16)
enc = Cipher(algorithms.AES(key), modes.CBC(iv)).encryptor()
ct = enc.update(pad(b"hello", 16)) + enc.finalize() # pad to block size
Treat CBC as legacy: fine for data encrypted years ago that you must keep reading, not a choice for new systems.
CTR - Counter Mode
CTR turns the cipher into a stream cipher by encrypting counters and XORing the results with the plaintext. It parallelizes and needs no padding, but like all stream modes it is malleable - flip a ciphertext bit and the corresponding plaintext bit flips. Use only with an attached MAC, at which point GCM is usually the simpler equivalent.
OFB and CFB
OFB (output feedback) produces a keystream independent of the plaintext - convenient for hardware channels where errors do not propagate. CFB is a feedback variant that works with smaller segment sizes. Both are unauthenticated stream constructions; in application code you will almost never pick them deliberately.
Selection Guide
| Mode | Authenticated | Verdict |
|---|---|---|
| GCM | yes (tag) | default for new code |
| ChaCha20-Poly1305 | yes (tag) | default where AES lacks hardware |
| CBC + HMAC | with your MAC | legacy support |
| CTR | no | only with a MAC; prefer GCM |
| ECB | no | never for data |
Summary
Choose GCM (or ChaCha20-Poly1305) and stop thinking about modes: both are authenticated, fast, and standard. Keep CBC only to read old data, never use ECB, and remember that any unauthenticated mode needs a MAC or it is malleable.