~~NOTOC~~
====== Scenario 11.1: Key Generation ======
**Category:** [[.:start|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 GenerateBatch(
int count,
PqAlgorithm algorithm,
string namePrefix)
{
using var ctx = PqCryptoContext.Initialize();
var keys = new Dictionary();
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 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 |
----
===== Related Scenarios =====
^ Relationship ^ Scenario ^ Description ^
| **Next Step** | [[.:speicherung|11.2 Key Storage]] | Secure storage |
| **Related** | [[.:rotation|11.3 Key Rotation]] | Regular exchange |
| **Related** | [[en:int:pqcrypt:szenarien:csr:csr_server|2.1 Server CSR]] | Create CSR |
----
<< [[.:start|← Key Overview]] | [[en:int:pqcrypt:szenarien:start|↑ Scenarios]] | [[.:speicherung|11.2 Key Storage →]] >>
{{tag>scenario key generation ml-dsa ml-kem entropy}}
----
//Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//