Weak or risky cryptographic algorithms

Weak cryptographic algorithms and unsafe cipher modes

Description

Legacy or weak algorithms such as DES/3DES, RC2/RC4, and IDEA, unsafe modes such as ECB, and weak hashes or signatures such as MD5, SHA-1, SHA1withRSA, and MD5withRSA can undermine confidentiality and integrity. ECB exposes repeated block patterns. DES has a short key vulnerable to brute force, while the 64-bit blocks of DES/3DES create collision risks for large volumes of data, including Sweet32 attacks. Practical MD5 and SHA-1 collisions can undermine signatures and integrity checks. Fast general-purpose hashes also make password guessing inexpensive.

Potential impact

  • Data disclosure through repeated patterns, weak keys, or cryptanalysis.
  • Forgery of files, tokens, or update signatures through hash collisions.
  • Account compromise when passwords stored with MD5 or SHA-1 can be guessed with rainbow tables or GPU-assisted brute force.
  • Failure to meet applicable requirements, such as NIST or PCI DSS cryptographic requirements.

Remediation

  • Use strong algorithms: at least AES-128, preferably an authenticated mode such as AES/GCM/NoPadding. For signatures, use SHA256withRSA with keys of at least 2048 bits, or ECDSA with P-256 or stronger.
  • Do not use ECB. Use authenticated modes such as GCM/CCM, or combine CBC with appropriate integrity protection such as HMAC.
  • Replace MD5, SHA-1, SHA1withRSA, and MD5withRSA in cryptographic hash or signature uses with SHA-256 or stronger alternatives.
  • Store passwords with a dedicated scheme such as Argon2id, scrypt, bcrypt, or PBKDF2, with adequate work and a salt. For PBKDF2-HMAC-SHA256, use at least 600,000 iterations and tune the cost to the server's performance.
  • Generate random IVs, nonces, and salts with SecureRandom, using getInstanceStrong where appropriate. Do not reuse an IV or nonce under the same key.
  • Apply key-length, rotation, and secure-storage controls, including KMS or HSM where appropriate.
  • Restrict algorithms in code and configuration and maintain cryptographic libraries and providers.

Examples

Before

java
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.Signature;

public class LegacyCrypto {
    // Insecure: ECB exposes plaintext patterns
    public byte[] encryptEcb(byte[] plaintext, SecretKey key) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key);
        return cipher.doFinal(plaintext);
    }

    // Insecure: MD5 is collision-prone and fast to brute-force
    public byte[] weakDigest(byte[] data) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");
        return md.digest(data);
    }

    // Insecure: SHA1-based signature is deprecated
    public byte[] signSha1(byte[] data, PrivateKey privKey) throws Exception {
        Signature sig = Signature.getInstance("SHA1withRSA");
        sig.initSign(privKey);
        sig.update(data);
        return sig.sign();
    }
}

After

java
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import java.nio.ByteBuffer;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.util.Base64;

public class ModernCrypto {
    // Secure: AES-GCM (AEAD) with random 96-bit nonce, 128-bit tag
    public byte[] encryptGcm(byte[] plaintext, SecretKey key) throws Exception {
        byte[] nonce = new byte[12];
        SecureRandom.getInstanceStrong().nextBytes(nonce);
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        GCMParameterSpec spec = new GCMParameterSpec(128, nonce);
        cipher.init(Cipher.ENCRYPT_MODE, key, spec);
        byte[] ct = cipher.doFinal(plaintext);
        return ByteBuffer.allocate(nonce.length + ct.length).put(nonce).put(ct).array();
    }

    // Secure password hashing with PBKDF2 (salt + high iteration)
    public String hashPassword(char[] password) throws Exception {
        byte[] salt = new byte[16];
        SecureRandom.getInstanceStrong().nextBytes(salt);
        PBEKeySpec spec = new PBEKeySpec(password, salt, 600_000, 256);
        SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        byte[] hash = skf.generateSecret(spec).getEncoded();
        return Base64.getEncoder().encodeToString(salt) + ":" + Base64.getEncoder().encodeToString(hash);
    }

    // Strong signature with SHA-256
    public byte[] signStrong(byte[] data, PrivateKey privKey) throws Exception {
        Signature sig = Signature.getInstance("SHA256withRSA");
        sig.initSign(privKey);
        sig.update(data);
        return sig.sign();
    }
}

Explanation:

  • Before: AES/ECB exposes repeated blocks. MD5 is vulnerable to collisions and is too fast for password storage. SHA1withRSA has collision-related forgery risks and is no longer recommended.
  • After: AES/GCM provides authenticated encryption, using a nonce that must not repeat under the key and a 128-bit tag to detect modification. Replay prevention needs separate protocol controls. PBKDF2WithHmacSHA256 uses a salt and a high iteration count to increase the cost of password guessing. SHA256withRSA uses a collision-resistant hash for signatures.

References