Post-Quantum .NET: Introducing ML-KEM and ML-DSA

T

TheRealSenpai

New Member
Joined
October 30, 2025
Messages
4
Reaction score
0
Points
1
When I think back on those hacker movies where passwords get cracked in seconds, the reality is much more complicated. Our modern cryptography depends on hard mathematical problems—like factoring huge numbers or solving discrete logarithms. Unfortunately, with quantum computing looming on the horizon, we’re in a race against time. Shor’s algorithm, once it runs on a practical quantum computer, will completely break RSA, DSA, ECDSA, and other widely used algorithms.

I remember asking a cryptographer in 2019, “How long until quantum computers are a real threat?” He said 15 years, but also that we need to start preparing now. He was right. In August 2024, NIST formalized three post-quantum cryptography standards:

- ML-KEM (formerly Kyber) – FIPS-203, a module-lattice key encapsulation mechanism
- ML-DSA (formerly Dilithium) – FIPS-204, a module-lattice digital signature algorithm
- SLH-DSA (formerly SPHINCS+) – FIPS-205, a stateless hash-based digital signature


These algorithms are designed to resist both classical and quantum attacks. They’re a drop-in replacement for RSA and ECC—not symmetric algorithms (like AES or SHA-3), which aren’t directly threatened by quantum computing.



Standards and Industry Context

The push began in earnest with a 2016 NIST competition, and over several rounds (and many rejected candidates), Kyber (ML-KEM) and Dilithium (ML-DSA) emerged as the winners. Google and Microsoft moved quickly: Google started post-quantum experiments in TLS as early as 2016, and in 2025, Microsoft delivered direct support for ML-KEM and ML-DSA in both Windows and .NET 10 Preview 6.

If you’re active in sectors like finance or healthcare, don’t underestimate how tough this migration will be. The transition from SHA-1 to SHA-2 took a large bank I worked with almost two years. Migrating all asymmetric cryptography to post-quantum? It’s an order of magnitude more challenging.



ML-KEM and ML-DSA: What Are They?

ML-KEM (module-lattice key encapsulation) is the successor to Kyber. It’s built for safely exchanging symmetric keys over insecure networks, and its security depends on module-lattice math—a structure where even quantum computers make little headway. I once tried writing the lattice arithmetic from scratch: trust me, it's the fastest way to go gray in a weekend!

ML-DSA (module-lattice digital signature algorithm, based on Dilithium) certifies the authenticity and integrity of data. Its mathematics makes it quantum-resistant, basing its security on finding short vectors in a high-dimensional lattice—a problem that’s currently considered quantum-hard.

Compared to RSA/ECDSA:
1. Key & signature size: Post-quantum keys and signatures are much bigger (e.g., ML-KEM-768’s public key is ~1.2 KB vs ECDSA’s 32 bytes).
2. Underlying math: Instead of factoring or discrete logs, lattice problems are at the core.
3. Attack resistance: Designed for both classical and quantum resistance.
4. Performance: Can be faster for some ops, slower for others.

For most use cases, I recommend ML-KEM-768 (NIST Level 3 / 128-bit post-quantum security).



.NET – First Steps

There are two main ways to use post-quantum cryptography in .NET:

1. BouncyCastle.NET Library
BouncyCastle.NET 2.5.0 and later includes ML-KEM/Dilithium support.
csharp
dotnet add package BouncyCastle.Cryptography

In code:
Code:
 csharp
using Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber;
using Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium;
using Org.BouncyCastle.Security;
ML-KEM and ML-DSA are still labeled as Kyber/Dilithium in the namespaces.

2. Native Windows API (CNG) and .NET 10 Preview
From Windows build 27852 and .NET 10 Preview 6, Microsoft adds native classes MLKem and MLDsa.

Before using, check API availability:
Code:
 csharp
if (!MLKem.IsSupported) {
    Console.WriteLine("ML-KEM is not supported on this version of Windows");
    return;
}
using var keyPair = MLKem.GenerateKey(MLKemAlgorithm.MLKem768);


ML-KEM – Key Exchange Example

With BouncyCastle:
Code:
 csharp
var random = new SecureRandom();
var keyGenParameters = new MLKemKeyGenerationParameters(random, MLKemParameters.ml_kem_768);
var keyPairGenerator = new MLKemKeyPairGenerator();
keyPairGenerator.Init(keyGenParameters);

var aliceKeyPair = keyPairGenerator.GenerateKeyPair();
var alicePublicKey = (MLKemPublicKeyParameters)aliceKeyPair.Public;
var alicePrivateKey = (MLKemPrivateKeyParameters)aliceKeyPair.Private;

// Bob
var kemGenerator = new MLKemKEMGenerator(random);
var encapsulationResult = kemGenerator.GenerateEncapsulated(alicePublicKey);
var bobSecret = encapsulationResult.GetSecret();
var cipherText = encapsulationResult.GetEncapsulation();

// Alice
var kemExtractor = new MLKemKEMExtractor(alicePrivateKey);
var aliceSecret = kemExtractor.ExtractSecret(cipherText);

bool secretsMatch = bobSecret.SequenceEqual(aliceSecret);
Console.WriteLine($"Secrets match: {secretsMatch}");

With the Windows API in .NET 10:
Code:
 csharp
using var aliceKeyPair = MLKem.GenerateKey(MLKemAlgorithm.MLKem768);
byte[] publicKeyBytes = aliceKeyPair.ExportEncapsulationKey();

// Bob
using var bobKey = MLKem.ImportEncapsulationKey(MLKemAlgorithm.MLKem768, publicKeyBytes);
bobKey.Encapsulate(out byte[] cipherText, out byte[] bobSecret);

// Alice
byte[] aliceSecret = aliceKeyPair.Decapsulate(cipherText);
bool secretsMatch = bobSecret.SequenceEqual(aliceSecret);
Console.WriteLine($"Secrets match: {secretsMatch}");

Converting the shared secret to an AES key:

Code:
 csharp
using var aesAlg = Aes.Create();
aesAlg.Key = aliceSecret;
aesAlg.GenerateIV();



Practical Tips

- Use buffer pools for memory-intensive cryptographic operations.
- Apply async patterns for high-load systems.
- Always monitor and log cryptographic operations—Application Insights, for example, is helpful here.
- Integrate with modern key vaults (like Azure) for secure private key storage.
- Implement robust error handling:

Code:
 csharp
try {
    byte[] secret = aliceKeyPair.Decapsulate(possiblyCorruptedCipherText);
    if (secret.Length != 32) throw new CryptographicException("Incorrect secret size");
} catch (CryptographicException ex) {
    Console.WriteLine($"Cryptography error: {ex.Message}");
}


ML-DSA – Digital Signatures

With BouncyCastle:

Code:
 csharp
var random = new SecureRandom();
var parameters = new MLDsaKeyGenerationParameters(random, MLDsaParameters.ml_dsa_65);
var keyPairGenerator = new MLDsaKeyPairGenerator();
keyPairGenerator.Init(parameters);
var keyPair = keyPairGenerator.GenerateKeyPair();

var privateKey = (MLDsaPrivateKeyParameters)keyPair.Private;
var publicKey = (MLDsaPublicKeyParameters)keyPair.Public;

byte[] message = Encoding.UTF8.GetBytes("Important message");

var signer = new MLDsaSigner();
signer.Init(true, privateKey);
byte[] signature = signer.GenerateSignature(message);

var verifier = new MLDsaSigner();
verifier.Init(false, publicKey);
bool valid = verifier.VerifySignature(message, signature);
Console.WriteLine($"Signature valid: {valid}");

With .NET 10 Native API:

Code:
 csharp
using var keyPair = MLDsa.GenerateKey(MLDsaAlgorithm.MLDsa65);
byte[] message = Encoding.UTF8.GetBytes("Important message");
byte[] signature = keyPair.SignData(message);
bool valid = keyPair.VerifyData(message, signature);
Console.WriteLine($"Signature valid: {valid}");

Hybrid (Classical + Post-Quantum) Signature Example:
Code:
 csharp
public static (byte[] ecdsa, byte[] mlDsa) CreateHybridSignature(byte[] data, ECDsa ecdsaKey, MLDsa.SignatureKey mlDsaKey) {
    byte[] ecdsaSignature = ecdsaKey.SignData(data, HashAlgorithmName.SHA256);
    byte[] mlDsaSignature = mlDsaKey.SignData(data);
    return (ecdsaSignature, mlDsaSignature);
}

public static bool VerifyHybridSignature(byte[] data, byte[] ecdsaSig, byte[] mlDsaSig, ECDsa ecdsaKey, MLDsa.VerificationKey mlDsaKey) {
    return ecdsaKey.VerifyData(data, ecdsaSig, HashAlgorithmName.SHA256) && mlDsaKey.VerifyData(data, mlDsaSig);
}



Key takeaways:
If you need cryptographic flexibility, post-quantum readiness, or hybrid compatibility, start working with ML-KEM and ML-DSA right now—either through BouncyCastle or with the latest .NET 10 APIs. The sooner you build experience with these standards, the less painful your migration will be when quantum computers become a real threat.

If you need extra .NET code or best practices for production systems, I provide competitive pricing for such projects, feel free to ask.

Thank You!
 
Activity
So far there's no one here