Love is in the air — Enjoy 20% off on all Individual annual plans with coupon ‘CUPIDCODE20’.

10 Cryptography Mistakes You're Probably Making

PUBLISHED:
February 26, 2025
|
BY:
Debarshi Das
Ideal for
Security Engineer
Developer

In 2023, a major cloud provider leaked sensitive data due to improper key storage. The impact? Millions of accounts compromised.

Cryptographic mistakes are expensive — not only financially, but also as irreparable damage to your brand's trust and reputation. One hardcoded key or reused nonce can lead to data breaches, lawsuits, fines, and a lifetime of being featured in “what not to do” security talks.

But hey, you’re here, so let’s make sure you’re doing everything right. Dive in to learn about the common cryptographic anti-patterns and how to avoid them.

Table of Contents

  1. Hardcoded Secrets in Code
  2. Your Random Is My Calculable
  3. Why You Must Stop Using MD5, SHA-1, and DES in 2025
  4. Right Algorithm, Wrong Mode
  5. Nonce Reuse
  6. Weak Key Management
  7. Data-at-Rest Needs Protection
  8. Insecure SSL/TLS Configuration
  9. Rolling Your Own Crypto
  10. Authorization Keys Aren’t Encryption Keys
  11. Catching and Mitigating Crypto Vulnerabilities in SDLC

Hardcoded Secrets in Code

Hardcoded credentials in the codebase are much more common than you think. A forgotten comment here, a testing variable there (sometimes intentional) can quickly become a nightmare if found by threat actors and can be abused to easily waltz right into your system.

This is really common in mobile applications and web applications where developers just minify/obfuscate the client-side code and think they’re good to go. Spoiler alert: obfuscation is security by obscurity, and therefore, not security!

So, what's a better approach?

  • Use environment variables or secret management tools like AWS Secrets Manager, HashiCorp Vault, or Azure Key Vault.
  • Never commit secrets to version control (yes, even in private repos). Use .gitignore or tools like git-secrets to prevent accidental commits.
  • Rotate secrets regularly. Yes, it’s a pain, but so is explaining to your CEO why your company is trending on Twitter(or X) for all the wrong reasons.

Your Random Is My Calculable

Randomness is the foundational primitive for many cryptographic operations, from generating encryption keys, creating secure tokens to uniquely identifying users. Developers often fall into the trap of thinking they can create randomness from predictable inputs.

Knowing the stakes, it’s clear that failure in generating secure randomness jeopardizes the safety of your entire system. Take the following code snippet as an example:

private static String generatePasswordResetkey(User user){

    long timeInMillis = Instant.now().toEpochMilli();

    String input = timeInMillis + user.getUsername();

    MessageDigest digest = MessageDigest.getInstance("SHA-256");

    byte[] hash = digest.digest(input.getBytes(StandardCharsets.UTF_8));

    return bytesToHex(hash);

}

At first glance, it might seem fine. You’re using the current time and a username to generate a password reset key. But the details matter:

  • Time is predictable. A threat actor can guess the timestamp, especially if they know the approximate time the key was generated.
  • Usernames are predictable. If an attacker knows the username (which they often do), they’re halfway to cracking your “random” key.
  • SHA-256 is a hash function, not a random number generator. It’s deterministic, meaning the same input will always produce the same output. That’s the opposite of random.

Besides insecure design like the example above, developers often unknowingly use insecure defaults in programming languages such as Math.random() which are known to not be cryptographically secure.

Used SecureRandom, I should be secure now?

Well, it depends. SecureRandom is a cryptographically secure randomness generator but, if it’s not configured properly, it will not be able to provide secure randomness.

A common anti-pattern when using SecureRandom is manually setting the seed with setSeed(...). Sure, the documentation says you can seed it, but that doesn’t mean you should. 

Here’s why:

  • Predictable seeds: If you use something like System.currentTimeMillis() or a user-provided value as the seed, attackers can guess or brute-force it. Once they have the seed, they can reproduce your “random” numbers.
  • Low entropy seeds: Using a small or predictable seed (like “12345” or “password”) drastically reduces the entropy of your random number generator. It’s like using a single-digit combination lock — easy to crack.

Why You Must Stop Using MD5, SHA-1, and DES in 2025

Let’s talk about cryptographic algorithms that belong in a museum, not your codebase. MD5, SHA-1, and DES are the dinosaurs of cryptography, once mighty, now extinct (or at least, they should be). 

Yet, like a bad sequel, they keep showing up in legacy systems, third-party libraries, and even new projects where developers copy-paste code from StackOverflow circa 2012.

Why it’s a problem:

  • MD5 and SHA-1 are cryptographically broken. MD5 collisions can be generated in seconds, and SHA-1 was officially “shaken to death” by Google researchers in 2017.
  • DES uses a 56-bit key, which can be brute-forced by modern GPUs in under a day.
  • RC4, another relic, is riddled with biases that make it trivial to crack.

How to fix it:

  • Hashing: Replace MD5/SHA-1 with SHA-256 or SHA-3.
  • Encryption: Ditch DES/RC4 for AES-256 (GCM mode) or ChaCha20.
  • Code audits: Use SAST tooling to hunt for legacy algorithm usage in your codebase.

Right Algorithm, Wrong Mode

Using AES? Great! But if you’re using it in ECB mode, you might as well paint your plaintext on a billboard. AES has several modes of operation. In ECB (Electronic Codebook) mode, it encrypts identical plaintext blocks into identical ciphertext blocks, leaking patterns like a sieve.

The picture you see above is more than just varying portraits of a Tux penguin. This is what you get when you encrypt the original image with AES ECB. Yeah, not the best “encryption”, is it?

Why it’s a problem:

  • Pattern exposure: Structured data like credit cards or passwords, becomes recognizable.
  • No integrity checks: Attackers can tamper with ciphertext without detection.

How to fix it:

  • Use AES-GCM (best practice) or AES-CBC with HMAC for authenticated encryption.
  • Always generate a unique IV and never reuse it.

Nonce Reuse

Nonce stands for “number used once.” Emphasis on once. Nonces are critical in algorithms like AES-GCM, ChaCha20-Poly1305, and ECDSA. Reusing them catastrophically undermines security.

What could go wrong:

  • AES-GCM Nonce Reuse
    • Repeating a nonce in AES-GCM exposes the authentication key, allowing attackers to forge messages.
    • If you encrypt two different plaintexts P and P’ using the same key K and the same nonce N, AES-GCM generates the same keystream for both messages. This allows an attacker to extract information by XORing the two ciphertexts.
  • ECDSA Nonce Reuse
    • Reusing a nonce in ECDSA allows attackers to compute the private key. The 2010 PlayStation 3 breach exploited this.

How to fix it:

  • Random nonces: Generate at least 112 bit nonces via a CSPRNG for AES-GCM.
  • Counter-based nonces: In stateful systems, use monotonic counters with safeguards against overflow.
  • Hybrid approaches: Combine a random prefix with a counter (e.g., first 4 bytes random, last 8 bytes incremental).

// AES-GCM with nonce

SecureRandom random = new SecureRandom();  

byte[] nonce = new byte[14];  

random.nextBytes(nonce);  

GCMParameterSpec spec = new GCMParameterSpec(128, nonce);  

Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");  

cipher.init(Cipher.ENCRYPT_MODE, key, spec); 

Weak Key Management

Your encryption is only as strong as your keys. However, mismanaging cryptographic keys such as storing them in plaintext configuration files, sharing them over insecure channels, or hardcoding them in Docker images renders even the most robust algorithms useless.

Why it’s a problem:

  • The 2023 LastPass breach involved compromised encryption keys stored in a cloud vault.
  • Developers often forget to rotate keys, leaving systems exposed for years.

The 2021 Codecov Breach

Attackers extracted AWS credentials from a Codecov script, allowing them to access encrypted customer data. Proper key isolation and short-lived credentials could have mitigated this.

How to fix it:

  • Use a Key Management Service (KMS): AWS KMS, Google Cloud KMS, or HashiCorp Vault for secure generation and storage.
  • Enforce key rotation: Automatically rotate keys every 90 days.
  • Least privilege access: Restrict key access using IAM roles and audit logs.
  • Hardware Security Modules (HSMs): For high-risk environments, use HSMs to isolate keys from networked systems.

Data-at-Rest Needs Protection

Encrypting data in transit is table stakes. But unencrypted data at rest? That’s a threat actor’s treasure chest. 

You need to make sure that your data at rest is both logically encrypted, for example, the keystores are encrypted as well as the hardware is encrypted with the use of HSM.

Why it’s a problem:

  • The 2023 MOVEit breach exposed unencrypted files stored on FTP servers.
  • Backups stored in S3 buckets with public-read ACLs are a ticking time bomb.

How to fix it:

  • Use database encryption (e.g., PostgreSQL TDE, AWS RDS Encryption).
  • Encrypt backups with AES-256 (at least 112 bits) and store keys in a KMS.

Insecure SSL/TLS Configuration

SSL/TLS is the bedrock of secure internet communication, but misconfigurations can render it ineffective. Modern threats like protocol downgrade attacks, weak cipher suites, and certificate mismanagement expose systems to eavesdropping, data tampering, and impersonation.

What could go wrong:

  • Supporting Deprecated Protocols
    • SSL 2.0/3.0 are vulnerable to attacks like POODLE and BEAST.
    • TLS 1.0/1.1 use outdated cryptographic primitives and are no longer considered secure.
    • Legacy systems forcing support for old protocols expose modern clients to downgrade attacks.
  • Weak Cipher Suites
    • NULL ciphers provide no encryption but may still be enabled by default.
    • RC4 stream cipher is cryptographically broken but often enabled for legacy support.
    • CBC mode ciphers in older TLS versions are vulnerable to padding oracle attacks.
    • Triple DES (3DES) is too slow and has known weaknesses.
  • Certificate Validation Issues
    • Disabling certificate validation entirely for "convenience" or testing.
    • Accepting self-signed certificates in production environments.
    • Missing intermediate certificate verification leading to trust chain breaks.
    • Improper handling of certificate expiration and revocation.
    • Using weak key sizes or outdated signing algorithms.
  • Hostname Verification Failures
    • Skipping hostname verification in custom TLS implementations.
    • Incorrect handling of wildcard certificates.
    • Case-sensitive domain name comparisons causing validation errors.
    • Improper Subject Alternative Name (SAN) checking.

How to fix it:

  • Protocol and cipher config:
    • Enable only TLS 1.2+ in production environments.
    • Configure strong cipher suites with Perfect Forward Secrecy (PFS).
    • Use ECDHE or DHE for key exchange.
    • Prefer AEAD ciphers (GCM, ChaCha20-Poly1305).
  • Certificate management:
    • Use automated certificate management (Let's Encrypt, ACME).
    • Implement proper certificate rotation procedures.
    • Use appropriate key sizes (RSA 2048+, ECC 256+).
  • Validation:
    • Verify the complete certificate chain.
    • Implement proper hostname verification.
    • Check certificate revocation status.
    • Use platform-provided certificate validation.
    • Avoid custom certificate validation logic.

Rolling Your Own Cryptography

Unless you’re a cryptographer with a PhD and a penchant for pain, don’t roll your own cryptography. Just don’t.

Why it’s bad:

  • Cryptography is hard. Like, really hard. Even experts make mistakes. Your homebrew algorithm is almost guaranteed to have vulnerabilities.

How to fix it:

  • Use well-established libraries like OpenSSL, libsodium, or Bouncy Castle.
  • Stick to vetted algorithms and implementations.
  • If you really think you’ve invented a new cryptographic algorithm, get it audited. Without an audit it’s no more serious than a caesar cipher.

Got it, I should use vetted libraries for best security. That should be easy, right?

Well yes, but there’s more. Just adding a good cryptography library to the project dependencies isn’t where it ends. You have to invoke the right functions from the library in the right mode at the right places. It’s not too rare that the right modules and right algorithms have been used but in the wrong configuration, say, a NULL nonce here, an insecure size there. That stuff happens all the time.

Authorization Keys Aren’t Encryption Keys

Cryptographic keys serve distinct purposes. Conflating them introduces systemic risks. When you reuse a key for encryption that you use for authorization you explicitly introduce a scenario where an attacker with access to authorization key will also be able to freely decrypt and tamper the encrypted data.

How to fix it:

  • Key Separation: Maintain distinct keys for signing, encryption, and key derivation.
  • Algorithm Alignment: Use Ed25519 for signing and XChaCha20 for encryption to avoid cross-protocol attacks.
  • Metadata Tagging: Label keys clearly (e.g., sig-2025, enc-2025) to prevent misuse.

Catching and Mitigating Cryptography Vulnerabilities in SDLC

Cryptographic vulnerabilities are often discovered too late: after a breach, during a pentest, or worse, in the hands of an attacker. 

The key to avoiding these pitfalls lies in shifting security left, embedding robust practices into every stage of the Software Development Lifecycle. By catching and mitigating cryptography issues early, you can save time, money, and your reputation.

For teams looking to master secure development practices, AppSecEngineer offers enterprise training that keeps teams ahead of emerging threats and equips them with the skills to orchestrate a secure SDLC.

Frequently Asked Questions

What are the most common cryptographic mistakes developers make?

Some of the most frequent cryptographic errors include:

  • Hardcoding secrets in source code.
  • Using weak or outdated algorithms like MD5, SHA-1, or DES.
  • Reusing nonces in AES-GCM or ECDSA, which can expose encryption keys.
  • Using predictable random number generation (e.g., Math.random() instead of SecureRandom).
  • Misconfiguring SSL/TLS, leading to weak encryption or protocol downgrade attacks.

Why is hardcoding cryptographic keys in source code a security risk?

Hardcoded keys can be easily extracted from code repositories, mobile apps, or reverse-engineered binaries. If an attacker gains access, they can decrypt sensitive data or impersonate legitimate users.

Fix: Use environment variables or secrets management tools like AWS Secrets Manager, HashiCorp Vault, or Azure Key Vault.

How can nonce reuse compromise encryption security?

A nonce (number used once) should never be reused because:

  • In AES-GCM, nonce reuse leaks authentication keys, allowing message forgery.
  • In ECDSA, reusing a nonce can expose private signing keys (e.g., PlayStation 3 hack).
  • Fix: Always generate nonces using a cryptographically secure random number generator (CSPRNG) or use counter-based nonces with safeguards.

What’s wrong with using MD5 or SHA-1 for cryptographic hashing?

MD5 and SHA-1 are vulnerable to collision attacks, where different inputs can produce the same hash. This allows attackers to forge data integrity checks.

Fix: Use SHA-256, SHA-3, or Argon2/PBKDF2 for password hashing.

Why is AES-ECB mode insecure? What should I use instead?

AES-ECB (Electronic Codebook) mode encrypts identical plaintext blocks into identical ciphertext blocks, leaking patterns in encrypted data.

Fix: Use AES-GCM (preferred) or AES-CBC with HMAC for authenticated encryption.

How do weak random number generators impact cryptographic security?

Weak randomness can make keys, session tokens, and cryptographic nonces predictable. For example:

  • Math.random() in JavaScript is not cryptographically secure.
  • Using predictable seeds (System.currentTimeMillis()) in SecureRandom reduces entropy and makes keys guessable.

Fix: Use SecureRandom (Java), crypto.getRandomValues() (JavaScript), or /dev/urandom (Linux). Never manually seed CSPRNGs.

What is key reuse, and why is it dangerous?

Using the same key for encryption and signing introduces systemic vulnerabilities. If an attacker gains access to one, they can decrypt or forge messages.

Fix: Use separate encryption keys (AES-GCM, XChaCha20) and signing keys (Ed25519, HMAC-SHA-256).

How should cryptographic keys be securely stored and managed?

Avoid storing keys in plaintext configuration files, source code, or logs.

Best practices:

  • Use cloud KMS (AWS KMS, Google Cloud KMS, HashiCorp Vault) for secure storage.
  • Implement key rotation every 90 days.
  • Apply least privilege access (IAM roles, ACLs) to limit key exposure.

What are the most common SSL/TLS misconfigurations?

Common SSL/TLS mistakes include:

  • Allowing weak protocols (SSL 2.0, SSL 3.0, TLS 1.0/1.1).
  • Using weak ciphers (RC4, 3DES, NULL ciphers).
  • Disabling certificate validation, making systems vulnerable to man-in-the-middle attacks.

Fix:

  • Enforce TLS 1.2 or 1.3.
  • Use ECDHE for key exchange and AES-GCM for encryption.
  • Verify SSL/TLS certificates properly and enable OCSP stapling.

Why is rolling your own cryptography a bad idea?

Cryptography is highly complex, and even minor mistakes can introduce severe vulnerabilities. Custom algorithms or protocols lack peer review and cryptanalysis, making them unsafe.

Fix: Always use well-vetted cryptographic libraries like OpenSSL, libsodium, or Bouncy Castle instead of writing your own encryption functions.

How can organizations catch cryptographic vulnerabilities early in development?

The best way to avoid cryptography mistakes is to integrate security into the Software Development Lifecycle (SDLC).

Best practices:

  • Use SAST tools (Static Application Security Testing) to detect weak algorithms and hardcoded secrets.
  • Perform code reviews with cryptography experts before production deployments.
  • Train developers on secure cryptography practices with hands-on security training like AppSecEngineer.


Meta Description : Avoid costly cryptographic mistakes that expose your data. Learn the top 10 security flaws and how to fix them with expert guidance

Keyword Suggestions : Cryptographic vulnerabilities, data protection

Debarshi Das

Blog Author
You can call me Deb, a vulnerability researcher, reverse engineer, and digital detective. I break things (ethically), dissect binaries, and hunt down security flaws before attackers do. If there’s a hidden bug, I’ll find it. When I’m not tearing apart code, I’m deep into psychology research, because understanding people is just as important as understanding exploits. Football, strategy, and security all go hand in hand for me. Every system has a weakness—you just have to be smart enough to find it.

Ready to Elevate Your Security Training?

Empower your teams with the skills they need to secure your applications and stay ahead of the curve.
Get Started Now
X
X
Copyright AppSecEngineer © 2025