如何在C#中验证DSA签名?
假设:
我尝试了很多方法,但没有取得任何成功:
OpenSSL.NET :库中的各种奇怪错误;我有open thread running with the author over on SourceForge但尚无法解决此问题。
Microsoft .NET API:无法解压缩DER签名以进行比较。 DSA签名是40个字节(两个20字节整数),但是表示为两个整数的DER编码序列,因此总长度可以在46到48个字节之间(有关快速概述,请参阅this post)。虽然.NET包含解析ASN.1 / DER的代码(因为它可以读取DER格式的证书),但它深埋,并且无法访问它,因此您可以从ASN.1 /中正确检索40个字节DER编码的sig。这个问题让我想到了下一个选择......
BouncyCastle:通过使用Org.BouncyCastle.Asn1
函数,我可以解析ASN.1签名并将其拉入其组件R和S整数值。但是,当我将这些传递给签名验证程序时,它没有给出任何解释。我不确定我做错了什么,因为C#API 完全没有文档,并且几乎没有记录Java版本(但是我找不到示例或HOWTO信息。)< / p>
我已经在这个问题上投入了大约一个星期了。我知道有人必须先做过,但我没有找到任何完整/有效的例子。
我有三个C#项目坐在这里,每个95%完成但有一个严重的缺陷导致它失败。任何工作示例代码都将非常受欢迎。
编辑:这是我正在尝试验证的签名示例,转换为Base64和ASCII十六进制以使其可用。这个特殊的一个是47字节,但是一个合适的解析器仍然必须接受它,在DER规范上读取更多信息(如果MSB为1,BER / DER添加前导00以确认符号)
Base64: MC0CFQCUgq2DEHWzp3O4nOdo38mDu8mStwIUadZmbin7BvXxpeoJh7dhquD2CTM=
ASCII Hex: 302d0215009482ad831075b3a773b89ce768dfc983bbc992b7021469d6666e29fb06f5f1a5ea0987b761aae0f60933
结构符合DER规范;它解析如下:
30 2d: sequence, length 45 (may vary from 44 to 46)
02 15: integer, length 21 (first byte is 00 to confirm sign)
009482ad831075b3a773b89ce768dfc983bbc992b7
02 14: integer, length 20 (leading 00 not necessary for this one)
69d6666e29fb06f5f1a5ea0987b761aae0f60933
编写我自己的DER解析器实际上不是一个选项,错误的空间太大,而且必须有一种方法来正确地执行此操作。
答案 0 :(得分:2)
看看这个:http://www.codeproject.com/KB/security/CryptoInteropSign.aspx解决了我遇到的与你的问题非常相似的问题。
答案 1 :(得分:1)
可以在NSsh项目中找到验证DSA签名的一段代码。它不适合您的确切需求,因为公钥不是从X.509证书中提取的,但可能会给您一个起点。
答案 2 :(得分:1)
另一个很好的例子是DotNetAutoUpdate代码。它使用RSA但切换到DSA应该非常简单。特别要看一下这个文件:
http://code.google.com/p/dotnetautoupdate/source/browse/trunk/source/DotNetAutoUpdate/UpdateKeys.cs
<小时/> 编辑:基本上你想要类似的东西:
var sha1 = new SHA1Managed();
var hash = sha1.ComputeHash(inputStream);
var signatureFormatter = new DSASignatureDeformatter(dsa);
signatureFormatter.SetHashAlgorithm("SHA1");
bool valid = signatureFormatter.VerifySignature(hash, signature);
有关MSDN的更多详情。
<小时/> 编辑:另一个选项是Mono.Security库:
我不确定这是否有帮助...
答案 3 :(得分:1)
使用BouncyCastle(v1.7),我可以这样做(当然不要忘记错误检查):
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using Org.BouncyCastle.Asn1;
byte[] signature = ReadFile("signature.bin");
byte[] dataToVerify = ReadFile("data.bin");
byte[] rawPublicKey = KeyResources.publickey; // My public key is in a resource
var x509 = new X509Certificate2(rawPublicKey);
var dsa = x509.PublicKey.Key as DSACryptoServiceProvider;
// extract signature components from ASN1 formatted signature
DSASignatureDeformatter DSADeformatter = new DSASignatureDeformatter(dsa);
DSADeformatter.SetHashAlgorithm("SHA1");
Asn1InputStream bIn = new Asn1InputStream(new MemoryStream(signature));
DerSequence seq = bIn.ReadObject() as DerSequence;
var r11 = seq[0].GetEncoded();
var r21 = seq[1].GetEncoded();
byte[] p1363 = new byte[40];
Array.Copy(r11, r11.Length - 20, p1363, 0, 20);
Array.Copy(r21, r21.Length - 20, p1363, 20, 20);
// and finally we can verify
if (!DSADeformatter.VerifySignature(new SHA1CryptoServiceProvider().ComputeHash(dataToVerify), p1363))
{
// Noo, mismatch!
}
我的signature.bin是使用OpenSSL生成的,例如openssl dgst -sha1 -sign private.key data.bin > signature.bin
答案 4 :(得分:0)
JFYI:有时我看到有效的45字节DER DSA签名(INTEGERS之一是19字节而不是20),由OpenSSL命令行工具生成。而且似乎可以有44个字节(都是19个字节),所以你最好期望6到48个字节而不是46到48个。; - )