Symmetric Encryption Lab
Hands-on exploration of modern symmetric encryption: try AES-GCM (AEAD), AES-CBC, and AES-CTR with randomly generated keys and nonces. See why nonce/IV rules matter and why ECB is unsafe.
{"version":1,"msgType":"PAYMENT","sender":"Alice","recipient":"Bob"} or HTTP-style fields like Content-Type: application/json, X-Msg-Id: 123e4567.Ciphertext
length: 64 parameter means the first 8 bytes are a fixed nonce prefix; only the last 8 bytes increment as the counter.Decrypted Output
Block Diff Explorer
See which ciphertext blocks change when you make a small edit. Behavior differs by mode:
- CBC — changes propagate to all later blocks due to chaining
- CTR — only the block(s) containing changed bytes differ
- GCM — same as CTR for the body, but the authentication tag always changes if anything changes
Ciphertext A blocks (marked vs B)
Ciphertext B blocks (marked vs A)
ECB-style Visualization (Unsafe)
Browsers don’t expose AES-ECB. This demo hashes each 16-byte block with SHA-256 and shows the first 8 bytes as a stand-in “ciphertext.” Equal plaintext blocks map to equal outputs, illustrating ECB’s pattern leak. Try a repeated pattern:
Guidance
1. Prefer AEAD: AES-GCM or ChaCha20-Poly1305
AEAD (Authenticated Encryption with Associated Data) provides both confidentiality and integrity in a single operation. Non-AEAD modes like CBC and CTR provide confidentiality only — an attacker can silently corrupt or tamper with ciphertext unless you add a separate MAC. Forgetting the MAC is a common and dangerous real-world mistake.
AES-GCM is the standard choice in most environments. ChaCha20-Poly1305 is preferred when hardware AES acceleration is unavailable or when constant-time execution is a hard requirement (e.g., on embedded or mobile devices).
2. Always supply AAD for metadata you want integrity-protected
GCM’s AAD field lets you authenticate metadata — routing headers, protocol version, sender/recipient identifiers — without encrypting it. If that metadata is modified in transit, decryption fails.
Without AAD, an attacker could alter a header (e.g., change the recipient or message type) while the body decrypts successfully and the application never knows the message was tampered with.
3. Nonce rules: unique per key, every single message
CTR: If two messages share the same key and nonce, an attacker who observes both ciphertexts can XOR them to cancel the keystream, exposing a linear combination of the two plaintexts. With enough known context, both messages can be fully recovered.
GCM: Nonce reuse is catastrophic. GCM authenticates messages using a polynomial hash (GHASH) keyed by the encryption of the zero block under the same key. Reusing a nonce reveals this GHASH key, allowing the attacker to forge arbitrary authenticated messages — indefinitely, without ever learning the encryption key.
Best practice: generate nonces randomly for each message (12 bytes / 96 bits for GCM). At 12 bytes, the probability of a random collision stays below 2−32 for up to 232 messages under the same key. Beyond that threshold, rotate the key.
4. CBC: use carefully, or avoid for new designs
CBC requires an IV that is unpredictable to the attacker before encryption. A predictable IV (e.g., a counter, or the previous ciphertext block) enables chosen-plaintext attacks. The BEAST attack exploited predictable IVs in TLS 1.0 to recover session cookies.
CBC provides no integrity guarantee on its own. Without a MAC, an attacker can flip bits in a ciphertext block to predictably corrupt the decrypted output in the following block. CBC with PKCS#7 padding is also vulnerable to padding oracle attacks if decryption errors leak whether padding was valid — the POODLE and Lucky13 attacks exploited exactly this.
For new designs, use GCM. If you must use CBC, pair it with HMAC-SHA256 (encrypt-then-MAC) and generate IVs with a CSPRNG.
5. Key management: CSPRNG and KDFs
Use a CSPRNG. Keys must be generated with a cryptographically secure random number generator. In a browser, crypto.getRandomValues() is the correct API — what this lab uses. Never use Math.random() for anything security-sensitive; it is not cryptographically secure and its output can be predicted.
Derive keys from passwords with a KDF. If the key source is a user password, use a Key Derivation Function (KDF) such as PBKDF2, scrypt, or Argon2. These are deliberately slow and memory-hard, making brute-force attacks expensive. PBKDF2 is available in WebCrypto; scrypt and Argon2 require a library. Never use a password directly as a key — a 10-character password has far less entropy than a 256-bit random key and follows predictable patterns that attackers exploit.