为什么 ECDiffieHellmanP256 与 ECDsaCng.SignData() 一起工作?

问题描述

在 .NET 中,有两种 P256 曲线算法可以与 CngKey 一起使用:

令我困惑的是,似乎可以使用 Cngalgorithm.ECDiffieHellmanP256 创建签名。

示例代码

// create private key and data
var privateKey = CngKey.Create(Cngalgorithm.ECDiffieHellmanP256);
Console.WriteLine($"privateKey: {privateKey.Algorithm} {privateKey.KeyUsage}");

// sign data
var data = new byte[] { 1,2,3 };
byte[] signature;
using (var dsa = new ECDsaCng(privateKey))
{
    signature = dsa.SignData(data);
    Console.WriteLine($"Signature: {Convert.ToBase64String(signature)}");
}

// create stand-alone public key,just to be sure this is working as expected
var publicKeyBlob = privateKey.Export(CngKeyBlobFormat.EccpublicBlob);
var publicKey = CngKey.Import(publicKeyBlob,CngKeyBlobFormat.EccpublicBlob);
Console.WriteLine($"Public key: {publicKey.Algorithm} {publicKey.KeyUsage} {Convert.ToBase64String(publicKeyBlob)}");

// verify signature
using (var dsa = new ECDsaCng(publicKey))
{
    var verified = dsa.VerifyData(data,signature);
    Console.WriteLine($"Verified: {verified}");
}

输出

privateKey: ECDH_P256 AllUsages
Signature: I1+Bapp8jxC7hUbTQTDTqscR9uoM/bo0OG1WVxgJUWYWq6jmW38a51JnuVRMXMKHosloClt+AlrjiL/hG7TaqQ==
Public key: ECDH_P256 AllUsages RUNLMSAAAAC9amJDYvEJF+6HXyIhHoOiyUyu3grcH7leeuiOjMAiGbKwFoLssph+Ncpy35g2dSHvNgaU11AavV/gAkPH6UPm
Verified: True

只是为了显示相似性;如果我改用 Cngalgorithm.ECDsaP256

privateKey: ECDSA_P256 AllUsages
Signature: meQ2ywrGWCOnVCaa0bm74Z0Sj37epzSJ5bz/b0x31hGvTn8zk3hcRt5If1+r1PgoR0A1cmSBDF4QUkY0UQjPhw==
Public key: ECDSA_P256 AllUsages RUNTMSAAAADfyG3BtOqGrI63Kh+FPy6V0EmpVX/4mBSbDQ+RxEerlaQCIVq0STrl87D+Re1b+iZ7a8/+S74cHrFNILqYqLXi
Verified: True

请注意,反过来执行此操作 - 尝试使用 DSA 密钥创建 DH 对象 - 使用 new ECDiffieHellmanCng(CngKey.Create(Cngalgorithm.ECDsaP256)) 会导致:

ArgumentException: 与 ECDiffieHellmanCng 算法一起使用的密钥必须具有 ECDiffieHellman 算法组。参数名称:key

这意味着密钥类型之间存在某种差异。


以这种方式使用 ECDH 密钥是否真的安全(例如:此代码是否生成安全数字签名)?

使用 ECDSA 密钥而不使用 ECDH 密钥有什么好处(除非您明确不想允许密钥交换)?

解决方法

ECDiffieHellmanCng(CngKey.Create(CngAlgorithm.ECDsaP256))
这意味着密钥类型之间存在某种差异。

当您尝试在运行时使用 initialize ECDiffieHellmanCng CngKey 验证您提供的 CngKey 是特定算法列表的一部分时,MSDN 调用它们是 Elliptic Curve Diffie-Hellman (ECDH) algorithm group,它有四个有效的算法组名称 ECDHECDiffieHellmanECDiffieHellmanCngSystem.Security.Cryptography.ECDiffieHellmanCng,它们 all refer to the same implementation

当您使用 CngKey 创建 CngAlgorithm.ECDiffieHellmanP256 时,您将获得一个有效的 ECDH 密钥,其 AlgorithmGroup 为 ECDH,它可作为参数来创建 { {1}} 执行密钥交换。

但是,当您使用 ECDiffieHellmanCng 创建 CngKey 时,您会得到一个 AlgorithmGroup 为 CngAlgorithm.ECDsaP256 的密钥,不是一个有效的 AlgorithmGroup 来创建 { {1}} 执行密钥交换。

ECDSA 算法组用于表示 ECDiffieHellmanCng 的目的是执行椭圆曲线数字签名,并且明确执行密钥交换。此密钥不能与 ECDSA 一起使用来执行密钥交换,因为它很可能不包含足够、有效和/或安全的信息来与另一方进行密钥交换。

您可以使用 CngKey 和 ECDH 和 ECDSA ECDiffieHellmanCng 构建有效的 EC 签名,因为它们都包含足够、有效或安全的信息来构建和执行数字签名。但是,由于 MSDN 在执行密钥交换时创建的限制以及 ECDsaCng 的实现,除了可能丢失的信息/格式之外,ECDSA CngKey 密钥会阻止正确计算,因此反过来就不一样了密钥交换。

我们可以用一个简短的测试脚本来验证这些信息

ECDiffieHellmanCng

我们可以看到 ECDH 包含正确的参数和信息来构建 ECDSA 曲线和 ECDH 曲线,但是 ECDSA Key 只能与 ECDSA 曲线(CngKey)一起使用,因为它的目的是为了执行签名。

使用 ECDSA 密钥而不使用 ECDH 密钥有什么好处(除非您明确不想允许密钥交换)?

以这种方式使用 ECDH 密钥是否真的安全(例如:此代码是否生成安全数字签名)?

我在 ECDSA vs ECDH 上找到了一篇文章,其中涵盖了两者之间的细微差别,甚至在上面提供了一些关于为什么这些键执行不同功能的信息。这是我认为会立即有用的摘录。

“ECDH 是一种密钥交换方法,两方可以使用它通过不安全的通信通道协商安全密钥。它是 DH(Diffie-Hellman)密钥交换方法的变体。ECDH 代表椭圆曲线 Diffie-Hellman . 然而ECDH只是一种方法,也就是说你不能只用在一个特定的椭圆曲线上,你可以用在许多不同的椭圆曲线上。

ECDSA 是一种签名算法,可用于对一段数据进行签名,对数据进行任何更改都会导致签名验证失败,但攻击者将无法正确地对数据重新签名。这样的变化。它是 DSA(数字签名算法)的变体。 ECDSA 代表椭圆曲线数字签名算法。此外,ECDSA 仅描述了一种可用于不同椭圆曲线的方法。” -Mecki