Inhaltsverzeichnis

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


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