CryptographicException:使用SHA-512时,“指定了无效的算法”

时间:2019-01-02 21:20:34

标签: c# .net windows x509certificate2 sha512

在我的WPF应用程序(.NET 4.6)中,我需要使用P12证书文件来使用SHA-512算法(包括在Web请求的标题中)对字符串进行签名。我这样做如下:

using (var rsa = myX509Certificate2.GetRSAPrivateKey()) {
  myBytes = rsa.SignData(
    Encoding.UTF8.GetBytes(stringToSign), 
    HashAlgorithmName.SHA512, 
    RSASignaturePadding.Pkcs1
  );
}

这适用于几乎所有客户的测试,但是奇怪的客户遇到以下异常:

System.Security.Cryptography.CryptographicException: Invalid algorithm specified.
  at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr)
  at System.Security.Cryptography.Utils.SignValue(SafeKeyHandle hKey, Int32 keyNumber, Int32 calgKey, Int32 calgHash, Byte[] hash, Int32 cbHash, ObjectHandleOnStack retSignature)
  at System.Security.Cryptography.Utils.SignValue(SafeKeyHandle hKey, Int32 keyNumber, Int32 calgKey, Int32 calgHash, Byte[] hash)
  at System.Security.Cryptography.RSACryptoServiceProvider.SignHash(Byte[] rgbHash, Int32 calgHash)
  at System.Security.Cryptography.RSACryptoServiceProvider.SignHash(Byte[] hash, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding)
  at System.Security.Cryptography.RSA.SignData(Byte[] data, Int32 offset, Int32 count, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding)
  at System.Security.Cryptography.RSA.SignData(Byte[] data, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding)

最近一次发生在Windows 7 SP1上的客户身上。

我正在努力通过现有的SO问题或一般从google找到答案。据我所知,这可能是由于幕后使用了不受支持的Windows加密服务提供商所致,但是我不确定,因为我自己无法复制该错误。

有任何想法如何通过代码或通过让受影响的客户安装任何特定的Windows更新来解决这一问题?

1 个答案:

答案 0 :(得分:0)

如果您使用的是cert.GetRSAPrivateKey(),并且它返回了一个RSACryptoServiceProvider实例,则表明它不是来自PFX,而是来自具有旧驱动程序的智能卡。既然您说它是来自.p12 / .pfx,那么PFX可能包含对CNG不会接管的常规加密服务提供者名称的引用(但我从未在软件密钥中看到它)。 (Occam的Razor询问:您确定他们不是偶然使用了错误的证书吗?)

如果您知道它来自PFX,并且已使用Exportable位将其导入,则可以将其从RSACryptoServiceProvider手动转换为RSACng:

using (RSA rsa = cert.GetRSAPrivateKey())
{
    byte[] toSign = Encoding.UTF8.GetBytes(stringToSign);
    myBytes = null;

    try
    {
        myBytes = rsa.SignData(
            toSign, 
            HashAlgorithmName.SHA512, 
            RSASignaturePadding.Pkcs1);
    }
    catch (CryptographicException)
    {
        try
        {
            using (RSA rsaCng = new RSACng())
            {
                rsaCng.ImportParameters(rsa.ExportParameters(true));

                myBytes = rsaCng.SignData(
                    toSign,
                    HashAlgorithmName.SHA512, 
                    RSASignaturePadding.Pkcs1);
            }
        }
        catch
        {
        }

        if (myBytes == null)
        {
            // Let the original exception continue
            throw;
        }
    }
}

(作为原始异常抛出的替代方法,您可以决定让“重试”异常抛出)


或者,Windows 10修复了许多RSACryptoServiceProvider“无效算法”行为,因此他们可以随时尝试升级。