Skip to content

Instantly share code, notes, and snippets.

@stormwild
Last active August 29, 2015 13:56
Show Gist options
  • Save stormwild/8857776 to your computer and use it in GitHub Desktop.
Save stormwild/8857776 to your computer and use it in GitHub Desktop.

Based on http://www.jensign.com/opensslkey/opensslkey.cs

http://stackoverflow.com/questions/1162504/decrypting-with-private-key-from-pem-file-in-c-sharp-with-net-crypto-library?lq=1

// Parses binary ans.1 RSA private key; returns RSACryptoServiceProvider

public class CryptographyTools
{
    protected int GetIntegerSize(BinaryReader binr)
    {
        byte bt = 0;
        byte lowbyte = 0x00;
        byte highbyte = 0x00;
        int count = 0;
        bt = binr.ReadByte();
        if (bt != 0x02)		//expect integer
            return 0;
        bt = binr.ReadByte();

        if (bt == 0x81)
            count = binr.ReadByte();	// data size in next byte
        else
            if (bt == 0x82)
            {
                highbyte = binr.ReadByte();	// data size in next 2 bytes
                lowbyte = binr.ReadByte();
                byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
                count = BitConverter.ToInt32(modint, 0);
            }
            else
            {
                count = bt;		// we already have the data size
            }

        while (binr.ReadByte() == 0x00)
        {	//remove high order zeros in data
            count -= 1;
        }
        binr.BaseStream.Seek(-1, SeekOrigin.Current);		//last ReadByte wasn't a removed zero, so back up a byte
        return count;
    }

    public string ReadPemFile(string path)
    {
        return File.ReadAllText(path, Encoding.UTF8);
    }

    public byte[] GetKey(string pem, string type = "RSA PRIVATE KEY")
    {
        string header = string.Format("-----BEGIN {0}-----\\n", type);
        string footer = string.Format("-----END {0}-----", type);
        int start = pem.IndexOf(header) + header.Length;
        int end = pem.IndexOf(footer);
        string key = pem.Substring(start, (end - start));
        return Convert.FromBase64String(key);
    }

    public 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);


            // ------- create RSACryptoServiceProvider instance and initialize with public key -----
            CspParameters CspParameters = new CspParameters();
            CspParameters.Flags = CspProviderFlags.UseMachineKeyStore;
            RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(1024, CspParameters);
            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 ex)
        {
            return null;
        }
        finally
        {
            binr.Close();
        }
    }

    public string Sign(string data, string path)
    {
        string pem = ReadPemFile(path);
        byte[] key = GetKey(pem);
        RSACryptoServiceProvider rsa = DecodeRSAPrivateKey(key);
        return Convert.ToBase64String(rsa.SignData(Encoding.UTF8.GetBytes(data), "SHA512"));
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment