Weak cryptographic algorithms

Use of broken or risky cryptographic algorithms

Description

Older ciphers such as DES/3DES, RC2/RC4, and Blowfish, or inappropriate modes such as AES-ECB, can weaken confidentiality or integrity depending on their use and configuration. DES's short key, RC4's known weaknesses, and ECB's exposure of repeated block patterns are different problems. MD5 and SHA-1 are vulnerable to collisions and unsuitable where integrity checks or signatures require collision resistance.

Potential impact

  • Exposure of plaintext patterns or sensitive information through weak encryption
  • Forged integrity checks or signatures when vulnerable hashes permit collisions
  • Authentication or authorization bypass where weak cryptographic designs enable token or message forgery

Remediation

  • Prefer authenticated encryption such as AES-GCM or ChaCha20-Poly1305, and hashes such as SHA-256/384/512 or SHA-3.
  • Avoid DES/3DES, RC2/RC4, Blowfish, MD5, SHA-1, and AES-ECB for these security uses.
  • Use the recommended 96-bit IV for AES-GCM. Never reuse an IV with the same key, and manage per-key usage and collision risk. Use at least 128-bit keys, preferably 256-bit.
  • Derive password-based keys with PBKDF2, Scrypt, or Argon2 and appropriate iteration or memory costs.
  • Prefer AEAD. Where it cannot be used, provide separate authentication such as HMAC-SHA-256.
  • Use established libraries such as the Web Crypto API (node:crypto webcrypto) or libsodium.

Examples

Before

javascript
const crypto = require("crypto");

// Before: weak encryption mode and hash.
function encryptEcb(plaintext, key) {
  // AES-ECB exposes patterns and provides no integrity protection.
  const cipher = crypto.createCipheriv("aes-128-ecb", key, null);
  return Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
}

function md5Checksum(data) {
  // MD5 lacks the collision resistance needed for security integrity checks.
  return crypto.createHash("md5").update(data).digest("hex");
}

// Fixed demonstration key (also insecure).
const key = Buffer.alloc(16, 0);
console.log(encryptEcb("secret text", key).toString("hex"));
console.log(md5Checksum("file-contents"));

After

javascript
const crypto = require("crypto");

// AES-256-GCM for confidentiality and integrity.
function encryptAesGcm(plaintext, key) {
  const iv = crypto.randomBytes(12); // Recommended 96-bit IV.
  const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
  const ciphertext = Buffer.concat([
    cipher.update(plaintext, "utf8"),
    cipher.final(),
  ]);
  const tag = cipher.getAuthTag();
  return {
    iv: iv.toString("hex"),
    ct: ciphertext.toString("hex"),
    tag: tag.toString("hex"),
  };
}

function decryptAesGcm(enc, key) {
  const iv = Buffer.from(enc.iv, "hex");
  const ct = Buffer.from(enc.ct, "hex");
  const tag = Buffer.from(enc.tag, "hex");
  const decipher = crypto.createDecipheriv("aes-256-gcm", key, iv);
  decipher.setAuthTag(tag);
  const plaintext = Buffer.concat([decipher.update(ct), decipher.final()]);
  return plaintext.toString("utf8");
}

// Use a strong hash for integrity checks.
function sha256Checksum(data) {
  return crypto.createHash("sha256").update(data).digest("hex");
}

// Use HMAC-SHA-256 for message authentication where needed.
function hmacSha256(data, key) {
  return crypto.createHmac("sha256", key).update(data).digest("hex");
}

// Generate a strong key (32 bytes for AES-256).
const key = crypto.randomBytes(32);
const enc = encryptAesGcm("secret text", key);
console.log(enc);
console.log("sha256:", sha256Checksum("file-contents"));
console.log("hmac:", hmacSha256("message", crypto.randomBytes(32)));

Explanation:

  • Before: AES-ECB exposes equal plaintext blocks and does not authenticate ciphertext. MD5 collisions undermine collision-resistant integrity checks. The fixed demonstration key also exposes the encrypted data.
  • After: AES-256-GCM provides authenticated encryption and checks the tag during decryption. SHA-256 can check integrity against a trusted reference digest, but an unkeyed hash does not authenticate the sender. Generate strong keys and a fresh IV for each encryption, while limiting per-key use and preventing reuse; random IVs still have collision risk.

References