Inhaltsverzeichnis
KeyDerivationExtensions
Namespace: WvdS.System.Security.Cryptography.KeyDerivation
Statische Klasse für Schlüsselableitung (Key Derivation Functions) mit Post-Quantum Support. Unterstützt HKDF, PBKDF2 und Argon2id.
Übersicht
Unterstützte KDF-Algorithmen:
| KDF | Standard | Verwendung |
|---|---|---|
| HKDF | RFC 5869 | Session-Keys aus Shared Secrets |
| PBKDF2 | RFC 8018 | Passwort-basierte Schlüssel |
| Argon2id | RFC 9106 | Memory-hard KDF (Passwörter) |
HKDF - Hash-based Key Derivation
DeriveKey
Leitet Schlüssel aus einem Shared Secret ab (HKDF-Extract-then-Expand).
// ML-KEM Shared Secret aus Key Exchange byte[] sharedSecret = session.SharedSecret; // Standard-Ableitung (SHA-256) byte[] aesKey = KeyDerivationExtensions.DeriveKey( sharedSecret, outputLength: 32); // 256 Bit // Mit Salt und Context-Info byte[] salt = RandomNumberGenerator.GetBytes(32); byte[] info = Encoding.UTF8.GetBytes("MyApp-Session-Key"); byte[] sessionKey = KeyDerivationExtensions.DeriveKey( sharedSecret, outputLength: 32, salt: salt, info: info, hashAlgorithm: HashAlgorithmName.SHA384); // Optional
HkdfExtract
Extrahiert PRK (Pseudorandom Key) aus Input Key Material.
byte[] inputKeyMaterial = GetSharedSecret(); byte[] salt = RandomNumberGenerator.GetBytes(32); byte[] prk = KeyDerivationExtensions.HkdfExtract( inputKeyMaterial, salt: salt, hashAlgorithm: HashAlgorithmName.SHA256); // PRK hat gleiche Länge wie Hash-Output (32 Bytes bei SHA-256)
HkdfExpand
Expandiert PRK zu Output Key Material.
byte[] prk = GetPrk(); // Encryption Key byte[] encKey = KeyDerivationExtensions.HkdfExpand( prk, outputLength: 32, info: Encoding.UTF8.GetBytes("encryption")); // MAC Key byte[] macKey = KeyDerivationExtensions.HkdfExpand( prk, outputLength: 32, info: Encoding.UTF8.GetBytes("mac"));
Hybrid Key Derivation
Kombiniert klassische (ECDH/DH) und PQ (ML-KEM) Shared Secrets.
DeriveHybridKey
byte[] ecdhSecret = GetEcdhSharedSecret(); byte[] mlKemSecret = GetMlKemSharedSecret(); // Hybrid-Modus: Beide Secrets werden kombiniert byte[] hybridKey = KeyDerivationExtensions.DeriveHybridKey( classicSecret: ecdhSecret, pqSecret: mlKemSecret, outputLength: 32, mode: CryptoMode.Hybrid); // Nur klassisch byte[] classicKey = KeyDerivationExtensions.DeriveHybridKey( classicSecret: ecdhSecret, pqSecret: null, outputLength: 32, mode: CryptoMode.Classic); // Nur Post-Quantum byte[] pqKey = KeyDerivationExtensions.DeriveHybridKey( classicSecret: null, pqSecret: mlKemSecret, outputLength: 32, mode: CryptoMode.PostQuantum); // Custom Info byte[] customKey = KeyDerivationExtensions.DeriveHybridKey( classicSecret: ecdhSecret, pqSecret: mlKemSecret, outputLength: 64, mode: CryptoMode.Hybrid, info: Encoding.UTF8.GetBytes("MyProtocol-v1"));
Schlüssel-Kombination:
Hybrid Mode: IKM = classicSecret || pqSecret Key = HKDF-SHA256(IKM, info="WvdS-Hybrid-Key")
DeriveHybridKeyMaterial
Leitet mehrere Schlüssel für verschiedene Zwecke ab.
using HybridKeyMaterial keyMaterial = KeyDerivationExtensions.DeriveHybridKeyMaterial( classicSecret: ecdhSecret, pqSecret: mlKemSecret, mode: CryptoMode.Hybrid); // Verwendung byte[] encKey = keyMaterial.EncryptionKey; // 32 Bytes byte[] macKey = keyMaterial.MacKey; // 32 Bytes byte[] iv = keyMaterial.Iv; // 16 Bytes byte[] authKey = keyMaterial.AuthKey; // 32 Bytes // IDisposable: Schlüssel werden sicher gelöscht
PBKDF2 - Passwort-basierte Ableitung
Pbkdf2
string password = "SecurePassword123!"; byte[] salt = RandomNumberGenerator.GetBytes(32); // Standard PBKDF2 byte[] key = KeyDerivationExtensions.Pbkdf2( password, salt, iterations: 100000, outputLength: 32); // Mit PQ-Entropy (zusätzlicher Schutz) byte[] pqEntropy = GetPqEntropy(); byte[] enhancedKey = KeyDerivationExtensions.Pbkdf2( password, salt, iterations: 100000, outputLength: 32, pqEntropy: pqEntropy, // Wird mit Salt kombiniert hashAlgorithm: HashAlgorithmName.SHA512);
Pbkdf2WithPqSalt
PBKDF2 mit PQ-verstärktem Salt (Public Key wird in Salt-Berechnung einbezogen).
string password = "UserPassword"; byte[] baseSalt = RandomNumberGenerator.GetBytes(16); byte[] mlKemPublicKey = GetRecipientPublicKey(); // Salt = SHA256(baseSalt || pqPublicKey) byte[] key = KeyDerivationExtensions.Pbkdf2WithPqSalt( password, baseSalt, mlKemPublicKey, iterations: 100000, outputLength: 32);
Argon2id - Memory-Hard KDF
Argon2id via OpenSSL 3.6 - widerstandsfähig gegen GPU/ASIC-Angriffe.
Argon2id (Byte-Array)
byte[] password = Encoding.UTF8.GetBytes("SecurePassword"); byte[] salt = RandomNumberGenerator.GetBytes(16); // Mindestens 16 Bytes byte[] key = KeyDerivationExtensions.Argon2id( password, salt, outputLength: 32, // Key-Länge iterations: 3, // Zeit-Kosten (t) memoryKiB: 65536, // Speicher: 64 MB parallelism: 4); // Threads (p)
Argon2id (String)
string password = "UserPassword123"; byte[] salt = RandomNumberGenerator.GetBytes(16); byte[] key = KeyDerivationExtensions.Argon2id( password, salt, outputLength: 32, iterations: 3, memoryKiB: 65536, parallelism: 4);
Empfohlene Parameter:
| Anwendung | Iterations (t) | Memory (m) | Parallelism (p) |
|---|---|---|---|
| Passwort-Hashing | 3 | 64 MB | 4 |
| Hohe Sicherheit | 4 | 256 MB | 4 |
| Low-Memory | 4 | 16 MB | 4 |
TLS Key Derivation
DeriveTlsKeys (TLS 1.2 Style)
byte[] preMasterSecret = GetPreMasterSecret(); byte[] clientRandom = GetClientRandom(); byte[] serverRandom = GetServerRandom(); using TlsKeyMaterial keys = KeyDerivationExtensions.DeriveTlsKeys( preMasterSecret, clientRandom, serverRandom, mode: CryptoMode.Hybrid); // Verwendung var clientKey = keys.ClientWriteKey; // 32 Bytes var serverKey = keys.ServerWriteKey; // 32 Bytes var clientIv = keys.ClientWriteIv; // 12 Bytes var serverIv = keys.ServerWriteIv; // 12 Bytes
DeriveTls13Keys
TLS 1.3 kompatible Key Schedule.
byte[]? pskSecret = null; // Pre-Shared Key (optional) byte[] ecdhSecret = GetEcdhSecret(); byte[] pqSecret = GetMlKemSecret(); byte[] clientHello = GetClientHelloBytes(); byte[] serverHello = GetServerHelloBytes(); using Tls13KeySchedule schedule = KeyDerivationExtensions.DeriveTls13Keys( pskSecret, ecdhSecret, pqSecret, clientHello, serverHello, mode: CryptoMode.Hybrid); // Handshake Traffic Secrets var clientHsSecret = schedule.ClientHandshakeTrafficSecret; var serverHsSecret = schedule.ServerHandshakeTrafficSecret; // Application Traffic Secrets var clientAppSecret = schedule.ClientApplicationTrafficSecret; var serverAppSecret = schedule.ServerApplicationTrafficSecret; // Resumption Secret var resumptionSecret = schedule.ResumptionMasterSecret;
Datenklassen
HybridKeyMaterial
Container für abgeleitete Schlüssel mit sicherer Speicherbereinigung.
| Eigenschaft | Typ | Länge | Beschreibung |
|---|---|---|---|
EncryptionKey | byte[] | 32 | AES-Schlüssel |
MacKey | byte[] | 32 | HMAC-Schlüssel |
Iv | byte[] | 16 | Initialisierungsvektor |
AuthKey | byte[] | 32 | Authentifizierungsschlüssel |
using HybridKeyMaterial keys = DeriveKeys(); // Keys werden bei Dispose() sicher gelöscht // (CryptographicOperations.ZeroMemory)
TlsKeyMaterial
TLS 1.2 Style Schlüsselmaterial.
| Eigenschaft | Typ | Beschreibung |
|---|---|---|
MasterSecret | byte[] | 48 Bytes Master Secret |
ClientWriteKey | byte[] | Client-seitiger Verschlüsselungsschlüssel |
ServerWriteKey | byte[] | Server-seitiger Verschlüsselungsschlüssel |
ClientWriteIv | byte[] | Client-seitiger IV |
ServerWriteIv | byte[] | Server-seitiger IV |
ClientWriteMacKey | byte[] | Client MAC Key (leer bei GCM) |
ServerWriteMacKey | byte[] | Server MAC Key (leer bei GCM) |
Tls13KeySchedule
TLS 1.3 Key Schedule.
| Eigenschaft | Typ | Beschreibung |
|---|---|---|
ClientHandshakeTrafficSecret | byte[]? | Client Handshake Traffic Secret |
ServerHandshakeTrafficSecret | byte[]? | Server Handshake Traffic Secret |
ClientApplicationTrafficSecret | byte[]? | Client Application Traffic Secret |
ServerApplicationTrafficSecret | byte[]? | Server Application Traffic Secret |
ResumptionMasterSecret | byte[]? | Session Resumption Secret |
Methoden-Übersicht
HKDF
| Methode | Parameter | Rückgabe |
|---|---|---|
DeriveKey | byte[] sharedSecret, int outputLength, byte[]? salt, byte[]? info, HashAlgorithmName? | byte[] |
HkdfExtract | byte[] ikm, byte[]? salt, HashAlgorithmName? | byte[] |
HkdfExpand | byte[] prk, int outputLength, byte[]? info, HashAlgorithmName? | byte[] |
Hybrid
| Methode | Parameter | Rückgabe |
|---|---|---|
DeriveHybridKey | byte[]? classicSecret, byte[]? pqSecret, int outputLength, CryptoMode, byte[]? info | byte[] |
DeriveHybridKeyMaterial | byte[]? classicSecret, byte[]? pqSecret, CryptoMode | HybridKeyMaterial |
PBKDF2
| Methode | Parameter | Rückgabe |
|---|---|---|
Pbkdf2 | string password, byte[] salt, int iterations, int outputLength, byte[]? pqEntropy, HashAlgorithmName? | byte[] |
Pbkdf2WithPqSalt | string password, byte[] baseSalt, byte[] pqPublicKey, int iterations, int outputLength | byte[] |
Argon2id
| Methode | Parameter | Rückgabe |
|---|---|---|
Argon2id | byte[] password, byte[] salt, int outputLength, int iterations, int memoryKiB, int parallelism | byte[] |
Argon2id | string password, byte[] salt, int outputLength, int iterations, int memoryKiB, int parallelism | byte[] |
TLS
| Methode | Parameter | Rückgabe |
|---|---|---|
DeriveTlsKeys | byte[] preMasterSecret, byte[] clientRandom, byte[] serverRandom, CryptoMode | TlsKeyMaterial |
DeriveTls13Keys | byte[]? psk, byte[]? ecdh, byte[]? pq, byte[] clientHello, byte[] serverHello, CryptoMode | Tls13KeySchedule |
Vollständiges Beispiel
using WvdS.System.Security.Cryptography; using WvdS.System.Security.Cryptography.KeyDerivation; using WvdS.System.Security.Cryptography.KeyExchange; // 1. Key Exchange durchführen using var session = new KeyExchangeService(); await session.InitiateKeyExchangeAsync(recipientPublicKey, CryptoMode.Hybrid); // 2. Hybrid Key Material ableiten using HybridKeyMaterial keys = KeyDerivationExtensions.DeriveHybridKeyMaterial( classicSecret: session.ClassicSharedSecret, pqSecret: session.PqSharedSecret, mode: CryptoMode.Hybrid); // 3. Schlüssel verwenden using var aes = Aes.Create(); aes.Key = keys.EncryptionKey; using var hmac = new HMACSHA256(keys.MacKey); // 4. Verschlüsselung durchführen // ... // 5. Schlüssel werden automatisch sicher gelöscht
Sicherheitshinweise
- Alle
IDisposableKlassen implementierenCryptographicOperations.ZeroMemory - Argon2id benötigt OpenSSL 3.6 (nicht in .NET BCL verfügbar)
- PBKDF2 mit weniger als 100.000 Iterationen wird nicht empfohlen
- Salt muss bei PBKDF2/Argon2id immer zufällig und ausreichend lang sein (min. 16 Bytes)
Im Hybrid-Modus wird der endgültige Schlüssel nur kompromittiert, wenn BEIDE Secrets (klassisch UND PQ) gebrochen werden. Dies bietet Schutz sowohl gegen klassische als auch gegen Quantenangriffe.
Siehe auch
Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional