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.
I see Alice and Bob create new instance of ECDiffieHellmanCng - do they both internally use the same common values (p and g)?
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 reallyn
andh
are computations from(p, a, b, G)
), and then ECC math is defined on top of that. Once ECC math is defined, ECDH issecret = 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), andsecp521r1
(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
, andsecp521r1
. So you can set KeySize to any of { 256, 384, 521 }.Creating it that way
Windows 10 added support for more curves, and the sizes became ambiguous. Does 256 mean
secp256r1
orbrainpoolp256r1
(orbrainpoolp256t1
,numsp256t1
,secp256k1
, ...)? Okay, it meanssecp256r1
, and more complicated API exists.The
ECDiffieHellman.Create
factory has an overload (.NET Core 2.1+, .NET Framework 4.7+) which accepts anECCurve
. So another way to create a curve oversecp384r1
would beIt 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 resultsThere 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)
.