Szenario 11.1: Schlüsselgenerierung

Kategorie: Schlüsselmanagement
Komplexität: ⭐⭐⭐ (Mittel)
Voraussetzungen: OpenSSL 3.6+, sichere Entropiequelle
Geschätzte Zeit: 15-20 Minuten


Beschreibung

Dieses Szenario beschreibt die sichere Generierung kryptographischer Schlüssel für Post-Quantum-Algorithmen. Die Schlüsselgenerierung ist der kritischste Schritt - schwache Schlüssel gefährden alle darauf basierenden Operationen.

Unterstützte Algorithmen:

Algorithmus Typ Sicherheit Schlüsselgröße (Public)
ML-DSA-44 Signatur 128-bit 1,312 Bytes
ML-DSA-65 Signatur 192-bit 1,952 Bytes
ML-DSA-87 Signatur 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[Entropie-Quelle] --> RNG[CSPRNG] RNG --> KEYGEN[Key Generation] PARAM[Parameter wählen] --> KEYGEN KEYGEN --> PUBKEY[Public Key] KEYGEN --> PRIVKEY[Private Key] PRIVKEY --> ENCRYPT[Verschlüsselt speichern] style ENTROPY fill:#fff3e0 style ENCRYPT fill:#e8f5e9


Code-Beispiel: ML-DSA Signaturschlüssel

using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ;
 
using var ctx = PqCryptoContext.Initialize();
 
// ML-DSA-65 Schlüsselpaar generieren (empfohlen)
using var signatureKey = ctx.GenerateKeyPair(PqAlgorithm.MlDsa65);
 
Console.WriteLine("ML-DSA-65 Schlüssel generiert:");
Console.WriteLine($"  Public Key: {signatureKey.PublicKey.GetRawData().Length} Bytes");
Console.WriteLine($"  OID: {signatureKey.PublicKey.Oid.Value}");
 
// Als PEM speichern
signatureKey.PublicKey.ToPemFile("signing.pub.pem");
signatureKey.ToEncryptedPemFile("signing.key.pem", "SecurePassword123!");
 
// Verschiedene Sicherheitsstufen
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 (Hochsicherheit)

Code-Beispiel: ML-KEM Verschlüsselungsschlüssel

using var ctx = PqCryptoContext.Initialize();
 
// ML-KEM-768 für Key Encapsulation (empfohlen)
using var kemKey = ctx.GenerateKeyPair(PqAlgorithm.MlKem768);
 
Console.WriteLine("ML-KEM-768 Schlüssel generiert:");
Console.WriteLine($"  Public Key: {kemKey.PublicKey.GetRawData().Length} Bytes");
Console.WriteLine($"  Verwendung: Key Encapsulation");
 
// Speichern
kemKey.PublicKey.ToPemFile("encryption.pub.pem");
kemKey.ToEncryptedPemFile("encryption.key.pem", "EncryptionPassword!");

Code-Beispiel: Hybrid-Schlüsselpaar

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

Batch-Generierung

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

Entropie und Zufallszahlen

public class EntropySource
{
    // System-CSPRNG (empfohlen)
    public static byte[] GetSystemEntropy(int bytes)
    {
        return RandomNumberGenerator.GetBytes(bytes);
    }
 
    // Hardware RNG prüfen
    public static bool IsHardwareRngAvailable()
    {
        try
        {
            // Intel RDRAND
            return System.Runtime.Intrinsics.X86.Rdrand.IsSupported;
        }
        catch
        {
            return false;
        }
    }
 
    // Zusätzliche Entropie einmischen (optional)
    public static byte[] EnhancedEntropy(int bytes)
    {
        var systemEntropy = RandomNumberGenerator.GetBytes(bytes);
 
        // Weitere Entropiequellen einmischen
        var timestamp = BitConverter.GetBytes(DateTime.UtcNow.Ticks);
        var processId = BitConverter.GetBytes(Environment.ProcessId);
        var gcMemory = BitConverter.GetBytes(GC.GetTotalMemory(false));
 
        // Hash kombinieren
        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);
 
        // Erweiterte Entropie für weitere 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;
    }
}

Branchenspezifische Anforderungen

Branche Min. Sicherheit Empfohlener Algorithmus HSM Pflicht?
Standard IT 128-bit ML-DSA-65 / ML-KEM-768 Nein
Finanzsektor 192-bit ML-DSA-65 / ML-KEM-768 Ja
Healthcare 192-bit ML-DSA-65 / ML-KEM-768 Empfohlen
Government 256-bit ML-DSA-87 / ML-KEM-1024 Ja
IoT 128-bit ML-DSA-44 / ML-KEM-512 Nein

Verwandte Szenarien

Beziehung Szenario Beschreibung
Nächster Schritt 11.2 Schlüsselspeicherung Sicheres Speichern
Verwandt 11.3 Schlüssel-Rotation Regelmäßiger Austausch
Verwandt 2.1 Server-CSR CSR erstellen

« ← Schlüssel-Übersicht | ↑ Szenarien | 11.2 Schlüsselspeicherung → »


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