SymmetricEncryptionExtensions

Namespace: WvdS.System.Security.Cryptography.Encryption

Statische Klasse für AES-GCM Verschlüsselung mit Post-Quantum Key-Support. Unterstützt klassische, hybride und reine PQ-Verschlüsselung.

Übersicht

Diese Klasse bietet drei Verschlüsselungsansätze:

Modus Klassisch ML-KEM Verwendung
Classic RSA-OAEP / ECDH - Standard .NET Verhalten
Hybrid RSA-OAEP / ECDH Maximale Sicherheit
PostQuantum - Rein post-quantum

AES-GCM mit PQ-Key

EncryptWithPqKey

Verschlüsselt Daten mit AES-GCM unter Verwendung eines ML-KEM Shared Secrets.

// Shared Secret aus ML-KEM Key Exchange
byte[] sharedSecret = session.SharedSecret;
 
// Verschlüsseln
byte[] plaintext = Encoding.UTF8.GetBytes("Geheime Nachricht");
byte[] encrypted = SymmetricEncryptionExtensions.EncryptWithPqKey(
    plaintext,
    sharedSecret);
 
// Mit Additional Authenticated Data (AAD)
byte[] aad = Encoding.UTF8.GetBytes("Kontext-Info");
byte[] encryptedWithAad = SymmetricEncryptionExtensions.EncryptWithPqKey(
    plaintext,
    sharedSecret,
    associatedData: aad);

DecryptWithPqKey

byte[] decrypted = SymmetricEncryptionExtensions.DecryptWithPqKey(
    encrypted,
    sharedSecret,
    associatedData: aad);  // Falls bei Encrypt verwendet
 
string message = Encoding.UTF8.GetString(decrypted);

Hybrid Encryption (RSA + ML-KEM)

Kombiniert RSA-OAEP Key Encapsulation mit ML-KEM für quantum-sichere hybride Verschlüsselung.

EncryptHybrid

using var rsa = RSA.Create(4096);
var (mlKemPublicKey, mlKemPrivateKey) = PqCrypto.GenerateKeyPair();
 
byte[] plaintext = GetSecretData();
 
// Hybrid-Verschlüsselung (RSA + ML-KEM)
HybridEncryptedData encrypted = SymmetricEncryptionExtensions.EncryptHybrid(
    plaintext,
    rsa,  // RSA Public Key des Empfängers
    mlKemPublicKey,  // ML-KEM Public Key des Empfängers
    CryptoMode.Hybrid);
 
// Serialisieren für Transport
byte[] serialized = encrypted.ToBytes();

DecryptHybrid

// Deserialisieren
HybridEncryptedData encrypted = HybridEncryptedData.FromBytes(serialized);
 
// Entschlüsseln
byte[] plaintext = SymmetricEncryptionExtensions.DecryptHybrid(
    encrypted,
    rsaPrivateKey,  // RSA Private Key
    mlKemPrivateKey);  // ML-KEM Private Key

ECDH + ML-KEM Encryption

ECIES-Style Verschlüsselung mit ephemerarem ECDH und ML-KEM.

EncryptEcdhPq

using var recipientEcdh = ECDiffieHellman.Create(ECCurve.NamedCurves.nistP384);
var (mlKemPublicKey, mlKemPrivateKey) = PqCrypto.GenerateKeyPair();
 
byte[] plaintext = GetSecretData();
 
// ECDH + ML-KEM Hybrid-Verschlüsselung
HybridEncryptedData encrypted = SymmetricEncryptionExtensions.EncryptEcdhPq(
    plaintext,
    recipientEcdh,  // ECDH Public Key des Empfängers
    mlKemPublicKey,  // ML-KEM Public Key
    CryptoMode.Hybrid);
 
// Ephemerer ECDH Public Key ist in encrypted.EphemeralPublicKey enthalten

DecryptEcdhPq

byte[] plaintext = SymmetricEncryptionExtensions.DecryptEcdhPq(
    encrypted,
    recipientEcdhPrivateKey,
    mlKemPrivateKey);

Core AES-GCM Operations

Direkte AES-256-GCM Verschlüsselung ohne Key Encapsulation.

EncryptAesGcm

byte[] key = RandomNumberGenerator.GetBytes(32);  // 256-bit Key
byte[] plaintext = GetData();
 
// Standard AES-GCM
byte[] encrypted = SymmetricEncryptionExtensions.EncryptAesGcm(
    plaintext,
    key);
 
// Mit AAD
byte[] aad = Encoding.UTF8.GetBytes("message-context");
byte[] encryptedWithAad = SymmetricEncryptionExtensions.EncryptAesGcm(
    plaintext,
    key,
    associatedData: aad);

Ausgabeformat:

┌─────────────────────────────────────────┐
│ [12 Bytes] Nonce (zufällig generiert)   │
│ [n Bytes]  Ciphertext                   │
│ [16 Bytes] GCM Authentication Tag       │
└─────────────────────────────────────────┘

DecryptAesGcm

byte[] plaintext = SymmetricEncryptionExtensions.DecryptAesGcm(
    encrypted,
    key,
    associatedData: aad);  // Falls verwendet

Stream-basierte Verschlüsselung

Für große Dateien mit Chunk-basierter Verarbeitung.

EncryptStream

byte[] key = RandomNumberGenerator.GetBytes(32);
 
using var inputStream = File.OpenRead("large-file.dat");
using var outputStream = File.Create("large-file.enc");
 
SymmetricEncryptionExtensions.EncryptStream(
    inputStream,
    outputStream,
    key,
    chunkSize: 64 * 1024);  // 64 KB Chunks (Standard)

Chunk-Format:

┌────────────────────────────────────────────┐
│ [12 Bytes] Base Nonce                       │
├────────────────────────────────────────────┤
│ Chunk 0:                                    │
│   [4 Bytes] Chunk-Länge                     │
│   [n Bytes] Verschlüsselte Daten            │
│   [16 Bytes] GCM Tag                        │
├────────────────────────────────────────────┤
│ Chunk 1: (Nonce = Base + 1)                 │
│   [4 Bytes] Chunk-Länge                     │
│   [n Bytes] Verschlüsselte Daten            │
│   [16 Bytes] GCM Tag                        │
├────────────────────────────────────────────┤
│ ... weitere Chunks ...                      │
├────────────────────────────────────────────┤
│ [4 Bytes] End-Marker (0x00000000)           │
└────────────────────────────────────────────┘

DecryptStream

using var inputStream = File.OpenRead("large-file.enc");
using var outputStream = File.Create("large-file.decrypted");
 
SymmetricEncryptionExtensions.DecryptStream(
    inputStream,
    outputStream,
    key);

Key Derivation

DeriveAesKey

Leitet einen AES-256 Key aus einem Shared Secret ab.

byte[] sharedSecret = GetMlKemSharedSecret();
 
// Standard-Ableitung
byte[] aesKey = SymmetricEncryptionExtensions.DeriveAesKey(sharedSecret);
 
// Mit Salt und Info
byte[] salt = RandomNumberGenerator.GetBytes(32);
byte[] info = Encoding.UTF8.GetBytes("MyApp-Encryption-Key");
 
byte[] aesKeyCustom = SymmetricEncryptionExtensions.DeriveAesKey(
    sharedSecret,
    salt: salt,
    info: info);

Interne Implementierung: HKDF-SHA256 mit info=„WvdS-PQ-AES-Key“

DeriveMultipleKeys

Leitet mehrere Schlüssel für verschiedene Zwecke ab.

byte[] sharedSecret = GetMlKemSharedSecret();
 
var (encryptionKey, macKey, iv) = SymmetricEncryptionExtensions.DeriveMultipleKeys(
    sharedSecret,
    salt: optionalSalt);
 
// encryptionKey: 32 Bytes (AES-256)
// macKey: 32 Bytes (HMAC)
// iv: 16 Bytes (Initialisierungsvektor)

HybridEncryptedData Klasse

Container für hybrid-verschlüsselte Daten mit Serialisierung.

Eigenschaften

Eigenschaft Typ Beschreibung
Mode CryptoMode Verwendeter Verschlüsselungsmodus
ClassicEncapsulatedKey byte[]? RSA-verschlüsselter Content Key
EphemeralPublicKey byte[]? Ephemerer ECDH Public Key
PqCiphertext byte[]? ML-KEM Ciphertext
EncryptedContent byte[] AES-GCM verschlüsselte Daten

Serialisierung

HybridEncryptedData encrypted = EncryptData();
 
// Zu Byte-Array
byte[] serialized = encrypted.ToBytes();
 
// Von Byte-Array
HybridEncryptedData restored = HybridEncryptedData.FromBytes(serialized);

PqCrypto Convenience-Klasse

Vereinfachte API für reine PQ-Verschlüsselung.

// Schlüsselpaar generieren
var (publicKey, privateKey) = PqCrypto.GenerateKeyPair();
 
// Verschlüsseln
byte[] plaintext = Encoding.UTF8.GetBytes("Geheime Nachricht");
var (ciphertext, encryptedData) = PqCrypto.Encrypt(plaintext, publicKey);
 
// Entschlüsseln
byte[] decrypted = PqCrypto.Decrypt(ciphertext, encryptedData, privateKey);

Methoden-Übersicht

SymmetricEncryptionExtensions

Methode Parameter Rückgabe
EncryptWithPqKey byte[] plaintext, byte[] sharedSecret, byte[]? aad byte[]
DecryptWithPqKey byte[] ciphertext, byte[] sharedSecret, byte[]? aad byte[]
EncryptHybrid byte[] plaintext, RSA pubKey, byte[] pqPubKey, CryptoMode? HybridEncryptedData
DecryptHybrid HybridEncryptedData, RSA privKey, byte[] pqPrivKey byte[]
EncryptEcdhPq byte[] plaintext, ECDiffieHellman pubKey, byte[] pqPubKey, CryptoMode? HybridEncryptedData
DecryptEcdhPq HybridEncryptedData, ECDiffieHellman privKey, byte[] pqPrivKey byte[]
EncryptAesGcm byte[] plaintext, byte[] key, byte[]? aad byte[]
DecryptAesGcm byte[] ciphertext, byte[] key, byte[]? aad byte[]
EncryptStream Stream input, Stream output, byte[] key, int chunkSize void
DecryptStream Stream input, Stream output, byte[] key void
DeriveAesKey byte[] sharedSecret, byte[]? salt, byte[]? info byte[]
DeriveMultipleKeys byte[] sharedSecret, byte[]? salt (byte[], byte[], byte[])

PqCrypto

Methode Parameter Rückgabe
GenerateKeyPair - (byte[] PublicKey, byte[] PrivateKey)
Encrypt byte[] plaintext, byte[] recipientPublicKey (byte[] Ciphertext, byte[] EncryptedData)
Decrypt byte[] ciphertext, byte[] encryptedData, byte[] privateKey byte[]

Vollständiges Beispiel

using WvdS.System.Security.Cryptography;
using WvdS.System.Security.Cryptography.Encryption;
 
// 1. Schlüssel generieren (Empfänger)
using var rsa = RSA.Create(4096);
var (mlKemPublicKey, mlKemPrivateKey) = PqCrypto.GenerateKeyPair();
 
// 2. Public Keys an Sender übermitteln
// (In Praxis: Zertifikat mit eingebetteten PQ-Keys)
 
// --- Sender ---
 
// 3. Nachricht verschlüsseln
byte[] message = File.ReadAllBytes("document.pdf");
 
HybridEncryptedData encrypted = SymmetricEncryptionExtensions.EncryptHybrid(
    message,
    rsa,  // Empfänger RSA Public Key
    mlKemPublicKey,  // Empfänger ML-KEM Public Key
    CryptoMode.Hybrid);
 
// 4. Serialisieren und senden
byte[] package = encrypted.ToBytes();
File.WriteAllBytes("document.encrypted", package);
 
// --- Empfänger ---
 
// 5. Empfangen und deserialisieren
byte[] receivedPackage = File.ReadAllBytes("document.encrypted");
HybridEncryptedData receivedData = HybridEncryptedData.FromBytes(receivedPackage);
 
// 6. Entschlüsseln
byte[] decrypted = SymmetricEncryptionExtensions.DecryptHybrid(
    receivedData,
    rsa,  // Eigener RSA Private Key
    mlKemPrivateKey);  // Eigener ML-KEM Private Key
 
File.WriteAllBytes("document.decrypted.pdf", decrypted);

Sicherheitshinweise

  • AES-GCM Nonces dürfen NIEMALS wiederverwendet werden
  • Bei Hybrid-Modus wird Key aus klassischem UND PQ-Secret abgeleitet
  • DeriveAesKey ohne Salt ist deterministisch - nur für spezifische Anwendungsfälle
  • Stream-Verschlüsselung verwendet inkrementelle Nonces pro Chunk
Key-Kombinierung im Hybrid-Modus:
Combined Key = HKDF-SHA256(
    ikm = classicSecret || pqSecret,
    info = "WvdS-Hybrid-Key"
)

Selbst wenn ein Angreifer das klassische Secret kompromittiert, bleibt die Verschlüsselung durch das PQ-Secret geschützt (und umgekehrt).

Siehe auch


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

Zuletzt geändert: den 29.01.2026 um 15:12