Inhaltsverzeichnis

SignatureExtensions

Namespace: WvdS.System.Security.Cryptography.Signatures

Drop-In Replacement Extensions für digitale Signaturen mit Post-Quantum Support. Erweitert RSA, ECDsa und X509Certificate2 um PQ-hybride Signierfunktionen.

Übersicht

Diese Klasse bietet drei Arten von Signaturen:

Modus Klassisch ML-DSA Verwendung
Classic - Standard .NET Verhalten
Hybrid Maximale Sicherheit
PostQuantum - Rein post-quantum

RSA SignData/VerifyData

using var rsa = RSA.Create(2048);
byte[] data = Encoding.UTF8.GetBytes("Wichtige Daten");
 
// Signieren mit explizitem Modus
byte[] signature = rsa.SignData(
    data,
    HashAlgorithmName.SHA256,
    RSASignaturePadding.Pkcs1,
    CryptoMode.Hybrid);
 
// Verifizieren
bool isValid = rsa.VerifyData(
    data,
    signature,
    HashAlgorithmName.SHA256,
    RSASignaturePadding.Pkcs1,
    CryptoMode.Hybrid);

Stream-Signatur

using var fileStream = File.OpenRead("document.pdf");
 
byte[] signature = rsa.SignData(
    fileStream,
    HashAlgorithmName.SHA256,
    RSASignaturePadding.Pkcs1,
    CryptoMode.Hybrid);

ECDsa SignData/VerifyData

using var ecdsa = ECDsa.Create(ECCurve.NamedCurves.nistP256);
byte[] data = GetDataToSign();
 
// Signieren
byte[] signature = ecdsa.SignData(
    data,
    HashAlgorithmName.SHA256,
    CryptoMode.Hybrid);
 
// Verifizieren
bool isValid = ecdsa.VerifyData(
    data,
    signature,
    HashAlgorithmName.SHA256,
    CryptoMode.Hybrid);

Zertifikat-basierte Signaturen

var certificate = GetSigningCertificate();
byte[] data = GetDataToSign();
 
// Signieren (verwendet automatisch RSA oder ECDSA)
byte[] signature = certificate.SignData(
    data,
    HashAlgorithmName.SHA256,
    CryptoMode.Hybrid);
 
// Verifizieren
bool isValid = certificate.VerifyData(
    data,
    signature,
    HashAlgorithmName.SHA256,
    CryptoMode.Hybrid);

Der Key-Typ wird automatisch erkannt:

Standalone ML-DSA

Direkte ML-DSA Signaturen ohne klassischen Key:

// Key-Paar generieren
var (publicKey, privateKey) = SignatureExtensions.GenerateMlDsaKeyPair();
 
// Signieren
byte[] data = GetDataToSign();
byte[] signature = SignatureExtensions.SignMlDsa(data, privateKey);
 
// Verifizieren
bool isValid = SignatureExtensions.VerifyMlDsa(data, signature, publicKey);

Hybrides Signaturformat

┌────────────────────────────────────────────┐
│ [4 Bytes] Länge klassische Signatur        │
│ [n Bytes] Klassische Signatur (RSA/ECDSA)  │
│ [m Bytes] PQ-Signatur (ML-DSA-65)          │
└────────────────────────────────────────────┘
Komponente Typische Größe
Längenfeld 4 Bytes
RSA-2048 Signatur 256 Bytes
ECDSA P-256 Signatur ~70 Bytes
ML-DSA-65 Signatur 3.293 Bytes
Hybrid RSA ~3.553 Bytes
Hybrid ECDSA ~3.367 Bytes

Transiente PQ-Keys

Für Standalone-Signaturen (ohne Zertifikat) werden thread-lokale transiente Keys verwendet:

// Eigene Keys setzen
var (pubKey, privKey) = SignatureExtensions.GenerateMlDsaKeyPair();
SignatureExtensions.SetTransientPqKey(pubKey, privKey);
 
// Jetzt können SignData/VerifyData ohne Zertifikat verwendet werden
byte[] sig = rsa.SignData(data, HashAlgorithmName.SHA256,
    RSASignaturePadding.Pkcs1, CryptoMode.Hybrid);
 
// Nur Public Key für Verifikation
SignatureExtensions.SetTransientPqPublicKey(pubKey);
bool valid = rsa.VerifyData(data, sig, HashAlgorithmName.SHA256,
    RSASignaturePadding.Pkcs1, CryptoMode.Hybrid);
 
// Aufräumen (überschreibt Private Key mit Nullen)
SignatureExtensions.ClearTransientPqKey();

Methoden-Übersicht

RSA Extensions

Methode Parameter Rückgabe
SignData(data, hash, padding, mode) byte[], HashAlgorithmName, RSASignaturePadding, CryptoMode? byte[]
SignData(stream, hash, padding, mode) Stream, HashAlgorithmName, RSASignaturePadding, CryptoMode? byte[]
VerifyData(data, sig, hash, padding, mode) byte[], byte[], HashAlgorithmName, RSASignaturePadding, CryptoMode? bool

ECDsa Extensions

Methode Parameter Rückgabe
SignData(data, hash, mode) byte[], HashAlgorithmName, CryptoMode? byte[]
SignData(stream, hash, mode) Stream, HashAlgorithmName, CryptoMode? byte[]
VerifyData(data, sig, hash, mode) byte[], byte[], HashAlgorithmName, CryptoMode? bool

X509Certificate2 Extensions

Methode Parameter Rückgabe
SignData(data, hash, mode) byte[], HashAlgorithmName, CryptoMode? byte[]
VerifyData(data, sig, hash, mode) byte[], byte[], HashAlgorithmName, CryptoMode? bool

Standalone ML-DSA

Methode Parameter Rückgabe
GenerateMlDsaKeyPair() - (byte[] PublicKey, byte[] PrivateKey)
SignMlDsa(data, privateKey) byte[], byte[] byte[]
VerifyMlDsa(data, sig, publicKey) byte[], byte[], byte[] bool

Transiente Key-Verwaltung

Methode Beschreibung
SetTransientPqKey(pub, priv) Setzt Key-Paar für Thread
SetTransientPqPublicKey(pub) Setzt nur Public Key
ClearTransientPqKey() Löscht Keys sicher

Beispiel: Vollständiger Workflow

// 1. CryptoMode konfigurieren
CryptoConfig.DefaultMode = CryptoMode.Hybrid;
 
// 2. Zertifikat laden (mit PQ-Keys)
var cert = X509Certificate2ExportExtensions.ImportPfx(
    "signing-cert.pfx",
    "password");
 
// 3. Dokument signieren
byte[] documentData = File.ReadAllBytes("contract.pdf");
byte[] signature = cert.SignData(documentData, HashAlgorithmName.SHA256);
 
// 4. Signatur speichern
File.WriteAllBytes("contract.sig", signature);
 
// 5. Später verifizieren
var verifyCert = new X509Certificate2("signing-cert.cer");
bool isValid = verifyCert.VerifyData(
    File.ReadAllBytes("contract.pdf"),
    File.ReadAllBytes("contract.sig"),
    HashAlgorithmName.SHA256);
 
Console.WriteLine($"Signatur gültig: {isValid}");

Sicherheitshinweise

  • Im PostQuantum-Modus wird keine klassische Signatur erstellt - nicht rückwärtskompatibel
  • Transiente Keys werden thread-lokal gespeichert - nicht zwischen Threads teilen
  • ClearTransientPqKey() aufrufen, wenn Keys nicht mehr benötigt werden

Siehe auch


Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional