AsnContentException: The provided data is tagged with 'Universal' class value '16', but it should have been 'Universal' class value '2'

Viewed 1581

I'm trying to create an RSA keypair using BouncyCastle and then try to import generated public key and I'm receiving the following error

AsnContentException: The provided data is tagged with 'Universal' class value '16', but it should have been 'Universal' class value '2'.

The code is the following

RsaKeyPairGenerator rsaKeyPairGenerator = new RsaKeyPairGenerator();
rsaKeyPairGenerator.Init(new KeyGenerationParameters(new SecureRandom(), 2048));
    
AsymmetricCipherKeyPair keys = rsaKeyPairGenerator.GenerateKeyPair();
    
PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(keys.Private);
byte[] serializedPrivateBytes = privateKeyInfo.ToAsn1Object().GetDerEncoded();
    
SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keys.Public);
byte[] serializedPublicBytes = publicKeyInfo.ToAsn1Object().GetDerEncoded();
    
RSA publicRsaKey = RSA.Create();
publicRsaKey.ImportRSAPublicKey(serializedPublicBytes, out _);

Anyone know why am I getting this?

2 Answers

As already described in the comment by President James K. Polk, the exported public key serializedPublicBytes is a DER encoded key in X.509/SPKI format that can be imported with ImportSubjectPublicKeyInfo(), while ImportRSAPublicKey() expects a DER encoded public key in PKCS#1 format.

For completeness: The PKCS#1 format can be easily derived from publicKeyInfo with the following addition to the posted code:

RsaPublicKeyStructure rsaPublicKey = RsaPublicKeyStructure.GetInstance(publicKeyInfo.ParsePublicKey());
byte[] pkcs1Der = rsaPublicKey.ToAsn1Object().GetDerEncoded();

so that the import can also be done with ImportRSAPublicKey() passing pkcs1Der, or if the public key is needed in PKCS#1 format.

For any future searchers looking at this, you can also run into this error when trying to import a public key that's from Google's Tink cryptography libraries.

In this case, the public key value may actually be a base64-encoded protobuf value, which would need to be deserialized to get the actual embedded public key, according to these protobuf definitions.

Related