I'm trying to initialize an RSA instance via ImportRSAPublicKey and I'm getting an ASN1 corrupted data. error.
Simple case:
var r1 = RSA.Create();
var base = new RSACryptoServiceProvider(4096);
// throws
r1.ImportRSAPublicKey(base.ExportSubjectPublicKeyInfo(), out _);
// what I want/need
return new RsaSecurityKey(r1);
Version Info reference:
#region Assembly System.Security.Cryptography.Algorithms, Version=4.3.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// C:\Program Files (x86)\dotnet\packs\Microsoft.NETCore.App.Ref\3.0.0\ref\netcoreapp3.0\System.Security.Cryptography.Algorithms.dll
#endregion
Do I need to do some other conversion first?
The example above is contrived, as I would expect the immediately exported value to be able to import right away again.
It looks like you are mixing the expected formats up. You are exporting with ExportSubjectPublicKeyInfo which exports a SPKI, but importing with ImportRSAPublicKey which is expecting the key to be in PKCS#1 format.
If you import with ImportSubjectPublicKeyInfo, then it works as expected:
var r1 = RSA.Create();
var @base = new RSACryptoServiceProvider(4096);
r1.ImportSubjectPublicKeyInfo(@base.ExportSubjectPublicKeyInfo(), out _);
Likewise ImportRSAPublicKey should be paired with ExportRSAPublicKey if that is more preferable for you:
r1.ImportRSAPublicKey(@base.ExportRSAPublicKey(), out _);
ImportRSAPublicKey imports the RSAPublicKey format from PKCS#1 (https://tools.ietf.org/html/rfc3447#appendix-A.1.1) (the PEM key format which starts with "BEGIN RSA PUBLIC KEY"). ExportSubjectPublicKeyInfo exports the key in the X.509 SubjectPublicKeyInfo format for RSA keys (the PEM key format which starts with "BEGIN PUBLIC KEY").
As @vcsjones mentioned, you need to match your export format and your import format.
@vcsjones @bartonjs What the first parameter of RSA.ImportRSAPublicKey(ReadOnlySpan
The bytes of a PKCS#1 RSAPublicKey structure in the ASN.1-BER encoding.
I tried to use publick key generated on site http://crypt-online.ru/en/crypts/rsa/, convert the hex string to Span
And I got the error info
System.Security.Cryptography.CryptographicException: ASN1 corrupted data.
at System.Security.Cryptography.Asn1.AsnReader.ReadTagAndLength(Nullable1& contentsLength, Int32& bytesRead) at System.Security.Cryptography.Asn1.AsnReader.PeekEncodedValue() at System.Security.Cryptography.RSA.ImportRSAPublicKey(ReadOnlySpan1 source, Int32& bytesRead)
@chucklu
I tried to use publick key generated on site http://crypt-online.ru/en/crypts/rsa/
I took a look at what that site is doing and it appears that the "public key" in the public key textbox is just the modulus from the RSA key (n), hex encoded. An RSAPublicKey consists of the modulus (n) and the public exponent (e) in an ASN.1 sequence.
RSAPublicKey ::= SEQUENCE {
modulus INTEGER, - n
publicExponent INTEGER - e
}
Having just the n value from that site isn't enough. Anecdotally, the site appears to use a hard coded e of 0x10001, which is actually fine.
If you need to generate an RSA key, I would recommend using something that can export to a standardized key format. Using .NET for example:
```c#
using System.Security.Cryptography;
using RSA rsa = RSA.Create(2048);
byte[] pkcs1PublicKey = rsa.ExportRSAPublicKey();
```
@vcsjones Thanks for your test and explanation, I tried with the byte array generate by the code you provided successfully.
Another question is about, what kind of key formats are supported to import directly?
According https://www.cryptosys.net/pki/rsakeyformats.html, there are three formats.
Binary DER-encoded format,
PEM or base64 format
XML format
I know the third one xml format is supported, and how about the other two?
To use the terms that the site used in its headers, Binary/PEM/XML are "encodings" rather than "formats". (It unfortunately used "binary format" in the section on "encodings", which doesn't really help things)
ImportRSAPublicKey only supports one "format": RSAPublicKey. It only supports it in one "encoding": binary (which happens to be BER instead of DER for this format).
There are other formats that are supported, but they're different methods:
All of these formats, except the xmldsig RSAKeyValue format, are also available from PEM encoded data
Similar logic applies for the ECDsa, DSA, and ECDiffieHellman types; the binary encodings all use individual dedicated methods (some of which are unique to the algorithm, some of which are common to all algorithms) and then the ImportFromPem method can process all of the PEM formats (except the one that also requires a password).
It may also be worth noting, anything that accepts "BER" can also accept "DER", as DER is just a subset of BER.
@bartonjs @vcsjones Thanks for your information, I will check the detail later.
Most helpful comment
It looks like you are mixing the expected formats up. You are exporting with
ExportSubjectPublicKeyInfowhich exports a SPKI, but importing withImportRSAPublicKeywhich is expecting the key to be in PKCS#1 format.If you import with
ImportSubjectPublicKeyInfo, then it works as expected: