这是我的代码。
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“指定的算法无效。”
我做错了什么?
更新:
id = 2.16.840.1.101.3.4.2.1
对于 dot net Framework 4.7.0 或更高版本,不采用 sha1,因此在应用程序启动中配置以下内容。这对我来说效果很好。
AppContext.SetSwitch("Switch.System.Security.Cryptography.Xml.UseInsecureHashAlgorithms", true);
AppContext.SetSwitch("Switch.System.Security.Cryptography.Pkcs.UseInsecureHashAlgorithms", true);
.NET 代码或您提供的 CSP 代码没有问题。
您的问题是 CSP 不支持 SHA 256。您可以在此处
获取更多信息当您将应用程序从 .NET Framework 4.7 及更早版本迁移到 4.7.1 或更高版本时,您可能会来到这里。
如果您遇到异常
System.Security.Cryptography.CryptographicException: Invalid algorithm specified.
,原因是针对 .NET Framework 4.7.1 及更高版本的应用程序,默认的 SignedXML 和 SignedXMS 算法已更改为 SHA256(来自 Microsoft .NET 迁移指南)
在该指南中,您还将找到解决方案:
对于面向 .NET Framework 4.7.1 及更高版本的应用程序,如果不希望使用 SHA256,您可以通过将以下配置开关添加到应用程序配置文件的运行时部分来将默认值恢复为 SHA1:
<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);
}
请注意,我使用 SHA512,但 SHA256 将适用于以下示例:
“指定的算法无效”花了我很长时间才弄清楚,我几乎尝试了所有方法。
第 1 步 - 证书必须是 SHA512 并使用支持 SHA512 的 CSP(加密服务提供商)。以下是 CSP 及其功能的列表。如果您寻找 SHA512,您会找到“Microsoft 增强型 RSA 和 AES 加密提供程序”。默认情况下,生成证书不使用此选项(至少在 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.");
}
}
}
}
}
有类似的问题,但刚刚解决了。如果您不使用 X509 而只是使用普通的 RSACryptoServiceProvider 来获取密钥,则仅支持 SHA1。
您可以通过 appSettings 在 Web 配置中设置 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>
我通过升级依赖项解决了该问题。
我不再依赖我之前使用多年的 GAC 版本,而是改用了最新的 NuGet 包 (v16.8.0):
这为我们解决了这个问题。
你需要使用
RSA rsaKey = cert.GetRSAPrivateKey();
而不是
RSACryptoServiceProvider csp = (RSACryptoServiceProvider)pXCert.PrivateKey;
当您签署参考文献时,请指定 DigestMethod 和 SignatureMethod
Reference reference = new Reference();
reference.Uri = "";
// Specify SHA-256 as the hash algorithm
reference.DigestMethod = SignedXml.XmlDsigSHA256Url;
signedXml.AddReference(reference);
// Add the key info to specify the signature method
signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigRSASHA256Url;
signedXml.ComputeSignature();