how to get private key from PEM file?

后端 未结 6 752
迷失自我
迷失自我 2020-11-27 02:51

i have a .PEM file that includes public key and a private key for SSL data transfer like this:

-----BEGIN RSA PRIVATE KEY-----
      private key data
-----EN         


        
6条回答
  •  借酒劲吻你
    2020-11-27 03:35

    I had the same problem and - for the record - I post here a complete, working code sample (the key is cut for known reasons). It's mostly a compilation of stuff found on the Internet and my home project requirements.

    Following code's features

    • Loads a PEM certificate ("-----BEGIN CERTIFICATE-----") from openssl that may contain "-----BEGIN RSA PRIVATE KEY-----"
    • returns X509Certificate2
    • private key for x509 is stored in the machine store (windows feature), with access rule for everyone
    • private key cannot be exported from the store

    The code:

    using System;
    using System.IO;
    using System.Security.Cryptography;
    using System.Security.Cryptography.X509Certificates;
    using System.Security.Principal;
    using System.Security.AccessControl;
    
    namespace Test1
    {
        public static class Test
        {
            public static int Main()
            {
                string pemCertWithPrivateKeyText = @"-----BEGIN CERTIFICATE-----
    ...
    bjEdMBsGA1UEChQUVGV4YXMgQSZNIFV5jZTESMBAGA1UEAxMJVXNlciBOYW1lMSA
    ...
    YXMgQSZNIFV5jZTESMBAGA1e2yX28ERsgBD6xx7mJDrPxkqWyV/a9tCF8W6jGSs=
    -----END CERTIFICATE-----
    -----BEGIN RSA PRIVATE KEY-----
    MIIEow..................
    jZMxBWg+imTpbGb+TpR2kxBWctnzFOWRuVYdSQIDAQABAoIBAFSKz/RLtkmZKE1d
    ....
    BWctnzFOWRuVYdSdsf+WDqNxEzrL08SU1w5WuSxIsbxchUvG4
    -----END RSA PRIVATE KEY-----
    "; // just an example
    
                X509Certificate2 cert = PEMToX509.Convert(pemCertWithPrivateKeyText);
    
                return (cert.HasPrivateKey ? 1 : -1);
            }
        }
    
        internal static class PEMToX509
        {
            const string KEY_HEADER = "-----BEGIN RSA PRIVATE KEY-----";
            const string KEY_FOOTER = "-----END RSA PRIVATE KEY-----";
    
            internal static X509Certificate2 Convert(string pem)
            {
                try
                {
                    byte[] pemCertWithPrivateKey = System.Text.Encoding.ASCII.GetBytes(pem);
    
                    RSACryptoServiceProvider rsaPK = GetRSA(pem);
    
                    X509Certificate2 cert = new X509Certificate2();
                    cert.Import(pemCertWithPrivateKey, "", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
    
                    if (rsaPK != null)
                    {
                        cert.PrivateKey = rsaPK;
                    }
    
                    return cert;
                }
                catch
                {
                    return null;
                }
            }
    
            private static RSACryptoServiceProvider GetRSA(string pem)
            {
                RSACryptoServiceProvider rsa = null;
    
                if (IsPrivateKeyAvailable(pem))
                {
                    RSAParameters privateKey = DecodeRSAPrivateKey(pem);
    
                    SecurityIdentifier everyoneSI = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
                    CryptoKeyAccessRule rule = new CryptoKeyAccessRule(everyoneSI, CryptoKeyRights.FullControl, AccessControlType.Allow);
    
                    CspParameters cspParameters = new CspParameters();
                    cspParameters.KeyContainerName = "MY_C_NAME";
                    cspParameters.ProviderName = "Microsoft Strong Cryptographic Provider";
                    cspParameters.ProviderType = 1;
                    cspParameters.Flags = CspProviderFlags.UseNonExportableKey | CspProviderFlags.UseMachineKeyStore;
    
                    cspParameters.CryptoKeySecurity = new CryptoKeySecurity();
                    cspParameters.CryptoKeySecurity.SetAccessRule(rule);
    
                    rsa = new RSACryptoServiceProvider(cspParameters);
                    rsa.PersistKeyInCsp = true;
                    rsa.ImportParameters(privateKey);
                }
    
                return rsa;
            }
    
            private static bool IsPrivateKeyAvailable(string privateKeyInPEM)
            {
                return (privateKeyInPEM != null && privateKeyInPEM.Contains(KEY_HEADER)
                    && privateKeyInPEM.Contains(KEY_FOOTER));
            }
    
            private static RSAParameters DecodeRSAPrivateKey(string privateKeyInPEM)
            {
                if (IsPrivateKeyAvailable(privateKeyInPEM) == false)
                    throw new ArgumentException("bad format");
    
                string keyFormatted = privateKeyInPEM;
    
                int cutIndex = keyFormatted.IndexOf(KEY_HEADER);
                keyFormatted = keyFormatted.Substring(cutIndex, keyFormatted.Length - cutIndex);
                cutIndex = keyFormatted.IndexOf(KEY_FOOTER);
                keyFormatted = keyFormatted.Substring(0, cutIndex + KEY_FOOTER.Length);
                keyFormatted = keyFormatted.Replace(KEY_HEADER, "");
                keyFormatted = keyFormatted.Replace(KEY_FOOTER, "");
                keyFormatted = keyFormatted.Replace("\r", "");
                keyFormatted = keyFormatted.Replace("\n", "");
                keyFormatted = keyFormatted.Trim();
    
                byte[] privateKeyInDER = System.Convert.FromBase64String(keyFormatted);
    
                byte[] paramModulus;
                byte[] paramDP;
                byte[] paramDQ;
                byte[] paramIQ;
                byte[] paramE;
                byte[] paramD;
                byte[] paramP;
                byte[] paramQ;
    
                MemoryStream memoryStream = new MemoryStream(privateKeyInDER);
                BinaryReader binaryReader = new BinaryReader(memoryStream);
    
                ushort twobytes = 0;
                int elements = 0;
                byte bt = 0;
    
                try
                {
                    twobytes = binaryReader.ReadUInt16();
                    if (twobytes == 0x8130) 
                        binaryReader.ReadByte();
                    else if (twobytes == 0x8230) 
                        binaryReader.ReadInt16();
                    else 
                        throw new CryptographicException("Wrong data");
    
                    twobytes = binaryReader.ReadUInt16();
                    if (twobytes != 0x0102) 
                        throw new CryptographicException("Wrong data");
    
                    bt = binaryReader.ReadByte();
                    if (bt != 0x00) 
                        throw new CryptographicException("Wrong data");
    
                    elements = GetIntegerSize(binaryReader);
                    paramModulus = binaryReader.ReadBytes(elements);
    
                    elements = GetIntegerSize(binaryReader);
                    paramE = binaryReader.ReadBytes(elements);
    
                    elements = GetIntegerSize(binaryReader);
                    paramD = binaryReader.ReadBytes(elements);
    
                    elements = GetIntegerSize(binaryReader);
                    paramP = binaryReader.ReadBytes(elements);
    
                    elements = GetIntegerSize(binaryReader);
                    paramQ = binaryReader.ReadBytes(elements);
    
                    elements = GetIntegerSize(binaryReader);
                    paramDP = binaryReader.ReadBytes(elements);
    
                    elements = GetIntegerSize(binaryReader);
                    paramDQ = binaryReader.ReadBytes(elements);
    
                    elements = GetIntegerSize(binaryReader);
                    paramIQ = binaryReader.ReadBytes(elements);
    
                    EnsureLength(ref paramD, 256);
                    EnsureLength(ref paramDP, 128);
                    EnsureLength(ref paramDQ, 128);
                    EnsureLength(ref paramE, 3);
                    EnsureLength(ref paramIQ, 128);
                    EnsureLength(ref paramModulus, 256);
                    EnsureLength(ref paramP, 128);
                    EnsureLength(ref paramQ, 128);
    
                    RSAParameters rsaParameters = new RSAParameters();
                    rsaParameters.Modulus = paramModulus;
                    rsaParameters.Exponent = paramE;
                    rsaParameters.D = paramD;
                    rsaParameters.P = paramP;
                    rsaParameters.Q = paramQ;
                    rsaParameters.DP = paramDP;
                    rsaParameters.DQ = paramDQ;
                    rsaParameters.InverseQ = paramIQ;
    
                    return rsaParameters;
                }
                finally
                {
                    binaryReader.Close();
                }
            }
    
            private static int GetIntegerSize(BinaryReader binary)
            {
                byte bt = 0;
                byte lowbyte = 0x00;
                byte highbyte = 0x00;
                int count = 0;
    
                bt = binary.ReadByte();
    
                if (bt != 0x02) 
                    return 0;
    
                bt = binary.ReadByte();
    
                if (bt == 0x81) 
                    count = binary.ReadByte();
                else if (bt == 0x82)
                {
                    highbyte = binary.ReadByte();
                    lowbyte = binary.ReadByte();
                    byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
                    count = BitConverter.ToInt32(modint, 0);
                }
                else 
                    count = bt;
    
                while (binary.ReadByte() == 0x00)
                    count -= 1;
    
                binary.BaseStream.Seek(-1, SeekOrigin.Current);
    
                return count;
            }
    
            private static void EnsureLength(ref byte[] data, int desiredLength)
            {
                if (data == null || data.Length >= desiredLength)
                    return;
    
                int zeros = desiredLength - data.Length;
    
                byte[] newData = new byte[desiredLength];
                Array.Copy(data, 0, newData, zeros, data.Length);
    
                data = newData;
            }
        }
    }
    

提交回复
热议问题