Skip to content

CWE-780: Use of RSA Without OAEP

Overview

Using RSA encryption without OAEP (Optimal Asymmetric Encryption Padding) enables padding oracle attacks, chosen ciphertext attacks, and message malleability. OAEP adds randomness and integrity checks, making RSA encryption secure against modern attacks.

OWASP Classification

A04:2025 - Cryptographic Failures

Risk

High: RSA without OAEP (textbook RSA or PKCS#1 v1.5 padding) enables Bleichenbacher's attack, timing attacks, partial message recovery, and deterministic encryption (same plaintext = same ciphertext), compromising confidentiality.

Remediation Strategy

Use RSA with OAEP Padding (Primary Defense)

Always specify OAEP padding when using RSA encryption:

  • Use OAEP with SHA-256 or better (not SHA-1)
  • Specify MGF1 (Mask Generation Function) with matching hash
  • Never use "default" RSA without explicitly specifying OAEP
  • This eliminates padding oracle and chosen-ciphertext attacks

Use Hybrid Encryption for Large Data

RSA is limited to small data (typically < 256 bytes for 2048-bit keys):

  • Generate random symmetric key (AES-256)
  • Encrypt data with symmetric cipher (AES-GCM or ChaCha20-Poly1305)
  • Encrypt symmetric key with RSA-OAEP
  • Store encrypted key + ciphertext together
  • This approach is faster and handles unlimited data sizes

Choose Appropriate Key Sizes

Use sufficient RSA key sizes for current security requirements:

  • Minimum 2048 bits (current standard)
  • 3072 bits for higher security or long-term use
  • 4096 bits for very sensitive data
  • Larger keys provide more security but slower performance

Use PSS for Signatures (Not OAEP)

For RSA signatures (not encryption), use PSS padding:

  • OAEP is for encryption only
  • PSS (Probabilistic Signature Scheme) is for signatures
  • PSS provides similar security benefits for signatures
  • Specify hash algorithm (SHA-256 or better)

Remediation Steps

Core principle: Use RSA-OAEP for RSA encryption; never use raw RSA/PKCS#1 v1.5 when OAEP is required.

Follow these steps to fix security findings for CWE-780:

  1. Locate RSA encryption calls
  2. Check padding specification
  3. Update cipher configuration
  4. Verify hash algorithms
  5. Implement hybrid encryption
  6. Test encryption/decryption
  7. Scan for other RSA usage

Common Vulnerable Patterns

  • Default RSA cipher without explicit padding specification
  • Using PKCS#1 v1.5 padding (legacy, vulnerable)
  • "Textbook RSA" with no padding at all
  • Using SHA-1 in OAEP parameters (deprecated)
  • Attempting to encrypt data larger than key size

Vulnerable Patterns

No Padding Specified

cipher = RSA_CIPHER("default")
encrypted = cipher.encrypt(message, public_key)

Why is this vulnerable: PKCS#1 v1.5 padding (the default in many libraries) is vulnerable to Bleichenbacher's padding oracle attack, discovered in 1998 but still exploitable today. An attacker who can determine whether decryption succeeds or fails (even through timing differences) can decrypt RSA ciphertexts by making millions of decryption attempts.

Textbook RSA Without Padding

encrypted = pow(message, e, n)  // Extremely vulnerable!

Why is this vulnerable: Textbook RSA without any padding is deterministic - encrypting the same message twice produces identical ciphertext, leaking information. It's also malleable - attackers can modify ciphertexts to produce predictable plaintext changes. This is the most insecure way to use RSA.

Weak Hash in OAEP

encrypted = cipher.encrypt(message, public_key,
    padding=OAEP(hash=SHA1))  // SHA-1 deprecated

Why is this vulnerable: Using SHA-1 in OAEP parameters undermines security since SHA-1 is cryptographically broken with practical collision attacks. Additionally, attempting to encrypt data larger than the key modulus (e.g., 256 bytes for 2048-bit RSA) fails or truncates data, and padding reduces available space further.

Secure Patterns

Explicit OAEP with Strong Hash

cipher = RSA_CIPHER(
    padding=OAEP,
    hash=SHA256,
    mgf=MGF1(SHA256)
)
encrypted = cipher.encrypt(message, public_key)

Why this works:

  • OAEP adds random padding making encryption probabilistic (same plaintext → different ciphertext each time)
  • SHA-256 + MGF1 spread randomness throughout the message, preventing bit-level manipulation
  • Eliminates padding oracle attacks - no exploitable information leaks during decryption failures
  • All-or-nothing transformation: any ciphertext modification causes decryption to fail
  • Industry standard for RSA encryption since early 2000s

Hybrid Encryption for Large Data

symmetric_key = generate_random_bytes(32)  // AES-256
data_ciphertext = AES_GCM.encrypt(data, symmetric_key)
key_ciphertext = RSA_OAEP.encrypt(symmetric_key, public_key)
store(key_ciphertext, data_ciphertext)

Why this works:

  • RSA-OAEP encrypts only the small AES key (32 bytes), not the entire payload
  • AES-GCM handles bulk data encryption efficiently with built-in authentication
  • Combines RSA's key exchange security with symmetric cipher's speed
  • No size limitations - can encrypt gigabytes of data
  • Only the private key holder can decrypt the AES key and access the data

Migration Considerations

IMPORTANT: Changing RSA padding will make existing encrypted data unreadable.

What Breaks

  • Existing RSA-encrypted data cannot be decrypted with different padding
  • Session keys encrypted with PKCS#1 v1.5 become inaccessible
  • Stored credentials encrypted with old padding are lost
  • Systems expecting specific padding format will fail

Migration Approach

Dual-Padding Support (Recommended)

  1. Implement support for both old and new padding temporarily
  2. Try decrypting with OAEP first (secure method)
  3. Fall back to legacy padding if OAEP fails
  4. Always encrypt new data with OAEP
  5. Batch re-encrypt existing stored data
  6. Add padding version metadata to distinguish formats
  7. Remove legacy padding support after 100% migration

Big-Bang Migration (when dual-read not feasible)

  1. Schedule maintenance window
  2. Decrypt all stored data with old padding
  3. Re-encrypt with OAEP
  4. Update all records in database
  5. Deploy new code simultaneously
  6. Have backup and rollback plan ready

Rollback Procedures

If migration causes issues:

  1. Revert code to support legacy padding
  2. Restore database from pre-migration backup
  3. Re-enable old cipher configuration
  4. Document failures for retry

Testing Recommendations

  • Test OAEP encryption/decryption works correctly
  • Test dual-padding decryption (both formats)
  • Verify migration script on staging data
  • Test rollback procedure
  • Monitor error rates during rollout
  • Set up alerts for decryption failures

Test Cases to Validate Remediation

  1. Normal encryption: Encrypt known plaintext, verify decryption
  2. Large data: Test hybrid encryption with > 1KB data
  3. Invalid ciphertext: Attempt to decrypt modified ciphertext (should fail)
  4. Padding verification: Confirm OAEP is being used (check logs/debugging)

Attack Simulation

  • Attempt padding oracle attack (should fail with OAEP)
  • Try chosen-ciphertext attack (should be prevented)
  • Verify same plaintext produces different ciphertexts (probabilistic)
  • Check that partial ciphertext modification is detected

Verification Steps

  • RSA cipher explicitly specifies OAEP padding
  • Hash algorithm is SHA-256 or better
  • MGF1 uses same hash as OAEP
  • Key size meets minimum requirements (2048+ bits)
  • Large data uses hybrid encryption
  • Decryption properly validates padding

Language-Specific Guidance

  • Java - Cipher with RSA/ECB/OAEPPadding, OAEPParameterSpec
  • JavaScript/Node.js - crypto.publicEncrypt with oaepHash
  • Python - cryptography library, OAEP padding with SHA-256

Additional Resources