如何从PEM文件中获取私钥?

时间:2011-09-13 10:39:47

标签: .net ssl cryptography private-key pem

我有一个.PEM文件,其中包含用于SSL数据传输的公钥和私钥,如下所示:

-----BEGIN RSA PRIVATE KEY-----
      private key data
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
      public key data
-----END CERTIFICATE-----

当我想通过以下代码加载.PEM文件时:

X509Certificate2 xx = new X509Certificate2("c:\\myKey.pem");

我得到一个异常,上面写着:“找不到请求的对象。” ,有完整的堆栈:

System.Security.Cryptography.CryptographicException was unhandled
  Message=Cannot find the requested object.

  Source=mscorlib
  StackTrace:
       at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr)
       at System.Security.Cryptography.X509Certificates.X509Utils._QueryCertFileType(String fileName)
       at System.Security.Cryptography.X509Certificates.X509Certificate.LoadCertificateFromFile(String fileName, Object password, X509KeyStorageFlags keyStorageFlags)
       at System.Security.Cryptography.X509Certificates.X509Certificate..ctor(String fileName)
       at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(String fileName)
       at DLLTest.SSL_Test.test() in E:\Projects\DLLTest\DLLTest\SSL_Test.cs:line 165
       at DLLTest.SSL_Test.Run() in E:\Projects\DLLTest\DLLTest\SSL_Test.cs:line 21
       at DLLTest.Program.Main(String[] args) in E:\Projects\DLLTest\DLLTest\Program.cs:line 21
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 

如果我交换私钥部分和公钥部分的位置,代码工作并加载数据,我可以从对象获得公钥信息,例如。发行者名称, 并且它的HasPrivateKey是错误的。为什么?我误解了,做错了什么?

8 个答案:

答案 0 :(得分:31)

有一个article on the Code Project,其中包含您执行此操作所需的所有代码。它只是几个类,所以它是一个轻量级的解决方案。

要从PEM文件获取证书或密钥的字节,无论文件中的密钥和证书的顺序如何,以下方法都将起作用。

 byte[] GetBytesFromPEM( string pemString, string section )
 {
     var header = String.Format("-----BEGIN {0}-----", section);
     var footer = String.Format("-----END {0}-----", section);

     var start= pemString.IndexOf(header, StringComparison.Ordinal);
     if( start < 0 )
        return null;

     start += header.Length;
     var end = pemString.IndexOf(footer, start, StringComparison.Ordinal) - start;

     if( end < 0 )
        return null;

     return Convert.FromBase64String( pemString.Substring( start, end ) );
 }

将PEM文件加载到字符串中并调用上面的方法以获取表示证书的字节。接下来,将获得的字节传递给X509Certificate2的构造函数:

 var pem = System.IO.File.ReadAllText( "c:\\myKey.pem" )
 byte[] certBuffer = GetBytesFromPEM( pem, "CERTIFICATE" );
 var certificate = new X509Certificate2( certBuffer );

从PEM文件加载(RSA)私钥有点复杂,但您可以使用Crypto.DecodeRsaPrivateKey方法在上述文章中找到对此的支持。

答案 1 :(得分:16)

AFAIK .NET框架在任何地方都不支持PEM。

您可以轻松解决X509Certificate部分问题,因为您可以在 ----- BEGIN CERTIFICATE ----- 之间提取base64字符串 ----- END CERTIFICATE ----- 行,将其转换为byte[]并从中创建X509Certificate

一个简单的解决方案是从Mono.Security的X509Certificate.cs复制粘贴代码来执行此操作。

获取私钥有点棘手,因为获取byte[]对重建RSA实例没有太大帮助(我们可以假设,因为PEM头表明它是RSA)。

这次你最好从Mono.Security的PKCS8.cs文件中复制粘贴,然后调用解码方法。

免责声明: 我是上面讨论过的Mono代码的主要作者,并且它都是在MIT.X11许可下提供的

答案 2 :(得分:9)

我遇到了同样的问题 - 为了记录 - 我在这里发布了一个完整的,有效的代码示例(由于已知原因,密钥被删除)。它主要是在互联网和我的家庭项目要求中找到的东西的汇编。

遵循代码的功能

  • 从openssl加载PEM证书(“----- BEGIN CERTIFICATE -----”),其中可能包含“----- BEGIN RSA PRIVATE KEY -----”
  • 返回X509Certificate2
  • x509的私钥存储在机器商店(Windows功能)中,每个人都有访问规则
  • 无法从商店导出私钥

代码:

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;
        }
    }
}

答案 3 :(得分:6)

另一种方法是将客户端PEM证书转换为Windows支持的PFX格式。这可以使用例如openssl,通过运行:

来完成
__prepare__

(其中&#34; cert.pfx&#34;是输出文件,&#34; cert.key&#34;包含私钥,&#34; cert.pem&#34;包含输入证书,和&#34; ca.pem&#34;包含签名者的证书。)

答案 4 :(得分:1)

你不知道。
.NET不支持它。
您会看到,PEM编码确实支持多种密钥类型(例如ECDSA)。
因此,如果有人为您提供了一种从PEM文件中读取.NET RSA密钥的方法,则您也许可以读取该RSA密钥(如果PEM还具有D,P,Q,DP DQ,InverseQ),但这就是距离阅读PEM还有很长的路要走。
此外,.NET版本的RSA仅基于(模数,指数 D,P,Q,DP,DQ,InverseQ)实现RSA。真正的PEM编码的RSA密钥不需要支持参数D,P,Q,DP,DQ,InverseQ。可以,但不是必须的。 RSA真正需要的只是模量和指数。仅包含模数和指数的PEM编码的RSA密钥是绝对有效的PEM密钥,尤其是当您需要与Python互操作时,这样做。

但是,您可以使用BouncyCastle读取PEM编码的私钥和公钥。
见下文。

要在不添加对BouncyCastle的依赖的情况下,将这些加密密钥(任何类型)通用化至.NET,最好的选择是读取BouncyCastle中的PEM文件,创建一个PFX文件(包含私钥和公钥) ,然后使用System.Security.Cryptography.X509Certificates.X509Certificate2读取该PFX文件。假定它们使用了.NET确实支持的一种加密算法,则可以从该证书中获得已经解码的私钥和公钥。

namespace SslCertificateGenerator
{
    
    
    // https://gist.github.com/therightstuff/aa65356e95f8d0aae888e9f61aa29414
    public class KeyImportExport
    {
        
        
        // KeyImportExport.GetPemKeyPair
        public static PrivatePublicPemKeyPair GetPemKeyPair(Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair keyPair)
        {
            PrivatePublicPemKeyPair result = new PrivatePublicPemKeyPair();
            
            // id_rsa
            using (System.IO.TextWriter textWriter = new System.IO.StringWriter())
            {
                Org.BouncyCastle.OpenSsl.PemWriter pemWriter = new Org.BouncyCastle.OpenSsl.PemWriter(textWriter);
                pemWriter.WriteObject(keyPair.Private);
                pemWriter.Writer.Flush();

                result.PrivateKey = textWriter.ToString();
            } // End Using textWriter 
            
            
            // id_rsa.pub
            using (System.IO.TextWriter textWriter = new System.IO.StringWriter())
            {
                Org.BouncyCastle.OpenSsl.PemWriter pemWriter = new Org.BouncyCastle.OpenSsl.PemWriter(textWriter);
                pemWriter.WriteObject(keyPair.Public);
                pemWriter.Writer.Flush();

                result.PublicKey = textWriter.ToString();
            } // End Using textWriter 
            
            
            // // This writes the same as private key, not both
            //using (System.IO.TextWriter textWriter = new System.IO.StringWriter())
            //{
            //    Org.BouncyCastle.OpenSsl.PemWriter pemWriter = new Org.BouncyCastle.OpenSsl.PemWriter(textWriter);
            //    pemWriter.WriteObject(keyPair);
            //    pemWriter.Writer.Flush();
            
            //    bothKeys = textWriter.ToString();
            //} // End Using textWriter 
            
            return result;
        } // End Sub GetPemKeyPair
        
        
        // KeyImportExport.ReadPublicKey
        public static Org.BouncyCastle.Crypto.AsymmetricKeyParameter ReadPublicKey(string publicKey)
        {
            Org.BouncyCastle.Crypto.AsymmetricKeyParameter keyParameter = null;

            using (System.IO.TextReader reader = new System.IO.StringReader(publicKey))
            {
                Org.BouncyCastle.OpenSsl.PemReader pemReader =
                    new Org.BouncyCastle.OpenSsl.PemReader(reader);

                object obj = pemReader.ReadObject();

                if ((obj is Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair))
                    throw new System.ArgumentException("The given publicKey is actually a private key.", "publicKey");

                if (!(obj is Org.BouncyCastle.Crypto.AsymmetricKeyParameter))
                    throw new System.ArgumentException("The given publicKey is not a valid assymetric key.", "publicKey");

                keyParameter = (Org.BouncyCastle.Crypto.AsymmetricKeyParameter)obj;
            }
            
            return keyParameter;
        } // End Function ReadPublicKey 
        
        
        public static Org.BouncyCastle.Crypto.AsymmetricKeyParameter ReadPrivateKey(string privateKey)
        {
            Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair keyPair = null;
            
            using (System.IO.TextReader reader = new System.IO.StringReader(privateKey))
            {
                Org.BouncyCastle.OpenSsl.PemReader pemReader =
                    new Org.BouncyCastle.OpenSsl.PemReader(reader);

                object obj = pemReader.ReadObject();

                if (obj is Org.BouncyCastle.Crypto.AsymmetricKeyParameter)
                    throw new System.ArgumentException("The given privateKey is a public key, not a privateKey...", "privateKey");

                if (!(obj is Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair))
                    throw new System.ArgumentException("The given privateKey is not a valid assymetric key.", "privateKey");

                keyPair = (Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair)obj;
            } // End using reader 
            
            // Org.BouncyCastle.Crypto.AsymmetricKeyParameter priv = keyPair.Private;
            // Org.BouncyCastle.Crypto.AsymmetricKeyParameter pub = keyPair.Public;
            
            // Note: 
            // cipher.Init(false, key);
            // !!!
            
            return keyPair.Private;
        } // End Function ReadPrivateKey
        
        
        public static Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair ReadKeyPair(string privateKey)
        {
            Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair keyPair = null;

            using (System.IO.TextReader reader = new System.IO.StringReader(privateKey))
            {
                Org.BouncyCastle.OpenSsl.PemReader pemReader =
                    new Org.BouncyCastle.OpenSsl.PemReader(reader);
                
                object obj = pemReader.ReadObject();
                
                if (obj is Org.BouncyCastle.Crypto.AsymmetricKeyParameter)
                    throw new System.ArgumentException("The given privateKey is a public key, not a privateKey...", "privateKey");
                
                if (!(obj is Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair))
                    throw new System.ArgumentException("The given privateKey is not a valid assymetric key.", "privateKey");
                
                keyPair = (Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair)obj;
            }
            
            // Org.BouncyCastle.Crypto.AsymmetricKeyParameter priv = keyPair.Private;
            // Org.BouncyCastle.Crypto.AsymmetricKeyParameter pub = keyPair.Public;
            
            // Note: 
            // cipher.Init(false, key);
            // !!!
            
            return keyPair;
        } // End Function ReadPrivateKey
        
        
        public static Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair ReadKeyPairFromFile(string fileName)
        {
            Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair KeyPair = null;

            //  Stream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
            using (System.IO.FileStream fs = System.IO.File.OpenRead(fileName))
            {

                using (System.IO.StreamReader sr = new System.IO.StreamReader(fs))
                {
                    Org.BouncyCastle.OpenSsl.PemReader pemReader = new Org.BouncyCastle.OpenSsl.PemReader(sr);
                    KeyPair = (Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair)pemReader.ReadObject();
                    // System.Security.Cryptography.RSAParameters rsa = Org.BouncyCastle.Security.
                    //     DotNetUtilities.ToRSAParameters((Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters)KeyPair.Private);
                } // End Using sr 

            } // End Using fs 

            return KeyPair;
        } // End Function ImportKeyPair 
        
        
        //public static void ReadPrivateKeyFile(string privateKeyFileName)
        //{
        //    Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters key = null;

        //    using (System.IO.StreamReader streamReader = System.IO.File.OpenText(privateKeyFileName))
        //    {
        //        Org.BouncyCastle.OpenSsl.PemReader pemReader = 
        //            new Org.BouncyCastle.OpenSsl.PemReader(streamReader);
        //        key = (Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters) pemReader.ReadObject();
        //    } // End Using streamReader 

        //    // Note: 
        //    // cipher.Init(false, key);
        //    // !!!
        //} // End Function ReadPrivateKey
        
        
        public Org.BouncyCastle.Crypto.AsymmetricKeyParameter ReadPublicKeyFile(string pemFilename)
        {
            Org.BouncyCastle.Crypto.AsymmetricKeyParameter keyParameter = null;

            using (System.IO.StreamReader streamReader = System.IO.File.OpenText(pemFilename))
            {
                Org.BouncyCastle.OpenSsl.PemReader pemReader = new Org.BouncyCastle.OpenSsl.PemReader(streamReader);
                keyParameter = (Org.BouncyCastle.Crypto.AsymmetricKeyParameter)pemReader.ReadObject();
            } // End Using fileStream 

            return keyParameter;
        } // End Function ReadPublicKey 
        
        
        public static void ExportKeyPair(Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair keyPair)
        {
            string privateKey = null;

            using (System.IO.TextWriter textWriter = new System.IO.StringWriter())
            {
                Org.BouncyCastle.OpenSsl.PemWriter pemWriter = new Org.BouncyCastle.OpenSsl.PemWriter(textWriter);
                pemWriter.WriteObject(keyPair.Private);
                pemWriter.Writer.Flush();

                privateKey = textWriter.ToString();
            } // End Using textWriter 

            System.Console.WriteLine(privateKey);
        } // End Sub ExportKeyPair 
        
        
        // https://stackoverflow.com/questions/22008337/generating-keypair-using-bouncy-castle
        // https://stackoverflow.com/questions/14052485/converting-a-public-key-in-subjectpublickeyinfo-format-to-rsapublickey-format-ja
        // https://stackoverflow.com/questions/10963756/get-der-encoded-public-key
        // http://www.programcreek.com/java-api-examples/index.php?api=org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory
        public static void CerKeyInfo(Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair keyPair)
        {
            Org.BouncyCastle.Asn1.Pkcs.PrivateKeyInfo pkInfo = Org.BouncyCastle.Pkcs.PrivateKeyInfoFactory.CreatePrivateKeyInfo(keyPair.Private);
            string privateKey = System.Convert.ToBase64String(pkInfo.GetDerEncoded());

            // and following for public:
            Org.BouncyCastle.Asn1.X509.SubjectPublicKeyInfo info = Org.BouncyCastle.X509.SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keyPair.Public);
            string publicKey = System.Convert.ToBase64String(info.GetDerEncoded());

            System.Console.WriteLine(privateKey);
            System.Console.WriteLine(publicKey);
        } // End Sub CerKeyInfo 
        
        
    } // End Class KeyImportExport 
    
    
} // End Namespace RedmineMailService.CertSSL 

哦,这是使用PFX进行操作的方法:

namespace SelfSignedCertificateGenerator
{


    public class PfxData
    {
        public Org.BouncyCastle.X509.X509Certificate Certificate;
        public Org.BouncyCastle.Crypto.AsymmetricKeyParameter PrivateKey;
    }


    public class PfxFile
    {


        // System.Security.Cryptography.X509Certificates.X509Certificate2.Import (string fileName);

        // https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.x509certificates.x509certificate2.import?view=netframework-4.7.2
        // https://gist.github.com/yutopio/a217a4af63cf6bcf0a530c14c074cf8f
        // https://gist.githubusercontent.com/yutopio/a217a4af63cf6bcf0a530c14c074cf8f/raw/42b2f8cb27f6d22b7e22d65da5bbd0f1ce9b2fff/cert.cs
        // https://stackoverflow.com/questions/44755155/store-pkcs12-container-pfx-with-bouncycastle
        // https://github.com/Worlaf/RSADemo/blob/328692e28e48db92340d55563480c8724d916384/RSADemo_WinForms/frmRsaDemo.cs
        public static void Create(
              string fileName
            , Org.BouncyCastle.X509.X509Certificate certificate
            , Org.BouncyCastle.Crypto.AsymmetricKeyParameter privateKey
              , string password = "")
        {
            // create certificate entry
            Org.BouncyCastle.Pkcs.X509CertificateEntry certEntry =
                new Org.BouncyCastle.Pkcs.X509CertificateEntry(certificate);
            string friendlyName = certificate.SubjectDN.ToString();

            if (!friendlyName.Contains("obelix", System.StringComparison.InvariantCultureIgnoreCase))
                friendlyName = "Skynet Certification Authority";
            else
                friendlyName = "Coopérative Ménhir Obelix Gmbh & Co. KGaA";


            // get bytes of private key.
            Org.BouncyCastle.Asn1.Pkcs.PrivateKeyInfo keyInfo = Org.BouncyCastle.Pkcs.PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateKey);
            //byte[] keyBytes = keyInfo.ToAsn1Object().GetEncoded();

            Org.BouncyCastle.Pkcs.Pkcs12StoreBuilder builder = new Org.BouncyCastle.Pkcs.Pkcs12StoreBuilder();
            builder.SetUseDerEncoding(true);



            Org.BouncyCastle.Pkcs.Pkcs12Store store = builder.Build();

            store.SetCertificateEntry(friendlyName, certEntry);

            // create store entry
            store.SetKeyEntry(
                  //keyFriendlyName
                  friendlyName
                , new Org.BouncyCastle.Pkcs.AsymmetricKeyEntry(privateKey)
                , new Org.BouncyCastle.Pkcs.X509CertificateEntry[] { certEntry }
            );


            byte[] pfxBytes = null;

            using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
            {
                // Cert is contained in store
                // null: no password, "": an empty passwords
                // note: Linux needs empty password on null...
                store.Save(stream, password == null ? "".ToCharArray() : password.ToCharArray(), new Org.BouncyCastle.Security.SecureRandom());
                // stream.Position = 0;
                pfxBytes = stream.ToArray();
            } // End Using stream 


#if WITH_MS_PFX
            WithMsPfx(pfxBytes, fileName, password);
#else
            byte[] result = Org.BouncyCastle.Pkcs.Pkcs12Utilities.ConvertToDefiniteLength(pfxBytes);
            // this.StoreCertificate(System.Convert.ToBase64String(result));

            using (System.IO.BinaryWriter writer = new System.IO.BinaryWriter(System.IO.File.Open(fileName, System.IO.FileMode.Create)))
            {
                writer.Write(result);
            } // End Using writer 
#endif

        } // End Sub Create


        private static void WithMsPfx(byte[] pfxBytes, string fileName, string password)
        {
            System.Security.Cryptography.X509Certificates.X509Certificate2 convertedCertificate =
                new System.Security.Cryptography.X509Certificates.X509Certificate2(pfxBytes,
                    "", // PW
                    System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.PersistKeySet | System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.Exportable);

            byte[] bytes = convertedCertificate.Export(System.Security.Cryptography.X509Certificates.X509ContentType.Pfx, password);
            System.IO.File.WriteAllBytes(fileName, bytes);
        } // End Sub WithMsPfx 



        public static PfxData Read(string pfxFilePath, string password = "")
        {
            Org.BouncyCastle.Pkcs.Pkcs12Store store = null;

            using (System.IO.Stream pfxStream = System.IO.File.OpenRead(pfxFilePath))
            {
                store = new Org.BouncyCastle.Pkcs.Pkcs12Store(pfxStream, password.ToCharArray());
            }

            // System.Console.WriteLine(store);


            foreach (string alias in store.Aliases)
            {
                Org.BouncyCastle.Pkcs.X509CertificateEntry certEntry = store.GetCertificate(alias);
                Org.BouncyCastle.X509.X509Certificate cert = certEntry.Certificate;

                // Org.BouncyCastle.Crypto.AsymmetricKeyParameter publicKey = cert.GetPublicKey();
                // System.Console.WriteLine(publicKey);

                // https://7thzero.com/blog/bouncy-castle-convert-a-bouncycastle-asymmetrickeyentry-to-a-.ne
                if (store.IsKeyEntry(alias))
                {
                    Org.BouncyCastle.Pkcs.AsymmetricKeyEntry keyEntry = store.GetKey(alias);
                    Org.BouncyCastle.Crypto.AsymmetricKeyParameter privateKey = keyEntry.Key;

                    if (privateKey.IsPrivate)
                        return new PfxData() 
                               { 
                                   Certificate = cert, 
                                   PrivateKey = privateKey 
                               };
                } // End if (store.IsKeyEntry((string)alias))

            } // Next alias 

            return null;
        } // End Sub Read


        public static System.Security.Cryptography.X509Certificates.X509Certificate2 
            MicrosoftCertificateFromPfx(string pfxFilePath, string password = "")
        {
            System.Security.Cryptography.X509Certificates.X509Certificate2 cert =
                  new System.Security.Cryptography.X509Certificates.X509Certificate2(
                  pfxFilePath
                , password
            );

            return cert;
        }


    }


}

答案 5 :(得分:0)

我遇到了相同的问题,并找到了以下解决方案:

首先使用此工具// {https://superdry.apphb.com/tools/online-rsa-key-converter

将prkey.pem转换为prkey.xml。
         var dataString = "test";

        byte[] dataToEncrypt = Encoding.UTF8.GetBytes(dataString);

        RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
        provider.FromXmlString(File.ReadAllText("C:\prkey.xml"));
        byte[] signedBytes = provider.SignData(dataToEncrypt, new SHA256CryptoServiceProvider());

        textBox3.Text = BitConverter.ToString(signedBytes);

答案 6 :(得分:-1)

我不知道.NET(但是Java),但答案应该是一样的 您的pem文件包含证书和私钥 这是OpenSSL中的常见导出 要在Java中实例化X509Certificate对象,您只能使用文件中的部分:

  

-----开始证书-----
        证书数据
  -----结束证书-----

在.NET中它应该是相同的 只需加载文件并加载PEM的那一部分。

对私钥执行相同操作。
在java中,您将使用相应的对象,即PrivateKey来加载它 使用适用于.NET的

答案 7 :(得分:-1)

您可以在http://pages.infinit.net/ctech/20040812-0816.html找到示例代码,它对我有用。