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.

4
  • 1
    "I know this is because Java uses signed bytes while C# doesn't." No, that's almost certainly not the reason. Commented Apr 9, 2014 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. Commented Apr 9, 2014 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. Commented Apr 9, 2014 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... Commented Apr 9, 2014 at 16:07

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

4 Comments

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: Surely it's 16 characters... Base64-encoded SHA-1 is 28 characters; base-64 encoded SHA-256 is 44 characters.
You're right, I was mentally calculating the Base64 expansion of the hex string.
OMG I spent one hour on this, convinced it was a signed/unsigned issue... Thank you for the tips.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.