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.
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 |
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);
byte[] decrypted = SymmetricEncryptionExtensions.DecryptWithPqKey( encrypted, sharedSecret, associatedData: aad); // Falls bei Encrypt verwendet string message = Encoding.UTF8.GetString(decrypted);
Kombiniert RSA-OAEP Key Encapsulation mit ML-KEM für quantum-sichere hybride Verschlüsselung.
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();
// Deserialisieren HybridEncryptedData encrypted = HybridEncryptedData.FromBytes(serialized); // Entschlüsseln byte[] plaintext = SymmetricEncryptionExtensions.DecryptHybrid( encrypted, rsaPrivateKey, // RSA Private Key mlKemPrivateKey); // ML-KEM Private Key
ECIES-Style Verschlüsselung mit ephemerarem ECDH und ML-KEM.
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
byte[] plaintext = SymmetricEncryptionExtensions.DecryptEcdhPq( encrypted, recipientEcdhPrivateKey, mlKemPrivateKey);
Direkte AES-256-GCM Verschlüsselung ohne Key Encapsulation.
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 │ └─────────────────────────────────────────┘
byte[] plaintext = SymmetricEncryptionExtensions.DecryptAesGcm( encrypted, key, associatedData: aad); // Falls verwendet
Für große Dateien mit Chunk-basierter Verarbeitung.
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) │ └────────────────────────────────────────────┘
using var inputStream = File.OpenRead("large-file.enc"); using var outputStream = File.Create("large-file.decrypted"); SymmetricEncryptionExtensions.DecryptStream( inputStream, outputStream, key);
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“
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)
Container für hybrid-verschlüsselte Daten mit Serialisierung.
| 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 |
HybridEncryptedData encrypted = EncryptData(); // Zu Byte-Array byte[] serialized = encrypted.ToBytes(); // Von Byte-Array HybridEncryptedData restored = HybridEncryptedData.FromBytes(serialized);
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);
| 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[]) |
| 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[] |
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);
DeriveAesKey ohne Salt ist deterministisch - nur für spezifische AnwendungsfälleCombined 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).
Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional