Guide
Security
Cryptography
Developer Reference

Common Encryption Mistakes (and How to Avoid Them)

A practical reference to the cryptography errors that appear repeatedly in production systems — and the specific, actionable fixes for each.

Direct Answer

The most dangerous encryption mistakes are not obscure — they are predictable patterns: hashing passwords with MD5 or SHA-256 instead of bcrypt or Argon2, using unauthenticated encryption modes like AES-CBC without a MAC, hardcoding keys in source code, confusing encoding with encryption, and building custom cryptographic schemes instead of using vetted libraries.

TL;DR

  • Never use encryption for passwords — use bcrypt, Argon2id, or PBKDF2
  • MD5 and SHA-1 are cryptographically broken — use SHA-256 or SHA-3
  • Use AES-GCM or ChaCha20-Poly1305 (AEAD) — never AES-CBC without a MAC
  • Never hardcode keys — use environment variables or a secrets manager
  • Rotate keys on schedule and on any suspected exposure
  • Never ignore certificate errors — MITM is the threat model
  • Base64 is encoding, not encryption — never rely on it for security
  • Verify data integrity at every trust boundary
  • HTTPS alone is not enough — defense in depth is required
  • Never write your own crypto — use audited, standardized libraries

1. Using Encryption Instead of Hashing for Passwords

Passwords should be hashed with a dedicated password hashing algorithm, not encrypted. Encryption is reversible — if your key is compromised, all passwords are exposed. Hashing is one-way — a hash verifies without storing the original.

✗ Dangerous

Encrypt(password, secret_key) — reversible if key leaks

✗ Insufficient

SHA-256(password) — fast hash, easily brute-forced

✓ Correct

Argon2id(password, salt, cost) — slow by design, memory-hard

Read more: How Password Hashing Works: bcrypt, Argon2, PBKDF2 Explained

2. Using Outdated Algorithms (MD5, SHA-1)

MD5 and SHA-1 are cryptographically broken. Collision attacks — finding two different inputs that produce the same hash — have been demonstrated for both. SHA-1 was deprecated by NIST in 2011; MD5 has been considered broken since 2004. Using either for integrity verification, digital signatures, or certificates creates real security risk.

MD5Broken — collisions demonstrated in seconds on a laptop
SHA-1Broken — Google SHAttered attack (2017) produced a practical collision
SHA-256Secure — use for integrity verification and general hashing
SHA-3Secure — structurally different design (Keccak sponge), NIST standardized

For a full comparison, see MD5 vs SHA-256.

3. Not Using Authenticated Encryption

Encryption provides confidentiality — it hides the content. But it does not prevent an attacker from modifying the ciphertext. Without authentication, a modified ciphertext may decrypt to different plaintext — enabling padding oracle attacks (AES-CBC), bit-flipping attacks, and chosen-ciphertext attacks.

AEAD (Authenticated Encryption with Associated Data) provides both confidentiality and integrity in a single operation. Use AES-GCM or ChaCha20-Poly1305 — both are standardized and hardware-accelerated on modern hardware.

✗ Vulnerable Pattern

AES-CBC without a MAC → padding oracle, ciphertext manipulation

✓ Correct Pattern

AES-256-GCM → confidentiality + integrity + authentication tag

See AES-GCM vs AES-CBC and the Authenticated Encryption and Integrity guide.

4. Hardcoding Keys in Source Code

Hardcoded encryption keys, API secrets, and private keys committed to source code are one of the most common and consequential security mistakes. They appear in public repositories, build artifacts, Docker image layers, compiled binaries, and configuration files — often for years before discovery.

✗ Never

const SECRET_KEY = "abc123hardcoded"

✓ Always

const SECRET_KEY = process.env.SECRET_KEY

Use environment variables for development, and a proper secrets manager for production: AWS Secrets Manager, HashiCorp Vault, GCP Secret Manager, Azure Key Vault, or Doppler. Enable secret scanning in your CI/CD pipeline to catch leaks before they reach production.

5. Not Rotating Keys

Even a well-protected key can be compromised — through insider threats, credential leaks, vendor breaches, or cryptanalysis of large ciphertext volumes. Keys that are never rotated become more valuable to attackers over time and make compromise harder to contain.

Set rotation schedules

Rotate encryption keys on a defined schedule — annually for data-at-rest keys, more frequently for high-value operations. Automate rotation through your secrets manager.

Rotate immediately on exposure

If a key may have been exposed — a leaked log, an unexpected access, a compromised system — rotate immediately. Do not wait for confirmation.

Maintain key versioning

Use envelope encryption: a key-encrypting key (KEK) wraps data-encrypting keys (DEKs). Rotate the KEK; re-encrypt only DEKs, not all data.

Keep old keys for decryption only

After rotation, retain old keys read-only long enough to decrypt previously encrypted data. Do not use old keys for new encryptions.

6. Ignoring Certificate Warnings

Certificate validation errors are not inconveniences — they are your only warning that a man-in-the-middle (MITM) attack may be in progress. Disabling certificate verification in code is a critical vulnerability:

requests.get(url, verify=False)

Even in development, this trains developers to ignore certificate errors and may end up in production builds. Instead, add the development CA certificate to your trust store, use a tool like mkcert to generate locally trusted certificates, or use a DNS-based solution like a local resolver.

For how certificate validation works in TLS, see the What Is TLS? guide.

7. Confusing Encoding with Encryption

Encoding (Base64, URL encoding, hex) is a format transformation — it is trivially reversible by anyone with the encoded data and knowledge of the scheme. No key is required. Encoding provides zero confidentiality.

Encryption requires a secret key. Without the key, the ciphertext reveals nothing about the plaintext (assuming a sound algorithm and correct implementation).

Encoding (not secure)

  • Base64
  • URL encoding
  • Hex
  • UTF-8

Reversible without a key. Used for data compatibility, not security.

Hashing (one-way)

  • SHA-256
  • bcrypt
  • Argon2id
  • HMAC

Non-reversible. Used for integrity and password storage.

Encryption (reversible with key)

  • AES-GCM
  • ChaCha20-Poly1305
  • RSA-OAEP

Reversible only with the correct key. Used for confidentiality.

See Complete Guide to Encryption, Hashing & Encoding for a full breakdown, or compare Base64 vs URL Encoding.

8. Skipping Integrity Verification

Data can be corrupted or tampered with in transit or at rest — by network errors, storage faults, or malicious actors. Without integrity verification, corruption goes undetected and may propagate silently.

API responses: Verify HMAC or digital signatures on API payloads where the source matters — not just HTTPS transit.
File downloads: Always verify checksums (SHA-256) for downloaded binaries, packages, and archives. Compare against a trusted source.
Database records: For sensitive records, store a MAC or hash of critical fields. Detect tampering on read, not on audit.
Encrypted data: Use AES-GCM or ChaCha20-Poly1305 — both verify integrity before returning plaintext, preventing tampering attacks.

Learn about HMAC for integrity: Hashing and HMAC guide.

9. Over-Relying on HTTPS

HTTPS protects data in transit between client and server. It does not protect:

  • Data at rest in your database (a DB breach exposes plaintext)
  • Data being processed in memory on the server
  • Credentials if your server-side code is compromised
  • Secrets in environment variables if the host is breached
  • Data sent to third-party services your app calls

A complete security posture requires: encryption at rest, field-level encryption for high-sensitivity data, access controls, key management, logging and monitoring, and least-privilege principles — in addition to HTTPS.

See also: What Is a Digital Signature? — signatures verify the origin of data independent of transport.

10. DIY Cryptography

"Don't roll your own crypto" is the most repeated rule in cryptographic engineering — and still the most violated. Subtle implementation errors in encryption, key derivation, or protocol design can completely break security in ways that are not apparent from code review or standard testing.

Use audited libraries

libsodium, Web Crypto API, OpenSSL/BoringSSL, Java JCE, Python cryptography — these libraries have been reviewed by specialists and tested extensively.

Use high-level APIs

Prefer NaCl/libsodium secretbox over building your own AES+HMAC. Prefer TLS over building your own record layer. Higher-level primitives have fewer error-prone decisions.

Never invent new algorithms

XOR ciphers, custom substitution ciphers, and novel constructions are almost always trivially broken. The security of standard algorithms like AES comes from decades of public cryptanalysis.

Try the Tools

Explore hashing, encryption, and encoding with these browser-based tools — all processing runs locally with no data uploaded.

Frequently Asked Questions

Related Resources