仅使用 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 公钥的主要内容,如果未能解决你的问题,请参考以下文章