仅使用 Bouncy Castle 读取 PEM RSA 公钥

Posted

技术标签:

【中文标题】仅使用 Bouncy Castle 读取 PEM RSA 公钥【英文标题】:Reading PEM RSA Public Key Only using Bouncy Castle 【发布时间】: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 仅读取公钥?

【问题讨论】:

单个公钥不是密钥对。密钥对是一个公钥一个私钥。 【参考方案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));

【讨论】:

以上是关于仅使用 Bouncy Castle 读取 PEM RSA 公钥的主要内容,如果未能解决你的问题,请参考以下文章

Bouncy Castle J2ME 加载现有私钥

如何使用Bouncy Castle Crypto API来加密和解密数据

在 C# 中使用 Bouncy Castle 加密/解密

Bouncy Castle Java PGP加解密

markdown CSS 3D Bouncy Castle

Bouncy Castle PGP 解密问题