Java md5 example with MessageDigest

chris (2004-09-09 11:51:40)
172060 views
16 replies
This is a quick tip for implementing md5 encryption in java. We use the MessageDigest class in the java.security package and some string manipulation to turn the plain text into a byte array. The digest is then updated from the bytes from the byte array and a hash computation is conducted upon them. To quote from the Sun java api docs, The MessageDigest class provides applications the functionality of a message digest algorithm, such as MD5 or SHA. Message digests are secure one-way hash functions that take arbitrary-sized data and output a fixed-length hash value.

Anyway the md5 example code below takes a session id (this is just a string which I wanted to encrypt - It could just as easily be a document, say a lump of xml or any old bit of text). This session id is pulled into the bytes array, defaultBytes and then the MessageDigest is instantiated as an instance of an md5 encryption.

Java developers who have come over from PERL or PHP often get frustrated with such a longwinded means of running what could simply be a single line of code, however the snippet below could be wrapped into an md5sum class which conducts the encryption and simply returns a string of cipher text.
include java.security.*;

... etc

sessionid="12345";
        
byte[] defaultBytes = sessionid.getBytes();
try{
	MessageDigest algorithm = MessageDigest.getInstance("MD5");
	algorithm.reset();
	algorithm.update(defaultBytes);
	byte messageDigest[] = algorithm.digest();
            
	StringBuffer hexString = new StringBuffer();
	for (int i=0;i<messageDigest.length;i++) {
		hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
	}
	String foo = messageDigest.toString();
	System.out.println("sessionid "+sessionid+" md5 version is "+hexString.toString());
	sessionid=hexString+"";
}catch(NoSuchAlgorithmException nsae){
            
}

Remember to import the java.security package. The original plain text and cipher text strings are echod to the java console just to demonstrate what has happened.


Hope that's useful,

christo

follow me on twitter: http://www.twitter.com/planet_guru
comment
gipak
2004-09-23 09:11:47

not exactly correct

if you use Integer.toHexString(int a), if a>=0 and a<=15 you will get a String consisting of only one char!!!! you need to do something like this:

StringBuffer sb=new StringBuffer();
for (int i = 0; i < bytes.length; i++) {
     String hex=Integer.toHexString(0xff & bytes[i]);
     if(hex.length()==1) sb.append('0');
     sb.append(hex);
}
reply icon
anonymous
2006-12-18 16:59:38

Java md5 example with MessageDigest - - immer 32 z

Vielen Dank für dieses Beispiel,
ich bin mal so frei und hab den Code aufbereitet, das er passt.
D.h. es kommt als Ergebnis immer ein gültiger 32 Zeichelänge MD5-String raus.

import java.security.*;

... etc

String pass = "123456";


byte[] defaultBytes = pass.getBytes();
try{
     MessageDigest algorithm = MessageDigest.getInstance("MD5");
     algorithm.reset();
     algorithm.update(defaultBytes);
     byte messageDigest[] = algorithm.digest();

     StringBuffer hexString = new StringBuffer();
     for (int i=0;i<messageDigest.length;i++) {
	String hex = Integer.toHexString(0xFF & messageDigest[i]); 
	if(hex.length()==1)
	hexString.append('0');

	hexString.append(hex);
     }
						     
						     
     //*** Testausgabe
     System.out.println("pass "+pass+"   md5 version is "+hexString.toString());
     pass = hexString+"";
}
catch(NoSuchAlgorithmException nsae){
						                    
}

Danke an Euch Zwei. ICh wäre da selbst nicht drauf gekommen.
reply icon
anonymous
2006-11-28 16:43:09

Thanks!

These codes were very useful to me !
Thank you!
reply icon
anonymous
2007-03-30 09:36:31

The following code works well if you only need to print the digest value:

for (byte b : md.digest())
System.out.printf("%02x", 0xFF&b);
reply icon
anonymous
2007-03-30 15:38:19

SHA-256

Cheers.

package test;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MD5Test
{
    public static void main(String[] args)
    {
        String md5val = "";
        MessageDigest algorithm = null;

        try
        {
            algorithm = MessageDigest.getInstance("MD5");
        }
        catch (NoSuchAlgorithmException nsae)
        {
            System.out.println("Cannot find digest algorithm");
            System.exit(1);
        }
        
        for (String arg : args)
        {
            byte[] defaultBytes = arg.getBytes();
            algorithm.reset();
            algorithm.update(defaultBytes);
            byte messageDigest[] = algorithm.digest();
            StringBuffer hexString = new StringBuffer();

            for (int i = 0; i < messageDigest.length; i++)
            {
                String hex = Integer.toHexString(0xFF & messageDigest[i]);
                if (hex.length() == 1)
                {
                    hexString.append('0');
                }
                hexString.append(hex);
            }
            md5val = hexString.toString();
            System.out.println("MD5 ("" + arg + "") = " + md5val);
        }
    }
}

this lets you test on the command line against the command line md5 command to check it works correctly:

g@h ~/bin$ md5 -s dammitjanet
MD5 ("dammitjanet") = ea309a2eb146a4d8bdf8946c4df23c71
g@h ~/bin$ java -cp . test.MD5Test dammitjanet
MD5 ("dammitjanet") = ea309a2eb146a4d8bdf8946c4df23c71

Please note that if you are using MD5 for authentication means, you really really should consider using a salt alongside the value you wish to create an md5 of to increase security. Better to use SHA-256 although you need to use more characters in your database password table.

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

g@h ~/bin$ java -cp . test.MD5Test "bark at the moon"  
SHA-256 ("bark at the moon") = a5bb786220762b74c9569cd9f150a4176f9da3c2ac29d776a65487b2a77d4429
reply icon
iandesouza
2007-05-17 17:27:19

shorter version

You can use BigInteger to do the byte array conversion....
    static String getMd5Digest(String input)
        {
            try
            {
                MessageDigest md = MessageDigest.getInstance("MD5");
                byte[] messageDigest = md.digest(input.getBytes());
                BigInteger number = new BigInteger(1,messageDigest);
                return number.toString(16);
            }
            catch(NoSuchAlgorithmException e)
            {
                throw new RuntimeException(e);
            }
        }
reply icon
pedroha
2007-05-21 19:35:08

Short correction

I liked the short version, so I used it but it didn't match during my testing.

I tried with the following input:
"bbb": 8F8E0260C64418510CEFB2B06EEE5CD

So I checked against MySQL md5():
08F8E0260C64418510CEFB2B06EEE5CD

You have to prepend zero's until you get 32 chars to simulate this behaviour.

Regards,
Pedro

reply icon
jn
2008-05-26 06:07:07

You can use BigInteger to do the byte array conversion....
    static String getMd5Digest(String input)
        {
            try
            {
                MessageDigest md = MessageDigest.getInstance("MD5");
                byte[] messageDigest = md.digest(input.getBytes());
                BigInteger number = new BigInteger(1,messageDigest);
                return number.toString(16);
            }
            catch(NoSuchAlgorithmException e)
            {
                throw new RuntimeException(e);
            }
        }

ty so much, never thought of using BigInteger, best solution ever :) (after the PHP solution in 1 line :P)
reply iconedit reply
Ismael
2008-11-24 11:17:28

Thank you very much, it is really useful.
reply iconedit reply
Golovach Ivan
2008-11-27 09:49:17

error desicion

BAD TEST:

public class CheckSumUtils {

public static String calcPlayerPasswordChecksum(String pass) {
byte[] passBytes = pass.getBytes();
try {
MessageDigest algorithm = MessageDigest.getInstance("MD5");
algorithm.reset();
algorithm.update(passBytes);
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] messageDigest = md.digest(passBytes);
BigInteger number = new BigInteger(1, messageDigest);
return number.toString(16).toUpperCase();
} catch (NoSuchAlgorithmException e) {
throw new Error("invalid JRE: have not 'MD5' impl.", e);
}
}

public static void main(String[] args) {
System.out.println(calcPlayerPasswordChecksum("a"));
System.out.println(calcPlayerPasswordChecksum("aa"));
System.out.println(calcPlayerPasswordChecksum("aaa"));
}
}

running this test return answ:
CC175B9C0F1B6A831C399E269772661
4124BC0A9335C27F086F24BA207A4912
47BCE5C74F589F4867DBD57E9CA9F808

so, arg 'a' translate to 31 (not 32) lenth result :(
reply iconedit reply
Paul Uszak
2009-02-15 14:26:57

I have to side with Ivan - the Big Integer approach does not seem to work properly. I did this:-


public static void main(String[] args) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("MD5");


for (int i = 0; i < 1E+4; i++) {
byte[] messageDigest = md.digest(new Date().toString().getBytes());
BigInteger number = new BigInteger(1, messageDigest);
System.out.println(number.toString(16));
}
}



and while looking at the output, came across these MD5s:-



8150f16d3efeddda79787fb9e8a235
8150f16d3efeddda79787fb9e8a235
8150f16d3efeddda79787fb9e8a235
8150f16d3efeddda79787fb9e8a235
4e9b15f5c1df1905f63faec3bb6a49d2
4e9b15f5c1df1905f63faec3bb6a49d2
4e9b15f5c1df1905f63faec3bb6a49d2
4e9b15f5c1df1905f63faec3bb6a49d2



I'm not an expert and don't really understand how it works, but I thought that all MD5s were the same length...
reply iconedit reply
Mr. Pickles
2009-02-16 01:37:54

leading zeroes don't matter!

You could argue that leading zeroes are insignificant. Depending on how you use the hash bytes, they may or may not matter. Here is an easy way to check a user supplied password against a saved hash value;


MessageDigest m = MessageDigest.getInstance("SHA"); // or MD5
BigInteger supplied = new BigInteger(1, m.digest(password.getBytes()));
BigInteger checkval = new BigInteger(stored, 16);
if (supplied.equals(checkval)) {
// do something
};

Where 'password' is the user supplied String, and 'stored' is the String of the stored hash. You could easily combine it into a one line statement, but this is very clear and easy to read (besides which, you need to wrap in a try/catch anyway).

By viewing the stored hash and the supplied hash as BigIntegers, you can check for equality easily, and not have to worry about leading zeroes in the stored hash value.

My 2 cents.
reply iconedit reply
pkelleners
2010-02-19 13:49:17

public String getMD5Hash(String value)
throws NoSuchAlgorithmException, UnsupportedEncodingException {

final StringBuilder sbMd5Hash = new StringBuilder();
final MessageDigest m = MessageDigest.getInstance("MD5");
m.update(value.getBytes("UTF-8"));

final byte data[] = m.digest();

for (byte element : data) {
sbMd5Hash.append(Character.forDigit((element >> 4) & 0xf, 16));
sbMd5Hash.append(Character.forDigit(element & 0xf, 16));
}

return sbMd5Hash.toString();
}

BigInteger is not correct for example "Cash"
with BigInteger = 69b30db06d047a398f9eb0940d3279c
Right is = 069b30db06d047a398f9eb0940d3279c
reply iconedit reply
Andrew Carter
2010-03-24 01:04:50

This one works...

This code always gives me the expected 32 bit result. Easier than including another apache commons lib!

public String getMD5Hash(String value)
throws NoSuchAlgorithmException, UnsupportedEncodingException {

final StringBuilder sbMd5Hash = new StringBuilder();
final MessageDigest m = MessageDigest.getInstance("MD5");
m.update(value.getBytes("UTF-8"));

final byte data[] = m.digest();

for (byte element : data) {
sbMd5Hash.append(Character.forDigit((element >> 4) & 0xf, 16));
sbMd5Hash.append(Character.forDigit(element & 0xf, 16));
}

return sbMd5Hash.toString();
}

BigInteger is not correct for example "Cash"
with BigInteger = 69b30db06d047a398f9eb0940d3279c
Right is = 069b30db06d047a398f9eb0940d3279c
reply iconedit reply
anonymous
2010-04-03 23:55:12

only a full program

import java.security.*;
import java.io.*;
import java.math.BigInteger;

public class Checksum {

    //
    // returns 0 error
    //         1 ok (create)
    //         1 same (check)
    //         2 different (check)
    //
    public static void main(String args[]) {
        if (args.length == 2) {
            if (args[0].equalsIgnoreCase("create")) {
                System.exit(new Checksum().create(args[1]));
            } else if (args[0].equalsIgnoreCase("check")) {
                System.exit(new Checksum().check(args[1]));
            }
        } else {
            System.out.println("Usage : java Checksum create [filename]n" +
                    "        java Checksum check  [filename]");
        }
    }

    public int create(String filename) {
        try {
            int sum;
            String salida = new String();
            byte[] chk = createChecksum(filename);
            File f = new File(filename + ".chk");
            OutputStream os = new FileOutputStream(f);
            //muestra la cadena MD5 y es la misma quela del program MD5Check.exe
            BigInteger bigInt = new BigInteger(1, chk);
            String output = bigInt.toString(16).toUpperCase();;
            if (output.length() < 32){
				System.out.println("Menor de 32");
                sum = 32 - output.length();
                for ( int i = 1 ; i == sum;i++){
                    salida=salida.concat("0");
                }
                salida = salida.concat(output);
            }
            System.out.println("MD5: " + output+" = "+ salida);
            os.write(chk);
            os.close();
            return 1;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    public int check(String filename) {
        int rc = 0;
        try {
            byte[] chk1 = createChecksum(filename);
            byte[] chk2 = new byte[chk1.length];
            File f = new File(filename + ".chk");
            InputStream is = new FileInputStream(f);

            is.read(chk2);
            //muestra la cadena MD5 y es la misma quela del program MD5Check.exe
            BigInteger bigInt1 = new BigInteger(1, chk1);
            String output1 = bigInt1.toString(16).toUpperCase();;
            System.out.println("MD5: " + filename + "     " + output1);
            BigInteger bigInt2 = new BigInteger(1, chk2);
            String output2 = bigInt2.toString(16).toUpperCase();;
            System.out.println("MD5: " + filename + ".chk " + output2);
            //fin muestra
            //if (new String(chk2).equals(new String(chk1))) {
            if (output2.equals(output1)) {
                System.out.println("Same!");
                rc = 1;
            } else {
                System.out.println("Different!");
                rc = 2;
            }
            is.close();
            return rc;
        } catch (Exception e) {
            e.printStackTrace();
            return rc;
        }
    }

    public byte[] createChecksum(String filename) throws Exception {
        InputStream fis = new FileInputStream(filename);

        byte[] buffer = new byte[1024];
        MessageDigest complete = MessageDigest.getInstance("MD5");
        int numRead;
        do {
            numRead = fis.read(buffer);
            if (numRead > 0) {
                complete.update(buffer, 0, numRead);
            }
        } while (numRead != -1);
        fis.close();
        return complete.digest();
    }
}
reply iconedit reply
Manfrizy
2010-04-11 22:47:50

Wrong md5

import java.security.*;
import java.io.*;
import java.math.BigInteger;

public class Checksum {

    //
    // returns 0 error
    //         1 ok (create)
    //         1 same (check)
    //         2 different (check)
    //
    public static void main(String args[]) {
        if (args.length == 2) {
            if (args[0].equalsIgnoreCase("create")) {
                System.exit(new Checksum().create(args[1]));
            } else if (args[0].equalsIgnoreCase("check")) {
                System.exit(new Checksum().check(args[1]));
            }
        } else {
            System.out.println("Usage : java Checksum create [filename]n" +
                    "        java Checksum check  [filename]");
        }
    }

    public int create(String filename) {
        try {
            int sum;
            String salida = new String();
            byte[] chk = createChecksum(filename);
            File f = new File(filename + ".chk");
            OutputStream os = new FileOutputStream(f);
            //muestra la cadena MD5 y es la misma quela del program MD5Check.exe
            BigInteger bigInt = new BigInteger(1, chk);
            String output = bigInt.toString(16).toUpperCase();;
            if (output.length() < 32){
				System.out.println("Menor de 32");
                sum = 32 - output.length();
                for ( int i = 1 ; i == sum;i++){
                    salida=salida.concat("0");
                }
                salida = salida.concat(output);
            }
            System.out.println("MD5: " + output+" = "+ salida);
            os.write(chk);
            os.close();
            return 1;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    public int check(String filename) {
        int rc = 0;
        try {
            byte[] chk1 = createChecksum(filename);
            byte[] chk2 = new byte[chk1.length];
            File f = new File(filename + ".chk");
            InputStream is = new FileInputStream(f);

            is.read(chk2);
            //muestra la cadena MD5 y es la misma quela del program MD5Check.exe
            BigInteger bigInt1 = new BigInteger(1, chk1);
            String output1 = bigInt1.toString(16).toUpperCase();;
            System.out.println("MD5: " + filename + "     " + output1);
            BigInteger bigInt2 = new BigInteger(1, chk2);
            String output2 = bigInt2.toString(16).toUpperCase();;
            System.out.println("MD5: " + filename + ".chk " + output2);
            //fin muestra
            //if (new String(chk2).equals(new String(chk1))) {
            if (output2.equals(output1)) {
                System.out.println("Same!");
                rc = 1;
            } else {
                System.out.println("Different!");
                rc = 2;
            }
            is.close();
            return rc;
        } catch (Exception e) {
            e.printStackTrace();
            return rc;
        }
    }

    public byte[] createChecksum(String filename) throws Exception {
        InputStream fis = new FileInputStream(filename);

        byte[] buffer = new byte[1024];
        MessageDigest complete = MessageDigest.getInstance("MD5");
        int numRead;
        do {
            numRead = fis.read(buffer);
            if (numRead > 0) {
                complete.update(buffer, 0, numRead);
            }
        } while (numRead != -1);
        fis.close();
        return complete.digest();
    }
}

Hi guyz,
am a newby in this and i tried to calculate md5 for 123456789012347 using the code snippet given in the very first post and i get something different from what i expect.

RESULT: 33ee13aecb36180f03cceab4b214e665

EXPECTED RESULT: 8f43ae1a3319c649cc57408b6a392d6b

can someone please tell me what is wrong and what i should edit.

Your reply is highly appreciated



reply icon