无法导出RSA私钥参数,不支持请求的操作

编程入门 行业动态 更新时间:2024-10-15 04:26:03
本文介绍了无法导出RSA私钥参数,不支持请求的操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我有另一方提供的证书文件,该文件正在我的应用程序中加载,无法导出其私钥参数。看来证书使用的是CNG而不是CryptoAPI,所以我不能仅使用GetRSAPrivateKey()方法直接访问私钥。该方法返回 RSACngKey 而不是 RSACryptoServiceProvider ,后者是RSA的另一种实现。问题在于返回的密钥在其导出策略中似乎缺少 CngExportPolicies.AllowPlaintextExport ,因此我无法从此证书中导出RSA参数。我可以通过生成缺少必要出口政策的新证书来重现该问题:

I have a certificate file provided by another party which I'm loading in my application and cannot export its private key parameters. It looks like the certificate is using CNG rather than CryptoAPI, so I can't access the private key directly, only with GetRSAPrivateKey() method. The method returns RSACngKey rather than RSACryptoServiceProvider which is a different implementation of RSA. The problem is that the returned key seems to be missing CngExportPolicies.AllowPlaintextExport in its export policies, and so I can't export RSA parameters from this certificate. I can reproduce the problem by generating a new certificate that misses necessary export policies:

using System; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; namespace TestRsaCngConsole { class Program { static void Main(string[] args) { var oldCertificate = CreateCertificate(); var oldCertificateBytes = oldCertificate.Export(X509ContentType.Pfx, ""); var newCertificate = new X509Certificate2(oldCertificateBytes, "", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet); LogCertificate(oldCertificate, "old certificate"); // this fails LogCertificate(newCertificate, "new certificate"); // works only on Win10 Console.ReadKey(); } private static X509Certificate2 CreateCertificate() { var keyParams = new CngKeyCreationParameters(); keyParams.KeyUsage = CngKeyUsages.Signing; keyParams.Provider = CngProvider.MicrosoftSoftwareKeyStorageProvider; keyParams.ExportPolicy = CngExportPolicies.AllowExport; // here I don't have AllowPlaintextExport keyParams.Parameters.Add(new CngProperty("Length", BitConverter.GetBytes(2048), CngPropertyOptions.None)); var cngKey = CngKey.Create(CngAlgorithm.Rsa, Guid.NewGuid().ToString(), keyParams); var rsaKey = new RSACng(cngKey); var req = new CertificateRequest("cn=mah_cert", rsaKey, HashAlgorithmName.SHA256, RSASignaturePadding.Pss); // requires 4.7.2 var cert = req.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddYears(5)); return cert; } private static void LogCertificate(X509Certificate2 certificate, string name) { Console.WriteLine("----- Testing " + name + " ------"); try { var rsaPrivateKey = certificate.GetRSAPrivateKey(); var parameters = rsaPrivateKey.ExportParameters(true); Console.WriteLine("Certificate private key RSA parameters were successfully exported."); var privateKey = certificate.PrivateKey; Console.WriteLine("Certificate private key is accessible."); } catch (Exception e) { Console.WriteLine(e.ToString()); } } } }

程序在Windows 10上运行时显示以下输出:

The program shows the following output when running on Windows 10:

----- Testing old certificate ------ System.Security.Cryptography.CryptographicException: The requested operation is not supported. at System.Security.Cryptography.NCryptNative.ExportKey(SafeNCryptKeyHandle key, String format) at System.Security.Cryptography.CngKey.Export(CngKeyBlobFormat format) at System.Security.Cryptography.RSACng.ExportParameters(Boolean includePrivateParameters) at TestRsaCngConsole.Program.LogCertificate(X509Certificate2 certificate, String name) in D:\Projects\TestRsaCngConsole\TestRsaCngConsole\Program.cs:line 44 ----- Testing new certificate ------ Certificate private key RSA parameters were successfully exported. Certificate private key is accessible.

因此第一个证书无法导出私钥,因为它的导出策略中缺少AllowPlaintextExport标志。但是在用可导出标志重新加载旧证书之后,我可以导出新证书参数。但是,它在Windows Server 2012或Windows Server 2016上不起作用,并且会为两个证书抛出异常:

So the first certificate fails to export the private key, because it is missing AllowPlaintextExport flag in its export policies. But after re-loading the old certificate with exportable flags I can export the new certificate parameters just fine. However it doesn't work on Windows Server 2012 or Windows Server 2016 and throws exceptions for both certificates:

----- Testing old certificate ------ System.Security.Cryptography.CryptographicException: The requested operation is not supported. at System.Security.Cryptography.NCryptNative.ExportKey(SafeNCryptKeyHandle key, String format) at System.Security.Cryptography.CngKey.Export(CngKeyBlobFormat format) at System.Security.Cryptography.RSACng.ExportParameters(Boolean includePrivateParameters) at TestRsaCngConsole.Program.LogCertificate(X509Certificate2 certificate, String name) in D:\Projects\TestRsaCngConsole\TestRsaCngConsole\Program.cs:line 44 ----- Testing new certificate ------ System.Security.Cryptography.CryptographicException: The requested operation is not supported. at System.Security.Cryptography.NCryptNative.ExportKey(SafeNCryptKeyHandle key, String format) at System.Security.Cryptography.CngKey.Export(CngKeyBlobFormat format) at System.Security.Cryptography.RSACng.ExportParameters(Boolean includePrivateParameters) at TestRsaCngConsole.Program.LogCertificate(X509Certificate2 certificate, String name) in D:\Projects\TestRsaCngConsole\TestRsaCngConsole\Program.cs:line 44

我需要能够修复证书并能够导出RSA参数,即使证书最初缺少AllowPlaintextExport。在Windows Server上有何不同之处,并且有一种方法可以修复证书?

I need to be able to fix the certificate and make it possible to export the RSA parameters, even if the cert was originally missing AllowPlaintextExport. What is so different on Windows Server and is there a way to fix the certificate?

推荐答案

不幸的是,导出证书的唯一方法该状态下的密钥是P / Invoke到NCryptExportKey中以设置加密的导出;然后通过NCryptImportKey将其导入到新密钥中,然后将导出策略设置为AllowPlaintextExport。

Unfortunately, the only way to export the key in that state is to P/Invoke into NCryptExportKey to set up an encrypted export; then import that into a new key via NCryptImportKey, and then set the export policy to AllowPlaintextExport.

从.NET Core 3.0开始,这将变得更加容易:

Starting in .NET Core 3.0 this will be easier:

using (RSA exportRewriter = RSA.Create()) { // Only one KDF iteration is being used here since it's immediately being // imported again. Use more if you're actually exporting encrypted keys. exportRewriter.ImportEncryptedPkcs8( "password", rsa.ExportEncryptedPkcs8( "password", new PbeParameters( PbeEncryptionAlgorithm.Aes128Cbc, HashAlgorithmName.SHA256, 1)), out _); return exportRewriter.ExportParameters(true); }

用于导出加密的.NET Core代码位于 github/dotnet/corefx/blob/64477348da1ff57a43deb65a4b12d32986ed00bd/src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/CngKey.Export.cs#L126-L237 ,不是一个非常好的API,必须从C#调用。

The .NET Core code for exporting encrypted is at github/dotnet/corefx/blob/64477348da1ff57a43deb65a4b12d32986ed00bd/src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/CngKey.Export.cs#L126-L237, it's not a very nice API to have to call from C#.

更多推荐

无法导出RSA私钥参数,不支持请求的操作

本文发布于:2023-11-12 10:52:56,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1581284.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:不支持   参数   操作   RSA

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!