Verwendung des RSA-Algorithmus ohne OAEP

Beschreibung

Verwendung des RSA-Algorithmus ohne OAEP ist eine kryptografische Schwäche, bei der Software RSA-Verschlüsselung verwendet, aber Optimal Asymmetric Encryption Padding (OAEP) auslässt, was die Sicherheitseigenschaften der Verschlüsselung schwächt. RSA ohne ordnungsgemäßes Padding (insbesondere bei Verwendung von PKCS#1 v1.5 oder gar kein Padding) ist anfällig für verschiedene Angriffe einschließlich Padding-Oracle-Angriffe, Chosen-Ciphertext-Angriffe und statistische Analyse. OAEP, spezifiziert in PKCS#1 v2.x, bietet semantische Sicherheit, indem es Ciphertexte ununterscheidbar macht und Angreifer daran hindert, Informationen über Plaintexte aus Mustern in Ciphertexten abzuleiten.

Risiko

RSA ohne OAEP ist anfällig für mehrere Angriffsvektoren. Ohne Padding erzeugen identische Plaintexte identische Ciphertexte, was statistische Analyse ermöglicht. PKCS#1 v1.5 Padding ist anfällig für Bleichenbachers Angriff (ein Padding-Oracle-Angriff), der Ciphertexte entschlüsseln oder Signaturen fälschen kann. Ohne OAEP kann RSA Informationen über Plaintext-Struktur preisgeben, insbesondere für kleine oder vorhersagbare Nachrichten. Viele hochkaratige Schwachstellen (ROBOT, DROWN) haben schwaches RSA-Padding ausgenutzt.

Lösung

Verwenden Sie immer RSA mit OAEP-Padding (RSA-OAEP) für Verschlüsselung. In Java verwenden Sie "RSA/ECB/OAEPWithSHA-256AndMGF1Padding" oder ähnliche OAEP-Modi. Vermeiden Sie "RSA/NONE/NoPadding" oder "RSA/ECB/PKCS1Padding" für Verschlüsselung. Für Signaturen verwenden Sie PSS (Probabilistic Signature Scheme) anstelle von PKCS#1 v1.5. Erwägen Sie moderne Alternativen zu RSA wie ECDH für Schlüsselaustausch und EdDSA für Signaturen. Halten Sie kryptografische Bibliotheken aktuell.

Häufige Auswirkungen

AuswirkungDetails
VertraulichkeitBereich: Vertraulichkeit

Anwendungsdaten lesen - Schwaches RSA-Padding ermöglicht Angriffe, die verschlüsselte Daten entschlüsseln können.
ZugriffskontrolleBereich: Zugriffskontrolle

Schutzmechanismus umgehen - Ohne OAEP bietet RSA-Verschlüsselung schwachere Sicherheitsgarantien, die Angreifer ausnutzen können.
IntegritätBereich: Integrität

Anwendungsdaten ändern - Einige Padding-Angriffe ermöglichen Signatur-Fälschung oder Ciphertext-Manipulation.

Beispielcode

Verwundbarer Code

// Verwundbar: RSA ohne 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 {
        // Verwundbar: Kein Padding macht Verschlüsselung deterministisch und schwach
        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 {
        // Verwundbar: PKCS#1 v1.5 Padding anfällig für Bleichenbacher-Angriff
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(plaintext);
    }
}
# Verwundbar: RSA ohne 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)
    # Verwundbar: PKCS1_v1_5 ist veraltet und verwundbar
    cipher = PKCS1_v1_5.new(key)
    return cipher.encrypt(message)

# Verwundbar: Rohes RSA verwenden
def vulnerable_raw_encrypt(message_int, public_key):
    # Verwundbar: Lehrbuch-RSA ohne jegliches Padding
    # c = m^e mod n
    return pow(message_int, public_key.e, public_key.n)

Gefixter Code

// Gefixt: RSA mit OAEP-Padding
import javax.crypto.Cipher;
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 {
        // Gefixt: OAEP mit SHA-256 verwenden
        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 {
        // Gefixt: Explizite OAEP-Parameter für mehr Kontrolle
        Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPPadding");

        OAEPParameterSpec oaepParams = new OAEPParameterSpec(
            "SHA-256",                    // Hash-Algorithmus
            "MGF1",                       // Mask-Generation-Funktion
            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);
    }
}
# Gefixt: RSA mit 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)
    # Gefixt: OAEP mit SHA-256 verwenden
    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 mit cryptography-Bibliothek
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
// Gefixt: RSA OAEP in Go
package main

import (
    "crypto/rand"
    "crypto/rsa"
    "crypto/sha256"
)

func fixedEncrypt(plaintext []byte, publicKey *rsa.PublicKey) ([]byte, error) {
    // Gefixt: OAEP mit SHA-256 verwenden
    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)
}

Erkennungsmethoden

  • Automatisierte statische Analyse: SAST-Tools können RSA-Cipher-Instanzen ohne OAEP-Padding identifizieren.
  • Code-Review: Nach Cipher.getInstance()-Aufrufen mit "NoPadding" oder "PKCS1Padding" für RSA suchen.
  • Kryptografisches Audit: Alle RSA-Nutzung auf korrekte Padding-Modi überprüfen.

Referenzen

  1. MITRE Corporation. "CWE-780: Use of RSA Algorithm without OAEP." https://cwe.mitre.org/data/definitions/780.html
  2. NIST. "Recommendation for Pair-Wise Key Establishment Schemes Using Integer Factorization Cryptography." SP 800-56B.
  3. Bleichenbacher, Daniel. "Chosen Ciphertext Attacks Against Protocols Based on the RSA Encryption Standard PKCS#1."