为什么我会收到“指定的算法无效”异常?

26

这是我的代码。

X509Certificate pXCert = new X509Certificate2(@"keyStore.p12", "password");
RSACryptoServiceProvider csp = (RSACryptoServiceProvider)pXCert.PrivateKey;
string id = CryptoConfig.MapNameToOID("SHA256");
return csp.SignData(File.ReadAllBytes(filePath), id);

在最后一行我遇到了异常:

System.Security.Cryptography.CryptographicException "Invalid algorithm specified."

我做错了什么?

更新:

id = 2.16.840.1.101.3.4.2.1


我已经更新了问题的id值。 - scott
6
请使用pXCert.GetRSAPrivateKey()代替。 - thangcao
1
是的@thangcao,救命稻草的评论!我还要补充一点,现在在2020年,对于.NET 4.6及以上版本,RSA本身支持SignData,如下所示:((RSA)cert.GetRSAPrivateKey()).SignData(bytes, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1) - oflahero
8个回答

18

对于 .NET Framework 4.7.0 或更高版本,不会使用 sha1,因此需要在应用程序启动时配置以下内容。这对我来说很有效。

 AppContext.SetSwitch("Switch.System.Security.Cryptography.Xml.UseInsecureHashAlgorithms", true);
 AppContext.SetSwitch("Switch.System.Security.Cryptography.Pkcs.UseInsecureHashAlgorithms", true);

这是真正的答案,如果你必须使用那个证书,并且正在寻找代码解决方案。谢谢。 - Morcilla de Arroz

16

.NET代码或提供的CSP代码没有问题。

你的问题在于,CSP不支持SHA 256。你可以在这里获取更多信息。


有没有办法让这个工作?我正在从Java移植它,并且需要使用相同的算法。据我所知,它正在使用RSA + SHA。 - scott
您可能希望查看位于 .Net Framework 中的 SHA256 类,请访问http://msdn.microsoft.com/en-us/library/system.security.cryptography.sha256.aspx。但是,我并没有使用过它。 - Patrick Desjardins
此版本仅支持对称密钥用途的SHA-256,例如Kerberos密钥,并且不使用X.509证书来签署消息。由于.NET Framework 3.0目前缺乏RSA-SHA256的支持,因此WCF不支持使用SHA-256哈希的RSA签名(用于X.509证书)。(来源:http://msdn.microsoft.com/en-us/library/aa738624.aspx) - Patrick Desjardins
2
http://hintdesk.com/c-how-to-fix-invalid-algorithm-specified-when-signing-with-sha256/ - Gonzalo Gallotti
我成功解决了这个问题,方法是在创建RSACryptoServiceProvider的新实例时不传入任何CspParameters。 - Nathan Moinvaziri
显示剩余2条评论

12

请注意,我使用SHA512,但SHA256也可以在以下示例中使用:

"Invalid algorithm specified" 对我来说花费了很长时间才找到解决方案,我尝试过几乎所有可能的方法。

步骤1 - 证书必须是SHA512,并使用支持SHA512的CSP(加密服务提供程序)。以下是CSP及其功能列表。如果您寻找SHA512,您将找到“Microsoft Enhanced RSA and AES Cryptographic Provider”。默认情况下,在Windows中生成证书不会使用它,因此您必须在创建证书时指定它。

如果您使用openssl创建证书,您可以使用-CSP选项设置正确的CSP以使其正常工作。如果您有现成的pfx,则可以使用openssl将其转换为PEM文件,然后再转回pfx以添加该选项。

创建私钥和证书-此步骤将询问您问题,如州,地区等。

openssl req -x509 -nodes -sha512 -newkey rsa:2048 -keyout 512key.pem -out 512cert.pem -days 3650

使用Microsoft增强型RSA和AES加密提供程序创建PFX文件,以便导入到您的证书存储中:

openssl pkcs12 –export –in 512cert.pem –inkey 512key.pem –CSP “Microsoft Enhanced RSA and AES Cryptographic Provider” –out 512pfx.pfx

步骤2: 感谢Gonzalo Gallotti发布了帮助我的代码片段的链接。我对我的代码进行了注释以显示每个步骤的操作。注意:如步骤1所述,如果没有正确生成的证书,此代码将无法运行。

public void GetCertificate() {
    
    // Get the Machine Cert Store
    var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);

    string alg = CryptoConfig.MapNameToOID("SHA512");

    // Open the cert store
    store.Open(OpenFlags.ReadWrite);

    // Loop through each certificate within the store
    foreach (X509Certificate2 myCert in store.Certificates)
    {
        // Get the certificate we are looking for
        if (myCert.IssuerName.Name.Contains("CN=YourSite"))
        {
            // Check if the certificate has a private key
            if (myCert.HasPrivateKey)
            {
                // Get your custom signature as a string
                string mySignature = GetSignatureString();

                // Convert signature to byte array
                byte[] originalData = Encoding.UTF8.GetBytes(mySignature);

                // Create RSA provider from private key
                RSACryptoServiceProvider rsaProvider = (RSACryptoServiceProvider)myCert.PrivateKey;

                // Sign the signature with SHA512
                byte[] signedSignature = signedSignature = rsaProvider.SignData(originalData, alg);

                if (rsaProvider.VerifyData(originalData, alg, signedSignature))
                {
                    // Signature is verified Do Stuff
                }
                else
                {
                    throw new Exception("The data does not match the signature.");
                }
            }
        }
    }
}

不确定这个踩票是为了什么..它确实帮助了我,非常感谢!+1 +1 - Tjad Clark
@TjadClark,开头的冗长代码隐藏了答案的最后一部分,其中描述了正确的操作步骤!我会进行编辑以更正。 - jmd
我认为这里缺少了哈希算法。 - undefined

12
你可能正在将应用程序从.NET Framework 4.7及更早版本迁移到4.7.1或更高版本时来到这里。
如果你遇到异常System.Security.Cryptography.CryptographicException: Invalid algorithm specified.,原因是默认的SignedXML和SignedXMS算法在针对.NET Framework 4.7.1及更高版本的应用程序中已更改为SHA256(来源:Microsoft .NET迁移指南)。
在该指南中,您还将找到解决方案:

For applications that target the .NET Framework 4.7.1 and later versions, if the use of SHA256 is undesirable, you can restore the default to SHA1 by adding the following configuration switch to the runtime section of your app config file:

<AppContextSwitchOverrides value="Switch.System.Security.Cryptography.Xml.UseInsecureHashAlgorithms=true;  
                  Switch.System.Security.Cryptography.Pkcs.UseInsecureHashAlgorithms=true" />
但这种方式可能并不总是适用,特别是对于Web应用程序而言,正如您可以在这篇博客文章中所读到的那样,幸运的是,答案也在其中。只需要在Application_Start中添加几行代码即可。
protected void Application_Start(object sender, EventArgs e)
{
   [...]
   AppContext.SetSwitch("Switch.System.Security.Cryptography.Xml.UseInsecureHashAlgorithms", true);
   AppContext.SetSwitch("Switch.System.Security.Cryptography.Pkcs.UseInsecureHashAlgorithms", true);
}

4
您可以使用 certutil 工具(在 Windows 上)检查您的证书使用哪个 CSP。
certutil yourCertificate.p12

enter image description here

例子:

  • 微软增强加密提供程序 v1.0 => 在使用 C# 4.7 及以上版本时会出错
  • 微软增强 RSA 和 AES 加密提供程序 => 可以正常工作

3

我有一个类似的问题,但已经解决了。如果您没有使用X509,而只是使用普通的RSACryptoServiceProvider获取密钥,则只支持SHA1。


2

您可以通过appSettings在web.config中设置AppContext开关:

<appSettings>
  <add key="AppContext.SetSwitch:Switch.System.Security.Cryptography.Xml.UseInsecureHashAlgorithms" value="true" />
  <add key="AppContext.SetSwitch:Switch.System.Security.Cryptography.Pkcs.UseInsecureHashAlgorithms" value="true" />
</appSettings>

0

我通过升级我的依赖项来解决了这个问题。

我不再依赖我之前使用多年的 GAC 版本,而是转向最新的 NuGet 包(v16.8.0):

  • Microsoft.Build.Tasks.Core
  • Microsoft.Build.Utilities.Core
  • Microsoft.Build.Framework

这对我们解决了这个问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接