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, useSHA256withRSAwith 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, andMD5withRSAin 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, usinggetInstanceStrongwhere 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.
SHA1withRSAhas 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.
PBKDF2WithHmacSHA256uses a salt and a high iteration count to increase the cost of password guessing.SHA256withRSAuses a collision-resistant hash for signatures.