Skillversitas

Best Practices and Pitfalls

Most real-world crypto failures are not exotic ciphers - they are standard ciphers misused. This chapter collects the recurring mistakes, what each one breaks, and the habit that prevents it. Read it as a pre-merge checklist.

The Big Pitfalls

  • ECB mode: identical plaintext blocks produce identical ciphertext blocks, so structure leaks. Use GCM or ChaCha20-Poly1305.
  • Nonce/IV reuse with the same key: in GCM it breaks both confidentiality and authenticity; in CTR it XORs two plaintexts together. Generate a fresh nonce per message and store it with the ciphertext.
  • Unauthenticated encryption: CBC or CTR without a MAC is malleable - flipped bits flip predictably. Prefer AEAD; if you add a MAC manually, do encrypt-then-MAC and check the MAC before decrypting (that kills padding oracles).
  • MD5 / SHA-1 for security: both have practical collision attacks. SHA-256 is the floor; SHA-512 if you want headroom.
  • Home-rolled crypto: "AES with a custom padding step" is a new cipher nobody has analyzed. Use library primitives exactly as designed.
  • Predictable randomness: random, time-based seeds, or user input as nonces. Security values come from secrets / os.urandom.
  • Weak or missing KDF work: a bare SHA-256 password hash cracks on GPUs in seconds. Use PBKDF2, scrypt, or Argon2 with a tuned work factor.
  • Keys in source code: keys belong in a secret manager, environment, or a key file with 0600 permissions - and they rotate.
  • Non-constant-time comparison: == on tokens and MACs leaks a timing signal. Use compare_digest.
  • Verification disabled "temporarily": CERT_NONE and check_hostname = False in production are an open door. Verify, or do not connect.

Pre-Merge Checklist

  1. Is the primitive from a reviewed library (stdlib, cryptography) with a standard mode?
  2. Is every key generated by a CSPRNG, stored outside the code, and sized for its algorithm?
  3. Is every nonce/IV fresh per message, and stored where decryption can find it?
  4. Is the encryption authenticated (AEAD or MAC-first), and is the tag checked before use?
  5. Are digests SHA-256 or better, and are comparisons constant-time?
  6. Can a wrong key or tampered byte be distinguished from a valid one? If yes, you have an oracle - make the error uniform.
  7. Is there a rotation plan (MultiFernet, versioned container headers) and a revocation story?

When in Doubt

Prefer the boring choice: Fernet for application-level secrets, AES-256-GCM for bulk data, X25519 and Ed25519 for key exchange and signatures, TLS for transport, Argon2id for passwords. Each one is a solved problem behind a library call; novelty is where vulnerabilities hide.

Summary

Run the checklist on every crypto change: standard mode, fresh nonces, authentication on, CSPRNG keys, constant-time compares, verified TLS. When in doubt, pick the boring primitive - the goal is to make correctness a property of the library, not an achievement of your code.