EXERCISE 3 — Hashing vs encryption, and "don't roll your own crypto" ==================================================================== THE HASHING-VS-ENCRYPTION DECISION: - Ask one question: "Do I ever need to RECOVER the original value?" * NO -> HASH it (one-way). You only need to VERIFY. * YES -> ENCRYPT it (reversible, with a key). You need to READ IT BACK. PASSWORDS -> HASH. - You never need the original password. To check a login, you hash the submitted attempt and compare it to the stored hash. So store a ONE-WAY hash — specifically a SLOW, SALTED password hash (Argon2id / bcrypt), not a fast hash. Recovery is neither needed nor desirable. A RECOVERABLE CARD NUMBER (charged monthly) -> ENCRYPT. - You MUST get the actual number back to charge it again, so a one-way hash is useless here. Use strong reversible encryption (AES-GCM) with proper key management — or better, TOKENIZE via a PCI-compliant vault so you store a token instead of the card. The need to recover the value forces encryption, not hashing. WHY STORING PASSWORDS "ENCRYPTED" IS A FAILURE: - Encryption is REVERSIBLE and depends on a KEY. If passwords are encrypted, then whoever obtains the key — an attacker who breaches the server, a malicious insider, a leaked/hardcoded key — can DECRYPT EVERY PASSWORD back to plaintext. The key becomes a single point of TOTAL compromise. - Hashing has no key to steal and no way back, so a breach of hashes doesn't directly yield passwords. Since you never need to recover a password, encryption adds risk (the key) for a capability you don't want. - Hence "we encrypt passwords" is a RED FLAG: it signals the wrong primitive. Passwords must be HASHED (slow + salted), never encrypted, never plaintext. WHY "DON'T ROLL YOUR OWN CRYPTO" IS THE STRONGEST SINGLE A02 ADVICE: - Most cryptographic failures come from IMPLEMENTING crypto incorrectly, and crypto is uniquely unforgiving: a subtle error produces output that LOOKS fine and "works" in tests but is broken — and the break is usually INVISIBLE until an attacker exploits it (no crash, no error). You can't tell correct crypto from broken crypto by looking at the ciphertext. - Vetted, maintained libraries and high-level constructs (your platform's TLS stack, libsodium / the language standard crypto, a maintained password-hashing library, a KMS) encode decades of expert review and patching. Using them correctly is FAR safer than any homemade scheme, and it's what the HTTPS and Auth courses both conclude. TWO WAYS HOMEMADE CRYPTO GOES WRONG: 1. WRONG MODE / PARAMETER MISUSE: e.g. using AES in ECB mode (identical plaintext blocks produce identical ciphertext, leaking patterns — the infamous "ECB penguin"), or REUSING an IV/nonce with a stream/GCM cipher (which can catastrophically break confidentiality/integrity). These are easy to write and look like "we used AES," but are insecure. 2. NON-CONSTANT-TIME / NON-CRYPTO PRIMITIVES: comparing secrets (tokens, MACs) with a normal == that returns early leaks information via TIMING (timing attacks); or using a non-CSPRNG (Math.random) for keys/IVs/ tokens so they're predictable; or confusing ENCODING (base64) with ENCRYPTION (reversible by anyone). All produce something that "runs" but isn't secure. (Others: home-grown "encryption" that's really XOR/obfuscation, missing authentication on encryption — encrypt-without-MAC — enabling tampering.) ONE-LINE TAKEAWAY: Hash what you only verify (passwords -> Argon2id/bcrypt) and encrypt what you must read back (cards) — never encrypt passwords; and above all DON'T ROLL YOUR OWN CRYPTO, because subtle, invisible implementation errors (wrong mode, reused IV, non-constant-time compares) silently break it — use vetted libraries correctly.