从文件导入 CNG ECC 公/私钥

6

我已经试图寻找导入ECC密钥的方法很长一段时间,无论通过任何方式。我尝试从Windows证书存储、.p12文件和PKCS#8 OpenSSL密钥文件中访问ECC证书,但都没有成功。

其中我尝试的一种方法是:

StreamReader fs = new StreamReader("key.pem");
String key = fs.ReadToEnd();
byte[] tempkey = System.Text.Encoding.ASCII.GetBytes(key);
CngKey cngKey = CngKey.Import(tempkey, CngKeyBlobFormat.Pkcs8PrivateBlob);

但是没有提供描述性错误消息,只有最后一行要么具有无效参数,要么像上面的代码一样出现了“在编码或解码操作期间发生错误”的错误。

我正在使用 MSDN 的 示例程序 进行 ECDH,并对其进行了修改以使用 AES 的 GCM 模式。所有这些都很好,直到我尝试使用预生成的 ECC 密钥而不是 Microsoft 示例中默认在运行时创建的密钥为止。我已经随机尝试了所有的 CngKeyBlobFormat,但坦率地说,我无法很好地调试它,因为我不知道这些特定格式在原始数据中看起来像什么。

我的密钥采用以下格式,但我愿意使用任何可行的格式(.p12,Microsoft Store,PKCS#8 等)。

key.pem

-----BEGIN EC PARAMETERS-----
##############################
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
##############################
-----END EC PRIVATE KEY-----

资源

MSDN API 和示例:ECDiffieHellmanCng 类

MSDN API:CngKey 类

MSDN 博客:AES GCM 模式

OpenSSL - 创建 ECC 密钥

2个回答

2
  1. 使用OpenSSL生成PEM格式的ECC密钥:
& openssl ecparam -name "secp521r1" -genkey -param_enc explicit -out ".\private.key"

文件的内容如下:
-----BEGIN EC PARAMETERS-----
MIIBwwIBATBNBgcqhkjOPQEBAkIB////////////////////////////////////
//////////////////////////////////////////////////8wgZ8EQgH/////
////////////////////////////////////////////////////////////////
/////////////////ARCAFGVPrlhjhyaH5KaIaC2hUDuotpyW5mzFfO4tImRjvEJ
4VYZOVHsfpN7FlLAvTuxvwc1c9+IPSw08e9FH9RrUD8AAxUA0J6IACkcuFOWzGcX
OTKEqqDaZLoEgYUEAMaFjga3BATpzZ4+y2YjlbRCnGSBOQU/tSH4KK9ga009uqFL
Xnfv51ko/h3BJ6L/qN4zSLPBhWpCm/l+fjHC5b1mARg5KWp4mjvABFyKX7QsfRvZ
mPVESVebRGgXr70XJz5mLJfucple9CZAxVC5AT+tB2E1PHCGonLCQIi+lHaf0WZQ
AkIB///////////////////////////////////////////6UYaHg78vlmt/zAFI
9wml0Du1ybiJnEeuu2+3HpE4ZAkCAQE=
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MIICngIBAQRCABEwHYVa214LUODzm4BXWkBFSTBDU/N/nNwTB/mAP1Khpn0vd0QH
b/8BrfMbUYzzWXtXsvRvxPzKB2Sc6s7JC8CfoIIBxzCCAcMCAQEwTQYHKoZIzj0B
AQJCAf//////////////////////////////////////////////////////////
////////////////////////////MIGfBEIB////////////////////////////
//////////////////////////////////////////////////////////wEQgBR
lT65YY4cmh+SmiGgtoVA7qLacluZsxXzuLSJkY7xCeFWGTlR7H6TexZSwL07sb8H
NXPfiD0sNPHvRR/Ua1A/AAMVANCeiAApHLhTlsxnFzkyhKqg2mS6BIGFBADGhY4G
twQE6c2ePstmI5W0QpxkgTkFP7Uh+CivYGtNPbqhS1537+dZKP4dwSei/6jeM0iz
wYVqQpv5fn4xwuW9ZgEYOSlqeJo7wARcil+0LH0b2Zj1RElXm0RoF6+9Fyc+ZiyX
7nKZXvQmQMVQuQE/rQdhNTxwhqJywkCIvpR2n9FmUAJCAf//////////////////
////////////////////////+lGGh4O/L5Zrf8wBSPcJpdA7tcm4iZxHrrtvtx6R
OGQJAgEBoYGJA4GGAAQAIzBvnlURokMqtUyYrOJ5Kd1Mz0/7xGXkbhOR4ReIt9mt
hsL2tK3PQWj/j28IEajPRbVtxxA7McxQfayY9vUKdF8A6+qkOBCji82nKwKyu2+9
7l5FowAW05SdWRgJnqHU5ENf2h3Hje5UH1AidcpDZgTDuCV263PRKCUqUwX+LRN3
t7Y=
-----END EC PRIVATE KEY-----

哎呀,我误发布了一把私钥——这是生成的密钥,并未被使用 :-)

该文件以SEC.1格式存储了密钥,但Cng无法导入。因此,我们将其转换为PKCS#8格式:

& openssl pkcs8 -topk8 -inform pem -in ".\private.key" -outform PEM -nocrypt -out ".\private_plain.p8"

以下是PKCS#8内容:

-----BEGIN PRIVATE KEY-----
MIICsAIBADCCAdAGByqGSM49AgEwggHDAgEBME0GByqGSM49AQECQgH/////////
////////////////////////////////////////////////////////////////
/////////////zCBnwRCAf//////////////////////////////////////////
///////////////////////////////////////////8BEIAUZU+uWGOHJofkpoh
oLaFQO6i2nJbmbMV87i0iZGO8QnhVhk5Uex+k3sWUsC9O7G/BzVz34g9LDTx70Uf
1GtQPwADFQDQnogAKRy4U5bMZxc5MoSqoNpkugSBhQQAxoWOBrcEBOnNnj7LZiOV
tEKcZIE5BT+1Ifgor2BrTT26oUted+/nWSj+HcEnov+o3jNIs8GFakKb+X5+McLl
vWYBGDkpaniaO8AEXIpftCx9G9mY9URJV5tEaBevvRcnPmYsl+5ymV70JkDFULkB
P60HYTU8cIaicsJAiL6Udp/RZlACQgH/////////////////////////////////
//////////pRhoeDvy+Wa3/MAUj3CaXQO7XJuImcR667b7cekThkCQIBAQSB1jCB
0wIBAQRCABEwHYVa214LUODzm4BXWkBFSTBDU/N/nNwTB/mAP1Khpn0vd0QHb/8B
rfMbUYzzWXtXsvRvxPzKB2Sc6s7JC8CfoYGJA4GGAAQAIzBvnlURokMqtUyYrOJ5
Kd1Mz0/7xGXkbhOR4ReIt9mthsL2tK3PQWj/j28IEajPRbVtxxA7McxQfayY9vUK
dF8A6+qkOBCji82nKwKyu2+97l5FowAW05SdWRgJnqHU5ENf2h3Hje5UH1AidcpD
ZgTDuCV263PRKCUqUwX+LRN3t7Y=
-----END PRIVATE KEY-----

未读取PKCS#8并导入密钥:

$bytes = [Convert]::FromBase64String(
  [String]::Join(
    [String]::Empty, 
    ([IO.File]::ReadAllLines(".\private_plain.p8") `
      | Where-Object { $_.StartsWith("-") -ne $true })));

$key = [System.Security.Cryptography.CngKey]::Import(
  $bytes, 
  [System.Security.Cryptography.CngKeyBlobFormat]::Pkcs8PrivateBlob);

Write-Host $key.Algorithm

0

虽然这可能不是唯一的问题,但你不能简单地将 PEM 文件 ASCII 编码,然后将其视为 PKCS#8 编码的 blob。PKCS#8 在 ASN.1 中指定,通常是 BER/DER 编码的。PEM base 64 对此二进制编码进行编码,然后在 base 64 周围放置标题和页脚以指示编码的数据类型。

请注意,可能需要跳过编码参数。希望这些参数存在于私钥的编码中。


抱歉晚了,用这种方式导入CNG密钥可能仍然非常棘手 - 如果不起作用,您可能需要自己解码PEM格式(以及PKCS#8格式中的密钥部分)。 - Maarten Bodewes

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