How can I verify a DSA signature in C#?
Given:
- the message text,
- a signed digest (typically ASN.1 DER format),
- the public key (in a signed X.509 certificate, PEM or DER format)
I've tried a number of approaches, but haven't had any success:
OpenSSL.NET: various strange errors with the library; I've got an open thread running with the author over on SourceForge but haven't been able to resolve this yet.
Microsoft .NET API: can't unpack the DER signature for comparison. A DSA signature is 40 bytes (two 20-byte integers), but is presented as an DER-encoded sequence of two integers, so the total length can range from 46 to 48 bytes (see this post for a quick overview.) While .NET includes code to parse ASN.1/DER (because it can read certificates in DER format), it's buried deep, and there's no way to access it so that you can correctly retrieve the 40 bytes from the ASN.1/DER encoded sig. This issue led me to the next option...
BouncyCastle: through the use of the
Org.BouncyCastle.Asn1
functions, I can parse the ASN.1 signature and pull it into it's component R and S integer values. But when I pass these to the signature verification routines, it's failing with no explanation given. I'm not sure if I'm doing anything wrong, because the C# API is completely undocumented, and the Java version is barely documented (but there's no example or HOWTO information that I can find.)
I've been throwing myself at this problem for about a week now. I know someone must have done it before, but I haven't found any complete/working examples.
I've got three C# projects sitting here, each 95% complete but with one critical flaw that causes it to fail. Any working example code would be tremendously appreciated.
edit: here's an example of a signature I'm trying to verify, converted to Base64 and ASCII hex to make it postable. This particular one is 47 bytes but a proper parser must still accept it, read up on the DER spec for more info (BER/DER adds a leading 00 to confirm the sign if the MSB is 1)
Base64: MC0CFQCUgq2DEHWzp3O4nOdo38mDu8mStwIUadZmbin7BvXxpeoJh7dhquD2CTM=
ASCII Hex: 302d0215009482ad831075b3a773b89ce768dfc983bbc992b7021469d6666e29fb06f5f1a5ea0987b761aae0f60933
Structure is per the DER spec; it parses as follows:
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
Writing my own DER parser is really not an option, too much room for error and there's got to be a way to do this properly.
A piece of code that verifies a DSA signature can be found in the NSsh project. It doesn't suit your exact needs since the public key is not pulled from an X.509 certificate but it may give you a starting point.
Another good example is the DotNetAutoUpdate code. It uses RSA but it should be quite simple to switch over to DSA. In particular have a look at this file:
http://code.google.com/p/dotnetautoupdate/source/browse/trunk/source/DotNetAutoUpdate/UpdateKeys.cs
Edit: basically you want something similar to this:
More details on MSDN.
Edit: Another option is the Mono.Security libraries:
I'm not sure if that helps...
Using BouncyCastle (v1.7), I can do this (don't forget error checking, of course):
My signature.bin is generated using OpenSSL, e.g.
openssl dgst -sha1 -sign private.key data.bin > signature.bin
JFYI: Sometimes I see valid 45-bytes DER DSA signatures (one of INTEGERS was 19 bytes not 20), generated by OpenSSL command line tool. And it seems that there can be 44 bytes (both are 19 bytes), so you better expect anything from 6 to 48 bytes rather than from 46 to 48. ;-)
Take a look at this: http://www.codeproject.com/KB/security/CryptoInteropSign.aspx which resolved the problem I was having that seems very similar to your's.