【问题标题】:Reading PEM RSA Public Key Only using Bouncy Castle仅使用 Bouncy Castle 读取 PEM RSA 公钥
【发布时间】:2012-07-05 23:13:48
【问题描述】:

我正在尝试使用 C# 读取仅包含 RSA 公钥的 .pem 文件。我无权访问私钥信息,我的应用程序也不需要它。文件myprivatekey.pem文件以

开头

-----BEGIN PUBLIC KEY----- 并以 -----END PUBLIC KEY-----.

我目前的代码如下:

    Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair keyPair;

    using (var reader = File.OpenText(@"c:\keys\myprivatekey.pem"))
        keyPair = (Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair)new Org.BouncyCastle.OpenSsl.PemReader(reader).ReadObject();

但是代码会抛出带有消息的InvalidCastException

无法转换类型的对象 'Org.BouncyCastle.Crypto.Parameters.DsaPublicKeyParameters' 输入 'Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair'。

当没有可用的私钥信息时,如何使用 Bouncy Castle 的 PemReader 仅读取公钥?

【问题讨论】:

  • 单个公钥不是密钥对。密钥对是一个公钥一个私钥。

标签: c# bouncycastle public-key pem


【解决方案1】:

以下代码将从给定文件名中读取公钥。应该为任何生产代码更改异常处理。这个方法返回一个AsymetricKeyParameter

public Org.BouncyCastle.Crypto.AsymmetricKeyParameter ReadAsymmetricKeyParameter(string pemFilename)
{
    var fileStream = System.IO.File.OpenText(pemFilename);
    var pemReader = new Org.BouncyCastle.OpenSsl.PemReader(fileStream);
    var KeyParameter = (Org.BouncyCastle.Crypto.AsymmetricKeyParameter)pemReader.ReadObject();
    return KeyParameter;
}

【讨论】:

  • 这也可以用来读取私钥吗?然后只需在密码函数中传入 false 如:cipher.Init(false, privatekey)。我没有运气就试过了。
【解决方案2】:

代替:

keyPair = (Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair)new Org.BouncyCastle.OpenSsl.PemReader(reader).ReadObject();

用途:

keyPair = (Org.BouncyCastle.Crypto.AsymmetricKeyParameter)new Org.BouncyCastle.OpenSsl.PemReader(reader).ReadObject();

由于您只使用公钥,并且实际上没有一对密钥(公钥和私钥),因此您不能将其转换为“AsymmetricCipherKeyPair”,您应该将其转换为“AsymmetricKeyParameter”。

【讨论】:

    【解决方案3】:

    编辑: 看起来这取决于您使用的密钥文件类型。对于 ssh-keygen 密钥,私钥的类型似乎为 AsymmetricCipherKeyPair,但对于 openssl 密钥,私钥的类型为 RsaPrivateCrtKeyParameters


    Bryan Jyh Herng Chong 的回答似乎不再适合我(至少在 Bouncy Castle v1.8.5 版中)。看来kp.GetType().GetProperty("Private") 不再针对公钥和私钥 PEM 对象进行不同的设置。似乎使用PemReader.ReadObject() 返回的对象现在直接是RsaPrivateCrtKeyParameters 对象,因此不再需要首先通过AsymmetricCipherKeyPair 对象进行转换。

    我把那行改成了这样,它就像一个魅力:

    return (kp.GetType() == typeof(RsaPrivateCrtKeyParameters)) ? MakePrivateRCSP(rsaKey, (RsaPrivateCrtKeyParameters)kp)) : MakePublicRCSP(rsaKey, (RsaKeyParameters)kp);
    

    【讨论】:

      【解决方案4】:

      试试下面的代码:

      Using Org.BouncyCastle.Crypto;
      
      
      string path = HttpContext.Current.Server.MapPath(@"~\key\ABCD.pem");
      
      
      
      AsymmetricCipherKeyPair Key;
      
      TextReader tr = new StreamReader(@path);
      
       PemReader pr = new PemReader(tr);
              Key = (AsymmetricCipherKeyPair)pr.ReadObject();
              pr.Reader.Close();
              tr.Close();
      
      
      
               AsymmetricKeyParameter keaa = Key.Public;
      

      【讨论】:

        【解决方案5】:

        这是一个将公共和私有 PEM 文件读入 RSACryptoServiceProvider 的可能解决方案:

        public class PemReaderB
        {
            public static RSACryptoServiceProvider GetRSAProviderFromPem(String pemstr)
            {
                CspParameters cspParameters = new CspParameters();
                cspParameters.KeyContainerName = "MyKeyContainer";
                RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParameters);
        
                Func<RSACryptoServiceProvider, RsaKeyParameters, RSACryptoServiceProvider> MakePublicRCSP = (RSACryptoServiceProvider rcsp, RsaKeyParameters rkp) =>
                {
                    RSAParameters rsaParameters = DotNetUtilities.ToRSAParameters(rkp);
                    rcsp.ImportParameters(rsaParameters);
                    return rsaKey;
                };
        
                Func<RSACryptoServiceProvider, RsaPrivateCrtKeyParameters, RSACryptoServiceProvider> MakePrivateRCSP = (RSACryptoServiceProvider rcsp, RsaPrivateCrtKeyParameters rkp) =>
                {
                    RSAParameters rsaParameters = DotNetUtilities.ToRSAParameters(rkp);
                    rcsp.ImportParameters(rsaParameters);
                    return rsaKey;
                };
        
                PemReader reader = new PemReader(new StringReader(pemstr));
                object kp = reader.ReadObject();
        
                // If object has Private/Public property, we have a Private PEM
                return (kp.GetType().GetProperty("Private") != null) ? MakePrivateRCSP(rsaKey, (RsaPrivateCrtKeyParameters)(((AsymmetricCipherKeyPair)kp).Private)) : MakePublicRCSP(rsaKey, (RsaKeyParameters)kp);
            }
        
            public static RSACryptoServiceProvider GetRSAProviderFromPemFile(String pemfile)
            {
                return GetRSAProviderFromPem(File.ReadAllText(pemfile).Trim());
            }
        }
        

        希望这对某人有所帮助。

        【讨论】:

        • 对于 Linux / .NET 标准,我最终只是使用无参数构造函数创建了一个新的 RSACryptoServiceProvider。
        【解决方案6】:

        在回答 c0d3Junk13 时,我在 PEM 私钥方面遇到了同样的问题,我花了整个下午才找到使用 C# BouncyCastle 版本 1.7 和 Visual Studio 2013 Desktop Express 的解决方案。不要忘记将项目引用添加到 BouncyCastle.Crypto.dll

        using System;
        using System.Collections.Generic;
        using System.ComponentModel;
        using System.Data;
        using System.Drawing;
        using System.Linq;
        using System.Text;
        using System.Threading.Tasks;
        using System.Windows.Forms;
        using System.Collections;
        using System.IO;
        using Org.BouncyCastle.Asn1.X509;
        using Org.BouncyCastle.Asn1.Pkcs;
        using Org.BouncyCastle.Crypto.Digests;
        using Org.BouncyCastle.Crypto.Parameters;
        using Org.BouncyCastle.Crypto.Signers;
        using Org.BouncyCastle.X509;
        using Org.BouncyCastle.Math;
        using Org.BouncyCastle.Math.EC;
        using Org.BouncyCastle.Utilities.Collections;
        using Org.BouncyCastle.Utilities.Encoders;
        using Org.BouncyCastle.Crypto; 
        using Org.BouncyCastle.Crypto.Engines; 
        using Org.BouncyCastle.OpenSsl;
        
        /* 
            For an Active Directory generated pem, strip out everything in pem file before line:
            "-----BEGIN PRIVATE KEY-----" and re-save.
        */
        string privateKeyFileName = @"C:\CertificateTest\CS\bccrypto-net-1.7-bin\private_key3.pem";
        
        TextReader reader = File.OpenText(privateKeyFileName);
        
        Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters key;
        
        using (reader = File.OpenText(privateKeyFileName))
        {
            key = (Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters)new PemReader(reader).ReadObject();
        }
        
        cipher.Init(false, key);
        
        //Decrypting the input bytes
        
        byte[] decipheredBytes = cipher.ProcessBlock(cipheredBytes, 0, cipheredBytes.Length);
        
        MessageBox.Show(Encoding.UTF8.GetString(decipheredBytes));
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-03-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-10-06
          相关资源
          最近更新 更多