C# - 如何使用 Bouncy Castle 解密加密的私钥
C# - How to Decrypt an Encrypted Private Key with Bouncy Castle
我有一个由 运行:
生成的私钥
openssl req -new -sha384 -x509 -days 63524 -subj "/C=CA/ST=State/L=City/O=Org/CN=Org-CA" -extensions v3_ca -keyout Org-CA.key -out Org-CA.pem -passout pass:pass1234
我需要使用这个私钥和证书来签署客户端 CSR。我曾经使用 OpenSSL 来执行此操作,但我需要在 C# 中执行此操作。
我在网上找到了我想做的事情的示例,但这些示例使用的是充气城堡和未加密的私钥。
密钥文件如下所示:
-----BEGIN ENCRYPTED PRIVATE KEY-----
....
-----END ENCRYPTED PRIVATE KEY-----
我正在尝试通过这样做来加载它:
var privatekey = File.ReadAllBytes(@"Org-CA.key");
var rsaKeyParameters = PrivateKeyFactory.DecryptKey("pass1234".ToArray(), privatekey);
但这不起作用。我收到一条错误消息 Wrong number of elements in sequence (Parameter 'seq')'
这就是我解密和加载私钥的方式吗?
根据您的 .NET 版本,您可能根本不需要 BouncyCastle。从 .NET Core 3.1 开始,PEM 编码的加密密钥有 RSA.ImportEncryptedPkcs8PrivateKey()
for DER encoded encrypted private PKCS#8 keys and as of .NET 5.0 there is even RSA.ImportFromEncryptedPem()
。
否则,使用 C#/BouncyCastle 可以导入加密的 PKCS#8 私钥,例如与:
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
...
string encPkcs8 = @"-----BEGIN ENCRYPTED PRIVATE KEY-----
...
-----END ENCRYPTED PRIVATE KEY-----";
StringReader stringReader = new StringReader(encPkcs8);
PemReader pemReader = new PemReader(stringReader, new PasswordFinder("<your password>"));
RsaPrivateCrtKeyParameters keyParams = (RsaPrivateCrtKeyParameters)pemReader.ReadObject();
...
使用 IPasswordFinder
接口的以下实现:
private class PasswordFinder : IPasswordFinder
{
private string password;
public PasswordFinder(string pwd) => password = pwd;
public char[] GetPassword() => password.ToCharArray();
}
如有必要,可以通过以下方式从 keyParams
转换为 System.Security.Cryptography.RSAParameters
:
using Org.BouncyCastle.Security;
...
RSAParameters rsaParameters = DotNetUtilities.ToRSAParameters(keyParams);
可以直接导入 e.g. RSA.ImportParameters()
.
编辑:
翻了C#/BouncyCastle的源码,你的方法也是可以的(之前不知道)
DecryptKey()
有几个重载,其中一个可以处理 DER 编码的加密密钥,正如 Maarten Bodewes 在他的评论中所怀疑的那样。后者可以很容易地用 Org.BouncyCastle.Utilities.IO.Pem.PemReader()
class.
生成
请注意,此 PemReader
与第一个实现中的不同(不同的命名空间),这就是我在以下代码片段中显式使用命名空间的原因。使用这种方法,可以按如下方式生成 RsaPrivateCrtKeyParameters
实例:
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto.Parameters;
...
StringReader stringReader = new StringReader(encPkcs8);
Org.BouncyCastle.Utilities.IO.Pem.PemReader pemReader = new Org.BouncyCastle.Utilities.IO.Pem.PemReader(stringReader);
Org.BouncyCastle.Utilities.IO.Pem.PemObject pem = pemReader.ReadPemObject();
RsaPrivateCrtKeyParameters keyParams = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.DecryptKey("<your password>".ToCharArray(), pem.Content);
...
pem.Content
包含 DER 编码的加密私钥 PKCS#8。
我有一个由 运行:
生成的私钥openssl req -new -sha384 -x509 -days 63524 -subj "/C=CA/ST=State/L=City/O=Org/CN=Org-CA" -extensions v3_ca -keyout Org-CA.key -out Org-CA.pem -passout pass:pass1234
我需要使用这个私钥和证书来签署客户端 CSR。我曾经使用 OpenSSL 来执行此操作,但我需要在 C# 中执行此操作。
我在网上找到了我想做的事情的示例,但这些示例使用的是充气城堡和未加密的私钥。
密钥文件如下所示:
-----BEGIN ENCRYPTED PRIVATE KEY-----
....
-----END ENCRYPTED PRIVATE KEY-----
我正在尝试通过这样做来加载它:
var privatekey = File.ReadAllBytes(@"Org-CA.key");
var rsaKeyParameters = PrivateKeyFactory.DecryptKey("pass1234".ToArray(), privatekey);
但这不起作用。我收到一条错误消息 Wrong number of elements in sequence (Parameter 'seq')'
这就是我解密和加载私钥的方式吗?
根据您的 .NET 版本,您可能根本不需要 BouncyCastle。从 .NET Core 3.1 开始,PEM 编码的加密密钥有 RSA.ImportEncryptedPkcs8PrivateKey()
for DER encoded encrypted private PKCS#8 keys and as of .NET 5.0 there is even RSA.ImportFromEncryptedPem()
。
否则,使用 C#/BouncyCastle 可以导入加密的 PKCS#8 私钥,例如与:
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
...
string encPkcs8 = @"-----BEGIN ENCRYPTED PRIVATE KEY-----
...
-----END ENCRYPTED PRIVATE KEY-----";
StringReader stringReader = new StringReader(encPkcs8);
PemReader pemReader = new PemReader(stringReader, new PasswordFinder("<your password>"));
RsaPrivateCrtKeyParameters keyParams = (RsaPrivateCrtKeyParameters)pemReader.ReadObject();
...
使用 IPasswordFinder
接口的以下实现:
private class PasswordFinder : IPasswordFinder
{
private string password;
public PasswordFinder(string pwd) => password = pwd;
public char[] GetPassword() => password.ToCharArray();
}
如有必要,可以通过以下方式从 keyParams
转换为 System.Security.Cryptography.RSAParameters
:
using Org.BouncyCastle.Security;
...
RSAParameters rsaParameters = DotNetUtilities.ToRSAParameters(keyParams);
可以直接导入 e.g. RSA.ImportParameters()
.
编辑:
翻了C#/BouncyCastle的源码,你的方法也是可以的(之前不知道)
DecryptKey()
有几个重载,其中一个可以处理 DER 编码的加密密钥,正如 Maarten Bodewes 在他的评论中所怀疑的那样。后者可以很容易地用 Org.BouncyCastle.Utilities.IO.Pem.PemReader()
class.
生成
请注意,此 PemReader
与第一个实现中的不同(不同的命名空间),这就是我在以下代码片段中显式使用命名空间的原因。使用这种方法,可以按如下方式生成 RsaPrivateCrtKeyParameters
实例:
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto.Parameters;
...
StringReader stringReader = new StringReader(encPkcs8);
Org.BouncyCastle.Utilities.IO.Pem.PemReader pemReader = new Org.BouncyCastle.Utilities.IO.Pem.PemReader(stringReader);
Org.BouncyCastle.Utilities.IO.Pem.PemObject pem = pemReader.ReadPemObject();
RsaPrivateCrtKeyParameters keyParams = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.DecryptKey("<your password>".ToCharArray(), pem.Content);
...
pem.Content
包含 DER 编码的加密私钥 PKCS#8。