Agree on a hybrid key
Two sides of your own protocol need to agree on a shared key, and that key must stay secure as long as either ECDH or ML-KEM is secure.
Solution overview
| Element | Purpose |
|---|---|
ECDiffieHellman.Create(ECCurve.NamedCurves.nistP384) | the recipient's classical key pair, from .NET |
MLKemKey.Generate(MLKemParameterSet.MLKem768) | the recipient's ML-KEM key pair |
HybridKeyAgreement.Encapsulate | sender: derives the key and returns what the recipient needs to derive it too |
HybridKeyAgreement.Decapsulate | recipient: derives the same key |
HybridEncapsulation | the sender's result: SharedKey, EphemeralPublicKey, MLKemCiphertext |
By default, both methods combine the secrets with KeyCombine as defined in NIST SP 800-227, as BSI TR-02102-1 recommends; see Post-quantum algorithm policy.
Implementation
The recipient generates its keys and passes the public parts to the sender:
using var recipientEcdh = ECDiffieHellman.Create(ECCurve.NamedCurves.nistP384); using var recipientKem = MLKemKey.Generate(MLKemParameterSet.MLKem768); ECDiffieHellmanPublicKey ecdhPublic = recipientEcdh.PublicKey; byte[] kemPublic = recipientKem.ExportEncapsulationKey();
The sender derives the key and sends EphemeralPublicKey and MLKemCiphertext to the recipient:
byte[] info = Encoding.UTF8.GetBytes("example.com file transfer v1"); using var kemForSender = MLKemKey.ImportEncapsulationKey(MLKemParameterSet.MLKem768, kemPublic); var sent = HybridKeyAgreement.Encapsulate(ecdhPublic, kemForSender, info); byte[] message = SymmetricEncryptionExtensions.EncryptAesGcm( Encoding.UTF8.GetBytes("Hello"), sent.SharedKey);
The recipient derives the same key and decrypts:
byte[] key = HybridKeyAgreement.Decapsulate( recipientEcdh, recipientKem, sent.EphemeralPublicKey, sent.MLKemCiphertext, info); Console.WriteLine(Encoding.UTF8.GetString(SymmetricEncryptionExtensions.DecryptAesGcm(message, key)));
The samples need using System.Security.Cryptography;, using System.Text;,
using WKL.System.Security.Cryptography;, using WKL.System.Security.Cryptography.KeyDerivation;, and
using WKL.System.Security.Cryptography.Encryption;.
Remarks
- Same values on both sides.
info,keyLength, andcombinermust match on both sides. A different value doesn't cause an exception; it produces a different key. Decryption then fails the AES-GCM authentication check. - Tampered data. A modified ciphertext or someone else's ephemeral key also produce a different key. That's by design: ML-KEM doesn't reject invalid ciphertexts with an error, and the protocol on top detects the tampering.
- Parameter sets. ML-KEM-768 and ML-KEM-1024 are allowed without an exemption. With ML-KEM-512,
Encapsulatethrows aCryptographicExceptionas long asPostQuantumExemptions.ReducedParameterSetsisn't set. - Peers on an earlier version. If the peer runs a version of the library with the first combiner, pass
combiner: HybridKeyCombiner.Version1to both methods. The recipient doesn't need an exemption for that and raises thePolicyDeviationevent. The sender needsPostQuantumExemptions.NonRecommendedCombiners. - Your own protocols with other algorithms. For a pairing other than ECDH and ML-KEM,
KeyCombiner.Combinecombines two secrets with their ciphertexts and public keys according to KeyCombine.
Related topics
en/wiki/pqcrypt/lib/how-to/agree-hybrid-keys.txt · Last modified: by Wolfgang van der Stille