Inhaltsverzeichnis

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


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