我正在尝试使用 BouncyCastle 将 RSA 私钥读入 .Net 来测试我之前加密的数据。使用公钥和 Bouncy Castle 加密的数据工作正常,我还使用了与下面相同的私钥(DER 格式)在 PHP 应用程序中成功解密我的数据,但我不知道为什么我不能在 .Net 中创建私钥以执行相同的操作:
byte[] privatekey = File.ReadAllBytes(@"C:\Users\Luke\privkey.der");
var rsaKeyParameters = (RsaKeyParameters)PrivateKeyFactory.CreateKey(privatekey);
第二行抛出异常:
“工厂中的未知对象:DerInteger 参数名称:obj"
我还尝试使用流而不是字节数组,并且发生了相同的错误。密钥对是使用 OpenSSL 创建的,如上所述,在 PHP 中使用 openssl_private_decrypt() 和与 .Net 代码中相同的密钥进行解密。我还尝试了相同密钥的 PEM 格式,但这也不起作用(但我不认为 BC 直接支持 PEM)
以前有人这样做过吗?谢谢
问题是我假设 PublicKeyFactory 和 PrivateKeyFactory 是互补的,因为它们位于同一名称空间中。他们不是!
要解码私钥,我需要以下替代代码:
var privKeyObj = Asn1Object.FromStream(privatekey);
var privStruct = new RsaPrivateKeyStructure((Asn1Sequence)privKeyObj);
// Conversion from BouncyCastle to .Net framework types
var rsaParameters = new RSAParameters();
rsaParameters.Modulus = privStruct.Modulus.ToByteArrayUnsigned();
rsaParameters.Exponent = privStruct.PublicExponent.ToByteArrayUnsigned();
rsaParameters.D = privStruct.PrivateExponent.ToByteArrayUnsigned();
rsaParameters.P = privStruct.Prime1.ToByteArrayUnsigned();
rsaParameters.Q = privStruct.Prime2.ToByteArrayUnsigned();
rsaParameters.DP = privStruct.Exponent1.ToByteArrayUnsigned();
rsaParameters.DQ = privStruct.Exponent2.ToByteArrayUnsigned();
rsaParameters.InverseQ = privStruct.Coefficient.ToByteArrayUnsigned();
var rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(rsaParameters);
return Encoding.UTF8.GetString(rsa.Decrypt(Convert.FromBase64String(ciphertext), true));
非常感谢 owlstead 的帮助。
我编写了一个函数,该函数从
Stream
读取并自动检测私钥是 PEM 还是 DER,以及它是 PKCS1 还是 PKCS8 编码。如下:
public static RsaPrivateCrtKeyParameters ReadPrivateKey(Stream stream)
{
int firstByte = stream.ReadByte();
if (firstByte < 0)
throw new Exception($"File reached eof");
stream.Position = 0;
// First byte of DER is 0x30 https://stackoverflow.com/a/1362172/213871
bool isPem = firstByte != 0x30;
if (isPem)
{
using (var strReader = new StreamReader(stream))
{
var pemReader = new PemReader(strReader);
while (strReader.Peek() != -1)
{
var obj = pemReader.ReadObject();
var privatekey = obj as RsaPrivateCrtKeyParameters;
if (privatekey != null)
{
// It's a PKCS#8 encoded private key
return privatekey;
}
else
{
// When reading a PKCS#1 encoded private key BC wants
// to parse a key pair instead, but the private
// parameter seems to be correct
var pair = obj as AsymmetricCipherKeyPair;
if (pair != null && pair.Private != null)
{
return (RsaPrivateCrtKeyParameters)pair.Private;
}
}
}
}
}
else
{
var privKeyObj = Asn1Object.FromStream(stream);
var sequence = (Asn1Sequence)privKeyObj;
if (sequence[2] is Asn1OctetString)
{
// It's a PKCS#8 encoded private key
AsymmetricKeyParameter keyPair = PrivateKeyFactory.CreateKey(PrivateKeyInfo.GetInstance(privKeyObj));
return (RsaPrivateCrtKeyParameters)keyPair;
}
else
{
// Assume it's a PKCS#1 encoded private key
var privStruct = RsaPrivateKeyStructure.GetInstance(privKeyObj);
return new RsaPrivateCrtKeyParameters(privStruct);
}
}
throw new Exception("Could not read private key");
}