验证C#中的DSA签名是否为';使用BER/DER编码的ASN.1格式
如何在C#中验证DSA签名? 鉴于:验证C#中的DSA签名是否为';使用BER/DER编码的ASN.1格式,c#,.net,digital-signature,asn.1,C#,.net,Digital Signature,Asn.1,如何在C#中验证DSA签名? 鉴于: 信息文本 签名摘要(通常为ASN.1 DER格式) 公钥(采用签名的X.509证书、PEM或DER格式) 我尝试了很多方法,但都没有成功: :库中的各种奇怪错误;我有一个问题,但还没有解决 Microsoft.NET API:无法解压缩DER签名以进行比较。DSA签名是40字节(两个20字节的整数),但表示为两个整数的DER编码序列,因此总长度可以在46到48字节之间(请参阅快速概述)。虽然.NET包含解析ASN.1/DER的代码(因为它可以读取DER
- 信息文本
- 签名摘要(通常为ASN.1 DER格式)
- 公钥(采用签名的X.509证书、PEM或DER格式)
- :库中的各种奇怪错误;我有一个问题,但还没有解决
- Microsoft.NET API:无法解压缩DER签名以进行比较。DSA签名是40字节(两个20字节的整数),但表示为两个整数的DER编码序列,因此总长度可以在46到48字节之间(请参阅快速概述)。虽然.NET包含解析ASN.1/DER的代码(因为它可以读取DER格式的证书),但它被隐藏得很深,没有办法访问它,因此您可以从ASN.1/DER编码的sig中正确检索40个字节。这个问题让我想到了下一个选择
- BouncyCastle:通过使用
函数,我可以解析ASN.1签名并将其拉入其组件R和s整数值中。但是当我将这些传递给签名验证例程时,它失败了,没有给出任何解释。我不确定自己是否做错了什么,因为C#API完全没有文档记录,Java版本几乎没有文档记录(但我找不到示例或如何查找信息)Org.BouncyCastle.Asn1
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解析器真的不是一个选项,有太多的错误空间,必须有一种方法来正确地做到这一点。在项目中可以找到一段验证DSA签名的代码。它不适合您的具体需要,因为公钥不是从X.509证书中提取的,但它可能会为您提供一个起点。另一个很好的示例是代码。它使用RSA,但切换到DSA应该非常简单。请特别查看此文件:
编辑:基本上,您需要类似的内容:
var sha1 = new SHA1Managed();
var hash = sha1.ComputeHash(inputStream);
var signatureFormatter = new DSASignatureDeformatter(dsa);
signatureFormatter.SetHashAlgorithm("SHA1");
bool valid = signatureFormatter.VerifySignature(hash, signature);
更多详细信息
编辑:另一个选项是Mono.Security库:
- 有一节阅读课
- 还有一个用于阅读X.509铜币的标签
我不确定这是否有帮助……看看这个:它解决了我遇到的问题,看起来与您的问题非常相似。JFYI:有时我会看到OpenSSL命令行工具生成的DSA签名中有效的45字节(其中一个整数是19字节,而不是20字节)。而且似乎可以有44个字节(两个都是19个字节),所以最好是6到48个字节,而不是46到48个字节 使用BouncyCastle(v1.7),我可以做到这一点(当然,不要忘记错误检查):
My signature.bin是使用OpenSSL生成的,例如,
OpenSSL dgst-sha1-sign private.key data.bin>signature.bin
。.NET实现的问题是它无法解析签名的ASN.1格式-我无法生成“签名”对象。@andersop您能发布一个ASN.1签名的示例吗?@Luke Quinane:当然,我把它编辑到了OP中,因为注释不支持格式。@Luke:谢谢,但是Mono太大了,无法用于此目的。我将查看源代码,看看它是否给了我一些想法,尽管Mono.Security.dll只有285KB,不依赖于任何其他Mono资源。你可以在这里找到它:C:\ProgramFiles(x86)\Mono-2.4.2.3\lib\Mono\gac\Mono.Security\2.0.0\uuu 0738EB9F132ED756据我所知,它正在内部生成签名:SignatureOfH=hostKey.Sign(H);我需要阅读一个外部生成的签名,这导致了ASN.1问题(在更新的帖子中有更多描述)。我想知道您是否可以帮我一个忙,将标题从“用C#验证DSA签名”更改为“用ASN.1格式验证C#DSA签名”之类的内容。可能有助于搜索人员。作为评论;我将换一种方式(验证在.NET中创建的Java签名);我必须编写一个从.NETDSA格式(40字节的r | | s)到DER格式的转换器。根据我在这里发现的()DER格式期望r和s是big-endian,但这根本不起作用,所以我把它作为little-endian,它起作用了…我还没有发现任何关于这方面的清晰信息;应该是大端还是小端……如果有人知道,请插话!我也遇到了同样的问题,在这篇文章的帮助下,我决定手工解码ASN.1-DER;该规范令人望而生畏,但实际上破译两个20字节整数序列并不困难。一旦计算出.NET类希望签名以包含两个20字节整数的concatation的40字节数组的形式到达,就不难了。
var sha1 = new SHA1Managed();
var hash = sha1.ComputeHash(inputStream);
var signatureFormatter = new DSASignatureDeformatter(dsa);
signatureFormatter.SetHashAlgorithm("SHA1");
bool valid = signatureFormatter.VerifySignature(hash, signature);
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!
}