Java MD5 hashing not matching C# MD5 hashing
Asked Answered
G

1

5

I know very little about encryption/hashing.

I have to hash an encryption key. The example in Java is like this...

String encryptionKey = "test";

    MessageDigest messageDigest = MessageDigest.getInstance("MD5");
    messageDigest.update(encryptionKey.getBytes("UTF-8"), 0, encryptionKey.length());
    byte[] encryptionKeyBytes = messageDigest.digest();

Now correct me if I'm wrong, but the above code hashes the string with the MD5 algorithm.

And I want the same result when I hash the same string in C#.

My current C# code looks like this...

string encryptionKey = "test";

        var md5 = MD5.Create();
        var keyBytes = Encoding.UTF8.GetBytes(encryptionKey);
        byte[] encryptionKeyBytes = md5.ComputeHash(keyBytes);

But the end byte results do not match.

Java gets...

[0] 9   
[1] -113    
[2] 107 
[3] -51 
[4] 70  
[5] 33  
[6] -45 
[7] 115 
[8] -54 
[9] -34 
[10]    78  
[11]    -125    
[12]    38  
[13]    39  
[14]    -76 
[15]    -10 

C# gets...

    [0] 9   byte
    [1] 143 byte
    [2] 107 byte
    [3] 205 byte
    [4] 70  byte
    [5] 33  byte
    [6] 211 byte
    [7] 115 byte
    [8] 202 byte
    [9] 222 byte
    [10]    78  byte
    [11]    131 byte
    [12]    38  byte
    [13]    39  byte
    [14]    180 byte
    [15]    246 byte

I need my C# code to get the same result as the Java code (not the other way around), any ideas?

Thank you.

Giraudoux answered 14/6, 2012 at 18:14 Comment(6)
Java's bytes are signed. C# bytes are not. Notice that only the places the Java byte is negative it's wrong.Semivitreous
besides the equal result, you have a pretty bad mistake in java code: encryptionKey.getBytes("UTF-8"), 0, encryptionKey.length() I leave it to you to figure what the error is. Last comparing a direct string representation (toString) is always a bad ideaCusp
@Cusp I'm using a breakpoint to check the values. I think the breakpoint values are produced from the toString representation (might be wrong). How would you go about comparing byte values?Giraudoux
unsigned hex is usually the norm for presenting byte[] as you can easily see both nibbles. btw did you find out where the error is?Cusp
@Cusp It's using the byte[] array for the data, and the length is coming from the string (instead of the byte[]). Is that what you were pointing out? If not, I don't know. That java code is an encryption/decryption demo sent to me. The C# I have to write to produce the same result.Giraudoux
yes, the utf8 byte[] can have greater length than the originating string.Cusp
G
12

Actually, the results are identical. Like other integral types, a byte value may be interpreted as either signed or unsigned. For example, 10001111 would correspond to 143 (your second C# value) if interpreted as unsigned. However, if interpreted as signed (using two’s complement), its value would be -113 (your second Java value).

Thus, the disparity seems to be caused by your values being formatted as signed in Java but unsigned in C#. If you want to get signed bytes in C#, you can use:

sbyte[] encryptionKeyBytesSigned = 
    encryptionKeyBytes.Select(b => (sbyte)b).ToArray();

However, be careful that this is not merely a formatting issue that only arises when you display your values. When saved to file, both results should be identical.

Glauce answered 14/6, 2012 at 18:21 Comment(4)
Thank you for your answer... That last statement seems to contradict if I'm reading it correctly. If you save both to file and they are identical, then it IS merely a formatting issue that arises when you display the values. Can you clarify? I am going to take this hashed value (in byte[]) and use it as an encryption key. So if it's merely a displaying issue, I would think it'll be okay without conversion. I don't think the encryption function will take sbyte[] instead of a byte[].Giraudoux
N/m. You were just warning me to check and make sure. I got it.Giraudoux
@Theo: Yes, I assume that it’s a formatting issue and, when saved to file, the resulting files should be identical even without converting the C# values to signed byte. However, to be honest, I’m not that familiar with Java (I can only vouch for your C# code), so I would perform some testing to make sure.Glauce
You were right about the formatting issue. When written to file, the both show the same gibberish characters. Thank you for your help.Giraudoux

© 2022 - 2024 — McMap. All rights reserved.