Use of RSA Algorithm without OAEP
Description
Use of RSA Algorithm without OAEP is a cryptographic weakness where software uses RSA encryption but omits Optimal Asymmetric Encryption Padding (OAEP), weakening the encryption's security properties. RSA without proper padding (particularly using PKCS#1 v1.5 or no padding at all) is vulnerable to various attacks including padding oracle attacks, chosen ciphertext attacks, and statistical analysis. OAEP, specified in PKCS#1 v2.x, provides semantic security by making ciphertexts indistinguishable and preventing attackers from inferring information about plaintexts from patterns in ciphertexts.
Risk
RSA without OAEP is vulnerable to multiple attack vectors. Without padding, identical plaintexts produce identical ciphertexts, enabling statistical analysis. PKCS#1 v1.5 padding is vulnerable to Bleichenbacher's attack (a padding oracle attack) that can decrypt ciphertexts or forge signatures. Without OAEP, RSA may leak information about plaintext structure, especially for small or predictable messages. Attackers can exploit these weaknesses to decrypt sensitive data, forge signatures, or recover private keys in some scenarios. Many high-profile vulnerabilities (ROBOT, DROWN) have exploited weak RSA padding.
Solution
Always use RSA with OAEP padding (RSA-OAEP) for encryption. In Java, use "RSA/ECB/OAEPWithSHA-256AndMGF1Padding" or similar OAEP mode. Avoid "RSA/NONE/NoPadding" or "RSA/ECB/PKCS1Padding" for encryption. For signatures, use PSS (Probabilistic Signature Scheme) instead of PKCS#1 v1.5. Consider using modern alternatives to RSA like ECDH for key exchange and EdDSA for signatures. Keep cryptographic libraries updated to benefit from security fixes. Consult current cryptographic guidance from NIST, ENISA, or similar authorities for recommended algorithms and parameters.
Common Consequences
| Impact | Details |
|---|---|
| Confidentiality | Scope: Confidentiality Read Application Data - Weak RSA padding enables attacks that can decrypt encrypted data. |
| Access Control | Scope: Access Control Bypass Protection Mechanism - Without OAEP, RSA encryption provides weaker security guarantees that attackers can exploit. |
| Integrity | Scope: Integrity Modify Application Data - Some padding attacks enable signature forgery or ciphertext manipulation. |
Example Code
Vulnerable Code
// Vulnerable: RSA with no padding
import javax.crypto.Cipher;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
public class VulnerableRSA {
public byte[] vulnerableEncryptNoPadding(byte[] plaintext, PublicKey publicKey)
throws Exception {
// Vulnerable: No padding makes encryption deterministic and weak
Cipher cipher = Cipher.getInstance("RSA/NONE/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(plaintext);
}
public byte[] vulnerableEncryptPKCS1(byte[] plaintext, PublicKey publicKey)
throws Exception {
// Vulnerable: PKCS#1 v1.5 padding vulnerable to Bleichenbacher attack
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(plaintext);
}
}
# Vulnerable: RSA without OAEP
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
def vulnerable_encrypt(message, public_key_pem):
key = RSA.import_key(public_key_pem)
# Vulnerable: PKCS1_v1_5 is outdated and vulnerable
cipher = PKCS1_v1_5.new(key)
return cipher.encrypt(message)
# Vulnerable: Using raw RSA
from Crypto.PublicKey import RSA
def vulnerable_raw_encrypt(message_int, public_key):
# Vulnerable: Textbook RSA without any padding
# c = m^e mod n
return pow(message_int, public_key.e, public_key.n)
// Vulnerable: RSA without OAEP in .NET
using System.Security.Cryptography;
public class VulnerableRSA
{
public byte[] VulnerableEncrypt(byte[] data, RSA publicKey)
{
// Vulnerable: Using PKCS#1 v1.5 padding
return publicKey.Encrypt(data, RSAEncryptionPadding.Pkcs1);
}
}
// Vulnerable: RSA PKCS1v15 in Go
package main
import (
"crypto/rand"
"crypto/rsa"
)
func vulnerableEncrypt(plaintext []byte, publicKey *rsa.PublicKey) ([]byte, error) {
// Vulnerable: EncryptPKCS1v15 is not recommended
return rsa.EncryptPKCS1v15(rand.Reader, publicKey, plaintext)
}
Fixed Code
// Fixed: RSA with OAEP padding
import javax.crypto.Cipher;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.spec.MGF1ParameterSpec;
import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PSource;
public class FixedRSA {
public byte[] fixedEncryptOAEP(byte[] plaintext, PublicKey publicKey)
throws Exception {
// Fixed: Using OAEP with SHA-256
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(plaintext);
}
public byte[] fixedEncryptOAEPExplicit(byte[] plaintext, PublicKey publicKey)
throws Exception {
// Fixed: Explicit OAEP parameters for more control
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPPadding");
OAEPParameterSpec oaepParams = new OAEPParameterSpec(
"SHA-256", // Hash algorithm
"MGF1", // Mask generation function
MGF1ParameterSpec.SHA256, // MGF1 hash
PSource.PSpecified.DEFAULT // Label
);
cipher.init(Cipher.ENCRYPT_MODE, publicKey, oaepParams);
return cipher.doFinal(plaintext);
}
public byte[] fixedDecryptOAEP(byte[] ciphertext, PrivateKey privateKey)
throws Exception {
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(ciphertext);
}
}
# Fixed: RSA with OAEP in Python
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from Crypto.Hash import SHA256
def fixed_encrypt(message, public_key_pem):
key = RSA.import_key(public_key_pem)
# Fixed: Using OAEP with SHA-256
cipher = PKCS1_OAEP.new(key, hashAlgo=SHA256)
return cipher.encrypt(message)
def fixed_decrypt(ciphertext, private_key_pem):
key = RSA.import_key(private_key_pem)
cipher = PKCS1_OAEP.new(key, hashAlgo=SHA256)
return cipher.decrypt(ciphertext)
# Alternative with cryptography library
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
def fixed_encrypt_cryptography(message, public_key):
ciphertext = public_key.encrypt(
message,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
return ciphertext
// Fixed: RSA with OAEP in .NET
using System.Security.Cryptography;
public class FixedRSA
{
public byte[] FixedEncrypt(byte[] data, RSA publicKey)
{
// Fixed: Using OAEP with SHA-256
return publicKey.Encrypt(data, RSAEncryptionPadding.OaepSHA256);
}
public byte[] FixedDecrypt(byte[] data, RSA privateKey)
{
return privateKey.Decrypt(data, RSAEncryptionPadding.OaepSHA256);
}
}
// Fixed: RSA OAEP in Go
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
)
func fixedEncrypt(plaintext []byte, publicKey *rsa.PublicKey) ([]byte, error) {
// Fixed: Using OAEP with SHA-256
hash := sha256.New()
return rsa.EncryptOAEP(hash, rand.Reader, publicKey, plaintext, nil)
}
func fixedDecrypt(ciphertext []byte, privateKey *rsa.PrivateKey) ([]byte, error) {
hash := sha256.New()
return rsa.DecryptOAEP(hash, rand.Reader, privateKey, ciphertext, nil)
}
Detection Methods
- Automated Static Analysis: SAST tools can identify RSA cipher instances without OAEP padding.
- Code Review: Look for Cipher.getInstance() calls with "NoPadding" or "PKCS1Padding" for RSA.
- Cryptographic Audit: Review all RSA usage for proper padding modes.
References
- MITRE Corporation. "CWE-780: Use of RSA Algorithm without OAEP." https://cwe.mitre.org/data/definitions/780.html
- NIST. "Recommendation for Pair-Wise Key Establishment Schemes Using Integer Factorization Cryptography." SP 800-56B.
- Bleichenbacher, Daniel. "Chosen Ciphertext Attacks Against Protocols Based on the RSA Encryption Standard PKCS#1."