Using ECDiffieHellmanCng to exchange keys

3.1k views Asked by At

We plan to use ECDHE algorithm to exchange keys between client and server so that both can derive a common secret key to encrypt messages

Based on what I have read, to use ECDHE algorithm both parties (client and server) should agree on a pair of "common" values (p, g) first. Then each party will use a private key to generate a shared key ie client uses a private key (P1) to generate a shared key (S1) and server uses a private key (P2) to generate a shared key (S2) Ref: [https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange#Description]

Common value here refers to the common paint. These are actually the mod value (p) and base value (g) used by both parties to generate the shared keys.

Both parties then exchange the shared keys (S1 and S2) and use it with their own private key (P1 or P2) to derive the common secret (K)

When I look at samples that use ECDiffieHellmanCng to generate keys, I do not see an option to specify these "common" values anywhere. In our case, I was expecting both client and server to agree on p and g and then use those values with "ECDiffieHellmanCng" to generate the common shared key.

Ref: https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.ecdiffiehellmancng?view=netframework-4.7.2

I see Alice and Bob create new instance of ECDiffieHellmanCng - do they both internally use the same common values (p and g)?

2

There are 2 answers

0
bartonjs On BEST ANSWER

In your question you link to an article explaining (classic/IFC) Diffie-Hellman, which is secret = (g ^^ (alice * bob)) % p. You then mention ECDHE and ask about the ECDiffieHellman(Cng) class in .NET, which is about Elliptic Curve Diffie-Hellman... the ECC variant of the IFC (Integer Factorization Cryptography) algorithm.

(IFC)DH definitely has a bootstrapping problem of picking a good (g, p) combination, and not being tricked by a man in the middle. For TLS the server side of the connection gets to make up whatever (g, p) it wants and then tells the client what it picked, but the client can't really tell if it's being tricked. If you own both sides you can solve this problem by generating a quality group in the 2048-bit space, and sticking with it.

There is no support for (IFC) Diffie-Hellman provided in-box in .NET.

ECDH has a different set of parameters, which are collectively called "the curve". For a prime curve (the most common form) the parameters are the tuple (p, a, b, G, n, h) (though really n and h are computations from (p, a, b, G)), and then ECC math is defined on top of that. Once ECC math is defined, ECDH is secret = X-Coordinate((alice * bob) * G). ECC has the same pitfalls as (IFC)DH, choosing bad values for the parameters can let tricks be played on the other party. Because of the potential trickery, and the fact that the domain parameters are large, choices of domain parameters get standardized into "named curves". Two keys on the same curve, by definition, have the same set of domain parameters. In TLS you are only allowed to use the name (well, the Object Identifier value) of the curve. The server pretty much gets to choose what set of parameters, but for maximum interoperability usually only three curves are chosen from (as of 2018): secp256r1 (aka NIST P-256), secp384r1 (aka NIST P-384), and secp521r1 (aka NIST P-521).

ECDiffieHellmanCng defaults to using secp521r1, but you can control the curve in one of three different ways:

Setting ecdh.KeySize

Changing the KeySize value (setting it to any value other than what it currently holds) results in generating a key onto a curve of that size. This made total sense for Windows 7, 8, and 8.1... because Windows CNG only supported secp256r1, secp384r1, and secp521r1. So you can set KeySize to any of { 256, 384, 521 }.

using (ECDiffieHellman ecdh = ECDiffieHellman.Create())
{
    ecdh.KeySize = 384;
    ...
}

Creating it that way

Windows 10 added support for more curves, and the sizes became ambiguous. Does 256 mean secp256r1 or brainpoolp256r1 (or brainpoolp256t1, numsp256t1, secp256k1, ...)? Okay, it means secp256r1, and more complicated API exists.

The ECDiffieHellman.Create factory has an overload (.NET Core 2.1+, .NET Framework 4.7+) which accepts an ECCurve. So another way to create a curve over secp384r1 would be

using (ECDiffieHellman ecdh = ECDiffieHellman.Create(ECCurve.NamedCurves.nistP384))
{
    ...
}

It can still be set later

Maybe you're using DI and can't use the factory nicely. Well, you can use the GenerateKey method (.NET Core 2.1+, .NET Framework 4.7+) to achieve the same results

using (ECDiffieHellman ecdh = ECDiffieHellman.Create())
{
    ecdh.GenerateKey(ECCurve.NamedCurves.nistP384);
    ...
}

There are other ways of getting ECCurve values, such as ECCurve.CreateFromValue("1.3.132.0.34") or just manually building it from (p, a, b, G = (Gx, Gy), n, h).

2
kelalaka On
  • GF(q) denote the finite field with q elements
  • p is a base point

Yes, they must use same basepoint and same Elliptic Curve E over a Field Fq. these are public.