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

39

我有一个包含公钥和私钥的 .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: 

如果我交换私钥部分和公钥部分的位置,代码可以工作并加载数据,我可以从对象中获取公钥信息,例如IssuerName,而且它的HasPrivateKey为false。为什么?我是否有误解或做错了什么?

7个回答

39

这篇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 方法的支持。


比较部分的 start < 0 将始终为 false!end < 0 是可以的。原因:当 IndexOf 返回 -1 并且您添加 header.Length 时,它在任何情况下都将是正数。您应该先检索索引,然后将索引与 0 进行比较。稍后添加 header.Length。 - huha

19
据我所知,.NET框架没有任何地方支持 PEM。对于 X509Certificate 部分,您可以轻松地绕过此问题,因为您可以提取在-----BEGIN CERTIFICATE----------END CERTIFICATE-----行之间的 base64 字符串,将其转换为 byte[] 并从中创建 X509Certificate
一种简单的解决方案是从 Mono.Security 的 X509Certificate.cs 中复制粘贴代码以执行此操作。
获取私钥有点棘手,因为获取 byte[] 对于重构 RSA 实例不会有太大帮助(我们可以假设它是 RSA,因为 PEM 标头指定了它)。
这次最好从 Mono.Security 的 PKCS8.cs 文件中复制粘贴并简单调用 decode 方法。
免责声明:我是上面讨论的 Mono 代码的主要作者,它都在 MIT.X11 许可下可用。

当我移除了所有的单例类后,我最终使用了这个。 var PrivateKeyInfo = new PKCS8.PrivateKeyInfo(PrivateKey); rsa.ImportCspBlob(PrivateKeyInfo.PrivateKey); - Donny V.

14

我遇到了同样的问题,为了记录,我在这里发布一个完整的、可行的代码示例(因为特定原因密钥被剪切)。它主要是从互联网上找到的东西和我的家庭项目需求的编译。

下面是代码的特点:

  • 从openssl加载可能包含“-----BEGIN RSA PRIVATE KEY -----”的PEM证书
  • 返回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;
        }
    }
}

你使用的是哪个版本的 .net? - AaA
这段代码(特别是在GetIntegerSize中跳过前导零)可能会导致ImportParameters中出现CryptographicException,因为值太短了。它只会偶尔发生。如果不跳过前导零,则可能由于值过长而导致相同的异常。如果在GetIntegerSize中不跳过前导零,则不清楚值是否会变得太短,因为这取决于输入。有关详细信息,请参见https://dev59.com/jZrga4cB1Zd3GeqPiyki#39135984。 - Florian Winter
@andrew.fox:这一切都是正确的,除了对于RSA,除了模数和e之外,不需要指定任何参数...此外,PEM可以编码ECDSA密钥...这只适用于最简单的情况。 - Stefan Steiger

8

另一种方法是将客户端PEM证书转换为Windows支持的PFX格式。例如,可以使用openssl运行以下命令来完成此操作:

openssl pkcs12 -export -out cert.pfx -inkey cert.key -in cert.pem -certfile ca.pem

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


1
你不能这样做。
.NET不支持它。
你看,PEM编码支持多种密钥类型(例如ECDSA)。
因此,如果有人提供了一种从PEM文件中读取.NET RSA密钥的方法,如果PEM也具有D、P、Q、DP、DQ、InverseQ,则您可以读取该RSA密钥,但这与读取PEM还有很长的路要走。
另外,RSA的.NET版本仅基于(Modulus、Exponent和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://dev59.com/F3zaa4cB1Zd3GeqPV-iq
        // https://dev59.com/pmYq5IYBdhLWcg3w-FTQ
        // https://dev59.com/SWTWa4cB1Zd3GeqPGsri
        // 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://learn.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://dev59.com/HaLia4cB1Zd3GeqPqecd
        // 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;
        }


    }


}

-1

我不懂.NET(但懂Java),但答案应该是一样的。
您的pem文件包含证书和私钥。
这是OpenSSL中的常规导出方式。
在Java中实例化X509Certificate对象时,您只需要使用文件中的以下部分:

-----BEGIN CERTIFICATE-----
证书数据
-----END CERTIFICATE-----

.NET应该也是一样的。
只需加载文件并加载PEM的那一部分即可。

私钥也是同样的操作。
在Java中,您将使用相应的对象,即PrivateKey来加载它。
在.NET中使用适当的对象即可。


-2
我遇到了相同的问题,并找到了以下解决方案:
首先使用此工具(//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);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接