[英]How can I (properly) verify a file using RSA and SHA256 with .NET?
我正在按照这个关于使用.NET进行数字签名/验证数据的精彩教程 。 我修改了该示例代码以使用SHA256并点击“指定的无效算法”异常,这引发了我在.NET 4.0中使用SHA256签署数据的问题 。
该帖子的答案之一帮助我弄清楚如何通过显式加载支持SHA256的加密提供程序而不依赖于可导出的私钥来正确生成数字签名(请参阅以下方法底部的代码,其中构建了RSACryptoServiceProvider ) ):
static string mKeyContainerName;
static byte[] SignText(string text, string publicCertPath)
{
// Access Personal (MY) certificate store of current user
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
// Load the certificate we'll use to verify the signature from a file.
X509Certificate2 publicCert = new X509Certificate2(publicCertPath);
publicCert.Verify();
string publicHash = publicCert.GetCertHashString();
// Find the certificate we'll use to sign
X509Certificate2 privateCert = null;
foreach(X509Certificate2 cert in store.Certificates)
{
if(cert.GetCertHashString() == publicHash)
{
// We found it. Get its associated private key
privateCert = cert;
break;
}
}
store.Close();
if(privateCert == null)
{
throw new Exception("No valid private cert was found");
}
// Hash the string
UnicodeEncoding encoding = new UnicodeEncoding();
byte[] data = encoding.GetBytes(text);
SHA256Managed sha256 = new SHA256Managed();
byte[] hash = sha256.ComputeHash(data);
// The basic crypto provider only supports SHA-1.
// Force Enhanced RSA and AES Cryptographic Provider which supports SHA-256.
RSACryptoServiceProvider csp = (RSACryptoServiceProvider)privateCert.PrivateKey;
var enhCsp = new RSACryptoServiceProvider().CspKeyContainerInfo;
mKeyContainerName = csp.CspKeyContainerInfo.KeyContainerName;
var cspparams = new CspParameters
(
enhCsp.ProviderType, enhCsp.ProviderName, mKeyContainerName
);
csp = new RSACryptoServiceProvider(cspparams);
// Sign the hash
return csp.SignHash(hash, CryptoConfig.MapNameToOID("SHA256"));
}
值得注意的是,我使用的是makecert.exe的自签名证书。 根据同一篇文章中的另一个答案 ,如果我在makercert.exe中包含正确的-sp或-sy标志,则不会出现这些问题。 但是,即使指定了这些标志之一(当前使用-sy 24 ),我仍然需要执行变通方法。
此实现与该帖子中接受的答案略有不同(同样,由于我们的私钥不可导出)。 但该答案确实表明可以在不明确加载支持SHA256的加密提供程序的情况下完成验证。 因此,我应该能够在返回上述方法之前执行此操作:
RSACryptoServiceProvider csp = (RSACryptoServiceProvider)privateCert.PrivateKey;
var enhCsp = new RSACryptoServiceProvider().CspKeyContainerInfo;
mKeyContainerName = csp.CspKeyContainerInfo.KeyContainerName;
var cspparams = new CspParameters
(
enhCsp.ProviderType, enhCsp.ProviderName, mKeyContainerName
);
csp = new RSACryptoServiceProvider(cspparams);
// Sign the hash
byte[] signature = csp.SignHash(hash, CryptoConfig.MapNameToOID("SHA256"));
// Test to verify the signed hash with public cert
csp = (RSACryptoServiceProvider)publicCert.PublicKey.Key;
if (!csp.VerifyHash(hash, CryptoConfig.MapNameToOID("SHA256"), signature))
throw new CryptographicException();
return signature;
但是,这不会验证(顺便说一句,我已经尝试过SignData / VerifyData和SignHash / VerifyHash )。 我可以让它验证的唯一方法是我是否再次明确加载一个支持SHA256的加密提供程序。 不幸的是,从公共证书构造的CspKeyContainerInfo的KeyContainerName成员始终为null。 因此,我可以获得数据验证的唯一方法是缓存(或硬编码)私钥的KeyContainerName。 因此,上面的方法和片段中的mKeyContainerName字段的原因如下:
// Test to verify the signed hash with public cert
csp = (RSACryptoServiceProvider)publicCert.PublicKey.Key;
enhCsp = new RSACryptoServiceProvider().CspKeyContainerInfo;
cspparams = new CspParameters
(
enhCsp.ProviderType, enhCsp.ProviderName, mKeyContainerName
);
csp = new RSACryptoServiceProvider(cspparams);
if (!csp.VerifyHash(hash, CryptoConfig.MapNameToOID("SHA256"), signature))
throw new CryptographicException();
这确实验证了,但我不喜欢硬编码私钥的KeyContainerName 。 私钥在进行验证的计算机上不可用。
有谁知道更好的方法来实现这一目标? 谢谢!
我偶然发现了自己的答案。 原来使用makecert.exe创建的自签名证书是罪魁祸首。 如果我使用使用OpenSSL或商业证书创建的证书,我不再需要显式加载支持SHA256的加密提供程序。 因此,我不必在用于实例化RSACryptoServiceProvider的CspParameters对象中对容器名称进行硬编码。 此签名代码现在按预期工作:
RSACryptoServiceProvider csp = (RSACryptoServiceProvider)privateCert.PrivateKey;
// Sign the hash
byte[] signature = csp.SignHash(hash, CryptoConfig.MapNameToOID("SHA256"));
验证方面也是如此:
// Test to verify the signed hash with public cert
csp = (RSACryptoServiceProvider)publicCert.PublicKey.Key;
我从来没有发现makecert.exe生成的证书有什么不同,但它对我来说并不重要,因为我们现在正在签署商业证书。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.