Scenario 11.1: Key Generation

Category: Key Management
Complexity: ⭐⭐⭐ (Medium)
Prerequisites: OpenSSL 3.6+, secure entropy source
Estimated Time: 15-20 Minutes


Description

This scenario describes the secure generation of cryptographic keys for Post-Quantum algorithms. Key generation is the most critical step - weak keys endanger all operations based on them.

Supported Algorithms:

Algorithm Type Security Key Size (Public)
ML-DSA-44 Signature 128-bit 1,312 Bytes
ML-DSA-65 Signature 192-bit 1,952 Bytes
ML-DSA-87 Signature 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[Entropy Source] --> RNG[CSPRNG] RNG --> KEYGEN[Key Generation] PARAM[Select Parameters] --> KEYGEN KEYGEN --> PUBKEY[Public Key] KEYGEN --> PRIVKEY[Private Key] PRIVKEY --> ENCRYPT[Store Encrypted] style ENTROPY fill:#fff3e0 style ENCRYPT fill:#e8f5e9


Code Example: ML-DSA Signature Key

using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ;
 
using var ctx = PqCryptoContext.Initialize();
 
// Generate ML-DSA-65 key pair (recommended)
using var signatureKey = ctx.GenerateKeyPair(PqAlgorithm.MlDsa65);
 
Console.WriteLine("ML-DSA-65 key generated:");
Console.WriteLine($"  Public Key: {signatureKey.PublicKey.GetRawData().Length} Bytes");
Console.WriteLine($"  OID: {signatureKey.PublicKey.Oid.Value}");
 
// Save as PEM
signatureKey.PublicKey.ToPemFile("signing.pub.pem");
signatureKey.ToEncryptedPemFile("signing.key.pem", "SecurePassword123!");
 
// Different security levels
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 (High Security)

Code Example: ML-KEM Encryption Key

using var ctx = PqCryptoContext.Initialize();
 
// ML-KEM-768 for Key Encapsulation (recommended)
using var kemKey = ctx.GenerateKeyPair(PqAlgorithm.MlKem768);
 
Console.WriteLine("ML-KEM-768 key generated:");
Console.WriteLine($"  Public Key: {kemKey.PublicKey.GetRawData().Length} Bytes");
Console.WriteLine($"  Usage: Key Encapsulation");
 
// Save
kemKey.PublicKey.ToPemFile("encryption.pub.pem");
kemKey.ToEncryptedPemFile("encryption.key.pem", "EncryptionPassword!");

Code Example: Hybrid Key Pair

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();
 
        // Classical key
        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("Unknown algorithm")
        };
 
        // PQ key
        var pqKey = ctx.GenerateKeyPair(pq);
 
        return new HybridKeyPair
        {
            ClassicalKey = classicalKey,
            PqKey = pqKey
        };
    }
 
    public void SaveToFiles(string baseName, string password)
    {
        // Classical key
        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);
        }
 
        // PQ key
        PqKey.ToEncryptedPemFile($"{baseName}-pq.key.pem", password);
        PqKey.PublicKey.ToPemFile($"{baseName}-pq.pub.pem");
    }
}
 
public enum ClassicalAlgorithm
{
    RsA4096,
    EcdsaP384,
    EcdhP384
}

Batch Generation

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($"Generated: {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
            );
        }
    }
}

Entropy and Random Numbers

public class EntropySource
{
    // System CSPRNG (recommended)
    public static byte[] GetSystemEntropy(int bytes)
    {
        return RandomNumberGenerator.GetBytes(bytes);
    }
 
    // Check hardware RNG
    public static bool IsHardwareRngAvailable()
    {
        try
        {
            // Intel RDRAND
            return System.Runtime.Intrinsics.X86.Rdrand.IsSupported;
        }
        catch
        {
            return false;
        }
    }
 
    // Mix in additional entropy (optional)
    public static byte[] EnhancedEntropy(int bytes)
    {
        var systemEntropy = RandomNumberGenerator.GetBytes(bytes);
 
        // Mix in additional entropy sources
        var timestamp = BitConverter.GetBytes(DateTime.UtcNow.Ticks);
        var processId = BitConverter.GetBytes(Environment.ProcessId);
        var gcMemory = BitConverter.GetBytes(GC.GetTotalMemory(false));
 
        // Hash combined
        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);
 
        // Extended entropy for more 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;
    }
}

Industry-Specific Requirements

Industry Minimum Security Recommended Algorithm HSM Required?
Standard IT 128-bit ML-DSA-65 / ML-KEM-768 No
Financial Sector 192-bit ML-DSA-65 / ML-KEM-768 Yes
Healthcare 192-bit ML-DSA-65 / ML-KEM-768 Recommended
Government 256-bit ML-DSA-87 / ML-KEM-1024 Yes
IoT 128-bit ML-DSA-44 / ML-KEM-512 No

Relationship Scenario Description
Next Step 11.2 Key Storage Secure storage
Related 11.3 Key Rotation Regular exchange
Related 2.1 Server CSR Create CSR

« ← Key Overview | ↑ Scenarios | 11.2 Key Storage → »


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

Zuletzt geändert: on 2026/01/30 at 06:40 AM