使用Oid/ASNEncodeData创建PublicKey会引发CryptographyException [英] Creating PublicKey using Oid/ASNEncodeData throws CryptographyException

查看:132
本文介绍了使用Oid/ASNEncodeData创建PublicKey会引发CryptographyException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Oid和RSA公钥创建PublicKey实例,但是我遇到了一个CryptographyException,其中"ASN1错误标签值满足".我在在这里找到答案,以最终创建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()  

解决方案

在我解码你的公钥与分析器的此处,我可以看到这是一个完全形成ANS.1关键.您链接到那里的帖子中的解决方案有效...但是要使用不完整的密钥.我很ham愧地说出了我从发布的答案中遗漏的重要信息-此后,我将使用相关信息进行更新.

所以.简短的版本是我无法正确解码完整格式的公钥-我必须按字节提取.我们仍在等待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解析和生成-

好的,因此上面的内容为您提供了可以加载的公共密钥(种类).如何带回去?从链接的答案中复制/粘贴(假定您再次有文件字节);

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;

以上所述应使您进入工作状态.

I'm trying to create a PublicKey instance using an Oid and RSA public Key but I'm getting a CryptographyException with "ASN1 bad tag value met". I'm following the answer found here to eventually create a RSACryptoServiceProvider.

Here's my code:

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);
}     

And the output:

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()  

解决方案

After I decoded your public key with the parser here, I can see that is a fully formed ANS.1 key. The solution in the post you linked to there works...but for an incomplete key. An important piece of info that I'm ashamed to say that I omitted from my posted answer - I'll update with the relevant info after this.

So. The short version is that I wasn't ever able to correctly decode a fully formed public key - I had to extract by bytes. We're still awaiting MS's ASN parsing logic to be made public (it looks like it got paused while 3.0 rolled out). In my situation, I had control over how the public key was exported so I was able to control how the public key blob would be created in the PEM.

If this is the case for yourself, load the public + private keypair into an RSACryptoServiceProvider and then export it like so;

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);

If you create a PEM from this key, you'll be able to load it back in using the method described in the linked question. Why is this different? The call to cert.GetPublicKey() will actually return the ASN.1 block structure;

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

This is actually an incomplete DER blob but one which .NET can decode (full ASN.1 parsing and generation is not supported by .NET at time of writing - https://github.com/dotnet/designs/issues/11).

A correct DER (ASN.1) encoded public key bytes has the following structure;

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

OK, so the above gets you a public key (kind of) that you can load. How to bring it back in? A copy/paste from the linked answer (it assumes you've got the file bytes again);

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;

The above should get you into a working state.

这篇关于使用Oid/ASNEncodeData创建PublicKey会引发CryptographyException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆