====== SymmetricEncryptionExtensions ======
**Namespace:** ''WvdS.System.Security.Cryptography.Encryption''
Classe statica per la crittografia AES-GCM con supporto per chiavi Post-Quantum. Supporta crittografia classica, ibrida e puramente PQ.
===== Panoramica =====
Questa classe offre tre approcci di crittografia:
| Modalita | Classico | ML-KEM | Utilizzo |
| Classic | RSA-OAEP / ECDH | - | Comportamento standard .NET |
| Hybrid | RSA-OAEP / ECDH | ✓ | Massima sicurezza |
| PostQuantum | - | ✓ | Puramente post-quantum |
===== AES-GCM con chiave PQ =====
==== EncryptWithPqKey ====
Crittografa i dati con AES-GCM utilizzando un Shared Secret ML-KEM.
// Shared Secret da ML-KEM Key Exchange
byte[] sharedSecret = session.SharedSecret;
// Crittografare
byte[] plaintext = Encoding.UTF8.GetBytes("Messaggio segreto");
byte[] encrypted = SymmetricEncryptionExtensions.EncryptWithPqKey(
plaintext,
sharedSecret);
// Con Additional Authenticated Data (AAD)
byte[] aad = Encoding.UTF8.GetBytes("Info-contesto");
byte[] encryptedWithAad = SymmetricEncryptionExtensions.EncryptWithPqKey(
plaintext,
sharedSecret,
associatedData: aad);
==== DecryptWithPqKey ====
byte[] decrypted = SymmetricEncryptionExtensions.DecryptWithPqKey(
encrypted,
sharedSecret,
associatedData: aad); // Se usato durante Encrypt
string message = Encoding.UTF8.GetString(decrypted);
===== Hybrid Encryption (RSA + ML-KEM) =====
Combina RSA-OAEP Key Encapsulation con ML-KEM per crittografia ibrida quantum-sicura.
==== EncryptHybrid ====
using var rsa = RSA.Create(4096);
var (mlKemPublicKey, mlKemPrivateKey) = PqCrypto.GenerateKeyPair();
byte[] plaintext = GetSecretData();
// Crittografia ibrida (RSA + ML-KEM)
HybridEncryptedData encrypted = SymmetricEncryptionExtensions.EncryptHybrid(
plaintext,
rsa, // Chiave pubblica RSA del destinatario
mlKemPublicKey, // Chiave pubblica ML-KEM del destinatario
CryptoMode.Hybrid);
// Serializzare per il trasporto
byte[] serialized = encrypted.ToBytes();
==== DecryptHybrid ====
// Deserializzare
HybridEncryptedData encrypted = HybridEncryptedData.FromBytes(serialized);
// Decrittografare
byte[] plaintext = SymmetricEncryptionExtensions.DecryptHybrid(
encrypted,
rsaPrivateKey, // Chiave privata RSA
mlKemPrivateKey); // Chiave privata ML-KEM
===== ECDH + ML-KEM Encryption =====
Crittografia stile ECIES con ECDH effimero e ML-KEM.
==== EncryptEcdhPq ====
using var recipientEcdh = ECDiffieHellman.Create(ECCurve.NamedCurves.nistP384);
var (mlKemPublicKey, mlKemPrivateKey) = PqCrypto.GenerateKeyPair();
byte[] plaintext = GetSecretData();
// Crittografia ibrida ECDH + ML-KEM
HybridEncryptedData encrypted = SymmetricEncryptionExtensions.EncryptEcdhPq(
plaintext,
recipientEcdh, // Chiave pubblica ECDH del destinatario
mlKemPublicKey, // Chiave pubblica ML-KEM
CryptoMode.Hybrid);
// La chiave pubblica ECDH effimera e contenuta in encrypted.EphemeralPublicKey
==== DecryptEcdhPq ====
byte[] plaintext = SymmetricEncryptionExtensions.DecryptEcdhPq(
encrypted,
recipientEcdhPrivateKey,
mlKemPrivateKey);
===== Core AES-GCM Operations =====
Crittografia AES-256-GCM diretta senza Key Encapsulation.
==== EncryptAesGcm ====
byte[] key = RandomNumberGenerator.GetBytes(32); // Chiave 256-bit
byte[] plaintext = GetData();
// AES-GCM standard
byte[] encrypted = SymmetricEncryptionExtensions.EncryptAesGcm(
plaintext,
key);
// Con AAD
byte[] aad = Encoding.UTF8.GetBytes("message-context");
byte[] encryptedWithAad = SymmetricEncryptionExtensions.EncryptAesGcm(
plaintext,
key,
associatedData: aad);
**Formato di output:**
┌─────────────────────────────────────────┐
│ [12 Bytes] Nonce (generato casualmente) │
│ [n Bytes] Ciphertext │
│ [16 Bytes] GCM Authentication Tag │
└─────────────────────────────────────────┘
==== DecryptAesGcm ====
byte[] plaintext = SymmetricEncryptionExtensions.DecryptAesGcm(
encrypted,
key,
associatedData: aad); // Se utilizzato
===== Crittografia basata su Stream =====
Per file di grandi dimensioni con elaborazione a chunk.
==== EncryptStream ====
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); // Chunk da 64 KB (predefinito)
**Formato chunk:**
┌────────────────────────────────────────────┐
│ [12 Bytes] Base Nonce │
├────────────────────────────────────────────┤
│ Chunk 0: │
│ [4 Bytes] Lunghezza chunk │
│ [n Bytes] Dati crittografati │
│ [16 Bytes] GCM Tag │
├────────────────────────────────────────────┤
│ Chunk 1: (Nonce = Base + 1) │
│ [4 Bytes] Lunghezza chunk │
│ [n Bytes] Dati crittografati │
│ [16 Bytes] GCM Tag │
├────────────────────────────────────────────┤
│ ... altri chunk ... │
├────────────────────────────────────────────┤
│ [4 Bytes] Marcatore di fine (0x00000000) │
└────────────────────────────────────────────┘
==== DecryptStream ====
using var inputStream = File.OpenRead("large-file.enc");
using var outputStream = File.Create("large-file.decrypted");
SymmetricEncryptionExtensions.DecryptStream(
inputStream,
outputStream,
key);
===== Key Derivation =====
==== DeriveAesKey ====
Deriva una chiave AES-256 da un Shared Secret.
byte[] sharedSecret = GetMlKemSharedSecret();
// Derivazione standard
byte[] aesKey = SymmetricEncryptionExtensions.DeriveAesKey(sharedSecret);
// Con Salt e Info
byte[] salt = RandomNumberGenerator.GetBytes(32);
byte[] info = Encoding.UTF8.GetBytes("MyApp-Encryption-Key");
byte[] aesKeyCustom = SymmetricEncryptionExtensions.DeriveAesKey(
sharedSecret,
salt: salt,
info: info);
**Implementazione interna:** HKDF-SHA256 con ''info="WvdS-PQ-AES-Key"''
==== DeriveMultipleKeys ====
Deriva piu chiavi per scopi diversi.
byte[] sharedSecret = GetMlKemSharedSecret();
var (encryptionKey, macKey, iv) = SymmetricEncryptionExtensions.DeriveMultipleKeys(
sharedSecret,
salt: optionalSalt);
// encryptionKey: 32 Bytes (AES-256)
// macKey: 32 Bytes (HMAC)
// iv: 16 Bytes (Vettore di inizializzazione)
===== Classe HybridEncryptedData =====
Contenitore per dati crittografati ibridi con serializzazione.
==== Proprieta ====
^ Proprieta ^ Tipo ^ Descrizione ^
| ''Mode'' | CryptoMode | Modalita di crittografia utilizzata |
| ''ClassicEncapsulatedKey'' | byte[]? | Chiave contenuto crittografata RSA |
| ''EphemeralPublicKey'' | byte[]? | Chiave pubblica ECDH effimera |
| ''PqCiphertext'' | byte[]? | Ciphertext ML-KEM |
| ''EncryptedContent'' | byte[] | Dati crittografati AES-GCM |
==== Serializzazione ====
HybridEncryptedData encrypted = EncryptData();
// A byte array
byte[] serialized = encrypted.ToBytes();
// Da byte array
HybridEncryptedData restored = HybridEncryptedData.FromBytes(serialized);
===== Classe Convenience PqCrypto =====
API semplificata per crittografia puramente PQ.
// Generare coppia di chiavi
var (publicKey, privateKey) = PqCrypto.GenerateKeyPair();
// Crittografare
byte[] plaintext = Encoding.UTF8.GetBytes("Messaggio segreto");
var (ciphertext, encryptedData) = PqCrypto.Encrypt(plaintext, publicKey);
// Decrittografare
byte[] decrypted = PqCrypto.Decrypt(ciphertext, encryptedData, privateKey);
===== Panoramica metodi =====
==== SymmetricEncryptionExtensions ====
^ Metodo ^ Parametri ^ Ritorno ^
| ''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[]) |
==== PqCrypto ====
^ Metodo ^ Parametri ^ Ritorno ^
| ''GenerateKeyPair'' | - | (byte[] PublicKey, byte[] PrivateKey) |
| ''Encrypt'' | byte[] plaintext, byte[] recipientPublicKey | (byte[] Ciphertext, byte[] EncryptedData) |
| ''Decrypt'' | byte[] ciphertext, byte[] encryptedData, byte[] privateKey | byte[] |
===== Esempio completo =====
using WvdS.System.Security.Cryptography;
using WvdS.System.Security.Cryptography.Encryption;
// 1. Generare chiavi (Destinatario)
using var rsa = RSA.Create(4096);
var (mlKemPublicKey, mlKemPrivateKey) = PqCrypto.GenerateKeyPair();
// 2. Trasmettere le chiavi pubbliche al mittente
// (In pratica: Certificato con chiavi PQ incorporate)
// --- Mittente ---
// 3. Crittografare messaggio
byte[] message = File.ReadAllBytes("document.pdf");
HybridEncryptedData encrypted = SymmetricEncryptionExtensions.EncryptHybrid(
message,
rsa, // Chiave pubblica RSA del destinatario
mlKemPublicKey, // Chiave pubblica ML-KEM del destinatario
CryptoMode.Hybrid);
// 4. Serializzare e inviare
byte[] package = encrypted.ToBytes();
File.WriteAllBytes("document.encrypted", package);
// --- Destinatario ---
// 5. Ricevere e deserializzare
byte[] receivedPackage = File.ReadAllBytes("document.encrypted");
HybridEncryptedData receivedData = HybridEncryptedData.FromBytes(receivedPackage);
// 6. Decrittografare
byte[] decrypted = SymmetricEncryptionExtensions.DecryptHybrid(
receivedData,
rsa, // Propria chiave privata RSA
mlKemPrivateKey); // Propria chiave privata ML-KEM
File.WriteAllBytes("document.decrypted.pdf", decrypted);
===== Note di sicurezza =====
* I nonce AES-GCM non devono MAI essere riutilizzati
* In modalita ibrida la chiave viene derivata dal secret classico E da quello PQ
* ''DeriveAesKey'' senza Salt e deterministico - solo per casi d'uso specifici
* La crittografia stream utilizza nonce incrementali per chunk
**Combinazione chiavi in modalita ibrida:**
Combined Key = HKDF-SHA256(
ikm = classicSecret || pqSecret,
info = "WvdS-Hybrid-Key"
)
Anche se un attaccante compromette il secret classico, la crittografia rimane protetta dal secret PQ (e viceversa).
===== Vedi anche =====
* [[.:start|Namespace Encryption]]
* [[.:hybridencrypteddata|HybridEncryptedData]]
* [[.:pqcrypto|PqCrypto]]
* [[..:keyexchange:start|Namespace KeyExchange]]
* [[..:keyderivation:start|Namespace KeyDerivation]]
* [[it:int:pqcrypt:konzepte:algorithmen:ml-kem|Algoritmo ML-KEM]]
----
//Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//