问题描述
我的应用程序将获取一组文件并对其进行签名.(我不是要对程序集进行签名.)有一个 .p12 文件,我可以从中获取私钥.
My application will take a set of files and sign them. (I'm not trying to sign an assembly.) There is a .p12 file that I get the private key from.
这是我试图使用的代码,但我得到一个 System.Security.Cryptography.CryptographicException "Invalid algorithm specified."
.
This is the code I was trying to use, but I get a System.Security.Cryptography.CryptographicException "Invalid algorithm specified."
.
X509Certificate pXCert = new X509Certificate2(@"keyStore.p12", "password");
RSACryptoServiceProvider csp = (RSACryptoServiceProvider)pXCert.PrivateKey;
string id = CryptoConfig.MapNameToOID("SHA256");
return csp.SignData(File.ReadAllBytes(filePath), id);
根据这个答案无法完成(RSACryptoServiceProvider
不支持 SHA-256),但我希望可以使用不同的库,例如 Bouncy Castle.
According to this answer it can't be done (the RSACryptoServiceProvider
does not support SHA-256), but I was hoping that it might be possible using a different library, like Bouncy Castle.
我不熟悉这个东西,我发现 Bouncy Castle 非常令人困惑.我正在将 Java 应用程序移植到 C#,我必须使用相同类型的加密来签署文件,所以我坚持使用 RSA + SHA256.
I'm new to this stuff and I'm finding Bouncy Castle to be very confusing. I'm porting a Java app to C# and I have to use the same type of encryption to sign the files, so I am stuck with RSA + SHA256.
我如何使用 Bouncy Castle、OpenSSL.NET、Security.Cryptography 或其他我没听说过的第三方库来做到这一点?我假设,如果它可以在 Java 中完成,那么它可以在 C# 中完成.
How can I do this using Bouncy Castle, OpenSSL.NET, Security.Cryptography, or another 3rd party library I haven't heard of? I'm assuming, if it can be done in Java then it can be done in C#.
更新:
这是我从 poupou 的 anwser 中的链接中得到的
this is what I got from the link in poupou's anwser
X509Certificate2 cert = new X509Certificate2(KeyStoreFile, password");
RSACryptoServiceProvider rsacsp = (RSACryptoServiceProvider)cert.PrivateKey;
CspParameters cspParam = new CspParameters();
cspParam.KeyContainerName = rsacsp.CspKeyContainerInfo.KeyContainerName;
cspParam.KeyNumber = rsacsp.CspKeyContainerInfo.KeyNumber == KeyNumber.Exchange ? 1 : 2;
RSACryptoServiceProvider aescsp = new RSACryptoServiceProvider(cspParam);
aescsp.PersistKeyInCsp = false;
byte[] signed = aescsp.SignData(File.ReadAllBytes(file), "SHA256");
bool isValid = aescsp.VerifyData(File.ReadAllBytes(file), "SHA256", signed);
问题是我得到的结果与使用原始工具所得到的结果不同.据我阅读代码可以看出,进行实际签名的 CryptoServiceProvider 没有使用密钥存储文件中的 PrivateKey.对吗?
The problem is that I'm not getting the same results as I got with the original tool. As far as I can tell from reading the code the CryptoServiceProvider that does the actual signing is not using the PrivateKey from key store file. Is that Correct?
推荐答案
RSA + SHA256 可以并且将会工作...
RSA + SHA256 can and will work...
你后面的例子可能不会一直工作,它应该使用散列算法的 OID,而不是它的名字.根据您的第一个示例,这是通过调用 CryptoConfig.MapNameToOID(AlgorithmName)
其中 AlgorithmName
是您提供的(即SHA256").
Your later example may not work all the time, it should use the hash algorithm's OID, rather than it's name. As per your first example, this is obtained from a call to CryptoConfig.MapNameToOID(AlgorithmName)
where AlgorithmName
is what you are providing (i.e. "SHA256").
首先您需要的是带有私钥的证书.我通常通过使用公钥文件 (.cer
) 从 LocalMachine 或 CurrentUser 存储中读取我的私钥来识别私钥,然后枚举证书并匹配哈希...
First you are going to need is the certificate with the private key. I normally read mine from the LocalMachine or CurrentUser store by using a public key file (.cer
) to identify the private key, and then enumerate the certificates and match on the hash...
X509Certificate2 publicCert = new X509Certificate2(@"C:mycertificate.cer");
//Fetch private key from the local machine store
X509Certificate2 privateCert = null;
X509Store store = new X509Store(StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
foreach( X509Certificate2 cert in store.Certificates)
{
if (cert.GetCertHashString() == publicCert.GetCertHashString())
privateCert = cert;
}
无论如何,一旦您获得了带有私钥的证书,我们就需要重建它.由于证书创建私钥的方式,这可能是必需的,但我不确定为什么.无论如何,我们首先导出密钥,然后使用您喜欢的任何中间格式重新导入它,最简单的是 xml:
However you get there, once you've obtained a certificate with a private key we need to reconstruct it. This may be required due to the way the certificate creates it's private key, but I'm not really sure why. Anyway, we do this by first exporting the key and then re-importing it using whatever intermediate format you like, the easiest is xml:
//Round-trip the key to XML and back, there might be a better way but this works
RSACryptoServiceProvider key = new RSACryptoServiceProvider();
key.FromXmlString(privateCert.PrivateKey.ToXmlString(true));
一旦完成,我们现在可以对一段数据进行如下签名:
Once that is done we can now sign a piece of data as follows:
//Create some data to sign
byte[] data = new byte[1024];
//Sign the data
byte[] sig = key.SignData(data, CryptoConfig.MapNameToOID("SHA256"));
最后,可以直接使用证书的公钥进行验证,无需像使用私钥那样进行重构:
Lastly, the verification can be done directly with the certificate's public key without need for the reconstruction as we did with the private key:
key = (RSACryptoServiceProvider)publicCert.PublicKey.Key;
if (!key.VerifyData(data, CryptoConfig.MapNameToOID("SHA256"), sig))
throw new CryptographicException();
这篇关于如何通过 .NET 使用 RSA 和 SHA256 对文件进行签名?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!