====== KeyDerivationExtensions ======
**Namespace:** ''WvdS.System.Security.Cryptography.KeyDerivation''
Classe statica per la derivazione delle chiavi (Key Derivation Functions) con supporto Post-Quantum. Supporta HKDF, PBKDF2 e Argon2id.
===== Panoramica =====
Algoritmi KDF supportati:
^ KDF ^ Standard ^ Utilizzo ^
| HKDF | RFC 5869 | Chiavi di sessione da Shared Secrets |
| PBKDF2 | RFC 8018 | Chiavi basate su password |
| Argon2id | RFC 9106 | KDF memory-hard (password) |
===== HKDF - Hash-based Key Derivation =====
==== DeriveKey ====
Deriva chiavi da un Shared Secret (HKDF-Extract-then-Expand).
// ML-KEM Shared Secret da Key Exchange
byte[] sharedSecret = session.SharedSecret;
// Derivazione standard (SHA-256)
byte[] aesKey = KeyDerivationExtensions.DeriveKey(
sharedSecret,
outputLength: 32); // 256 Bit
// Con Salt e 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); // Opzionale
==== HkdfExtract ====
Estrae PRK (Pseudorandom Key) da Input Key Material.
byte[] inputKeyMaterial = GetSharedSecret();
byte[] salt = RandomNumberGenerator.GetBytes(32);
byte[] prk = KeyDerivationExtensions.HkdfExtract(
inputKeyMaterial,
salt: salt,
hashAlgorithm: HashAlgorithmName.SHA256);
// PRK ha la stessa lunghezza dell'output Hash (32 Bytes per SHA-256)
==== HkdfExpand ====
Espande PRK a 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 =====
Combina Shared Secrets classici (ECDH/DH) e PQ (ML-KEM).
==== DeriveHybridKey ====
byte[] ecdhSecret = GetEcdhSharedSecret();
byte[] mlKemSecret = GetMlKemSharedSecret();
// Modalita ibrida: entrambi i secrets vengono combinati
byte[] hybridKey = KeyDerivationExtensions.DeriveHybridKey(
classicSecret: ecdhSecret,
pqSecret: mlKemSecret,
outputLength: 32,
mode: CryptoMode.Hybrid);
// Solo classico
byte[] classicKey = KeyDerivationExtensions.DeriveHybridKey(
classicSecret: ecdhSecret,
pqSecret: null,
outputLength: 32,
mode: CryptoMode.Classic);
// Solo 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"));
**Combinazione chiavi:**
Hybrid Mode:
IKM = classicSecret || pqSecret
Key = HKDF-SHA256(IKM, info="WvdS-Hybrid-Key")
==== DeriveHybridKeyMaterial ====
Deriva piu chiavi per scopi diversi.
using HybridKeyMaterial keyMaterial = KeyDerivationExtensions.DeriveHybridKeyMaterial(
classicSecret: ecdhSecret,
pqSecret: mlKemSecret,
mode: CryptoMode.Hybrid);
// Utilizzo
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: le chiavi vengono cancellate in modo sicuro
===== PBKDF2 - Derivazione basata su password =====
==== Pbkdf2 ====
string password = "SecurePassword123!";
byte[] salt = RandomNumberGenerator.GetBytes(32);
// PBKDF2 standard
byte[] key = KeyDerivationExtensions.Pbkdf2(
password,
salt,
iterations: 100000,
outputLength: 32);
// Con PQ-Entropy (protezione aggiuntiva)
byte[] pqEntropy = GetPqEntropy();
byte[] enhancedKey = KeyDerivationExtensions.Pbkdf2(
password,
salt,
iterations: 100000,
outputLength: 32,
pqEntropy: pqEntropy, // Viene combinato con Salt
hashAlgorithm: HashAlgorithmName.SHA512);
==== Pbkdf2WithPqSalt ====
PBKDF2 con Salt rinforzato PQ (la chiave pubblica viene inclusa nel calcolo del Salt).
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);
**Vantaggio:** Anche con password e Base-Salt identici, si ottiene una chiave diversa per ogni destinatario (chiave pubblica PQ diversa).
===== Argon2id - Memory-Hard KDF =====
Argon2id via OpenSSL 3.6 - resistente agli attacchi GPU/ASIC.
==== Argon2id (Byte-Array) ====
byte[] password = Encoding.UTF8.GetBytes("SecurePassword");
byte[] salt = RandomNumberGenerator.GetBytes(16); // Minimo 16 Bytes
byte[] key = KeyDerivationExtensions.Argon2id(
password,
salt,
outputLength: 32, // Lunghezza chiave
iterations: 3, // Costo temporale (t)
memoryKiB: 65536, // Memoria: 64 MB
parallelism: 4); // Thread (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);
**Parametri raccomandati:**
^ Applicazione ^ Iterations (t) ^ Memory (m) ^ Parallelism (p) ^
| Hashing password | 3 | 64 MB | 4 |
| Alta sicurezza | 4 | 256 MB | 4 |
| Low-Memory | 4 | 16 MB | 4 |
===== TLS Key Derivation =====
==== DeriveTlsKeys (stile TLS 1.2) ====
byte[] preMasterSecret = GetPreMasterSecret();
byte[] clientRandom = GetClientRandom();
byte[] serverRandom = GetServerRandom();
using TlsKeyMaterial keys = KeyDerivationExtensions.DeriveTlsKeys(
preMasterSecret,
clientRandom,
serverRandom,
mode: CryptoMode.Hybrid);
// Utilizzo
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 ====
Key Schedule compatibile TLS 1.3.
byte[]? pskSecret = null; // Pre-Shared Key (opzionale)
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;
===== Classi dati =====
==== HybridKeyMaterial ====
Contenitore per chiavi derivate con pulizia sicura della memoria.
^ Proprieta ^ Tipo ^ Lunghezza ^ Descrizione ^
| ''EncryptionKey'' | byte[] | 32 | Chiave AES |
| ''MacKey'' | byte[] | 32 | Chiave HMAC |
| ''Iv'' | byte[] | 16 | Vettore di inizializzazione |
| ''AuthKey'' | byte[] | 32 | Chiave di autenticazione |
using HybridKeyMaterial keys = DeriveKeys();
// Le chiavi vengono cancellate in modo sicuro con Dispose()
// (CryptographicOperations.ZeroMemory)
==== TlsKeyMaterial ====
Materiale chiavi stile TLS 1.2.
^ Proprieta ^ Tipo ^ Descrizione ^
| ''MasterSecret'' | byte[] | Master Secret 48 Bytes |
| ''ClientWriteKey'' | byte[] | Chiave di crittografia lato client |
| ''ServerWriteKey'' | byte[] | Chiave di crittografia lato server |
| ''ClientWriteIv'' | byte[] | IV lato client |
| ''ServerWriteIv'' | byte[] | IV lato server |
| ''ClientWriteMacKey'' | byte[] | MAC Key client (vuoto per GCM) |
| ''ServerWriteMacKey'' | byte[] | MAC Key server (vuoto per GCM) |
==== Tls13KeySchedule ====
TLS 1.3 Key Schedule.
^ Proprieta ^ Tipo ^ Descrizione ^
| ''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 |
===== Panoramica metodi =====
==== HKDF ====
^ Metodo ^ Parametri ^ Ritorno ^
| ''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 ====
^ Metodo ^ Parametri ^ Ritorno ^
| ''DeriveHybridKey'' | byte[]? classicSecret, byte[]? pqSecret, int outputLength, CryptoMode, byte[]? info | byte[] |
| ''DeriveHybridKeyMaterial'' | byte[]? classicSecret, byte[]? pqSecret, CryptoMode | HybridKeyMaterial |
==== PBKDF2 ====
^ Metodo ^ Parametri ^ Ritorno ^
| ''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 ====
^ Metodo ^ Parametri ^ Ritorno ^
| ''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 ====
^ Metodo ^ Parametri ^ Ritorno ^
| ''DeriveTlsKeys'' | byte[] preMasterSecret, byte[] clientRandom, byte[] serverRandom, CryptoMode | TlsKeyMaterial |
| ''DeriveTls13Keys'' | byte[]? psk, byte[]? ecdh, byte[]? pq, byte[] clientHello, byte[] serverHello, CryptoMode | Tls13KeySchedule |
===== Esempio completo =====
using WvdS.System.Security.Cryptography;
using WvdS.System.Security.Cryptography.KeyDerivation;
using WvdS.System.Security.Cryptography.KeyExchange;
// 1. Eseguire Key Exchange
using var session = new KeyExchangeService();
await session.InitiateKeyExchangeAsync(recipientPublicKey, CryptoMode.Hybrid);
// 2. Derivare Hybrid Key Material
using HybridKeyMaterial keys = KeyDerivationExtensions.DeriveHybridKeyMaterial(
classicSecret: session.ClassicSharedSecret,
pqSecret: session.PqSharedSecret,
mode: CryptoMode.Hybrid);
// 3. Utilizzare le chiavi
using var aes = Aes.Create();
aes.Key = keys.EncryptionKey;
using var hmac = new HMACSHA256(keys.MacKey);
// 4. Eseguire crittografia
// ...
// 5. Le chiavi vengono cancellate automaticamente in modo sicuro
===== Note di sicurezza =====
* Tutte le classi ''IDisposable'' implementano ''CryptographicOperations.ZeroMemory''
* Argon2id richiede OpenSSL 3.6 (non disponibile in .NET BCL)
* PBKDF2 con meno di 100.000 iterazioni non e raccomandato
* Il Salt deve essere sempre casuale e sufficientemente lungo per PBKDF2/Argon2id (min. 16 Bytes)
**Sicurezza modalita ibrida:**
In modalita ibrida la chiave finale viene compromessa solo se ENTRAMBI i secrets (classico E PQ) vengono violati. Questo fornisce protezione sia contro attacchi classici che quantistici.
===== Vedi anche =====
* [[.:start|Namespace KeyDerivation]]
* [[.:hybridkeymaterial|HybridKeyMaterial]]
* [[.:tlskeymaterial|TlsKeyMaterial]]
* [[.:tls13keyschedule|Tls13KeySchedule]]
* [[..:keyexchange:start|Namespace KeyExchange]]
* [[..:encryption:start|Namespace Encryption]]
* [[it:int:pqcrypt:konzepte:algorithmen:ml-kem|Algoritmo ML-KEM]]
----
//Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//