无法将带有私钥的生成证书导出到.net 4.0 / 4.5中的字节数组

我需要使用私钥导出和导入生成的证书到字节数组和从字节数组导入,除非我使用.NET framework 4.0和4.5,否则我没有任何问题。 我正在使用BouncyCastle库生成自签名证书,然后将它们转换为.net格式(X509Certificate2对象)。 不幸的是,升级到最新的框架我无法导出私钥。 这是代码:

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; } } } 

仔细查看生成的证书后,我注意到对于.NET Framework 3.5,PrivateKey.CspKeyContainerInfo.Exportable标志是正确的,但对于以后的版本,它会抛出:

 '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来摆脱这个标志:

 public static AsymmetricAlgorithm ToDotNetKey(RsaPrivateCrtKeyParameters privateKey) { var cspParams = new CspParameters { Flags = CspProviderFlags.UseMachineKeyStore }; var rsaProvider = new RSACryptoServiceProvider(cspParams); // ... 

但没有运气。 无论如何都添加了’CreateEphemeralKey’,因此我得到的结果是UseMachineKeyStore | CreateEphemeralKey UseMachineKeyStore | CreateEphemeralKey标志,我不知道如何删除它。 有没有办法可以忽略这个标志并通常用私钥导出证书?

我没有注意到在.NET 4.0和.NET 4.5中创建密钥后CspKeyContainerInfo.CspParameters.KeyContainerName为空,但是在.NET 3.5中自动生成。 我为容器设置了一个唯一的名称,现在我可以导出私钥。

 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); // ...