Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java MD5 Hash Not Matching .NET Hash

Tags:

java

hash

md5

I have a webservice that is written in C# handling some validation of values. In it I need to check a MD5 hash generated in the calling Java client.

The Java client generates the hash in this manner

Charset utf8Charset = Charset.forName("UTF-8");

byte[] bytesOfPhrase = phrase.getBytes(utf8Charset);
MessageDigest md = MessageDigest.getInstance("MD5");

byte[] thedigest = md.digest(bytesOfPhrase);
this._AuthenticationToken = new String(thedigest, utf8Charset);

The C# webservice generates its has in this manner:

private static string HashString(string toHash)
{
    MD5CryptoServiceProvider md5Provider = new MD5CryptoServiceProvider();

    byte[] hashedBytes = md5Provider.ComputeHash(_StringEncoding.GetBytes(toHash));
    return Convert.ToBase64String(hashedBytes);
}

I've tried several charsets in the Java code, but none of them produce a string that is anywhere similar to the Java produced string. Using hard coded values that are the same during every call (meaning that I've hardcoded the parameters so the hashes should match) still produces an odd Java string.

C# Example of hashed values:

6wM7McddLBjofdFJ3rU6/g==

I'd post the example of the string Java produces, but it has some very odd characters that I do not think I can paste in here.

What am I doing wrong?

like image 347
Mike G Avatar asked Jun 26 '26 17:06

Mike G


2 Answers

This is fundamentally broken code:

// Badly broken
byte[] thedigest = md.digest(bytesOfPhrase);
this._AuthenticationToken = new String(thedigest, utf8Charset);

Never, ever, ever try to encode arbitrary binary data by passing it to the String constructor. Always use base64, or hex, or something like that. Apache Commons Codec has a Base64 encoder, or this public domain version has a slightly more pleasant API.

The equivalent C# would be:

// Equally broken
byte[] hashedBytes = md5Provider.ComputeHash(Encoding.UTF8.GetBytes(toHash));
return Encoding.UTF8.GetString(hashedBytes);

What are the chances that the binary data produced by an MD5 digest is actually a valid UTF-8 byte sequence?

Two other things to note:

  • You can get hold of an MD5 hash slightly more simply in .NET using the MD5 class:

    byte[] hash;
    using (MD5 md5 = MD5.Create())
    {
        hash = md5.ComputeHash(bytes);
    }
    // Use hash
    

    Note the use of the using statement to dispose of the instance afterwards. My main preference for this is that it's easier to remember, read and type MD5 than MD5CryptoServiceProvider :)

  • You haven't made it clear what _StringEncoding is, but the code should really just use Encoding.UTF8 to match the Java.

like image 197
Jon Skeet Avatar answered Jun 29 '26 07:06

Jon Skeet


Your C# digest is in Base64, but your Java digest is not. Convert thedigest to Base64 as well.

like image 36
hrnt Avatar answered Jun 29 '26 07:06

hrnt