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

6

我需要将一个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中?


编辑

Base64编码中的密钥符合以下格式:

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

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

1
你可以尝试使用 Pkcs8PrivateBlob 格式吗?嗯,我相信这会起作用,请让我回答是否如此。 - Maarten Bodewes
@MaartenBodewes 看起来那个方法奏效了! - makerofthings7
1个回答

3
你的PEM / ASCII装甲钥匙(标题,尾巴和base 64)是使用RFC 5915:椭圆曲线私钥结构中描述的格式进行编码的。这最初是由高效密码组(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 特定结构。同时请参阅我的问题 这里。它无法与上述结构一起使用。

1
我做了一个修改,但没有更新问题,就是我运行了第二个OpenSSL命令,然后导入了那个私钥输出。"openssl pkcs8 -topk8 -nocrypt -in eckey.pem -out ec2.pem"。不确定这是否会改变答案,因为ASN1与您最初观察到的可能不同。 - makerofthings7
PKCS8(以十六进制表示)是否为ASN1格式?我尝试使用https://lapo.it/asn1js/进行解码,但似乎没有成功... - makerofthings7
1
@LamonteCristo 你认为我的解码是从哪里来的?不过你需要去掉头部/尾部。否则,只需使用PEM格式(默认)的openssl asn1parse即可。 - Maarten Bodewes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接