Every mistake in this lesson involves cryptography that is, in isolation, mathematically sound — AES really is secure, RSA really is secure — and every one of these bugs comes from using a sound primitive in an unsound way. This is the pattern behind nearly every real cryptographic vulnerability that isn't a flaw in the underlying math at all.
3 min read
Inventing a custom encryption scheme, "just XOR the data with a repeating key," or a homemade hashing scheme, is a strong, well-earned red flag. Professionally designed algorithms like AES and SHA-256 have survived years of dedicated, well-funded cryptanalysis attempting to break them — a scheme designed by one team, without that scrutiny, essentially never holds up in comparable ways. The practical rule: use established, standard algorithms and libraries; never implement cryptographic primitives from scratch for real use.
Lesson 2 established that CBC mode's IV must be random and never reused with the same key. Reusing an IV (or, in stream-cipher-style modes, a nonce — "number used once," used the same way) with the same key across two different messages often leaks the relationship between the two plaintexts, sometimes severely — in the worst documented cases, allowing full recovery of both messages. The name "number used once" states the requirement directly; violating it is one of the most common real-world cryptographic implementation bugs.
Lesson 2 already covered this directly — ECB visibly leaks structural patterns in the plaintext, demonstrated concretely by the "ECB penguin." It's listed again here because it remains a genuinely common default mistake: many crypto libraries' simplest, most obvious API defaults to ECB precisely because it requires no IV parameter to think about, which makes it an easy trap for anyone reaching for "the simple option."
Auth's password-hashing lesson mentioned this specifically for password
hash comparison — using == (or equivalent) to compare two secret
values can leak information through timing, since many comparison
implementations return as soon as they find the first mismatched byte.
An attacker measuring response times precisely enough can, in principle,
guess a secret one byte at a time. The fix is a constant-time comparison
function (hmac.compare_digest in Python, crypto.timingSafeEqual in
Node.js) that always takes the same amount of time regardless of where a
mismatch occurs.
Lesson 9 covered this at length — using an ordinary PRNG instead of a CSPRNG for anything security-relevant (a key, a token, a salt) undermines whatever sound cryptography sits on top of it, since the mathematics assumed genuinely unpredictable input that was never actually provided.
Lesson 2 covered GCM's built-in tamper detection as an improvement over plain CBC. A system using CBC (or another non-authenticated mode) without adding a separate integrity check (like an HMAC, lesson 5, over the ciphertext) is vulnerable to an attacker modifying the ciphertext in ways that can sometimes produce predictable, exploitable changes to the decrypted plaintext — encryption alone was never a promise that the decrypted result can't be manipulated, only that it can't be read without the key.
None of these six mistakes involves a broken cryptographic algorithm — every one of them involves sound cryptography used in a way that quietly throws away a guarantee it depended on. This is precisely why "we use AES" or "we use RSA" is never, by itself, a sufficient security claim (a point lesson 2 raised specifically about modes of operation) — the implementation details covered across this entire domain are exactly where real cryptographic vulnerabilities actually live in practice.
Check your understanding
A quick comprehension check — not tracked, not graded, just for you.
1. Why is rolling your own custom encryption algorithm considered a serious red flag?
2. Why is reusing a nonce or IV with the same key dangerous, even with a secure cipher?
3. What is the common pattern underlying all the mistakes covered in this lesson?
Cryptography Fundamentals