Search code examples
c#encryptionbouncycastle

Read DER private key in C# using BouncyCastle


I am trying to read an RSA private key into .Net using BouncyCastle to test data I have previously encrypted. The encrypted data is working fine using the public key and Bouncy Castle and I have also used the same private key as below (which is DER format) to successfully decrypt my data in a PHP application but I don't know why I can't create the private key in .Net to do the same thing:

byte[] privatekey = File.ReadAllBytes(@"C:\Users\Luke\privkey.der");
var rsaKeyParameters = (RsaKeyParameters)PrivateKeyFactory.CreateKey(privatekey);

The second line throws an exception:

"unknown object in factory: DerInteger\r\nParameter name: obj"

I also tried using a stream instead of a byte array and the same error occurs. The key pair was created using OpenSSL and as mentioned, decryption works in PHP using openssl_private_decrypt() and the same key as in the .Net code. I also tried a PEM format of the same key and that also didn't work (but I don't think BC supports PEM directly anyway)

Has anyone done this before? Thanks


Solution

  • The problem was that I had assumed PublicKeyFactory and PrivateKeyFactory were complimentary since they are in the same namespace. They are not!

    To decode the private key, I needed the following alternative code:

    var privKeyObj = Asn1Object.FromStream(privatekey);
    var privStruct = new RsaPrivateKeyStructure((Asn1Sequence)privKeyObj);
    
    // Conversion from BouncyCastle to .Net framework types
    var rsaParameters = new RSAParameters();
    rsaParameters.Modulus = privStruct.Modulus.ToByteArrayUnsigned();
    rsaParameters.Exponent = privStruct.PublicExponent.ToByteArrayUnsigned();
    rsaParameters.D = privStruct.PrivateExponent.ToByteArrayUnsigned();
    rsaParameters.P = privStruct.Prime1.ToByteArrayUnsigned();
    rsaParameters.Q = privStruct.Prime2.ToByteArrayUnsigned();
    rsaParameters.DP = privStruct.Exponent1.ToByteArrayUnsigned();
    rsaParameters.DQ = privStruct.Exponent2.ToByteArrayUnsigned();
    rsaParameters.InverseQ = privStruct.Coefficient.ToByteArrayUnsigned();
    var rsa = new RSACryptoServiceProvider();
    rsa.ImportParameters(rsaParameters);
    return Encoding.UTF8.GetString(rsa.Decrypt(Convert.FromBase64String(ciphertext), true));
    

    A BIG thankyou to owlstead for their help.