Decrypting with private key from .pem file in c# with .NET crypto library
Asked Answered
E

2

8

I know this is a similar question to this one but before I head down the Bouncey Castle route, does anyone know if its possible to load an RSA KeyPair from a .pem file, e.g.:

 -----BEGIN RSA PRIVATE KEY-----
 MIIBOgIBAAJBALKzy66nRuof8Fg0ItatyHS9RiDIKH0m5lorKzKn4y5wR6BXpVUv
 ZwnevrAJWBd6EPr/lcV3hjObxD6+q9vmN8ECAwEAAQJAGNcxWwfZrbXe3QPyS9FA
 aindU7U/G5aKssIJcTMxO0UYpGU+WArJbboKeEIE7bpNfhDOKTL7ZL6kWBR1Svlh
 WQIhAOhtx+xXuSrIot59tmXZaypBDjA4n+Xare0ObFLQxWuvAiEAxNMwm6w33bVr
 FHS9slkOh59Le2mgs0uNT6perHaRP48CIGMyRzrlDY/m5SvTtz6slgIIlceawxNU
 Sxp7J1wI4djdAiA6+BchHNjkCP2a9Fr9OydaRMSFpiDqduFQk/enbiKYSwIhANO3
 SQ51oLFtWN9gX3tfKTXflyO6BV8rgPo980d9CEsb
 -----END RSA PRIVATE KEY-----

directly with the .NET 3.5 crypto library without having to go to a 3rd party or roll my own?

Effeminacy answered 22/7, 2009 at 0:44 Comment(1)
@CraigMcQueen good question...in error I'd think.Effeminacy
I
13

http://www.jensign.com/opensslkey/index.html

with source at http://www.jensign.com/opensslkey/opensslkey.cs Update: Source code is no longer available at this url. It can be found at https://gist.github.com/stormwild/7887264 or https://web.archive.org/web/20170731015547/http://www.jensign.com/opensslkey/opensslkey.cs now.

edit: excerpted relevant code:

first, extract the text between the ---- BEGIN ---- and ---- END ---- sections, and base64-decode it into a byte array (see link above for details), then pass it to:

//------- Parses binary ans.1 RSA private key; returns RSACryptoServiceProvider  ---
public static RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey)
{
    byte[] MODULUS, E, D, P, Q, DP, DQ, IQ ;

// ---------  Set up stream to decode the asn.1 encoded RSA private key  ------
    MemoryStream  mem = new MemoryStream(privkey) ;
    BinaryReader binr = new BinaryReader(mem) ;    //wrap Memory Stream with BinaryReader for easy reading
    byte bt = 0;
    ushort twobytes = 0;
    int elems = 0;
    try {
        twobytes = binr.ReadUInt16();
        if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
            binr.ReadByte();    //advance 1 byte
        else if (twobytes == 0x8230)
            binr.ReadInt16();   //advance 2 bytes
        else
            return null;

        twobytes = binr.ReadUInt16();
        if (twobytes != 0x0102) //version number
            return null;
        bt = binr.ReadByte();
        if (bt !=0x00)
            return null;


//------  all private key components are Integer sequences ----
        elems = GetIntegerSize(binr);
        MODULUS = binr.ReadBytes(elems);

        elems = GetIntegerSize(binr);
        E = binr.ReadBytes(elems) ;

        elems = GetIntegerSize(binr);
        D = binr.ReadBytes(elems) ;

        elems = GetIntegerSize(binr);
        P = binr.ReadBytes(elems) ;

        elems = GetIntegerSize(binr);
        Q = binr.ReadBytes(elems) ;

        elems = GetIntegerSize(binr);
        DP = binr.ReadBytes(elems) ;

        elems = GetIntegerSize(binr);
        DQ = binr.ReadBytes(elems) ;

        elems = GetIntegerSize(binr);
        IQ = binr.ReadBytes(elems) ;

        Console.WriteLine("showing components ..");
        if (verbose) {
            showBytes("\nModulus", MODULUS) ;
            showBytes("\nExponent", E);
            showBytes("\nD", D);
            showBytes("\nP", P);
            showBytes("\nQ", Q);
            showBytes("\nDP", DP);
            showBytes("\nDQ", DQ);
            showBytes("\nIQ", IQ);
        }

// ------- create RSACryptoServiceProvider instance and initialize with public key -----
        RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
        RSAParameters RSAparams = new RSAParameters();
        RSAparams.Modulus =MODULUS;
        RSAparams.Exponent = E;
        RSAparams.D = D;
        RSAparams.P = P;
        RSAparams.Q = Q;
        RSAparams.DP = DP;
        RSAparams.DQ = DQ;
        RSAparams.InverseQ = IQ;
        RSA.ImportParameters(RSAparams);
        return RSA;
    }
    catch (Exception) {
        return null;
    }
    finally {
        binr.Close();
    }
}
Isomorphism answered 22/7, 2009 at 0:52 Comment(6)
I'll give this a go...what did you mean that was the solution for the other question? The accepted answer to question I referenced used the Bouncy Castle library (which works for me as well by the way). I am just wanting to minimise my reliance on 3rd party libraries where possible. Even those with very generous licensing.Effeminacy
@Tim Jarvis: the top answer for the other question currently is "You might take a look at JavaScience's source for OpenSSLKey." That's the same as what I've linked and copied above. (BouncyCastle is how the questioner answered it themselves, not the accepted answer...)Isomorphism
ah, of course. Cheers. Haven't tried this yet...about to go have some lunch. Will let you know how it goes. (thx by the way +1 with maybe a +15 to come)Effeminacy
Well, I don't know why this didn't work for the poster of the other question, but it worked fine for me. (with a couple minor mods.)Effeminacy
In order to proceed from this to exporting to PFX with key, I had to set a csp KeyContainerName. Instead of new RSACryptoServiceProvder(), do new RSACryptoServiceProvider(new CspParameters() { KeyContainerName = Guid.NewGuid().ToString("B").ToUpper() }); The content of the name might not matter at all, but an uppercase bracketed GUID is what I see elsewhere, and now I can X509Certificate2.Export and keep the private key.Mannuela
this is quite useful as well: codeproject.com/Articles/162194/Certificates-to-DB-and-BackHonorable
B
0

I've created a small helper NuGet package to create a X509 certificate based on public key and private (rsa) key.

See NuGet and Github-project for functionality and code-examples based on opensslkey.

Beckybecloud answered 16/7, 2017 at 14:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.