简体   繁体   中英

SHA-1 hashing on Java and C#

I'm trying to validate the content of an XML node with SHA-1 , basically, we generate an SHA-1 hash with the content of that node and both sides (client C# and server Java) should have exactly the same hash.

The problem is , I have checked with a diff tool the content of both texts and there is not any difference. But I'm getting a different hash than the client.

C# hash : 60-53-58-69-29-EB-53-BD-85-31-79-28-A0-F9-42-B6-DE-1B-A6-0A

Java hash: E79D7E6F2A6F5D776447714D896D4C3A0CBC793

The way the client (C#) is generating the hash is this:

try
    {
        Byte[] stream = null;
        using (System.Security.Cryptography.SHA1CryptoServiceProvider shaProvider = new System.Security.Cryptography.SHA1CryptoServiceProvider())
        {
            stream = shaProvider.ComputeHash(System.Text.Encoding.UTF8.GetBytes(text));
            if (stream == null)
            {
                hash = "Error";
            }
            else
            {
                hash = System.BitConverter.ToString(stream);
            }
        }
    }
    catch (Exception error)
    {
        hash = string.Format("Error SHA-1: {0}", error);
    }
    return hash;

and this is how the server (Java) is generating the hash:

        byte[] key = content.getBytes();


        MessageDigest md = MessageDigest.getInstance("SHA1");

        byte[] hash = md.digest(key);

        String result = "";
        for (byte b : hash) {
            result += Integer.toHexString(b & 255);
        }
        return result.toUpperCase();

can someone help me ? .. thanks :)

UPDATE: In order to check what's going on I have checked other ways to get a SHA1 hash in C# and I found this:

/// <summary>
        /// Compute hash for string encoded as UTF8
        /// </summary>
        /// <param name="s">String to be hashed</param>
        /// <returns>40-character hex string</returns>
        public static string SHA1HashStringForUTF8String(string s)
        {
            byte[] bytes = Encoding.UTF8.GetBytes(s);

            using (var sha1 = SHA1.Create())
            {
                byte[] hashBytes = sha1.ComputeHash(bytes);
                return System.BitConverter.ToString(hashBytes).Replace("-",string.Empty);
            }
        }

This code gives this output:

E79D07E6F2A6F5D776447714D896D4C3A0CBC793

AND !! I just noticed that Python is giving the same output (sorry, I should double checked this)

So this is the deal

Using this provider: System.Security.Cryptography.SHA1CryptoServiceProvider shaProvider = new System.Security.Cryptography.SHA1CryptoServiceProvider()

Is giving a completly different output on three different machines ..

Using the above method in C# gives the same result as python does , also, for some reason Java is giving a sightly different output :

E79D7E6F2A6F5D776447714D896D4C3A0CBC793

Ideas?, is java the problem? the byte to hex method on java is the problem? there is another alternative?

Your problem is that you're not hashing the same bytes in both API.

If you choose to modify java's version, it should look like this:

byte[] key = content.getBytes("UTF8");
[...]

If you choose to modify c#' version, it should look like this:

stream = shaProvider.ComputeHash(System.Text.Encoding.UTF16.GetBytes(text));
[...]

Either way, both api should get the key's bytes through the same encoding.

Try using this as your hashing in C#:

static string Hash(string input)
    {
        using (SHA1Managed sha1 = new SHA1Managed())
        {
            var hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(input));
            var sb = new StringBuilder(hash.Length * 2);

            foreach (byte b in hash)
            {
                // can be "x2" if you want lowercase
                sb.Append(b.ToString("x2"));
            }

            return sb.ToString();
        }
    }
Hash("test"); //a94a8fe5ccb19ba61c4c0873d391e987982fbbd3

And then use this as your Java hashing:

private static String convertToHex(byte[] data) {
    StringBuilder buf = new StringBuilder();
    for (byte b : data) {
        int halfbyte = (b >>> 4) & 0x0F;
        int two_halfs = 0;
        do {
            buf.append((0 <= halfbyte) && (halfbyte <= 9) ? (char) ('0' + halfbyte) : (char) ('a' + (halfbyte - 10)));
            halfbyte = b & 0x0F;
        } while (two_halfs++ < 1);
    }
    return buf.toString();
}

public static String SHA1(String text) throws NoSuchAlgorithmException, UnsupportedEncodingException {
    MessageDigest md = MessageDigest.getInstance("SHA-1");
    byte[] textBytes = text.getBytes("iso-8859-1");
    md.update(textBytes, 0, textBytes.length);
    byte[] sha1hash = md.digest();
    return convertToHex(sha1hash);
}
SHA1("test"); //a94a8fe5ccb19ba61c4c0873d391e987982fbbd3

Note you need the following imports:

import java.io.UnsupportedEncodingException; import
java.security.MessageDigest; import
java.security.NoSuchAlgorithmException;

Throws declarations are option, adjust to best fit your code!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM