====== KeyDerivationExtensions ======
**Namespace:** ''WvdS.System.Security.Cryptography.KeyDerivation''
Statični razred za izpeljavo ključev (Key Derivation Functions) s podporo za post-kvantno kriptografijo. Podpira HKDF, PBKDF2 in Argon2id.
===== Pregled =====
Podprti KDF-algoritmi:
^ KDF ^ Standard ^ Uporaba ^
| HKDF | RFC 5869 | Sejni ključi iz skupnih skrivnosti |
| PBKDF2 | RFC 8018 | Ključi iz gesel |
| Argon2id | RFC 9106 | Memory-hard KDF (gesla) |
===== HKDF - Izpeljava ključev na osnovi zgostitve =====
==== DeriveKey ====
Izpelje ključe iz skupne skrivnosti (HKDF-Extract-then-Expand).
// ML-KEM skupna skrivnost iz izmenjave ključev
byte[] sharedSecret = session.SharedSecret;
// Standardna izpeljava (SHA-256)
byte[] aesKey = KeyDerivationExtensions.DeriveKey(
sharedSecret,
outputLength: 32); // 256 bitov
// S soljo in kontekstnimi informacijami
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); // Opcijsko
==== HkdfExtract ====
Ekstrahira PRK (Pseudorandom Key) iz vhodnega materiala ključa.
byte[] inputKeyMaterial = GetSharedSecret();
byte[] salt = RandomNumberGenerator.GetBytes(32);
byte[] prk = KeyDerivationExtensions.HkdfExtract(
inputKeyMaterial,
salt: salt,
hashAlgorithm: HashAlgorithmName.SHA256);
// PRK ima enako dolžino kot izhod zgoščevalne funkcije (32 bajtov pri SHA-256)
==== HkdfExpand ====
Razširi PRK v izhodni material ključa.
byte[] prk = GetPrk();
// Šifrirni ključ
byte[] encKey = KeyDerivationExtensions.HkdfExpand(
prk,
outputLength: 32,
info: Encoding.UTF8.GetBytes("encryption"));
// MAC ključ
byte[] macKey = KeyDerivationExtensions.HkdfExpand(
prk,
outputLength: 32,
info: Encoding.UTF8.GetBytes("mac"));
===== Hibridna izpeljava ključev =====
Kombinira klasične (ECDH/DH) in PQ (ML-KEM) skupne skrivnosti.
==== DeriveHybridKey ====
byte[] ecdhSecret = GetEcdhSharedSecret();
byte[] mlKemSecret = GetMlKemSharedSecret();
// Hibridni način: Obe skrivnosti sta kombinirani
byte[] hybridKey = KeyDerivationExtensions.DeriveHybridKey(
classicSecret: ecdhSecret,
pqSecret: mlKemSecret,
outputLength: 32,
mode: CryptoMode.Hybrid);
// Samo klasično
byte[] classicKey = KeyDerivationExtensions.DeriveHybridKey(
classicSecret: ecdhSecret,
pqSecret: null,
outputLength: 32,
mode: CryptoMode.Classic);
// Samo post-kvantno
byte[] pqKey = KeyDerivationExtensions.DeriveHybridKey(
classicSecret: null,
pqSecret: mlKemSecret,
outputLength: 32,
mode: CryptoMode.PostQuantum);
// Lastne informacije
byte[] customKey = KeyDerivationExtensions.DeriveHybridKey(
classicSecret: ecdhSecret,
pqSecret: mlKemSecret,
outputLength: 64,
mode: CryptoMode.Hybrid,
info: Encoding.UTF8.GetBytes("MyProtocol-v1"));
**Kombinacija ključev:**
Hybrid Mode:
IKM = classicSecret || pqSecret
Key = HKDF-SHA256(IKM, info="WvdS-Hybrid-Key")
==== DeriveHybridKeyMaterial ====
Izpelje več ključev za različne namene.
using HybridKeyMaterial keyMaterial = KeyDerivationExtensions.DeriveHybridKeyMaterial(
classicSecret: ecdhSecret,
pqSecret: mlKemSecret,
mode: CryptoMode.Hybrid);
// Uporaba
byte[] encKey = keyMaterial.EncryptionKey; // 32 bajtov
byte[] macKey = keyMaterial.MacKey; // 32 bajtov
byte[] iv = keyMaterial.Iv; // 16 bajtov
byte[] authKey = keyMaterial.AuthKey; // 32 bajtov
// IDisposable: Ključi so varno izbrisani
===== PBKDF2 - Izpeljava ključev iz gesel =====
==== Pbkdf2 ====
string password = "SecurePassword123!";
byte[] salt = RandomNumberGenerator.GetBytes(32);
// Standardni PBKDF2
byte[] key = KeyDerivationExtensions.Pbkdf2(
password,
salt,
iterations: 100000,
outputLength: 32);
// S PQ-entropijo (dodatna zaščita)
byte[] pqEntropy = GetPqEntropy();
byte[] enhancedKey = KeyDerivationExtensions.Pbkdf2(
password,
salt,
iterations: 100000,
outputLength: 32,
pqEntropy: pqEntropy, // Kombinirana s soljo
hashAlgorithm: HashAlgorithmName.SHA512);
==== Pbkdf2WithPqSalt ====
PBKDF2 s PQ-okrepljeno soljo (javni ključ je vključen v izračun soli).
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);
**Prednost:** Tudi pri enakem geslu in osnovni soli se za vsakega prejemnika (različen PQ javni ključ) izpelje drugačen ključ.
===== Argon2id - Memory-Hard KDF =====
Argon2id preko OpenSSL 3.6 - odporen proti GPU/ASIC napadom.
==== Argon2id (polje bajtov) ====
byte[] password = Encoding.UTF8.GetBytes("SecurePassword");
byte[] salt = RandomNumberGenerator.GetBytes(16); // Najmanj 16 bajtov
byte[] key = KeyDerivationExtensions.Argon2id(
password,
salt,
outputLength: 32, // Dolžina ključa
iterations: 3, // Časovni stroški (t)
memoryKiB: 65536, // Pomnilnik: 64 MB
parallelism: 4); // Niti (p)
==== Argon2id (niz) ====
string password = "UserPassword123";
byte[] salt = RandomNumberGenerator.GetBytes(16);
byte[] key = KeyDerivationExtensions.Argon2id(
password,
salt,
outputLength: 32,
iterations: 3,
memoryKiB: 65536,
parallelism: 4);
**Priporočeni parametri:**
^ Aplikacija ^ Iteracije (t) ^ Pomnilnik (m) ^ Paralelizem (p) ^
| Zgoščevanje gesel | 3 | 64 MB | 4 |
| Visoka varnost | 4 | 256 MB | 4 |
| Nizek pomnilnik | 4 | 16 MB | 4 |
===== TLS izpeljava ključev =====
==== DeriveTlsKeys (TLS 1.2 stil) ====
byte[] preMasterSecret = GetPreMasterSecret();
byte[] clientRandom = GetClientRandom();
byte[] serverRandom = GetServerRandom();
using TlsKeyMaterial keys = KeyDerivationExtensions.DeriveTlsKeys(
preMasterSecret,
clientRandom,
serverRandom,
mode: CryptoMode.Hybrid);
// Uporaba
var clientKey = keys.ClientWriteKey; // 32 bajtov
var serverKey = keys.ServerWriteKey; // 32 bajtov
var clientIv = keys.ClientWriteIv; // 12 bajtov
var serverIv = keys.ServerWriteIv; // 12 bajtov
==== DeriveTls13Keys ====
TLS 1.3 kompatibilen razpored ključev.
byte[]? pskSecret = null; // Pre-Shared Key (opcijsko)
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;
===== Podatkovni razredi =====
==== HybridKeyMaterial ====
Vsebnik za izpeljane ključe z varnim čiščenjem pomnilnika.
^ Lastnost ^ Tip ^ Dolžina ^ Opis ^
| ''EncryptionKey'' | byte[] | 32 | AES-ključ |
| ''MacKey'' | byte[] | 32 | HMAC-ključ |
| ''Iv'' | byte[] | 16 | Inicializacijski vektor |
| ''AuthKey'' | byte[] | 32 | Overitveni ključ |
using HybridKeyMaterial keys = DeriveKeys();
// Ključi so pri Dispose() varno izbrisani
// (CryptographicOperations.ZeroMemory)
==== TlsKeyMaterial ====
TLS 1.2 stil materiala ključev.
^ Lastnost ^ Tip ^ Opis ^
| ''MasterSecret'' | byte[] | 48 bajtov Master Secret |
| ''ClientWriteKey'' | byte[] | Šifrirni ključ na strani odjemalca |
| ''ServerWriteKey'' | byte[] | Šifrirni ključ na strani strežnika |
| ''ClientWriteIv'' | byte[] | IV na strani odjemalca |
| ''ServerWriteIv'' | byte[] | IV na strani strežnika |
| ''ClientWriteMacKey'' | byte[] | MAC ključ odjemalca (prazen pri GCM) |
| ''ServerWriteMacKey'' | byte[] | MAC ključ strežnika (prazen pri GCM) |
==== Tls13KeySchedule ====
TLS 1.3 razpored ključev.
^ Lastnost ^ Tip ^ Opis ^
| ''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 |
===== Pregled metod =====
==== HKDF ====
^ Metoda ^ Parametri ^ Vrnjeno ^
| ''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[] |
==== Hibridno ====
^ Metoda ^ Parametri ^ Vrnjeno ^
| ''DeriveHybridKey'' | byte[]? classicSecret, byte[]? pqSecret, int outputLength, CryptoMode, byte[]? info | byte[] |
| ''DeriveHybridKeyMaterial'' | byte[]? classicSecret, byte[]? pqSecret, CryptoMode | HybridKeyMaterial |
==== PBKDF2 ====
^ Metoda ^ Parametri ^ Vrnjeno ^
| ''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 ====
^ Metoda ^ Parametri ^ Vrnjeno ^
| ''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 ====
^ Metoda ^ Parametri ^ Vrnjeno ^
| ''DeriveTlsKeys'' | byte[] preMasterSecret, byte[] clientRandom, byte[] serverRandom, CryptoMode | TlsKeyMaterial |
| ''DeriveTls13Keys'' | byte[]? psk, byte[]? ecdh, byte[]? pq, byte[] clientHello, byte[] serverHello, CryptoMode | Tls13KeySchedule |
===== Popoln primer =====
using WvdS.System.Security.Cryptography;
using WvdS.System.Security.Cryptography.KeyDerivation;
using WvdS.System.Security.Cryptography.KeyExchange;
// 1. Izvedba izmenjave ključev
using var session = new KeyExchangeService();
await session.InitiateKeyExchangeAsync(recipientPublicKey, CryptoMode.Hybrid);
// 2. Izpeljava hibridnega materiala ključev
using HybridKeyMaterial keys = KeyDerivationExtensions.DeriveHybridKeyMaterial(
classicSecret: session.ClassicSharedSecret,
pqSecret: session.PqSharedSecret,
mode: CryptoMode.Hybrid);
// 3. Uporaba ključev
using var aes = Aes.Create();
aes.Key = keys.EncryptionKey;
using var hmac = new HMACSHA256(keys.MacKey);
// 4. Izvedba šifriranja
// ...
// 5. Ključi so samodejno varno izbrisani
===== Varnostni nasveti =====
* Vsi ''IDisposable'' razredi implementirajo ''CryptographicOperations.ZeroMemory''
* Argon2id potrebuje OpenSSL 3.6 (ni na voljo v .NET BCL)
* PBKDF2 z manj kot 100.000 iteracijami ni priporočljiv
* Sol mora biti pri PBKDF2/Argon2id vedno naključna in dovolj dolga (min. 16 bajtov)
**Varnost hibridnega načina:**
V hibridnem načinu je končni ključ kompromitiran le, če sta ZLOMLJENI OBE skrivnosti (klasična IN PQ). To zagotavlja zaščito tako pred klasičnimi kot pred kvantnimi napadi.
===== Glej tudi =====
* [[.:start|KeyDerivation Namespace]]
* [[.:hybridkeymaterial|HybridKeyMaterial]]
* [[.:tlskeymaterial|TlsKeyMaterial]]
* [[.:tls13keyschedule|Tls13KeySchedule]]
* [[..:keyexchange:start|KeyExchange Namespace]]
* [[..:encryption:start|Encryption Namespace]]
* [[sl:int:pqcrypt:konzepte:algorithmen:ml-kem|Algoritem ML-KEM]]
----
//Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//