No Fools here! — Enjoy 35% off on all Individual annual plans with coupon ‘FOOLPROOF35’

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.

Debarshi Das

Blog Author
Hey, I’m Debarshi—vulnerability researcher, reverse engineer, and part-time digital detective. My life’s mission? Breaking things (ethically, of course) and figuring out how they tick. If there’s a sneaky bug hiding in your code, I’ll hunt it down like a cybersecurity bloodhound.

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
Made in Webflow