CWE-757: Selection of Less-Secure Algorithm
Overview
Using weak cryptographic algorithms (MD5, SHA-1, DES, RC4, weak RSA keys) instead of strong modern alternatives (SHA-256+, AES-256, RSA-2048+) exposes data to collision attacks, brute force, cryptanalysis, and compromises confidentiality and integrity.
OWASP Classification
A04:2025 - Cryptographic Failures
Risk
High: Weak algorithms enable data decryption (DES breakable in hours), hash collisions (MD5/SHA-1 broken), message forgery, password cracking, and compliance violations (PCI-DSS, HIPAA require strong crypto).
Remediation Strategy
Use Strong Hash Functions (Primary Defense)
# VULNERABLE - weak hashing
import hashlib
password_hash = hashlib.md5(password.encode()).hexdigest() # Broken!
file_hash = hashlib.sha1(data).hexdigest() # Collisions found
# SECURE - strong hashing
import hashlib
# For passwords - use password hashing (NOT general hash)
import bcrypt
password_hash = bcrypt.hashpw(password.encode(), bcrypt.gensalt())
# Or use Argon2 (winner of password hashing competition)
from argon2 import PasswordHasher
ph = PasswordHasher()
password_hash = ph.hash(password)
# For file integrity - use SHA-256 or better
file_hash = hashlib.sha256(data).hexdigest()
# Or SHA-512 for higher security
file_hash = hashlib.sha512(data).hexdigest()
Use Strong Encryption
# VULNERABLE - weak encryption
from Crypto.Cipher import DES # 56-bit key, broken
cipher = DES.new(key, DES.MODE_ECB) # Also ECB is insecure!
encrypted = cipher.encrypt(data)
# SECURE - AES-256 with GCM
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os
key = AESGCM.generate_key(bit_length=256) # 256-bit AES
aesgcm = AESGCM(key)
nonce = os.urandom(12) # 96-bit nonce for GCM
# Encrypts AND authenticates
encrypted = aesgcm.encrypt(nonce, plaintext, associated_data)
# Decryption verifies authenticity
try:
plaintext = aesgcm.decrypt(nonce, encrypted, associated_data)
except InvalidTag:
print("Authentication failed - data tampered!")
Use Strong Key Sizes
// VULNERABLE - weak RSA key
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(1024); // Too weak!
KeyPair keyPair = keyGen.generateKeyPair();
// SECURE - strong RSA key
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048); // Minimum 2048 bits
KeyPair keyPair = keyGen.generateKeyPair();
// For long-term security, use 4096 bits
keyGen.initialize(4096);
Replace Weak Algorithms
// VULNERABLE - Node.js weak crypto
const crypto = require('crypto');
const hash = crypto.createHash('md5') // Broken!
.update(data)
.digest('hex');
// SECURE - strong algorithms
const hash = crypto.createHash('sha256')
.update(data)
.digest('hex');
// For encryption, use modern algorithms
const algorithm = 'aes-256-gcm'; // Not aes-128-ecb!
const key = crypto.randomBytes(32); // 256 bits
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv(algorithm, key, iv);
Remediation Steps
Core principle: Never allow security guarantees to depend on a weak or legacy algorithm; algorithm selection must be server-controlled and restricted to a small allowlist of approved, modern primitives for each use case.
Follow these steps to fix security findings for CWE-757:
- Identify weak algorithm
-
Select appropriate replacement
- Passwords → bcrypt, Argon2, scrypt
- File integrity → SHA-256, SHA-512
- Encryption → AES-256-GCM, ChaCha20-Poly1305
- Signatures → RSA-2048+ with SHA-256, ECDSA
-
Plan migration
- Update code
- Test thoroughly
- Monitor
Algorithm Security Levels
BROKEN (Never Use):
- MD5: Hash collisions trivial
- SHA-1: Collisions demonstrated
- DES: 56-bit key broken in hours
- RC4: Biases in keystream
- RSA < 1024 bits: Factorable
WEAK (Legacy Only):
- 3DES: Slow, 64-bit blocks (Sweet32)
- RSA 1024-bit: Borderline
- AES-128 ECB: No authentication, pattern leakage
ACCEPTABLE:
- SHA-256: Good for general use
- AES-128 GCM: Acceptable but AES-256 preferred
- RSA 2048-bit: Current minimum
- ECDSA P-256: Acceptable
RECOMMENDED:
- SHA-512: Better security margin
- AES-256 GCM: Strong encryption + authentication
- RSA 4096-bit: Long-term security
- ChaCha20-Poly1305: Modern alternative to AES-GCM
- Ed25519: Modern signature algorithm
- Argon2id: Password hashing
Common Weak Algorithm Issues
Password Hashing:
# WRONG - general hash for passwords
password_hash = hashlib.sha256(password.encode()).hexdigest()
# Fast = easy to brute force!
# CORRECT - password-specific hashing
import bcrypt
password_hash = bcrypt.hashpw(password.encode(),
bcrypt.gensalt(rounds=12))
Encryption Mode:
// WRONG - ECB mode shows patterns
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
// CORRECT - authenticated encryption
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
Signature Algorithm:
# WEAK
signature = rsa_key.sign(data, 'SHA-1') // SHA-1 broken
# STRONG
signature = rsa_key.sign(data, 'SHA-256')
Migration Strategy
CRITICAL: Replacing weak cryptographic algorithms invalidates existing hashed/encrypted data.
What Breaks
- Password hashes: MD5/SHA-1 hashes won't validate with bcrypt/Argon2
- Encrypted data: DES-encrypted data unreadable with AES-256
- Digital signatures: SHA-1 signatures fail validation with SHA-256
- File checksums: Integrity checks need recalculation
Migration Approach
For Password Hashes:
See CWE-916 for detailed password hash migration (dual-read strategy).
For Encryption:
See CWE-327 for detailed encryption migration (decrypt with old, re-encrypt with new).
For File Hashes (Non-Breaking):
# Old checksums can coexist with new ones
file_record = {
'filename': 'document.pdf',
'md5_checksum': 'abc123...', # Legacy
'sha256_checksum': 'def456...', # New
'checksum_algorithm': 'sha256' # Current standard
}
# Gradually recalculate as files are accessed
def get_file_checksum(filename):
record = db.get_file_record(filename)
if not record.get('sha256_checksum'):
# Recalculate with strong algorithm
content = read_file(filename)
sha256_hash = hashlib.sha256(content).hexdigest()
db.update_file_record(filename, {
'sha256_checksum': sha256_hash,
'checksum_algorithm': 'sha256',
'updated_at': datetime.now()
})
return sha256_hash
return record['sha256_checksum']
Testing Recommendations
- Test dual-read for passwords (old hash still works)
- Test encryption migration (old data decrypts)
- Verify new algorithm performs acceptably
- Test rollback procedures
- Monitor migration progress
For detailed migration code examples, see related CWEs:
Test Cases
- Algorithm replacement: Verify new strong algorithm works correctly
- Key sizes: Confirm minimum key sizes met (RSA 2048+, AES 256)
- Backward compatibility: Test migration from old to new algorithm
- Performance: Ensure acceptable performance with stronger algorithms
- Compliance: Verify meets security standards (FIPS, PCI-DSS, etc.)
Security Checklist
- No MD5, SHA-1, DES, RC4, or other weak algorithms in use
- Minimum key sizes met (RSA 2048+, AES 128+)
- Modern modes used (GCM, not ECB)
- Password hashing uses bcrypt/Argon2/scrypt (not SHA-256)
- TLS 1.2+ used (not SSL, TLS 1.0/1.1)
- Cryptographic libraries up to date
Dynamic Scan Guidance
For guidance on remediating this CWE when detected by dynamic (DAST) scanners:
- Dynamic Scan Guidance - Analyzing DAST findings and mapping to source code