Search code examples
c#.net-3.5rsacryptoserviceprovider

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


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?


Solution

  • 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();
        }
    }