我正在尝试使用Oid和RSA公钥创建PublicKey实例,但是我遇到了一个CryptographyException,其中“ ASN1错误标签值满足”。我遵循找到的答案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()
[我用解析器here解码了您的公钥后,我看到这是一个完整的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解析和生成-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;
以上应该使您进入工作状态。