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:
- Locate RSA encryption calls
- Check padding specification
- Update cipher configuration
- Verify hash algorithms
- Implement hybrid encryption
- Test encryption/decryption
- 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
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
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
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)
- Implement support for both old and new padding temporarily
- Try decrypting with OAEP first (secure method)
- Fall back to legacy padding if OAEP fails
- Always encrypt new data with OAEP
- Batch re-encrypt existing stored data
- Add padding version metadata to distinguish formats
- Remove legacy padding support after 100% migration
Big-Bang Migration (when dual-read not feasible)
- Schedule maintenance window
- Decrypt all stored data with old padding
- Re-encrypt with OAEP
- Update all records in database
- Deploy new code simultaneously
- Have backup and rollback plan ready
Rollback Procedures
If migration causes issues:
- Revert code to support legacy padding
- Restore database from pre-migration backup
- Re-enable old cipher configuration
- 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
- Normal encryption: Encrypt known plaintext, verify decryption
- Large data: Test hybrid encryption with > 1KB data
- Invalid ciphertext: Attempt to decrypt modified ciphertext (should fail)
- 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