Scenario 11.1: Generazione chiavi

Categoria: Gestione chiavi
Complessità: Media
Prerequisiti: OpenSSL 3.6+, fonte di entropia sicura
Tempo stimato: 15-20 minuti


Descrizione

Questo scenario descrive la generazione sicura di chiavi crittografiche per algoritmi Post-Quantum. La generazione delle chiavi è il passo più critico - chiavi deboli compromettono tutte le operazioni basate su di esse.

Algoritmi supportati:

Algoritmo Tipo Sicurezza Dimensione chiave (Public)
ML-DSA-44 Firma 128-bit 1.312 Bytes
ML-DSA-65 Firma 192-bit 1.952 Bytes
ML-DSA-87 Firma 256-bit 2.592 Bytes
ML-KEM-512 KEM 128-bit 800 Bytes
ML-KEM-768 KEM 192-bit 1.184 Bytes
ML-KEM-1024 KEM 256-bit 1.568 Bytes

Workflow

flowchart LR ENTROPY[Fonte entropia] --> RNG[CSPRNG] RNG --> KEYGEN[Generazione chiave] PARAM[Scegliere parametri] --> KEYGEN KEYGEN --> PUBKEY[Chiave pubblica] KEYGEN --> PRIVKEY[Chiave privata] PRIVKEY --> ENCRYPT[Salvare crittografata] style ENTROPY fill:#fff3e0 style ENCRYPT fill:#e8f5e9


Esempio codice: Chiave firma ML-DSA

using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ;
 
using var ctx = PqCryptoContext.Initialize();
 
// Generare coppia chiavi ML-DSA-65 (consigliato)
using var signatureKey = ctx.GenerateKeyPair(PqAlgorithm.MlDsa65);
 
Console.WriteLine("Chiave ML-DSA-65 generata:");
Console.WriteLine($"  Chiave pubblica: {signatureKey.PublicKey.GetRawData().Length} Bytes");
Console.WriteLine($"  OID: {signatureKey.PublicKey.Oid.Value}");
 
// Salvare come PEM
signatureKey.PublicKey.ToPemFile("signing.pub.pem");
signatureKey.ToEncryptedPemFile("signing.key.pem", "SecurePassword123!");
 
// Diversi livelli di sicurezza
using var mlDsa44 = ctx.GenerateKeyPair(PqAlgorithm.MlDsa44);  // 128-bit
using var mlDsa65 = ctx.GenerateKeyPair(PqAlgorithm.MlDsa65);  // 192-bit (Standard)
using var mlDsa87 = ctx.GenerateKeyPair(PqAlgorithm.MlDsa87);  // 256-bit (Alta sicurezza)

Esempio codice: Chiave crittografia ML-KEM

using var ctx = PqCryptoContext.Initialize();
 
// ML-KEM-768 per Key Encapsulation (consigliato)
using var kemKey = ctx.GenerateKeyPair(PqAlgorithm.MlKem768);
 
Console.WriteLine("Chiave ML-KEM-768 generata:");
Console.WriteLine($"  Chiave pubblica: {kemKey.PublicKey.GetRawData().Length} Bytes");
Console.WriteLine($"  Utilizzo: Key Encapsulation");
 
// Salvare
kemKey.PublicKey.ToPemFile("encryption.pub.pem");
kemKey.ToEncryptedPemFile("encryption.key.pem", "EncryptionPassword!");

Esempio codice: Coppia chiavi ibride

public class HybridKeyPair
{
    public AsymmetricAlgorithm ClassicalKey { get; set; }
    public PqKeyPair PqKey { get; set; }
 
    public static HybridKeyPair Generate(
        ClassicalAlgorithm classical,
        PqAlgorithm pq)
    {
        using var ctx = PqCryptoContext.Initialize();
 
        // Chiave classica
        var classicalKey = classical switch
        {
            ClassicalAlgorithm.RsA4096 => RSA.Create(4096),
            ClassicalAlgorithm.EcdsaP384 => ECDsa.Create(ECCurve.NamedCurves.nistP384),
            ClassicalAlgorithm.EcdhP384 => ECDiffieHellman.Create(ECCurve.NamedCurves.nistP384),
            _ => throw new ArgumentException("Algoritmo sconosciuto")
        };
 
        // Chiave PQ
        var pqKey = ctx.GenerateKeyPair(pq);
 
        return new HybridKeyPair
        {
            ClassicalKey = classicalKey,
            PqKey = pqKey
        };
    }
 
    public void SaveToFiles(string baseName, string password)
    {
        // Chiave classica
        if (ClassicalKey is RSA rsa)
        {
            var rsaPem = rsa.ExportRSAPrivateKeyPem();
            File.WriteAllText($"{baseName}-classical.key.pem", rsaPem);
        }
        else if (ClassicalKey is ECDsa ecdsa)
        {
            var ecPem = ecdsa.ExportECPrivateKeyPem();
            File.WriteAllText($"{baseName}-classical.key.pem", ecPem);
        }
 
        // Chiave PQ
        PqKey.ToEncryptedPemFile($"{baseName}-pq.key.pem", password);
        PqKey.PublicKey.ToPemFile($"{baseName}-pq.pub.pem");
    }
}
 
public enum ClassicalAlgorithm
{
    RsA4096,
    EcdsaP384,
    EcdhP384
}

Generazione batch

public class KeyGenerationService
{
    public Dictionary<string, PqKeyPair> GenerateBatch(
        int count,
        PqAlgorithm algorithm,
        string namePrefix)
    {
        using var ctx = PqCryptoContext.Initialize();
        var keys = new Dictionary<string, PqKeyPair>();
 
        for (int i = 0; i < count; i++)
        {
            var name = $"{namePrefix}-{i:D4}";
            var keyPair = ctx.GenerateKeyPair(algorithm);
            keys[name] = keyPair;
 
            Console.WriteLine($"Generata: {name}");
        }
 
        return keys;
    }
 
    public void SaveBatch(
        Dictionary<string, PqKeyPair> keys,
        string outputDir,
        string password)
    {
        Directory.CreateDirectory(outputDir);
 
        foreach (var (name, key) in keys)
        {
            key.PublicKey.ToPemFile(Path.Combine(outputDir, $"{name}.pub.pem"));
            key.ToEncryptedPemFile(
                Path.Combine(outputDir, $"{name}.key.pem"),
                password
            );
        }
    }
}

Entropia e numeri casuali

public class EntropySource
{
    // Sistema CSPRNG (consigliato)
    public static byte[] GetSystemEntropy(int bytes)
    {
        return RandomNumberGenerator.GetBytes(bytes);
    }
 
    // Verificare Hardware RNG
    public static bool IsHardwareRngAvailable()
    {
        try
        {
            // Intel RDRAND
            return System.Runtime.Intrinsics.X86.Rdrand.IsSupported;
        }
        catch
        {
            return false;
        }
    }
 
    // Miscelare entropia aggiuntiva (opzionale)
    public static byte[] EnhancedEntropy(int bytes)
    {
        var systemEntropy = RandomNumberGenerator.GetBytes(bytes);
 
        // Miscelare altre fonti di entropia
        var timestamp = BitConverter.GetBytes(DateTime.UtcNow.Ticks);
        var processId = BitConverter.GetBytes(Environment.ProcessId);
        var gcMemory = BitConverter.GetBytes(GC.GetTotalMemory(false));
 
        // Combinare con hash
        using var sha = SHA256.Create();
        var combined = new byte[systemEntropy.Length + timestamp.Length + processId.Length + gcMemory.Length];
        Buffer.BlockCopy(systemEntropy, 0, combined, 0, systemEntropy.Length);
        Buffer.BlockCopy(timestamp, 0, combined, systemEntropy.Length, timestamp.Length);
        Buffer.BlockCopy(processId, 0, combined, systemEntropy.Length + timestamp.Length, processId.Length);
        Buffer.BlockCopy(gcMemory, 0, combined, systemEntropy.Length + timestamp.Length + processId.Length, gcMemory.Length);
 
        var hashed = sha.ComputeHash(combined);
 
        // Entropia estesa per ulteriori bytes
        var result = new byte[bytes];
        for (int i = 0; i < bytes; i += 32)
        {
            var blockSize = Math.Min(32, bytes - i);
            Buffer.BlockCopy(hashed, 0, result, i, blockSize);
            hashed = sha.ComputeHash(hashed);
        }
 
        return result;
    }
}

Requisiti specifici per settore

Settore Sicurezza min. Algoritmo consigliato HSM obbligatorio?
IT Standard 128-bit ML-DSA-65 / ML-KEM-768 No
Finanza 192-bit ML-DSA-65 / ML-KEM-768
Sanità 192-bit ML-DSA-65 / ML-KEM-768 Consigliato
Governo 256-bit ML-DSA-87 / ML-KEM-1024
IoT 128-bit ML-DSA-44 / ML-KEM-512 No

Scenari correlati

Relazione Scenario Descrizione
Passo successivo 11.2 Archiviazione chiavi Archiviazione sicura
Correlato 11.3 Rotazione chiavi Scambio regolare
Correlato 2.1 CSR Server Creare CSR

« Panoramica chiavi | Scenari | 11.2 Archiviazione chiavi »


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