Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams
  • 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.

    I was wondering if you could do me a favor and change the title from "Verify DSA signature in C#" to "Verify DSA signature in C# with ASN.1 format" or something of the like. Might help searching people a bit. – Greg Apr 5, 2012 at 17:28 Just as a comment; I'm going the other way (verify a signature in Java that was created in .NET); I had to write a converter from the .NET DSA format (which is just r||s in 40 bytes) to the DER format. According to what I found here (mombu.com/microsoft/security-crypto/…) the DER format expects r and s to be big-endian but that didn't work at all so I left it as little-endian and it works...I haven't found anything very clear on this; should it be big- or little -endian...if anybody knows then please chime in! – SonarJetLens Dec 10, 2014 at 14:59 I had the same problem, and with the help of this post I decided to do the ASN.1-DER decoding by hand; the spec is daunting, but actually deciphering a sequence of two 20-byte integers is not difficult. Once you've worked out that the .NET classes expect the signature to arrive in the form of a 40-byte array containing the concatation of two 20-byte integers, it's not difficult. – Michael Kay May 19, 2021 at 11:05 As far as I can see, it's generating the signature internally: SignatureOfH = hostKey.Sign(H); I need to read an externally generated signature, which leads to the ASN.1 problem (described a bit more in updated post.) – andersop Oct 28, 2009 at 4:42

    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:
    var sha1 = new SHA1Managed();
    var hash = sha1.ComputeHash(inputStream);
    var signatureFormatter = new DSASignatureDeformatter(dsa);
    signatureFormatter.SetHashAlgorithm("SHA1");
    bool valid = signatureFormatter.VerifySignature(hash, signature); 
    

    More details on MSDN.

    Edit: Another option is the Mono.Security libraries:
  • There is a class for reading ASN1
  • There is also an assembly for reading X.509 cerficiates.
  • I'm not sure if that helps...

    The issue with the .NET implementation is that it can't parse the ASN.1 format of the signatures - I can't generate the "signature" object in the example above. – andersop Oct 28, 2009 at 2:06 @Luke: thanks, but Mono is just too huge to pull in for this purpose. I'll take a look at the source and see if it gives me any ideas, though. – andersop Nov 4, 2009 at 19:50 @andersop the Mono.Security.dll is only 285KB and doesn't depend on any other Mono resources. You can find it here: C:\Program Files (x86)\Mono-2.4.2.3\lib\mono\gac\Mono.Security\2.0.0.0__0738eb9f132ed756 – Luke Quinane Nov 4, 2009 at 22:19

    Using BouncyCastle (v1.7), I can do this (don't forget error checking, of course):

    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!
    

    My signature.bin is generated using OpenSSL, e.g. openssl dgst -sha1 -sign private.key data.bin > signature.bin

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.