====== X509StoreExtensions ====== **Namespace:** ''WvdS.System.Security.Cryptography.X509Certificates'' Extensions for ''X509Store'' with post-quantum key persistence. Enables saving and restoring PQ keys in the Windows Certificate Store. ===== Overview ===== The Windows Certificate Store does not natively support post-quantum keys. These extensions store PQ keys in a separate, encrypted file storage: %LOCALAPPDATA%\WvdS.Crypto\PqKeys\{thumbprint}.pqkey The keys are automatically encrypted with DPAPI (Windows) or AES-256 (cross-platform). ===== Methods ===== ^ Method ^ Description ^ | ''Add(certificate, mode)'' | Adds certificate and persists PQ keys | | ''AddRange(collection, mode)'' | Adds multiple certificates | | ''Remove(certificate, deletePqKeys)'' | Removes certificate and optionally PQ keys | | ''RemoveRange(collection, deletePqKeys)'' | Removes multiple certificates | | ''Find(findType, findValue, validOnly, restorePqKeys)'' | Searches certificates and restores PQ keys | | ''GetCertificatesWithPqKeys()'' | All certificates with restored PQ keys | ===== Static Methods ===== ^ Method ^ Description ^ | ''PersistPqKeys(certificate)'' | Manually persists PQ keys | | ''RestorePqKeys(certificate)'' | Manually restores PQ keys | | ''DeletePqKeys(certificate)'' | Deletes persisted PQ keys | | ''HasPersistedPqKeys(certificate)'' | Checks if PQ keys exist | | ''GetPersistedPqKeyThumbprints()'' | Lists all thumbprints | ===== Adding a Certificate ===== using var store = new X509Store(StoreName.My, StoreLocation.CurrentUser); store.Open(OpenFlags.ReadWrite); // Add certificate with PQ keys var hybridCert = CreateHybridCertificate(); store.Add(hybridCert, CryptoMode.Hybrid); // PQ keys are automatically persisted Console.WriteLine($"PQ keys saved: {X509StoreExtensions.HasPersistedPqKeys(hybridCert)}"); ===== Finding Certificate with PQ Keys ===== using var store = new X509Store(StoreName.My, StoreLocation.CurrentUser); store.Open(OpenFlags.ReadOnly); // Search and restore PQ keys var certs = store.Find( X509FindType.FindBySubjectName, "MyCertificate", validOnly: true, restorePqKeys: true); // Automatically load PQ keys foreach (var cert in certs) { Console.WriteLine($"Found: {cert.Subject}"); Console.WriteLine($"Mode: {cert.GetCryptoMode()}"); // PQ keys are now available if (PqKeyStore.TryGetPublicKey(cert, out var pqKey)) { Console.WriteLine($"PQ key: {pqKey.Length} bytes"); } } ===== All Certificates with PQ Keys ===== using var store = new X509Store(StoreName.My, StoreLocation.CurrentUser); store.Open(OpenFlags.ReadOnly); var allCerts = store.GetCertificatesWithPqKeys(); foreach (var cert in allCerts) { var hasPq = X509StoreExtensions.HasPersistedPqKeys(cert); Console.WriteLine($"{cert.Subject}: PQ={hasPq}"); } ===== Removing a Certificate ===== using var store = new X509Store(StoreName.My, StoreLocation.CurrentUser); store.Open(OpenFlags.ReadWrite); var certToRemove = FindCertificate(store); // With PQ key cleanup (recommended) store.Remove(certToRemove, deletePqKeys: true); // Without PQ key cleanup (keys remain) store.Remove(certToRemove, deletePqKeys: false); ===== PqKeyStoreManager ===== Additional class for store management: // Clean up orphaned keys (keys without associated certificate) int deleted = PqKeyStoreManager.CleanupOrphanedKeys( StoreName.My, StoreLocation.CurrentUser); Console.WriteLine($"{deleted} orphaned keys deleted"); // Backup all PQ keys PqKeyStoreManager.BackupAllPqKeys( "pq-keys-backup.enc", "BackupPassword123!"); // Restore from backup int restored = PqKeyStoreManager.RestoreFromBackup( "pq-keys-backup.enc", "BackupPassword123!"); Console.WriteLine($"{restored} keys restored"); ===== Key Encryption ===== ==== Windows (DPAPI) ==== DataProtectionScope.CurrentUser - Only the current user can decrypt keys - Keys are bound to user profile ==== Cross-Platform (AES-256) ==== Key = SHA256(MachineName + UserName) IV = randomly generated - Keys are bound to machine + user - Less secure than DPAPI ===== Secure Deletion ===== PQ keys are securely deleted: // Internally executed: // 1. Overwrite file with random data var random = RandomNumberGenerator.GetBytes(fileLength); File.WriteAllBytes(keyPath, random); // 2. Delete file File.Delete(keyPath); ===== Example: Complete Workflow ===== // 1. Create hybrid certificate CryptoConfig.EnablePostQuantum(); var cert = CreateHybridCertificate("CN=Hybrid Test"); // 2. Add to store using (var store = new X509Store(StoreName.My, StoreLocation.CurrentUser)) { store.Open(OpenFlags.ReadWrite); store.Add(cert, CryptoMode.Hybrid); } // 3. Restart application... // 4. Load again later using (var store = new X509Store(StoreName.My, StoreLocation.CurrentUser)) { store.Open(OpenFlags.ReadOnly); var found = store.Find( X509FindType.FindBySubjectName, "Hybrid Test", true, restorePqKeys: true); var loadedCert = found[0]; // PQ keys are restored! var pqPublicKey = PqKeyStore.GetPublicKey(loadedCert); Console.WriteLine($"PQ key loaded: {pqPublicKey.Length} bytes"); } ===== Storage Location ===== ^ Operating System ^ Path ^ | Windows | ''%LOCALAPPDATA%\WvdS.Crypto\PqKeys\'' | | Linux | ''~/.local/share/WvdS.Crypto/PqKeys/'' | | macOS | ''~/Library/Application Support/WvdS.Crypto/PqKeys/'' | ===== Security Notes ===== * PQ keys are only accessible to the current user * Create backup before system migration * Run ''CleanupOrphanedKeys()'' regularly * Cross-platform encryption is less secure than DPAPI ===== See Also ===== * [[.:x509certificate2exportextensions|X509Certificate2ExportExtensions]] * [[.:x509certificate2extensions|X509Certificate2Extensions]] * [[.:truststoreextensions|TrustStoreExtensions]] ---- //Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//