在.NET Core 中导入和导出 RSA 密钥格式

.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”编码的,您需要在标签 BEGINEND 标头之间找到 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 配对:

  1. “BEGIN RSA PRIVATE KEY” => RSA.ImportRSAPrivateKey
  2. “BEGIN PRIVATE KEY” => RSA.ImportPkcs8PrivateKey
  3. “BEGIN ENCRYPTED PRIVATE KEY” => RSA.ImportEncryptedPkcs8PrivateKey
  4. “BEGIN RSA PUBLIC KEY” => RSA.ImportRSAPublicKey
  5. “BEGIN PUBLIC KEY” => RSA.ImportSubjectPublicKeyInfo

openssl 的一个问题是注意密钥格式的输出。 openssl 的一个很常见的任务是“给定这个 PEM 编码的 RSA 私钥,给我一个 PEM 编码的公钥”,通常这样完成就足够了:

openssl rsa -in key.pem -pubout

即使 key.pemPKCS#1 RSAPrivateKey(“BEGIN RSA PRIVATE KEY”)-pubout 选项也会输出 SPKI(“BEGIN PUBLIC KEY”),而不是 RSAPublicKey(“BEGIN RSA PUBLIC KEY”)。 为此,您需要使用 -RSAPublicKey_out 而不是 -pubout。openssl pkey 命令通常还会为您提供 PKCS#8SPKI 格式的密钥。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Java和.NETRSA密钥的存储格式不同,因此需要进行格式转换才能实现密钥的交换。下面是Java和.NET之间RSA密钥格式转换的详细步骤。 1. 将Java的公钥格式转换为.NET的公钥格式: Java的公钥格式为X.509证书格式,需要将其转换为XML格式。具体步骤如下: ``` KeyFactory keyFactory = KeyFactory.getInstance("RSA"); X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes); PublicKey publicKey = keyFactory.generatePublic(publicKeySpec); StringWriter sw = new StringWriter(); XmlWriter xw = XmlWriter.Create(sw); RSAParameters parameters = new RSAParameters(); parameters.Modulus = publicKey.getModulus().toByteArray(); parameters.Exponent = publicKey.getPublicExponent().toByteArray(); xw.WriteStartElement("RSAKeyValue"); xw.WriteElementString("Modulus", Convert.ToBase64String(parameters.Modulus)); xw.WriteElementString("Exponent", Convert.ToBase64String(parameters.Exponent)); xw.WriteEndElement(); xw.Flush(); ``` 2. 将Java的私钥格式转换为.NET的私钥格式: Java的私钥格式为PKCS#8格式,需要将其转换为XML格式。具体步骤如下: ``` KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes); PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec); StringWriter sw = new StringWriter(); XmlWriter xw = XmlWriter.Create(sw); RSAParameters parameters = new RSAParameters(); parameters.Modulus = privateKey.getModulus().toByteArray(); parameters.D = privateKey.getPrivateExponent().toByteArray(); parameters.P = privateKey instanceof RSAPrivateCrtKey ? ((RSAPrivateCrtKey)privateKey).getPrimeP().toByteArray() : null; parameters.Q = privateKey instanceof RSAPrivateCrtKey ? ((RSAPrivateCrtKey)privateKey).getPrimeQ().toByteArray() : null; parameters.DP = privateKey instanceof RSAPrivateCrtKey ? ((RSAPrivateCrtKey)privateKey).getPrimeExponentP().toByteArray() : null; parameters.DQ = privateKey instanceof RSAPrivateCrtKey ? ((RSAPrivateCrtKey)privateKey).getPrimeExponentQ().toByteArray() : null; parameters.InverseQ = privateKey instanceof RSAPrivateCrtKey ? ((RSAPrivateCrtKey)privateKey).getCrtCoefficient().toByteArray() : null; xw.WriteStartElement("RSAKeyValue"); xw.WriteElementString("Modulus", Convert.ToBase64String(parameters.Modulus)); xw.WriteElementString("Exponent", Convert.ToBase64String(privateKey.getPublicExponent().toByteArray())); xw.WriteElementString("D", Convert.ToBase64String(parameters.D)); xw.WriteElementString("P", Convert.ToBase64String(parameters.P)); xw.WriteElementString("Q", Convert.ToBase64String(parameters.Q)); xw.WriteElementString("DP", Convert.ToBase64String(parameters.DP)); xw.WriteElementString("DQ", Convert.ToBase64String(parameters.DQ)); xw.WriteElementString("InverseQ", Convert.ToBase64String(parameters.InverseQ)); xw.WriteEndElement(); xw.Flush(); ``` 3. 将.NET的公钥格式转换为Java的公钥格式.NET的公钥格式为XML格式,需要将其转换为X.509证书格式。具体步骤如下: ``` XmlDocument doc = new XmlDocument(); doc.LoadXml(xmlPublicKey); RSAParameters parameters = new RSAParameters(); parameters.Modulus = Convert.FromBase64String(doc.SelectSingleNode("//Modulus").InnerText); parameters.Exponent = Convert.FromBase64String(doc.SelectSingleNode("//Exponent").InnerText); RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); rsa.ImportParameters(parameters); RSACryptoServiceProvider rsaPublic = new RSACryptoServiceProvider(); rsaPublic.ImportParameters(rsa.ExportParameters(false)); byte[] x509publicKey = rsaPublic.ExportCspBlob(false); ``` 4. 将.NET的私钥格式转换为Java的私钥格式.NET的私钥格式为XML格式,需要将其转换为PKCS#8格式。具体步骤如下: ``` XmlDocument doc = new XmlDocument(); doc.LoadXml(xmlPrivateKey); RSAParameters parameters = new RSAParameters(); parameters.Modulus = Convert.FromBase64String(doc.SelectSingleNode("//Modulus").InnerText); parameters.D = Convert.FromBase64String(doc.SelectSingleNode("//D").InnerText); parameters.P = Convert.FromBase64String(doc.SelectSingleNode("//P").InnerText); parameters.Q = Convert.FromBase64String(doc.SelectSingleNode("//Q").InnerText); parameters.DP = Convert.FromBase64String(doc.SelectSingleNode("//DP").InnerText); parameters.DQ = Convert.FromBase64String(doc.SelectSingleNode("//DQ").InnerText); parameters.InverseQ = Convert.FromBase64String(doc.SelectSingleNode("//InverseQ").InnerText); RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); rsa.ImportParameters(parameters); byte[] pkcs8privateKey = rsa.ExportPkcs8PrivateKey(); ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值