9

Something in the back of my head is telling me I'm missing something obvious here.

I'm integrating an existing java project with a third-party api that uses an md5 hash of an api key for authentication. It's not working for me, and during debugging I realized that the hashes I'm generating don't match the examples that they've supplied. I've found some websites that create MD5 hashes from strings to check their examples, and as far as I can tell I'm wrong and they're right.

for example, according to this website, the string "hello" generates a hash of "5d41402abc4b2a76b9719d911017c592". (FWIW I don't know anything about this website except that it seems to correctly hash the examples that I have). When I run it through my code I get:

XUFAKrxLKna5cZ2REBfFkg==

Here is the simple method I'm using to generate the md5 hash/string.:

private String md5(String md5Me) throws Exception {
    MessageDigest md = MessageDigest.getInstance("MD5");
    md.reset();
    md.update(md5Me.getBytes("UTF-8"));

    return Base64.encodeBase64String(md.digest());
}

I used a very similar method to successfully authenticate a different API using the SHA1 algorithm last week. I'm wondering if the problem is related to the org.apache.commons.net.util.Base64.encodeBase64String... Any help is greatly appreciated, if only some tests to see if the byteArray is correct but the converted string is wrong.

eric
  • 2,699
  • 4
  • 29
  • 40
  • 1
    md.digest() should contain bytes you are looking for, you encode them further using Base64 algorithm and get different result – hoaz Nov 30 '12 at 19:32
  • I need to convert those bytes into a String for an http request, is there a better way to do that? – eric Nov 30 '12 at 19:33
  • 1
    new String(byte[] bytes) – Andy Nov 30 '12 at 19:34
  • 1
    The problem I guess is in different text encodings http://stackoverflow.com/questions/6839969/md5-hash-with-different-results – Momo Nov 30 '12 at 19:35
  • 1
    If you have the optional of using external libraries, [Apache Commons DigestUtils](http://commons.apache.org/codec/apidocs/org/apache/commons/codec/digest/DigestUtils.html) will create MD5 hashes for you, and has been battle tested in numerous apps. – Perception Nov 30 '12 at 19:37
  • DigestUtils.md5Hex gives me the correct string – eric Nov 30 '12 at 19:46

2 Answers2

9

for example, according to this website, the string "hello" generates a hash of "5d41402abc4b2a76b9719d911017c592". (FWIW I don't know anything about this website except that it seems to correctly hash the examples that I have). When I run it through my code I get:

XUFAKrxLKna5cZ2REBfFkg==

Both are correct ways of representing the same sixteen-byte hash. 5d41402abc4b2a76b9719d911017c592 represents each byte of the hash as two hexadecimal digits, whereas XUFAKrxLKna5cZ2REBfFkg== uses Base-64 to represent every three bytes of the hash as four characters.

To generate the hexadecimal-version that this third-party API is expecting, you can change this:

Base64.encodeBase64String(md.digest());

to this:

String.format("%032x", new BigInteger(1, md.digest()));

(mostly taken from this StackOverflow answer).

However, you might want to consider using an external library for this. Perception, in a comment above, mentions Apache Commons DigestUtils. If you use that, you'll want the md5hex method.

Community
  • 1
  • 1
ruakh
  • 175,680
  • 26
  • 273
  • 307
  • Marking this as correct since it solves my problem, explains what the hell is happening, and references Perception's suggestion to use DigestUtils (which works also). Thanks! – eric Nov 30 '12 at 19:50
3

The md5 Hash algorithm is part of the core java API so there is no need for any external libraries. Here is the method I used to encrypt a password with MD5.

import java.security.MessageDigest;

/**
 * Use to encrypt passwords using MD5 algorithm
 * @param password should be a plain text password.
 * @return a hex String that results from encrypting the given password.
 */
public static String encryptPassword(String password) {
    try {
        MessageDigest md = MessageDigest.getInstance("MD5");
        md.update(password.getBytes());

        byte byteData[] = md.digest();

        StringBuffer hexString = new StringBuffer();
        for (int i=0;i<byteData.length;i++) {
            String hex=Integer.toHexString(0xff & byteData[i]);
            if(hex.length()==1) hexString.append('0');
            hexString.append(hex);
        }
        return hexString.toString();
    }
    catch(java.security.NoSuchAlgorithmException missing) {
        return "Error.";
    }
}
Thorn
  • 4,015
  • 4
  • 23
  • 42