入门异常“无效的提供程序类型指定”或“项不存在”,而从X509Certificate2获得私钥偶尔
我得到以下例外之一,而试图从X509Certificate2证书私钥:入门异常“无效的提供程序类型指定”或“项不存在”,而从X509Certificate2获得私钥偶尔
System.Security.Cryptography.CryptographicException:指定了无效的提供程序类型。
OR
System.Security.Cryptography.CryptographicException:键不会在下面的代码行存在:的RSACryptoServiceProvider rsaKey =(的RSACryptoServiceProvider)digiSignCert.PrivateKey;
堆栈跟踪:
System.Security.Cryptography.CryptographicException:键不存在。在System.Security.Cryptography.Utils.GetKeyPairHelper(CspAlgorithmType关键字类型,CspParameters参数,布尔randomKeyContainer,的Int32 dwKeySize,SafeProvHandle & safeProvHandle,SafeKeyHandle & safeKeyHandle)在System.Security.Cryptography.RSACryptoServiceProvider.GetKeyPair()在System.Security.Cryptography。 RSACryptoServiceProvider..ctor(的Int32 dwKeySize,CspParameters参数,布尔useDefaultKeySize)在System.Security.Cryptography.X509Certificates.X509Certificate2.get_PrivateKey()在Api.CertificateUtil.GetSignedXml(字符串XML,X509Certificate2 privateCert)
代码:
public static RSACryptoServiceProvider rsaKey = null;
public X509Certificate2 _PrivateCert;
public APISearch()
{
byte[] privateCert = null;//We get the actual certificate file data here
GetPrivateCerificate(privateCert, "[email protected]");
GetSignedXml(_PrivateCert);
}
public void GetPrivateCerificate(byte[] privateCert, string pwd)
{
_PrivateCert = new X509Certificate2(privateCert, pwd, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
}
public void GetSignedXml(X509Certificate2 privateCert)
{
rsaKey = (RSACryptoServiceProvider)privateCert.PrivateKey; //Occassional Exception
}
预期结果:(RSACryptoServiceProvider)privateCert.PrivateKey
应始终生成一个私钥。
实际结果:有时上述例外,在这行抛出:
rsaKey = (RSACryptoServiceProvider)privateCert.PrivateKey;
,有时私钥被成功从证书文件中取得。截至目前,我们一直无法跟踪这个问题的模式。
RSACryptoServiceProvider
是一种通过Window Cryptographic API(CAPI)库执行RSA的类型。当.NET第一次创建时,CAPI是新的,并且始终是正确的答案(在Windows上)。从Windows Vista开始,有一个新库:加密:下一代(CNG)。为了兼容性,CNG了解如何与CAPI合作。但CAPI不能“做CAPI”和“了解CNG”。您看到的例外情况是,PFX表示应通过CNG存储私钥(或者店内证书表明其私钥通过CNG存储)。
当.NET Framework添加RSACng
时,已经决定有太多人已经写了(RSACryptoServiceProvider)cert.PrivateKey
这一行,这样属性就永远无法返回RSACng
实例。相反,在.NET 4.6中创建了新的(扩展)方法:cert.GetRSAPublicKey()
和cert.GetRSAPrivateKey()
,它们返回RSA
而不是AsymmetricAlgorithm
。同样在.NET 4.6中,RSA基类已得到增强,使Sign/Verify和Encrypt/Decrypt操作向下移动(尽管签名不同,因为自从CAPI写入以来RSA已获得新选项)。
预期结果:
(RSACryptoServiceProvider)privateCert.PrivateKey
应始终生成一个私钥。
实际的真相是cert.PrivateKey
(和cert.PublicKey.Key
)被软弃用。你不应该再打电话给他/他们了。 RSA(4.6),ECDSA(4.6.1)和DSA(4.6.2)都有Get [Algorithm] {Public | Private}键方法。
-
(RSACryptoServiceProvider)cert.PrivateKey
=>cert.GetRSAPrivateKey()
-
rsaCSP.Encrypt(data, false)
=>rsa.Encrypt(data, RSAEncryptionPadding.Pkcs1)
-
rsaCSP.Encrypt(data, true)
=>rsa.Encrypt(data, RSAEncryptionPadding.OaepSHA1)
-
rsaCSP.SignData(data, "SHA256")
=>rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)
类似为Decrypt
,SignHash
,VerifyData
,VerifyHash
;并且类似于ECDsa
和DSA
。
最后,请不要强制转换这些方法的返回值,它会根据需要进行更改......在Windows上,它可以返回RSACng或RSACryptoServiceProvider,它在Linux(.NET Core)上返回RSAOpenSsl ,并在macOS(.NET Core)上返回一个不可播放的对象。