TL;DR
When using BouncyCastle for ECDH key exchange in .NET with Microsoft CNG keys, you might encounter a mismatch error. This is usually due to differences in how the public key is represented. The solution involves explicitly specifying the OID (Object Identifier) when creating the parameters and ensuring consistent key derivation.
Solution Guide
- Understand the Problem: Microsoft CNG keys store ECDH parameters differently than BouncyCastle’s default expectations. This leads to different public key encodings, causing the mismatch during key agreement.
- Identify Your Key Store: Determine if you are using a CngKey or another type of key. This guide focuses on CngKey scenarios.
- Create ECDH Parameters with Explicit OID: When generating your ECDH parameters, explicitly specify the correct Object Identifier (OID) for the curve you’re using. Common OIDs include:
- secp256r1 (NIST P-256):
1.2.840.10045.2.1.1.7 - prime256v1 (SECG curve):
1.2.840.10045.2.1.1.1
Example using BouncyCastle:
ECParameterSpec ecSpec = ECPairGenerator.createECPair(ECCurve.getByName("secp256r1")); // or, explicitly: ECDomainParameters domainParams = new ECDomainParameters(ECCurve.getInstance(new ASN1ObjectIdentifier("1.2.840.10045.2.1.1.7")), ecSpec.Q, ecSpec.G, ecSpec.N); - secp256r1 (NIST P-256):
- Load the CngKey: Load your key from the CNG store.
using (CngKey cngKey = new CngKey(keyName, CngProvider.Microsoft)) { // ... use the key } - Convert CngKey to BouncyCastle Key: Convert the CngKey to a BouncyCastle PublicKey object.
Org.BouncyCastle.Crypto.AsymmetricKeyParameter publicKey = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(cngKey.ExportParameters(false)); - Derive the Secret Key: Use BouncyCastle’s ECDH algorithm to derive the shared secret.
Ensure you are using a KDF (Key Derivation Function) if necessary for your security requirements. A simple example without a KDF:
IBasicAgreement agreement = new ECDHBasicAgreement(); agreement.Init(privateKey, publicKey); byte[] sharedSecretBytes = agreement.GetAgreementOutput(); - Verify Key Agreement: If you are exchanging keys with another party, compare the derived secret key (after any KDF application) to ensure they match.
Differences can occur if either side uses incorrect parameters or a different KDF.
- Troubleshooting:
- Check OIDs: Double-check that both parties are using the *exact same* OID for the ECDH curve.
- Key Encoding: Inspect the public key encoding on both sides to confirm they are consistent. You can use a debugging tool or logging to examine the raw bytes of the encoded keys.
- KDF Configuration: If using KDFs, ensure that both parties have configured them identically (algorithm, salt, iteration count).

