====== 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//