.NET Core 3.0 引入了十几个新的 API,用于以不同格式导入和导出 RSA 密钥。 其中许多是另一个 API 略有不同的变体,但它们对于处理来自其他使用编码密钥的系统的私钥和公钥非常有用。
RSA 密钥可以采用多种不同的方式进行编码,具体取决于密钥是公开的还是私有的,还是受密码保护。 不同的程序将以不同的格式导入或导出 RSA 密钥等。
通常 RSA 密钥可以被描述为“PEM
”编码,但这对于密钥的实际编码方式已经是模棱两可了。 PEM 采用以下形式:
-----BEGIN LABEL-----
content
-----END LABEL-----
标签之间的内容是 base64
编码的。 最常见的可能是 BEGIN RSA PRIVATE KEY
,它经常用于 nginx、apache
等 Web 服务器中:
-----BEGIN RSA PRIVATE KEY-----
MII...
-----END RSA PRIVATE KEY-----
base64
编码的文本是来自 PKCS#1
规范的 RSAPrivateKey
,它只是构成 RSA 密钥的整数的 ASN.1
序列。 对应的 .NET Core 3 API 是 ImportRSAPrivateKey
,或其重载之一。 如果您的密钥是“PEM
”编码的,您需要在标签 BEGIN
和 END
标头之间找到 base64
文本,对其进行 base64
解码,然后传递给 ImportRSAPrivateKey
。 目前有一个 API 提案可以让阅读 PEM
文件更容易。 如果您的私钥是 DER
编码的,那么这仅意味着您可以将内容作为字节直接读取到 ImportRSAPrivateKey
中。
这是一个例子:
var privateKey = "MII..."; //Get just the base64 content.
var privateKeyBytes = Convert.FromBase64String(privateKey);
using var rsa = RSA.Create();
rsa.ImportRSAPrivateKey(privateKeyBytes, out _);
使用 openssl
时,openssl rsa
命令通常会输出 RSAPrivateKey PKCS#1
私钥,例如 openssl genrsa
。
私钥的另一种格式是 PKCS#8
。与 PKCS#1
中的 RSAPrivateKey
不同,PKCS#8
编码的密钥可以表示除 RSA
之外的其他类型的密钥。因此,PKCS#8
密钥的 PEM
标签是“BEGIN PRIVATE KEY
”(注意那里没有“RSA
”)。密钥本身包含一个 AlgorithmIdentifer
,说明它是什么类型的密钥。
PKCS#8
密钥也可以被加密保护。在这种情况下,PEM
标签将是“BEGIN ENCRYPTED PRIVATE KEY
”。
.NET Core 3 具有这两种 API。未加密的 PKCS#8
密钥可以使用 ImportPkcs8PrivateKey
导入,加密的 PKCS#8
密钥可以使用 ImportEncryptedPkcs8PrivateKey
导入。它们的用法类似于 ImportRSAPrivateKey
。
公钥具有类似的行为。带有“BEGIN RSA PUBLIC KEY
”标签的 PEM
编码密钥应使用 ImportRSAPublicKey
。与私钥一样,公钥也有一种自描述密钥算法的格式,称为主题公钥信息 (SPKI
),在 X509
和许多其他标准中大量使用。 PEM
标头是“BEGIN PUBLIC KEY
”,ImportSubjectPublicKeyInfo
是导入这些的正确方法。
所有这些 API 也都有自己的导出版本,因此如果您尝试将 .NET Core 3 中的密钥导出为特定格式,则需要使用正确的导出 API。
总结每个 PEM
标签和 API
配对:
- “BEGIN RSA PRIVATE KEY” =>
RSA.ImportRSAPrivateKey
- “BEGIN PRIVATE KEY” =>
RSA.ImportPkcs8PrivateKey
- “BEGIN ENCRYPTED PRIVATE KEY” =>
RSA.ImportEncryptedPkcs8PrivateKey
- “BEGIN RSA PUBLIC KEY” =>
RSA.ImportRSAPublicKey
- “BEGIN PUBLIC KEY” =>
RSA.ImportSubjectPublicKeyInfo
openssl
的一个问题是注意密钥格式的输出。 openssl
的一个很常见的任务是“给定这个 PEM
编码的 RSA
私钥,给我一个 PEM
编码的公钥”,通常这样完成就足够了:
openssl rsa -in key.pem -pubout
即使 key.pem
是 PKCS#1 RSAPrivateKey(“BEGIN RSA PRIVATE KEY”)
,-pubout
选项也会输出 SPKI(“BEGIN PUBLIC KEY”)
,而不是 RSAPublicKey(“BEGIN RSA PUBLIC KEY”)
。 为此,您需要使用 -RSAPublicKey_out
而不是 -pubout
。openssl pkey
命令通常还会为您提供 PKCS#8
或 SPKI
格式的密钥。