4

I am trying to hash a value (SHA1) in both C# and Java, and then return a base64 representation. I get 2 different results.

I know this is because Java uses signed bytes while C# doesn't.

C# version :

static public string toSHA1(string toEncrypt)
{
    return toSHA1(toEncrypt, new UTF8Encoding());
}

static public string toSHA1(string toEncrypt, Encoding encoding)
{
    String salt = "fE4wd#u*d9b9kdKszgè02ep5à4qZa!éi6";
    SHA256Managed sha256hasher = new SHA256Managed();
    byte[] hashedDataBytes = sha256hasher.ComputeHash(encoding.GetBytes(toEncrypt + salt));
    return Convert.ToBase64String(hashedDataBytes);
}

Java version :

public static String toSHA1(String toEncrypt) {
    return toSHA1(toEncrypt, "UTF-8");
}

public static String toSHA1(String toEncrypt, String encoding) {
    String salt = "fE4wd#u*d9b9kdKszgè02ep5à4qZa!éi6";
    String res = null;
    toEncrypt = toEncrypt + salt;
    try {
        byte[] dataBytes = toEncrypt.getBytes(encoding);
        MessageDigest md = MessageDigest.getInstance("SHA-1");
        res = Base64.encodeBytes(md.digest(dataBytes));
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    return res;
}

I can't manage to find a solution to get the correct base64 result using Java.

Converting signed values to unsigned ones forces the use of int data type, but as soon as I put it in a byte data type, I get my signed bytes back...

Base64.encodeBytes is waiting for a byte array, so is there any way I can pass an unsigned byte array to this method ? What can I do with that int array ? :

int[] dataInt = new int[dataBytes.length];
// signed to unsigned
for (int i=0; i<dataBytes.length; i++)
{
    dataInt[i] = (dataBytes[i] & 0xFF);
}

I can't modify the C# version, I have to adapt the Java version to give the same results.

Yann39
  • 14,285
  • 11
  • 56
  • 84
  • 1
    "I know this is because Java uses signed bytes while C# doesn't." No, that's almost certainly *not* the reason. – Jon Skeet Apr 09 '14 at 15:47
  • When comparing my 2 byte arrays, I can see negative values in the java version. The difference is exactly 256 with the C# version. – Yann39 Apr 09 '14 at 15:49
  • 2
    That surprises me greatly, given that in C# you're using SHA-256 and in the Java code you're using SHA-1. The byte arrays shouldn't even be the same size, as the result of SHA-1 is 160 bits, and the result of SHA-256 is 256 bits. – Jon Skeet Apr 09 '14 at 15:52
  • Sorry indeed I was comparing `encoding.GetBytes(toEncrypt + salt)` and `toEncrypt.getBytes(encoding)` just to see the signed/unsigned differences, and thought it was the source of the problem... – Yann39 Apr 09 '14 at 16:07

1 Answers1

6

The problem is very simple... From your C# code:

SHA256Managed sha256hasher = new SHA256Managed()

SHA-256 != SHA-1. Use the SHA1 class instead in C#, or use SHA-256 in Java as well. As you apparently can't change the C# code, you should change the Java instead:

MessageDigest md = MessageDigest.getInstance("SHA-256");

Once you've done that, the base64-encoded data should be the same in both platforms. Even though bytes are signed in Java, base64 encoders treat them as unsigned... they're only interested in the bits, basically.

I'd also strongly suggest that you represent your salt in ASCII in the source code, using \uxxxx escaping for any non-ASCII characters. This will prevent problems due to compiling using the wrong encoding.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • What strikes me as odd is that this answer should be very clear. A Base64-encoded SHA256 hash is a full 32 bytes longer than the Base64 encoded SHA1. – Phylogenesis Apr 09 '14 at 15:56
  • @Phylogenesis: Surely it's 16 characters... Base64-encoded SHA-1 is 28 characters; base-64 encoded SHA-256 is 44 characters. – Jon Skeet Apr 09 '14 at 15:59
  • You're right, I was mentally calculating the Base64 expansion of the hex string. – Phylogenesis Apr 09 '14 at 16:01
  • OMG I spent one hour on this, convinced it was a signed/unsigned issue... Thank you for the tips. – Yann39 Apr 09 '14 at 16:02