Skip to content

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:

  1. Identify weak algorithm
  2. 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
  3. Plan migration

  4. Update code
  5. Test thoroughly
  6. 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

  1. Algorithm replacement: Verify new strong algorithm works correctly
  2. Key sizes: Confirm minimum key sizes met (RSA 2048+, AES 256)
  3. Backward compatibility: Test migration from old to new algorithm
  4. Performance: Ensure acceptable performance with stronger algorithms
  5. 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:

Additional Resources