使用 ECDiffieHellmanCng 交换密钥

Using ECDiffieHellmanCng to exchange keys

我们计划使用 ECDHE 算法在客户端和服务器之间交换密钥,以便双方可以派生出一个共同的密钥来加密消息

根据我所读到的内容,要使用 ECDHE 算法,双方(客户端和服务器)应该首先就一对 "common" 值 (p, g) 达成一致。然后每一方将使用私钥生成共享密钥,即客户端使用私钥(P1)生成共享密钥(S1),服务器使用私钥(P2)生成共享密钥(S2) 参考:[https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange#Description]

这里的普通值是指普通的油漆。这些实际上是双方用来生成共享密钥的 mod 值(p)和基值(g)。

然后双方交换共享密钥(S1 和 S2)并将其与自己的私钥(P1 或 P2)一起使用以导出公共秘密 (K)

当我查看使用 ECDiffieHellmanCng 生成密钥的示例时,我没有在任何地方看到指定这些 "common" 值的选项。在我们的例子中,我期望客户端和服务器就 p 和 g 达成一致,然后将这些值与 "ECDiffieHellmanCng" 一起使用来生成公共共享密钥。

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

我看到 Alice 和 Bob 创建了 ECDiffieHellmanCng 的新实例 - 他们都在内部使用相同的公共值(p 和 g)吗?

  • GF(q)表示有q个元素的有限域
  • p是一个基点

是的,他们必须在 Field Fq 上使用相同的基点和相同的椭圆曲线 E。这些是 public.

在您的问题中,您 link 阅读了一篇解释 (classic/IFC) Diffie-Hellman 的文章,即 secret = (g ^^ (alice * bob)) % p。然后您提到 ECDHE 并询问 .NET 中的 ECDiffieHellman(Cng) class,这是关于椭圆曲线 Diffie-Hellman 的......IFC(整数分解密码术)算法的 ECC 变体。

(IFC)DH 肯定存在选择好的 (g, p) 组合的自举问题,并且不会被中间人欺骗。对于 TLS,连接的服务器端可以组成它想要的 (g, p) ,然后告诉客户端它选择了什么,但客户端无法真正判断它是否被欺骗了。如果你拥有双方,你可以通过在 2048 位 space 中生成一个质量组并坚持下去来解决这个问题。

不支持 .NET 中自带的 (IFC) Diffie-Hellman。

ECDH有一组不同的参数,统称为"the curve"。对于素数曲线(最常见的形式),参数是元组 (p, a, b, G, n, h)(尽管实际上 nh(p, a, b, G) 的计算),然后是 ECC math is defined on top of that.一旦定义了 ECC 数学,ECDH 就是 secret = X-Coordinate((alice * bob) * G)。 ECC 和 (IFC)DH 有同样的陷阱,参数选择错误的值可以让对方玩花样。由于潜在的诡计,以及域参数很大的事实,域参数的选择被标准化为 "named curves"。根据定义,同一条曲线上的两个键具有相同的域参数集。在 TLS 中,您只能使用曲线的名称(也就是对象标识符值)。服务器几乎可以选择一组参数,但为了获得最大的互操作性,通常只选择三个曲线(截至 2018 年):secp256r1(又名 NIST P-256),secp384r1(又名 NIST P-384)和 secp521r1(又名 NIST P-521)。

ECDiffieHellmanCng 默认使用 secp521r1,但您可以通过三种不同的方式之一控制曲线:

设置ecdh.KeySize

更改 KeySize 值(将其设置为当前值以外的任何值)会导致在该大小的曲线上生成密钥。这对 Windows 7、8 和 8.1 完全有意义...因为 Windows CNG 仅支持 secp256r1secp384r1secp521r1。所以你可以将 KeySize 设置为 { 256, 384, 521 } 中的任意一个。

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

以这种方式创建它

Windows10 增加了对更多曲线的支持,并且尺寸变得不明确。 256 是否表示 secp256r1brainpoolp256r1(或 brainpoolp256t1numsp256t1secp256k1、...)?好吧,就是secp256r1,还有更复杂的API存在

ECDiffieHellman.Create 工厂有一个重载(.NET Core 2.1+、.NET Framework 4.7+),它接受 ECCurve。因此,另一种在 secp384r1 上创建曲线的方法是

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

以后还可以设置

可能你正在使用 DI 而不能很好地使用工厂。那么,您可以使用 GenerateKey 方法(.NET Core 2.1+、.NET Framework 4.7+)来实现相同的结果

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

还有其他获取 ECCurve 值的方法,例如 ECCurve.CreateFromValue("1.3.132.0.34") 或仅从 (p, a, b, G = (Gx, Gy), n, h) 手动构建它。