In my current task I have to construct private key object from its DER bytes. In OpenSSL I can easily do this with d2i_RSAPrivateKey function but in .NET this doesn't seems to be an easy task. I hoped in BouncyCastle this can be done in single method call but it requires the following code to achieve the functionality

byte[] privateKeyDer = File.ReadAllBytes("PrivateKey.der"); var derSequence = new Asn1InputStream(privateKeyDer).ReadObject(); var privateKeyStructure = new RsaPrivateKeyStructure((Asn1Sequence)derSequence); var privateCrtKeyParameters = new RsaPrivateCrtKeyParameters(privateKeyStructure.Modulus, privateKeyStructure.PublicExponent, privateKeyStructure.PrivateExponent, privateKeyStructure.Prime1, privateKeyStructure.Prime2, privateKeyStructure.Exponent1, privateKeyStructure.Exponent2, privateKeyStructure.Coefficient); var privateKey = DotNetUtilities.ToRSA(privateCrtKeyParameters); // returns RSA object

Please note the classes

I recently realized that it is possible for the RSA components(e.g. modulus) to have lesser bits than the actual RSA key's bit size. For example, in one case the modulus is 255 bytes(2040 bits) instead of expected 256 bytes for a 2048 bits RSA key. Some validation code inside

We can make the

**Asn1InputStream**,**RsaPrivateKeyStructure**,**RsaPrivateCrtKeyParameters**and**DotNetUtilities**are provided by BouncyCastle.**03-Nov-2013 UPDATE:**I recently realized that it is possible for the RSA components(e.g. modulus) to have lesser bits than the actual RSA key's bit size. For example, in one case the modulus is 255 bytes(2040 bits) instead of expected 256 bytes for a 2048 bits RSA key. Some validation code inside

**RSACryptoServiceProvider.ImportParameters**method rejects these kind of RSA key parameters with exception "Invalid Parameter" as the bytes size is lesser than expected. I don't think it is a problem with BouncyCastle's BigInteger implementation as OpenSSL also encodes these big integers with fewer bytes like the BouncyCastle. But OpenSSL accepts these big integers without any issues but it is only the**RSACryptoServicer.ImportParameters**method that rejects it.We can make the

**ImportParameters**to work with these kind of big integers by padding zeros to the big integers. You can find the implementation below, so instead of calling**DotNetUtilities.ToRSA()**we should call our method**ToRsa()**to convert the RSA key parameters to RSA object.private static byte[] PadLeft(byte[] bytes, int sizeToPad) { if (bytes.Length < sizeToPad) { // byte default value is zero, so the paddedBytes array is filled with zero by default var paddedBytes = new byte[sizeToPad]; Buffer.BlockCopy(bytes, 0, paddedBytes, sizeToPad - bytes.Length, bytes.Length); bytes = paddedBytes; } return bytes; } public static System.Security.Cryptography.RSA ToRsa(RsaPrivateCrtKeyParameters privateKey, int bitSize) { var rsaParameters = new System.Security.Cryptography.RSAParameters(); rsaParameters.Modulus = PadLeft(privateKey.Modulus.ToByteArrayUnsigned(), bitSize / 8); rsaParameters.Exponent = PadLeft(privateKey.PublicExponent.ToByteArrayUnsigned(), 3); rsaParameters.D = PadLeft(privateKey.Exponent.ToByteArrayUnsigned(), bitSize / 8); rsaParameters.P = PadLeft(privateKey.P.ToByteArrayUnsigned(), bitSize / 16); rsaParameters.Q = PadLeft(privateKey.Q.ToByteArrayUnsigned(), bitSize / 16); rsaParameters.DP = PadLeft(privateKey.DP.ToByteArrayUnsigned(), bitSize / 16); rsaParameters.DQ = PadLeft(privateKey.DQ.ToByteArrayUnsigned(), bitSize / 16); rsaParameters.InverseQ = PadLeft(privateKey.QInv.ToByteArrayUnsigned(), bitSize / 16); var rsa = new System.Security.Cryptography.RSACryptoServiceProvider(); rsa.ImportParameters(rsaParameters); return rsa; }

## 2 comments:

Hi Siva,

I found the blog very helpful. I am trying to get private key of format der from the file system. But i am getting the below exception at line:

var privStruct = new RsaPrivateKeyStructure((Asn1Sequence)privKeyObj);

"Unable to cast object of type 'Org.BouncyCastle.Asn1.DerSequence' to type 'Org.BouncyCastle.Asn1.DerInteger'" Could you please help.

It looks like the DER is not in expected format. Are you sure it is in RSA private exported through OpenSSL d2i_RSAPrivateKey function? Please note it is a raw format in which the components of the key pair(i.e. modulus, public exponent, private exponent and etc.) are stored in ASN.1 form. So it is different from the standard PKCS1 or other container formats.

Post a Comment