Чтение открытого ключа PEM RSA только с использованием Bouncy Castle
Я пытаюсь использовать C# для чтения в .pem
файл, который содержит только открытый ключ RSA. У меня нет доступа к информации о секретных ключах, и мое приложение не требует этого. Файл 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's PemReader
читать только открытый ключ, когда информация о секретном ключе недоступна?
3 ответа
Следующий код будет читать открытый ключ только с учетом имени файла. Обработка исключений должна быть изменена для любого производственного кода. Этот метод возвращает 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;
}
Вот возможное решение, которое считывает как открытые, так и частные файлы 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());
}
}
Надеюсь, это кому-нибудь поможет.
Вместо того:
keyPair = (Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair) новый Org.BouncyCastle.OpenSsl.PemReader(читатель).ReadObject();
Использование:
keyPair = (Org.BouncyCastle.Crypto.AsymmetricKeyParameter) новый Org.BouncyCastle.OpenSsl.PemReader(читатель).ReadObject();
Поскольку вы используете только открытый ключ и на самом деле у вас нет пары ключей (открытого и закрытого), вы не можете преобразовать его как "AsymmetricCipherKeyPair", вы должны указать его как "AsymmetricKeyParameter".
РЕДАКТИРОВАТЬ: похоже, это зависит от того, какой тип файла ключа вы используете. Для ключей ssh-keygen закрытый ключ имеет вид AsymmetricCipherKeyPair
, но для ключей openssl закрытый ключ имеет тип RsaPrivateCrtKeyParameters
,
Ответ Брайана Джи Хернг Чонга больше не работает для меня (по крайней мере, в версии 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);
В ответ на 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));
Попробуйте следующий код:
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;