One of the answers从该帖子中帮助我弄清楚如何通过显式加载支持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的自签名证书.根据同一篇文章中的another answer,如果我在makercert.exe中包含正确的-sp或-sy标志,则不会出现这些问题.但是,即使指定了这些标志之一(当前使用-sy 24),我仍然需要执行变通方法.
此实现与该帖子中的accepted answer稍有不同(同样,因为我们的私钥不可导出).但该答案确实表明可以在不明确加载支持SHA256的加密提供程序的情况下完成验证.因此,我应该能够在返回上述方法之前执行此操作:
RSACryptoServiceProvider csp = (RSACryptoServiceProvider)privateCert.PrivateKey; var enhCsp = new RSACryptoServiceProvider().CspKeyContainerInfo; mKeyContainerName = csp.CspKeyContainerInfo.KeyContainerName; var cspparams = new CspParameters ( enhCsp.ProviderType,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,mKeyContainerName ); csp = new RSACryptoServiceProvider(cspparams); if (!csp.VerifyHash(hash,signature)) throw new CryptographicException();
这确实验证了,但我不喜欢硬编码私钥的KeyContainerName.私钥在进行验证的计算机上不可用.
有谁知道更好的方法来实现这一目标?谢谢!
解决方法
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生成的证书有什么不同,但它对我来说并不重要,因为我们现在正在签署商业证书.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。