Menu

DSA signature verification error

Help
2008-09-04
2013-05-28
  • Mark Gimelfarb

    Mark Gimelfarb - 2008-09-04

    Hello, all!
    I have  a strange issue with SharpSSH 1.1.1.13
    I have no issues using SFTP session connect() method from my WinXP machine with a linux host (little-endian X86 PC), but when connecting to another linux server (unknown processor type and endianness), I get an exception in verify() method, line 84, SignatureDSA.cs. The error message is "Bad Data \r\n" and the stack trace is:

      at System.Security.Cryptography.DSACryptoServiceProvider._ImportKey(IntPtr hCSP, Int32 algid, DSACspObject data)\r\n   at System.Security.Cryptography.DSACryptoServiceProvider.ImportParameters(DSAParameters parameters)\r\n   at Tamir.SharpSsh.jsch.jce.SignatureDSA.verify(Byte[] sig) in D:\\installs\\SharpSSH-1.1.1.13.src\\SharpSSH-1.1.1.13.src\\SharpSSH\\jsch\\jce\\SignatureDSA.cs:line 84\r\n   at Tamir.SharpSsh.jsch.DHG1.next(Buffer _buf) in D:\\installs\\SharpSSH-1.1.1.13.src\\SharpSSH-1.1.1.13.src\\SharpSSH\\jsch\\DHG1.cs:line 293\r\n   at Tamir.SharpSsh.jsch.Session.connect(Int32 connectTimeout) in D:\\installs\\SharpSSH-1.1.1.13.src\\SharpSSH-1.1.1.13.src\\SharpSSH\\jsch\\Session.cs:line 279

    I don't know anything about the  server that's causing the issue, since  I don't have control over that machine. I was thinking that the issue may be that the other side is big-endian, and the DSA  signature being verified is coming in in big-endian  byte order. Of course, this is a guess, and I might be totally off here.

    Does anyone have any suggestions on how to resolve the issue or what additional info is needed in order to help figure out what's going on?

    Thank you in advance.

    Regards,
    Mark.

     
  • Myagi

    Myagi - 2010-10-31

    2 years too late, but I had the same problem. The reason is that the crypto functions SharpSSH uses, only supports DSS with up to 1024-bit keys. New standards however support up to 3072-bits, and if you connect to a server that uses a >1024 DSS key, you get the Bad Data exception in ImportParameters.

    My solution was to snag BigInteger.cs from the Mono project (and comment out the "Prime Testing" and "Prime Number Generation" regions). Then I replaced the "verify" function in SignatureDSA.cs with the code below (borrowed from PuTTY). As a side effect, going by the comment in PuTTY, this will also allow to correctly connect to commercial SSH servers which do not send the "ssh-dss" header.

            public bool verify(byte[] sig)
            {
                cs.Close();
                BigInteger r, s, w, gu1p, yu2p, gu1yu2p, u1, u2, sha, v;
                BigInteger P = new BigInteger(DSAKeyInfo.P);
                BigInteger Q = new BigInteger(DSAKeyInfo.Q);
                BigInteger G = new BigInteger(DSAKeyInfo.G);
                BigInteger Y = new BigInteger(DSAKeyInfo.Y);
                // from PuTTY:
                /*
                 * Commercial SSH (2.0.13) and OpenSSH disagree over the format
                 * of a DSA signature. OpenSSH is in line with the IETF drafts:
                 * it uses a string "ssh-dss", followed by a 40-byte string
                 * containing two 160-bit integers end-to-end. Commercial SSH
                 * can't be bothered with the header bit, and considers a DSA
                 * signature blob to be _just_ the 40-byte string containing
                 * the two 160-bit integers. We tell them apart by measuring
                 * the length: length 40 means the commercial-SSH bug, anything
                 * else is assumed to be IETF-compliant.
                 */
                long i = 0;
                if (sig.Length != 40)
                {
                    int n = (int)((sig[i++]<<24)&0xff000000)|((sig[i++]<<16)&0x00ff0000)|
                        ((sig[i++]<<8)&0x0000ff00)|((sig[i++])&0x000000ff);
                    if (n != 7 || Util.getString(sig, (int)i, 7) != "ssh-dss")
                        throw new System.Security.Cryptography.CryptographicException("Bad Data!\r\n");
                    i += 7;
                    n = (int)((sig[i++]<<24)&0xff000000)|((sig[i++]<<16)&0x00ff0000)|
                        ((sig[i++]<<8)&0x0000ff00)|((sig[i++])&0x000000ff);
                    if (n != 40 || i+40 > sig.Length)
                        throw new System.Security.Cryptography.CryptographicException("Bad Data!\r\n");
                }
                // sig data 40 bytes (2 x 20-byte blocks)
                {
                    byte[] tmp = new byte[20];
                    Array.Copy(sig, i, tmp, 0, 20);
                    r = new BigInteger(tmp);
                    tmp = new byte[20];
                    Array.Copy(sig, i+20, tmp, 0, 20);
                    s = new BigInteger(tmp);
                }
                /*
                 * Step 1. w <- s^-1 mod q.
                 */
                w = modinv(s, Q);
                /*
                 * Step 2. u1 <- SHA(message) * w mod q.
                 */
                if (sha1.Hash.Length != 20)
                    throw new System.Security.Cryptography.CryptographicException("Bad Data!\r\n");
                sha = new BigInteger(sha1.Hash);
                u1 = modmul(sha, w, Q);
                /*
                 * Step 3. u2 <- r * w mod q.
                 */
                u2 = modmul(r, w, Q);
                /*
                 * Step 4. v <- (g^u1 * y^u2 mod p) mod q.
                 */
                gu1p = modpow(G, u1, P);
                yu2p = modpow(Y, u2, P);
                gu1yu2p = modmul(gu1p, yu2p, P);
                v = BigInteger.Modulus(gu1yu2p, Q);//v = modmul(gu1yu2p, One, Q);
                /*
                 * Step 5. v should now be equal to r.
                 */
                return bignum_cmp(v, r) == 0;
            }
            private BigInteger modinv(BigInteger a, BigInteger b) { return a.ModInverse(b); }
            private BigInteger modmul(BigInteger a, BigInteger b, BigInteger n) { return BigInteger.Modulus(a * b, n); }
            private BigInteger modpow(BigInteger a, BigInteger exp, BigInteger n) { return a.ModPow(exp, n); }
            private BigInteger.Sign bignum_cmp(BigInteger a, BigInteger b) { return a.Compare(b); }
            private BigInteger bigmod(BigInteger a, BigInteger b) { return BigInteger.Modulus(a, b); }
    
     
  • Myagi

    Myagi - 2010-10-31

    Forgot to mention that "Allow unsafe code" has to be enabled for this to work, because BigInteger has a couple of unsafe functions.

     
  • ofos

    ofos - 2011-04-27

    Works great. Just change the

    sig
    

    by

    sig[i++]
    

    in the new verify method given by SnowCoder in the

    if (sig.Length != 40)
    

    block.

    Check this archive for corrected version of the files (thanks to Daniel Cai):

     
  • ofos

    ofos - 2011-04-27

    (error in wiki editor)

    the correction is:      sig

     
  • ofos

    ofos - 2011-04-27

    Ok I got it.
    The Sourceforge forum does not show the characters "OpeningBracket" - "i" - "PlusPlus" - "ClosingBracket"

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.