问题描述
我需要导出和导入生成具有私钥证书,并从字节数组,除非我用.NET框架4.0和4.5,我没有任何问题。我生成与库自签名证书,然后将它们转换为.NET格式(X509Certificate2对象)。不幸的是在升级到最新的框架,我无法导出私钥。下面是代码:
I need to export and import generated certificates with private keys to and from byte arrays and I don't have any problems unless I use .NET framework 4.0 and 4.5. I'm generating self-signed certificates with BouncyCastle library and then converting them to .net format (X509Certificate2 object). Unfortunately with the upgrade to a newest framework I cannot export private keys. Here is the code:
using System;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Prng;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.X509;
namespace X509CertificateExport
{
class Program
{
static void Main(string[] args)
{
var certificate = Generate();
var exported = certificate.Export(X509ContentType.Pfx);
var imported = new X509Certificate2(exported, (string)null, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);
Console.WriteLine("Certificate has private key: " + imported.HasPrivateKey);
Console.ReadKey();
}
public static X509Certificate2 Generate()
{
var keyPairGenerator = new RsaKeyPairGenerator();
var secureRandom = new SecureRandom(new CryptoApiRandomGenerator());
keyPairGenerator.Init(new KeyGenerationParameters(secureRandom, 1024));
var keyPair = keyPairGenerator.GenerateKeyPair();
var publicKey = keyPair.Public;
var privateKey = (RsaPrivateCrtKeyParameters)keyPair.Private;
var generator = new X509V3CertificateGenerator();
generator.SetSerialNumber(BigInteger.ProbablePrime(120, new Random()));
generator.SetSubjectDN(new X509Name("CN=Test"));
generator.SetIssuerDN(new X509Name("CN=Test"));
generator.SetNotAfter(DateTime.Now + new TimeSpan(10, 10, 10, 10));
generator.SetNotBefore(DateTime.Now.Subtract(new TimeSpan(7, 0, 0, 0)));
generator.SetSignatureAlgorithm("MD5WithRSA");
generator.SetPublicKey(publicKey);
var newCert = generator.Generate(privateKey);
var dotNetPrivateKey = ToDotNetKey(privateKey);
var dotNetCert = new X509Certificate2(DotNetUtilities.ToX509Certificate(newCert));
dotNetCert.PrivateKey = dotNetPrivateKey;
return dotNetCert;
}
public static AsymmetricAlgorithm ToDotNetKey(RsaPrivateCrtKeyParameters privateKey)
{
var rsaProvider = new RSACryptoServiceProvider();
var parameters = new RSAParameters
{
Modulus = privateKey.Modulus.ToByteArrayUnsigned(),
P = privateKey.P.ToByteArrayUnsigned(),
Q = privateKey.Q.ToByteArrayUnsigned(),
DP = privateKey.DP.ToByteArrayUnsigned(),
DQ = privateKey.DQ.ToByteArrayUnsigned(),
InverseQ = privateKey.QInv.ToByteArrayUnsigned(),
D = privateKey.Exponent.ToByteArrayUnsigned(),
Exponent = privateKey.PublicExponent.ToByteArrayUnsigned()
};
rsaProvider.ImportParameters(parameters);
return rsaProvider;
}
}
}
在仔细看的生成的证书我注意到PrivateKey.CspKeyContainerInfo.Exportable标志用于.NET Framework 3.5的真实的,但更高版本的它抛出:
After a closer look to the generated certificate I've noticed that PrivateKey.CspKeyContainerInfo.Exportable flag is true for .NET framework 3.5, but for later versions it throws:
'Exportable' threw an exception of type
'System.Security.Cryptography.CryptographicException' / Key does not exist
我看到的唯一区别是在PrivateKey.CspKeyContainerInfo.m_parameters.Flags:
.NET 3.5 - 'NoFlags';
.NET 4.5 - 'CreateEphemeralKey。
文档指出CreateEphemeralKey创建时关联RSA对象被关闭时释放的临时密钥。其用4.0框架引入之前并不存在。我试图获得通过明确创建CspParameters摆脱掉这个标志:
The only difference I see is in PrivateKey.CspKeyContainerInfo.m_parameters.Flags:.NET 3.5 - 'NoFlags';.NET 4.5 - 'CreateEphemeralKey'.Documentation states that 'CreateEphemeralKey' creates a temporary key that is released when the associated RSA object is closed. It was introduced with 4.0 framework and didn't exist before. I've tried to get rid off this flag by creating CspParameters explicitly:
public static AsymmetricAlgorithm ToDotNetKey(RsaPrivateCrtKeyParameters privateKey)
{
var cspParams = new CspParameters
{
Flags = CspProviderFlags.UseMachineKeyStore
};
var rsaProvider = new RSACryptoServiceProvider(cspParams);
// ...
但没有运气。 CreateEphemeralKey反正是添加,所以我得到结果 UseMachineKeyStore | CreateEphemeralKey
标记,我不知道怎样才能将其删除。有没有什么办法可以忽略与正常私钥这个标志和出口证书?
but with no luck. 'CreateEphemeralKey' is added anyway, so I'm getting as a result UseMachineKeyStore | CreateEphemeralKey
flags and I don't see how I can remove it. Is there any way I can ignore this flag and export certificate with private key normally?
推荐答案
我还没有注意到 CspKeyContainerInfo.CspParameters.KeyContainerName
是在.NET 4.0和.NET 4.5密钥创建后空,但自动生成了.NET 3.5中。我给自己定的容器的唯一名称,现在我能够导出私钥。
I haven't noticed that CspKeyContainerInfo.CspParameters.KeyContainerName
is empty after key creation in .NET 4.0 and .NET 4.5, but was autogenerated in .NET 3.5. I've set a unique name for container and now I'm able to export private key.
public static AsymmetricAlgorithm ToDotNetKey(RsaPrivateCrtKeyParameters privateKey)
{
var cspParams = new CspParameters
{
KeyContainerName = Guid.NewGuid().ToString(),
KeyNumber = (int)KeyNumber.Exchange,
Flags = CspProviderFlags.UseMachineKeyStore
};
var rsaProvider = new RSACryptoServiceProvider(cspParams);
// ...
这篇关于不能与私有密钥导出生成的证书,以字节数组中.NET 4.0 / 4.5的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!