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


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

Zuletzt geändert: on 2026/01/30 at 12:18 AM