C# Extract public key from RSA PEM private key

前端 未结 2 1699
攒了一身酷
攒了一身酷 2021-01-07 11:10

I have a private key in PEM format. How can I extract the public key from it. I need to be able to do this in code, pragmatically, without executing a process (using openssl

相关标签:
2条回答
  • 2021-01-07 11:34

    In order to do this I had to combine a couple answers here:

    https://stackoverflow.com/a/28407693

    https://stackoverflow.com/a/32243171/645283

    I combined both of the above answers and refactored out GetRSAProviderFromPemString so I didn't need to read the private key from a file:

    //Adapted from https://stackoverflow.com/a/32243171/645283
    public class PemKeyUtils
    {
        const String pemprivheader = "-----BEGIN RSA PRIVATE KEY-----";
        const String pemprivfooter = "-----END RSA PRIVATE KEY-----";
        const String pempubheader = "-----BEGIN PUBLIC KEY-----";
        const String pempubfooter = "-----END PUBLIC KEY-----";
        const String pemp8header = "-----BEGIN PRIVATE KEY-----";
        const String pemp8footer = "-----END PRIVATE KEY-----";
        const String pemp8encheader = "-----BEGIN ENCRYPTED PRIVATE KEY-----";
        const String pemp8encfooter = "-----END ENCRYPTED PRIVATE KEY-----";
    
        static bool verbose = false;
    
        public static RSACryptoServiceProvider GetRSAProviderFromPemFile(String pemfile)
        {
            string pemstring = File.ReadAllText(pemfile).Trim();
            return GetRSAProviderFromPemString(pemstring);
        }
    
        public static RSACryptoServiceProvider GetRSAProviderFromPemString(String pemstr)
        {
            bool isPrivateKeyFile = true;
    
            if (pemstr.StartsWith(pempubheader) && pemstr.EndsWith(pempubfooter))
                isPrivateKeyFile = false;
    
            byte[] pemkey;
            if (isPrivateKeyFile)
                pemkey = DecodeOpenSSLPrivateKey(pemstr);
            else
                pemkey = DecodeOpenSSLPublicKey(pemstr);
    
            if (pemkey == null)
                return null;
    
            if (isPrivateKeyFile)
                return DecodeRSAPrivateKey(pemkey);
            else
                return DecodeX509PublicKey(pemkey);
    
        }
    
        //--------   Get the binary RSA PUBLIC key   --------
        static byte[] DecodeOpenSSLPublicKey(String instr)
        {
            const String pempubheader = "-----BEGIN PUBLIC KEY-----";
            const String pempubfooter = "-----END PUBLIC KEY-----";
            String pemstr = instr.Trim();
            byte[] binkey;
            if (!pemstr.StartsWith(pempubheader) || !pemstr.EndsWith(pempubfooter))
                return null;
            StringBuilder sb = new StringBuilder(pemstr);
            sb.Replace(pempubheader, "");  //remove headers/footers, if present
            sb.Replace(pempubfooter, "");
    
            String pubstr = sb.ToString().Trim();   //get string after removing leading/trailing whitespace
    
            try
            {
                binkey = Convert.FromBase64String(pubstr);
            }
            catch (System.FormatException)
            {       //if can't b64 decode, data is not valid
                return null;
            }
            return binkey;
        }
    
        static RSACryptoServiceProvider DecodeX509PublicKey(byte[] x509Key)
        {
            // encoded OID sequence for  PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1"
            byte[] seqOid = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };
            // ---------  Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob  ------
            using (var mem = new MemoryStream(x509Key))
            {
                using (var binr = new BinaryReader(mem))    //wrap Memory Stream with BinaryReader for easy reading
                {
                    try
                    {
                        var twobytes = binr.ReadUInt16();
                        switch (twobytes)
                        {
                            case 0x8130:
                                binr.ReadByte();    //advance 1 byte
                                break;
                            case 0x8230:
                                binr.ReadInt16();   //advance 2 bytes
                                break;
                            default:
                                return null;
                        }
    
                        var seq = binr.ReadBytes(15);
                        if (!CompareBytearrays(seq, seqOid))  //make sure Sequence for OID is correct
                            return null;
    
                        twobytes = binr.ReadUInt16();
                        if (twobytes == 0x8103) //data read as little endian order (actual data order for Bit String is 03 81)
                            binr.ReadByte();    //advance 1 byte
                        else if (twobytes == 0x8203)
                            binr.ReadInt16();   //advance 2 bytes
                        else
                            return null;
    
                        var bt = binr.ReadByte();
                        if (bt != 0x00)     //expect null byte next
                            return null;
    
                        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();
                        byte lowbyte = 0x00;
                        byte highbyte = 0x00;
    
                        if (twobytes == 0x8102) //data read as little endian order (actual data order for Integer is 02 81)
                            lowbyte = binr.ReadByte();  // read next bytes which is bytes in modulus
                        else if (twobytes == 0x8202)
                        {
                            highbyte = binr.ReadByte(); //advance 2 bytes
                            lowbyte = binr.ReadByte();
                        }
                        else
                            return null;
                        byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };   //reverse byte order since asn.1 key uses big endian order
                        int modsize = BitConverter.ToInt32(modint, 0);
    
                        byte firstbyte = binr.ReadByte();
                        binr.BaseStream.Seek(-1, SeekOrigin.Current);
    
                        if (firstbyte == 0x00)
                        {   //if first byte (highest order) of modulus is zero, don't include it
                            binr.ReadByte();    //skip this null byte
                            modsize -= 1;   //reduce modulus buffer size by 1
                        }
    
                        byte[] modulus = binr.ReadBytes(modsize); //read the modulus bytes
    
                        if (binr.ReadByte() != 0x02)            //expect an Integer for the exponent data
                            return null;
                        int expbytes = binr.ReadByte();        // should only need one byte for actual exponent data (for all useful values)
                        byte[] exponent = binr.ReadBytes(expbytes);
    
                        // We don't really need to print anything but if we insist to...
                        //showBytes("\nExponent", exponent);
                        //showBytes("\nModulus", modulus);
    
                        // ------- create RSACryptoServiceProvider instance and initialize with public key -----
                        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
                        RSAParameters rsaKeyInfo = new RSAParameters
                        {
                            Modulus = modulus,
                            Exponent = exponent
                        };
                        rsa.ImportParameters(rsaKeyInfo);
                        return rsa;
                    }
                    catch (Exception)
                    {
                        return null;
                    }
                }
            }
        }
    
        //------- Parses binary ans.1 RSA private key; returns RSACryptoServiceProvider  ---
        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(); }
        }
    
        private static 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;
        }
    
        //-----  Get the binary RSA PRIVATE key, decrypting if necessary ----
        static byte[] DecodeOpenSSLPrivateKey(String instr)
        {
            const String pemprivheader = "-----BEGIN RSA PRIVATE KEY-----";
            const String pemprivfooter = "-----END RSA PRIVATE KEY-----";
            String pemstr = instr.Trim();
            byte[] binkey;
            if (!pemstr.StartsWith(pemprivheader) || !pemstr.EndsWith(pemprivfooter))
                return null;
    
            StringBuilder sb = new StringBuilder(pemstr);
            sb.Replace(pemprivheader, "");  //remove headers/footers, if present
            sb.Replace(pemprivfooter, "");
    
            String pvkstr = sb.ToString().Trim();   //get string after removing leading/trailing whitespace
    
            try
            {        // if there are no PEM encryption info lines, this is an UNencrypted PEM private key
                binkey = Convert.FromBase64String(pvkstr);
                return binkey;
            }
            catch (System.FormatException)
            {       //if can't b64 decode, it must be an encrypted private key
                    //Console.WriteLine("Not an unencrypted OpenSSL PEM private key");  
            }
    
            StringReader str = new StringReader(pvkstr);
    
            //-------- read PEM encryption info. lines and extract salt -----
            if (!str.ReadLine().StartsWith("Proc-Type: 4,ENCRYPTED"))
                return null;
            String saltline = str.ReadLine();
            if (!saltline.StartsWith("DEK-Info: DES-EDE3-CBC,"))
                return null;
            String saltstr = saltline.Substring(saltline.IndexOf(",") + 1).Trim();
            byte[] salt = new byte[saltstr.Length / 2];
            for (int i = 0; i < salt.Length; i++)
                salt[i] = Convert.ToByte(saltstr.Substring(i * 2, 2), 16);
            if (!(str.ReadLine() == ""))
                return null;
    
            //------ remaining b64 data is encrypted RSA key ----
            String encryptedstr = str.ReadToEnd();
    
            try
            {   //should have b64 encrypted RSA key now
                binkey = Convert.FromBase64String(encryptedstr);
            }
            catch (System.FormatException)
            {  // bad b64 data.
                return null;
            }
    
            //------ Get the 3DES 24 byte key using PDK used by OpenSSL ----
    
            SecureString despswd = GetSecPswd("Enter password to derive 3DES key==>");
            //Console.Write("\nEnter password to derive 3DES key: ");
            //String pswd = Console.ReadLine();
            byte[] deskey = GetOpenSSL3deskey(salt, despswd, 1, 2);    // count=1 (for OpenSSL implementation); 2 iterations to get at least 24 bytes
            if (deskey == null)
                return null;
            //showBytes("3DES key", deskey) ;
    
            //------ Decrypt the encrypted 3des-encrypted RSA private key ------
            byte[] rsakey = DecryptKey(binkey, deskey, salt); //OpenSSL uses salt value in PEM header also as 3DES IV
            if (rsakey != null)
                return rsakey;  //we have a decrypted RSA private key
            else
            {
                Console.WriteLine("Failed to decrypt RSA private key; probably wrong password.");
                return null;
            }
        }
    
    
        // ----- Decrypt the 3DES encrypted RSA private key ----------
        static byte[] DecryptKey(byte[] cipherData, byte[] desKey, byte[] IV)
        {
            MemoryStream memst = new MemoryStream();
            TripleDES alg = TripleDES.Create();
            alg.Key = desKey;
            alg.IV = IV;
            try
            {
                CryptoStream cs = new CryptoStream(memst, alg.CreateDecryptor(), CryptoStreamMode.Write);
                cs.Write(cipherData, 0, cipherData.Length);
                cs.Close();
            }
            catch (Exception exc)
            {
                Console.WriteLine(exc.Message);
                return null;
            }
            byte[] decryptedData = memst.ToArray();
            return decryptedData;
        }
    
        //-----   OpenSSL PBKD uses only one hash cycle (count); miter is number of iterations required to build sufficient bytes ---
        static byte[] GetOpenSSL3deskey(byte[] salt, SecureString secpswd, int count, int miter)
        {
            IntPtr unmanagedPswd = IntPtr.Zero;
            int HASHLENGTH = 16;    //MD5 bytes
            byte[] keymaterial = new byte[HASHLENGTH * miter];     //to store contatenated Mi hashed results
    
    
            byte[] psbytes = new byte[secpswd.Length];
            unmanagedPswd = Marshal.SecureStringToGlobalAllocAnsi(secpswd);
            Marshal.Copy(unmanagedPswd, psbytes, 0, psbytes.Length);
            Marshal.ZeroFreeGlobalAllocAnsi(unmanagedPswd);
    
            //UTF8Encoding utf8 = new UTF8Encoding();
            //byte[] psbytes = utf8.GetBytes(pswd);
    
            // --- contatenate salt and pswd bytes into fixed data array ---
            byte[] data00 = new byte[psbytes.Length + salt.Length];
            Array.Copy(psbytes, data00, psbytes.Length);      //copy the pswd bytes
            Array.Copy(salt, 0, data00, psbytes.Length, salt.Length); //concatenate the salt bytes
    
            // ---- do multi-hashing and contatenate results  D1, D2 ...  into keymaterial bytes ----
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] result = null;
            byte[] hashtarget = new byte[HASHLENGTH + data00.Length];   //fixed length initial hashtarget
    
            for (int j = 0; j < miter; j++)
            {
                // ----  Now hash consecutively for count times ------
                if (j == 0)
                    result = data00;    //initialize 
                else
                {
                    Array.Copy(result, hashtarget, result.Length);
                    Array.Copy(data00, 0, hashtarget, result.Length, data00.Length);
                    result = hashtarget;
                    //Console.WriteLine("Updated new initial hash target:") ;
                    //showBytes(result) ;
                }
    
                for (int i = 0; i < count; i++)
                    result = md5.ComputeHash(result);
                Array.Copy(result, 0, keymaterial, j * HASHLENGTH, result.Length);  //contatenate to keymaterial
            }
            //showBytes("Final key material", keymaterial);
            byte[] deskey = new byte[24];
            Array.Copy(keymaterial, deskey, deskey.Length);
    
            Array.Clear(psbytes, 0, psbytes.Length);
            Array.Clear(data00, 0, data00.Length);
            Array.Clear(result, 0, result.Length);
            Array.Clear(hashtarget, 0, hashtarget.Length);
            Array.Clear(keymaterial, 0, keymaterial.Length);
    
            return deskey;
        }
    
        static SecureString GetSecPswd(String prompt)
        {
            SecureString password = new SecureString();
    
            Console.ForegroundColor = ConsoleColor.Gray;
            Console.Write(prompt);
            Console.ForegroundColor = ConsoleColor.Magenta;
    
            while (true)
            {
                ConsoleKeyInfo cki = Console.ReadKey(true);
                if (cki.Key == ConsoleKey.Enter)
                {
                    Console.ForegroundColor = ConsoleColor.Gray;
                    Console.WriteLine();
                    return password;
                }
                else if (cki.Key == ConsoleKey.Backspace)
                {
                    // remove the last asterisk from the screen...
                    if (password.Length > 0)
                    {
                        Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop);
                        Console.Write(" ");
                        Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop);
                        password.RemoveAt(password.Length - 1);
                    }
                }
                else if (cki.Key == ConsoleKey.Escape)
                {
                    Console.ForegroundColor = ConsoleColor.Gray;
                    Console.WriteLine();
                    return password;
                }
                else if (Char.IsLetterOrDigit(cki.KeyChar) || Char.IsSymbol(cki.KeyChar))
                {
                    if (password.Length < 20)
                    {
                        password.AppendChar(cki.KeyChar);
                        Console.Write("*");
                    }
                    else
                    {
                        Console.Beep();
                    }
                }
                else
                {
                    Console.Beep();
                }
            }
        }
    
        static bool CompareBytearrays(byte[] a, byte[] b)
        {
            if (a.Length != b.Length)
                return false;
            int i = 0;
            foreach (byte c in a)
            {
                if (c != b[i])
                    return false;
                i++;
            }
            return true;
        }
    
        static void showBytes(String info, byte[] data)
        {
            Console.WriteLine("{0}  [{1} bytes]", info, data.Length);
            for (int i = 1; i <= data.Length; i++)
            {
                Console.Write("{0:X2}  ", data[i - 1]);
                if (i % 16 == 0)
                    Console.WriteLine();
            }
            Console.WriteLine("\n\n");
        }
    
        /// <summary>
        /// Export public key from MS RSACryptoServiceProvider into OpenSSH PEM string
        /// slightly modified from https://stackoverflow.com/a/28407693
        /// </summary>
        /// <param name="csp"></param>
        /// <returns></returns>
        public static string ExportPublicKey(RSACryptoServiceProvider csp)
        {
            StringWriter outputStream = new StringWriter();
            var parameters = csp.ExportParameters(false);
            using (var stream = new MemoryStream())
            {
                var writer = new BinaryWriter(stream);
                writer.Write((byte)0x30); // SEQUENCE
                using (var innerStream = new MemoryStream())
                {
                    var innerWriter = new BinaryWriter(innerStream);
                    innerWriter.Write((byte)0x30); // SEQUENCE
                    EncodeLength(innerWriter, 13);
                    innerWriter.Write((byte)0x06); // OBJECT IDENTIFIER
                    var rsaEncryptionOid = new byte[] { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 };
                    EncodeLength(innerWriter, rsaEncryptionOid.Length);
                    innerWriter.Write(rsaEncryptionOid);
                    innerWriter.Write((byte)0x05); // NULL
                    EncodeLength(innerWriter, 0);
                    innerWriter.Write((byte)0x03); // BIT STRING
                    using (var bitStringStream = new MemoryStream())
                    {
                        var bitStringWriter = new BinaryWriter(bitStringStream);
                        bitStringWriter.Write((byte)0x00); // # of unused bits
                        bitStringWriter.Write((byte)0x30); // SEQUENCE
                        using (var paramsStream = new MemoryStream())
                        {
                            var paramsWriter = new BinaryWriter(paramsStream);
                            EncodeIntegerBigEndian(paramsWriter, parameters.Modulus); // Modulus
                            EncodeIntegerBigEndian(paramsWriter, parameters.Exponent); // Exponent
                            var paramsLength = (int)paramsStream.Length;
                            EncodeLength(bitStringWriter, paramsLength);
                            bitStringWriter.Write(paramsStream.GetBuffer(), 0, paramsLength);
                        }
                        var bitStringLength = (int)bitStringStream.Length;
                        EncodeLength(innerWriter, bitStringLength);
                        innerWriter.Write(bitStringStream.GetBuffer(), 0, bitStringLength);
                    }
                    var length = (int)innerStream.Length;
                    EncodeLength(writer, length);
                    writer.Write(innerStream.GetBuffer(), 0, length);
                }
    
                var base64 = Convert.ToBase64String(stream.GetBuffer(), 0, (int)stream.Length).ToCharArray();
                // WriteLine terminates with \r\n, we want only \n
                outputStream.Write("-----BEGIN PUBLIC KEY-----\n");
                for (var i = 0; i < base64.Length; i += 64)
                {
                    outputStream.Write(base64, i, Math.Min(64, base64.Length - i));
                    outputStream.Write("\n");
                }
                outputStream.Write("-----END PUBLIC KEY-----");
            }
    
            return outputStream.ToString();
        }
    
        // https://stackoverflow.com/a/23739932/2860309
        private static void EncodeLength(BinaryWriter stream, int length)
        {
            if (length < 0) throw new ArgumentOutOfRangeException("length", "Length must be non-negative");
            if (length < 0x80)
            {
                // Short form
                stream.Write((byte)length);
            }
            else
            {
                // Long form
                var temp = length;
                var bytesRequired = 0;
                while (temp > 0)
                {
                    temp >>= 8;
                    bytesRequired++;
                }
                stream.Write((byte)(bytesRequired | 0x80));
                for (var i = bytesRequired - 1; i >= 0; i--)
                {
                    stream.Write((byte)(length >> (8 * i) & 0xff));
                }
            }
        }
    
        //https://stackoverflow.com/a/23739932/2860309
        private static void EncodeIntegerBigEndian(BinaryWriter stream, byte[] value, bool forceUnsigned = true)
        {
            stream.Write((byte)0x02); // INTEGER
            var prefixZeros = 0;
            for (var i = 0; i < value.Length; i++)
            {
                if (value[i] != 0) break;
                prefixZeros++;
            }
            if (value.Length - prefixZeros == 0)
            {
                EncodeLength(stream, 1);
                stream.Write((byte)0);
            }
            else
            {
                if (forceUnsigned && value[prefixZeros] > 0x7f)
                {
                    // Add a prefix zero to force unsigned if the MSB is 1
                    EncodeLength(stream, value.Length - prefixZeros + 1);
                    stream.Write((byte)0);
                }
                else
                {
                    EncodeLength(stream, value.Length - prefixZeros);
                }
                for (var i = prefixZeros; i < value.Length; i++)
                {
                    stream.Write(value[i]);
                }
            }
        }
    }
    

    Then, I was able to export (more like piece together) the public key like by calling PemKeyUtils.ExportPublicKey:

    using (RSACryptoServiceProvider rsaCsp = PemKeyUtils.GetRSAProviderFromPemString(privateKeyInPemFormat))
    {
        return PemKeyUtils.ExportPublicKey(rsaCsp); 
    }
    
    0 讨论(0)
  • 2021-01-07 11:53

    You aren't very clear on what you want. You can use the Bouncycastle library to parse the PEM data and return the RSA keypair, from which you can extract the public key. Here is some sample code:

    using System.IO;
    using Org.BouncyCastle.Crypto;
    using Org.BouncyCastle.OpenSsl;
    
    namespace ImportRSAPrivateKeyPEM
    {
        class MainClass
        {
            readonly static string PEM_PRIV_KEY = @"-----BEGIN RSA PRIVATE KEY-----
    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
    -----END RSA PRIVATE KEY-----";
    
    
            public static void Main(string[] args)
            {
                var rdr = new StringReader(PEM_PRIV_KEY);
                var pemReader = new PemReader(rdr);
                AsymmetricCipherKeyPair pemObject = (Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair)pemReader.ReadObject();
    
            }
        }
    }
    

    If you need to convert from Bouncycastle types to .NET types then the methods of Org.BouncyCastle.Security.DotNetUtilities can be used. The Org.BouncyCastle.Asn1.Pkcs.RsaPrivateKeyStructure may also be of use depending on what you want to do.

    Unfortunately documentation on the Bouncycastle C# library seems to be pretty thin. There always the source code itself, which is what I use.

    0 讨论(0)
提交回复
热议问题