如何将 OpenSSL ECDSA 密钥加载到 C# 中?

Posted

技术标签:

【中文标题】如何将 OpenSSL ECDSA 密钥加载到 C# 中?【英文标题】:How do I load an OpenSSL ECDSA key into C#? 【发布时间】:2017-04-01 17:59:33 【问题描述】:

我需要将 OpenSSL 私钥加载到基于 C# 的应用程序中。

我用来生成密钥的命令是:

$ openssl ecparam -name prime256v1 -genkey -noout -out eckey.pem
$ openssl ec -in eckey.pem
read EC key
writing EC key
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIMiuwhV+yI0od5E5pSU6ZGuUcflskYD4urONi1g3G7EPoAoGCCqGSM49
AwEHoUQDQgAEe+C/M6u171u5CcL2SQKuFEb+OIEibjw1rx+S5LK4gNNePlDV/bqu
Ofjwc5JDqXA07shbfHNIPUn6Hum7qdiUKg==
-----END EC PRIVATE KEY-----

openssl pkcs8 -topk8 -nocrypt -in eckey.pem -out ec2.pem
cat ec2.pem
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgyK7CFX7IjSh3kTml
JTpka5Rx+WyRgPi6s42LWDcbsQ+hRANCAAR74L8zq7XvW7kJwvZJAq4URv44gSJu
PDWvH5LksriA014+UNX9uq45+PBzkkOpcDTuyFt8c0g9Sfoe6bup2JQq
-----END PRIVATE KEY-----

我正在使用的 C# 代码

   string privKeyPKCS8 = @"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgyK7CFX7IjSh3kTmlJTpka5Rx+WyRgPi6s42LWDcbsQ+hRANCAAR74L8zq7XvW7kJwvZJAq4URv44gSJuPDWvH5LksriA014+UNX9uq45+PBzkkOpcDTuyFt8c0g9Sfoe6bup2JQq";
  byte[] privKeyBytes8 = Convert.FromBase64String(privKeyPKCS8);//Encoding.UTF8.GetBytes(privKeyEcc);

 var pubCNG = CngKey.Import(privKeyBytes, CngKeyBlobFormat.EccPrivateBlob);

将基于 EC 的密钥加载到 CngKey 中的正确方法是什么?


编辑

base 64 编码中的密钥遵循以下格式:

ECPrivateKey ::= SEQUENCE 
    version        INTEGER  ecPrivkeyVer1(1)  (ecPrivkeyVer1),
    privateKey     OCTET STRING,
    parameters [0] ECParameters  NamedCurve  OPTIONAL,
    publicKey  [1] BIT STRING OPTIONAL

使用 secp256r1 曲线和未压缩点格式的公钥。

【问题讨论】:

你可以试试Pkcs8PrivateBlob 格式吗?嗯,非常确信这会起作用,如果是这样,请让我回答。 @MaartenBodewes 看起来成功了! 【参考方案1】:

您的密钥 PEM / ASCII 装甲(页眉、页脚和基数 64)使用RFC 5915: Elliptic Curve Private Key Structure 中描述的格式进行编码。这是由高效密码学标准组 (SECG) 首次指定的,这也是命名曲线 secp256r1 的名称来源。 Microsoft CNG 支持该曲线。

ECPrivateKey ::= SEQUENCE 
    version        INTEGER  ecPrivkeyVer1(1)  (ecPrivkeyVer1),
    privateKey     OCTET STRING,
    parameters [0] ECParameters  NamedCurve  OPTIONAL,
    publicKey  [1] BIT STRING OPTIONAL

您首先需要使用(更新的)问题中的命令将此“原始”EC 私钥结构转换为 PKCS#8 结构:

openssl pkcs8 -topk8 -nocrypt -in eckey.pem -out ec2.pem

得到:

SEQUENCE(3 elem)
  INTEGER 0 # version of PKCS#8 structure
  SEQUENCE (2 elem)
    OBJECT IDENTIFIER 1.2.840.10045.2.1 # it's an EC key)
    OBJECT IDENTIFIER 1.2.840.10045.3.1.7 # it's secp256r1
  OCTET STRING (1 elem) # the key structure
    SEQUENCE (3 elem)
      INTEGER 1 # version 
      OCTET STRING (32 byte) # private key value (removed)
      [1] (1 elem)
        BIT STRING (520 bit) # public key value (removed)

生成的结构并没有那么不同,您所看到的实际上与初始结构相同。除了 PKCS#8 结构具有用于指定键类型的对象标识符 (OID) 和前面的曲线本身的 OID,而您的键后面只有 OID 作为参数。两者都在 BIT STRING 中携带(可选)公钥值。

所以解码器识别出这种类型并返回EC私钥。


您使用的EccPrivateBlob 需要Microsoft specific structure。另请参阅我的问题here。它不适用于上述结构。

【讨论】:

我做了一个更改,但没有更新问题,是我运行了第二个 OpenSSL 命令,然后导入了该私钥输出。 openssl pkcs8 -topk8 -nocrypt -in eckey.pem -out ec2.pem。不确定这是否会改变答案 /b/c ASN1 可能与您最初观察到的不同。 PKCS8(以上十六进制)是 ASN1 格式吗?我尝试使用lapo.it/asn1js 对其进行解码,但它似乎不起作用...... @LamonteCristo 你认为我的解码是从哪里来的?你需要去掉页眉/页脚。否则,只需使用 PEM 格式的openssl asn1parse(默认)。

以上是关于如何将 OpenSSL ECDSA 密钥加载到 C# 中?的主要内容,如果未能解决你的问题,请参考以下文章

组合 ECDSA 密钥

java - 如何在java中生成与openssl生成的相同类型的ecdsa密钥对?

无法从 Java 读取 OpenSSL 生成的 ECDSA 密钥:InvalidKeySpecException

SSL/TLS深度解析--OpenSSL 生成自签证书

OpenSSL DER ECDSA 编码错误

如何使用 C#.NET 的 PEM 文件中的 P-256 密钥计算 ECDSA 签名?