0

I am facing an issue while trying to integrate HMACSHA256 (hashing) in different programmng languages. I have tried to implement the standard algorith with standard predefined methods in Java and C# and I am getting different results in different languages. Please see below my implementations in Java and C#:

Java:

    public static String convertSHAWithSalt(String value, String salt)
                throws NoSuchAlgorithmException, InvalidKeyException {
            String data = "";
            try {
                MessageDigest md = MessageDigest.getInstance("SHA-256");
                md.update(salt.getBytes(StandardCharsets.UTF_8));
                byte[] bytes = md.digest(value.getBytes(StandardCharsets.UTF_8));
                StringBuilder sb = new StringBuilder();
                for (byte b : bytes) {
                    sb.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
                }
                data = sb.toString();
                System.out.println(data);
                } catch (NoSuchAlgorithmException e) {
                  e.printStackTrace();
               }
            }

Result for string value 'abcd' and an empty salt value: 88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589

C#:

       public static string createHash(string message, string secret)
        {

            byte[] keyByte = System.Text.Encoding.UTF8.GetBytes(secret);

            byte[] messageBytes = System.Text.Encoding.UTF8.GetBytes(message);

            HMACSHA256  hmacsha256 = new HMACSHA256(keyByte);
            byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
            return BitConverter.ToString(hashmessage).Replace("-", "").ToLower();
        }

Result for string value 'abcd' and an empty salt value: 527ff4c28c22a090fe39908139363e81b8fb10d0695a135518006abfa21cf5a2

Please suggest why there is a difference in both of the results. I have also tried the below implementation in java but it is not working for empty salt value:

public static String convertSHAWithSalt(String value, String salt)
            throws NoSuchAlgorithmException, InvalidKeyException {
        String data = "";
        Mac sha256Hmac = Mac.getInstance("HmacSHA256");
            SecretKeySpec secretkey = new SecretKeySpec(salt.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            sha256Hmac.init(secretkey);
            data = bytesToHex(sha256Hmac.doFinal(data.getBytes(StandardCharsets.UTF_8)));
            System.out.println(data);
    }
Chetan chadha
  • 558
  • 1
  • 4
  • 19
  • I recommend taking a look at: https://www.bouncycastle.org/ they have a Java and C# implementation, having the same source behind it could make this easier. – usselite Mar 06 '19 at 08:09
  • See following : https://stackoverflow.com/questions/39518616/converting-sha256-from-java-to-c-sharp – jdweng Mar 06 '19 at 10:13

1 Answers1

1

There is a difference between SHA-256 and HMAC-SHA-256. HMAC-SHA-256 (see also HMAC) is an algorithm for generating a MAC using the SHA-256-hash-algorithm.

The result of the first Java-code and the C#-code are different, because the Java-code uses SHA-256 and the C#-code HMAC-SHA-256.

Since you want to use HMAC-SHA-256 I focus on that and I ignore the first Java-code.

The result of the C#-code for the text

This is an arbitrary text!

with the key

1234567890

is

25583e6e0b6c2c3a5c50ebd9ea48138a960a7ca2a215fae2b4b82ee99734deb4

The second Java-code uses HMAC-SHA-256 as well. If you replace the lines

data = bytesToHex(sha256Hmac.doFinal(data.getBytes(StandardCharsets.UTF_8)));
System.out.println(data);

with

data = bytesToHex(sha256Hmac.doFinal(value.getBytes(StandardCharsets.UTF_8)));
return data;

then, the ouput is the same (provided that your (not posted) bytesToHex-method works in a proper way, see e.g. How to convert a byte array to a hex string in Java?).

Btw, in the second Java-code you should change the labeling salt to something like key since that's the common wording in the context of a MAC. A salt is typically used in combination with a password hashing like in your first Java-code.

Note: In the Java-code it's not allowed to use an empty byte-array as SecretKeySpec-input. This throws an IllegalArgumentException (Empty key). However, the HMACSHA256-ctor in the C#-code accepts an empty byte-array and internally pads it with 0-values. Thus, with regard to your testcase (text: abcd, empty key) you can simulate in the Java-code the empty byte-array by a byte-array containing a single 0-value. Then, the output of the Java-code equals the output of the C#-code. Sure, an empty key should only be used for this testcase.

Topaco
  • 40,594
  • 4
  • 35
  • 62