简体   繁体   English

仅使用 Bouncy Castle 读取 PEM RSA 公钥

[英]Reading PEM RSA Public Key Only using Bouncy Castle

I am trying to use C# to read in a .pem file that contains only a RSA public key.我正在尝试使用 C# 读取仅包含 RSA 公钥的.pem文件。 I do not have access to the private key information, nor does my application require it.我无权访问私钥信息,我的应用程序也不需要它。 The file myprivatekey.pem file begins with文件myprivatekey.pem文件以

-----BEGIN PUBLIC KEY----- and ends with -----END PUBLIC KEY----- . -----BEGIN PUBLIC KEY-----并以-----END PUBLIC KEY-----

My current code is as follows:我目前的代码如下:

    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();

However the code throws an InvalidCastException with the message但是代码会抛出一个InvalidCastException消息

Unable to cast object of type 'Org.BouncyCastle.Crypto.Parameters.DsaPublicKeyParameters' to type 'Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair'.无法将“Org.BouncyCastle.Crypto.Parameters.DsaPublicKeyParameters”类型的对象转换为类型“Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair”。

How can I use Bouncy Castle's PemReader to read only a public key, when no private key information is available?当没有可用的私钥信息时,如何使用 Bouncy Castle 的PemReader只读取公钥?

The following code will read a public key from a given filename.以下代码将从给定文件名中读取公钥。 The exception handling should be changed for any production code.应针对任何生产代码更改异常处理。 This method returns an AsymetricKeyParameter :此方法返回一个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;
}

Here's a possible solution that reads both public and private PEM files into RSACryptoServiceProvider:这是将公共和私有 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());
    }
}

Hope this helps someone.希望这对某人有帮助。

In answer to c0d3Junk13, I had the same issue for a PEM private key and it took me all afternoon to find the solution using the C# BouncyCastle Version 1.7 and Visual Studio 2013 Desktop Express.在回答 c0d3Junk13 时,我遇到了与 PEM 私钥相同的问题,我花了整个下午才找到使用 C# BouncyCastle 1.7 版和 Visual Studio 2013 Desktop Express 的解决方案。 Don't forget to add the project reference to BouncyCastle.Crypto.dll不要忘记将项目引用添加到 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));

EDIT : It looks like this depends on what type of key file you are using.编辑:这看起来取决于您使用的密钥文件类型。 For ssh-keygen keys, the private key appears to have a type of AsymmetricCipherKeyPair , but for openssl keys, the private key has a type of RsaPrivateCrtKeyParameters .对于ssh-keygen密钥,私钥似乎具有AsymmetricCipherKeyPair类型,但对于openssl密钥,私钥具有RsaPrivateCrtKeyParameters类型。


Bryan Jyh Herng Chong's answer no longer appears to work for me (at least with Bouncy Castle version v1.8.5). Bryan Jyh Herng Chong 的回答似乎不再适合我(至少对于 Bouncy Castle 版本 v1.8.5)。 It appears kp.GetType().GetProperty("Private") is no longer set differently for public vs private key PEM objects.看起来kp.GetType().GetProperty("Private")不再为公钥和私钥 PEM 对象设置不同。 It also appears that the object returned using PemReader.ReadObject() is now directly a RsaPrivateCrtKeyParameters object, so there's no longer a need to cast through a AsymmetricCipherKeyPair object first.看起来使用PemReader.ReadObject()返回的对象现在直接是RsaPrivateCrtKeyParameters对象,因此不再需要先通过AsymmetricCipherKeyPair对象进行转换。

I changed that line to this and it worked like a charm:我将该行更改为此,它就像一个魅力:

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

Instead of:代替:

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

Use:采用:

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

Since you are only using a public key and you don't actually have a pair of keys (public & private) you can't cast it as 'AsymmetricCipherKeyPair' you should cast it as 'AsymmetricKeyParameter'.由于您只使用公钥并且实际上没有一对密钥(公钥和私钥),因此您不能将其转换为“AsymmetricCipherKeyPair”,您应该将其转换为“AsymmetricKeyParameter”。

Try the following code:试试下面的代码:

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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM