【问题标题】:Creating PublicKey using Oid/ASNEncodeData throws CryptographyException使用 Oid/ASNEncodeData 创建 PublicKey 会引发 CryptographyException
【发布时间】:2020-03-15 09:04:24
【问题描述】:

我正在尝试使用 Oid 和 RSA 公钥创建一个 PublicKey 实例,但我得到一个 CryptographyException 并显示“ASN1 bad tag value met”。我正在按照here 找到的答案最终创建一个 RSACryptoServiceProvider。

这是我的代码:

string pem = @"-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkxqnUqh5WYis/Q+sQc5h
O9i5aX7XvVEVdrhrnFcbwSb1/GyQWPvn1ZydQB88zW9CnNFq08QRg+IYaBYdqs12
EbxkET20eWY7xvI8kBICPxOdYAHBb0JWpdK4GjSCSxCFrJIXXmHtnRqj6PmSoPrb
uFdC5MTFXfFwphgZi+Ae5MM2nxDu0P/UT8W1VMNVYRkC0dldo+csK1p9NLKga64z
MiNop9nM3meSHpOt+P65l1B+e5EeXM+qzrIeJH4ul95HJdKkPypDM18y4FkFA73S
r6vHYQvQjmBiGy0op1Qs7t+8UkpOX41j28IeiE2yyG7S6/k8Qcu0yv1uaFn3a9VJ
jwIDAQAB
-----END PUBLIC KEY-----";

var rsaPublicKeyStr = pem.Replace(
    "-----BEGIN PUBLIC KEY-----\r\n", "").Replace("\r\n-----END PUBLIC KEY-----", "");
var rsaPublicKey = Convert.FromBase64String(rsaPublicKeyStr);
Oid oid = new Oid("RSA");
AsnEncodedData keyValue = new AsnEncodedData(rsaPublicKey);           
AsnEncodedData keyParam = new AsnEncodedData(new byte[] { 05, 00 });    // ASN.1 code for NULL
PublicKey pubKeyRdr = new PublicKey(oid, keyParam, keyValue);

try
{
    var rsa = (RSACryptoServiceProvider)pubKeyRdr.Key;
}
catch (CryptographicException ce)
{
    Console.WriteLine(ce);
}     

还有输出:

System.Security.Cryptography.CryptographicException: ASN1 bad tag value met.

   at System.Security.Cryptography.X509Certificates.PublicKey.DecodePublicKeyObject(UInt32 aiPubKey, Byte[] encodedKeyValue, Byte[] encodedParameters, Byte[]& decodedData)
   at System.Security.Cryptography.X509Certificates.PublicKey.get_CspBlobData()
   at System.Security.Cryptography.X509Certificates.PublicKey.get_Key()
   at License.Crypto.doCryptoStuff()  

【问题讨论】:

  • 您需要从原始数据中提取模数和公共指数。您的编码值包括带有对象标识符的完整公钥。这部分应该从编码值中剥离,以便传递给PublicKey 类的构造函数。
  • @Crypt32:我什至不知道 .NET 有 ASN.1 类。我看了看,他们似乎没有任何有用的解析方法。
  • 没有可用于 ASN.1 的内置类。您必须使用 3rd 方库来解析 ASN 数据。

标签: c# rsa pem asn.1 rsacryptoserviceprovider


【解决方案1】:

在我使用解析器 here 解码您的公钥后,我可以看到这是一个完整的 ANS.1 密钥。您链接到那里的帖子中的解决方案有效……但是对于不完整的密钥。我很惭愧地说我在发布的答案中遗漏了一条重要信息 - 我将在此之后更新相关信息。

所以。简短的版本是我无法正确解码完全形成的公钥 - 我必须按字节提取。我们仍在等待 MS 的 ASN 解析逻辑公开(看起来它在 3.0 推出时暂停了)。在我的情况下,我可以控制如何导出公钥,因此我能够控制如何在 PEM 中创建公钥 blob。

如果您是这种情况,请将公钥 + 私钥对加载到 RSACryptoServiceProvider 中,然后像这样导出;

var cert = new X509Certificate2(keypairBytes, password,
                                X509KeyStorageFlags.Exportable 
                                | X509KeyStorageFlags.MachineKeySet);
var partialAsnBlockWithPublicKey = cert.GetPublicKey();

// export bytes to PEM format
var base64Encoded = Convert.ToBase64String(partialAsnBlockWithPublicKey, Base64FormattingOptions.InsertLineBreaks);
var pemHeader = "-----BEGIN PUBLIC KEY-----";
var pemFooter = "-----END PUBLIC KEY-----";
var pemFull = string.Format("{0}\r\n{1}\r\n{2}", pemHeader, base64Encoded, pemFooter);

如果您使用此密钥创建 PEM,您将能够使用链接问题中描述的方法重新加载它。为什么这不一样?对 cert.GetPublicKey() 的调用实际上会返回 ASN.1 块结构;

SEQUENCE(2 elem)
  INTEGER (2048 bit)
  INTEGER 65537

这实际上是一个不完整的 DER blob,但 .NET 可以解码(在撰写本文时 .NET 不支持完整的 ASN.1 解析和生成 - https://github.com/dotnet/designs/issues/11)。

正确的 DER (ASN.1) 编码的公钥字节具有以下结构;

SEQUENCE(2 elem)
  SEQUENCE(2 elem)
     OBJECT IDENTIFIER   "1.2.840.113549.1.1.1" - rsaEncryption(PKCS #1)
     NULL
BIT STRING(1 elem)
  SEQUENCE(2 elem)
    INTEGER (2048 bit)
    INTEGER 65537

好的,以上内容为您提供了一个可以加载的公钥(一种)。怎么带回来?来自链接答案的复制/粘贴(假设您再次获得了文件字节);

const string rsaOid = "1.2.840.113549.1.1.1";   // found under System.Security.Cryptography.CngLightup.RsaOid but it's marked as private
Oid oid = new Oid(rsaOid);
AsnEncodedData keyValue = new AsnEncodedData(publicKeyBytes);           // see question
AsnEncodedData keyParam = new AsnEncodedData(new byte[] { 05, 00 });    // ASN.1 code for NULL
PublicKey pubKeyRdr = new PublicKey(oid, keyParam, keyValue);
var rsaCryptoServiceProvider = (RSACryptoServiceProvider)pubKeyRdr.Key;

以上内容应该可以让您进入工作状态。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-07-08
    • 2015-02-12
    • 1970-01-01
    • 1970-01-01
    • 2012-05-01
    • 1970-01-01
    • 2019-12-16
    • 2017-08-28
    相关资源
    最近更新 更多