为什么 ECDiffieHellman P256 使用 ECDsaCng.SignData()?

Why does ECDiffieHellmanP256 work with 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: Keys used with the ECDiffieHellmanCng algorithm must have an algorithm group of ECDiffieHellman.Parameter name: key

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


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

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

ECDiffieHellmanCng(CngKey.Create(CngAlgorithm.ECDsaP256))
This implies there is some kind of difference between the key types.

当您尝试 initialize an ECDiffieHellmanCng using a CngKey during runtime is verifies that the CngKey that you provided is part of a particular list of algorithms, MSDN calls them the Elliptic Curve Diffie-Hellman (ECDH) algorithm group, which has four valid AlgorithmGroup names ECDH,ECDiffieHellman,ECDiffieHellmanCng, and System.Security.Cryptography.ECDiffieHellmanCng, which all refer to the same implementation.

当您使用 CngAlgorithm.ECDiffieHellmanP256 创建一个 CngKey 时,您会得到一个有效的 ECDH 密钥,其 AlgorithmGroup 是 ECDH,它作为用于创建 ECDiffieHellmanCng 以执行密钥交换的参数。

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

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

您可以使用 ECDsaCng 与 ECDH 和 ECDSA CngKey 构建有效的 EC 签名,因为它们都包含足够的、有效的或安全的信息来构建和执行数字签名。然而,由于 MSDN 在执行密钥交换时创建的限制,相反的情况是不一样的,他们实施 ECDiffieHellmanCng,除了可能丢失 information/format 之外,ECDSA CngKey 密钥阻止了正确计算密钥交换。

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

CngKey ECDHKey = CngKey.Create(CngAlgorithm.ECDiffieHellmanP256);

CngKey ECDSAKey = CngKey.Create(CngAlgorithm.ECDsaP256);

Console.WriteLine(ECDHKey.Algorithm);
Console.WriteLine(ECDHKey.AlgorithmGroup);

Console.WriteLine(ECDSAKey.Algorithm);
Console.WriteLine(ECDSAKey.AlgorithmGroup);

using var ECDH = new ECDiffieHellmanCng(key: ECDHKey);

Console.WriteLine($"Signature Algorithm: {ECDH.SignatureAlgorithm}");

var ECDSA = new ECDsaCng(key: ECDHKey);

Console.WriteLine($"Signature Algorithm: {ECDSA.SignatureAlgorithm}");

ECDSA.Dispose();

ECDSA = new ECDsaCng(key: ECDSAKey);

Console.WriteLine($"Signature Algorithm: {ECDSA.SignatureAlgorithm}");

ECDSA.Dispose();

// outputs
ECDH_P256
ECDH
ECDSA_P256
ECDSA
Signature Algorithm: 
Signature Algorithm: ECDsa
Signature Algorithm: ECDsa

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

Is there a benefit to using ECDSA keys over ECDH keys (other than if you explicitly didn't want to allow key exchange)?

Is it actually safe to use ECDH keys in this way (eg: is this code generating a secure digital signature)?

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

"ECDH is a key exchange method that two parties can use to negotiate a secure key over an insecure communication channel. It's a variation of the DH (Diffie-Hellman) key exchange method. ECDH stands for Elliptic-curve Diffie–Hellman. Yet ECDH is just a method, that means you cannot just use it with one specific elliptic curve, you can use it with many different elliptic curves.

ECDSA is a signature algorithm that can be used to sign a piece of data in such a way, that any change to the data would cause signature validation to fail, yet an attacker would not be able to correctly re-sign data after such a change. It is a variation of DSA (Digital Signature Algorithm). ECDSA stands for Elliptic Curve Digital Signature Algorithm. Also ECDSA only describes a method which can be used with different elliptic curves." -Mecki