Java MD5 Hashing & Salting: Secure Your Passwords

salt-hash-password-java

The MD5 Message-Digest Algorithm is a widely used cryptographic hash function that produces a 128-bit (16-byte) hash value. MD5 has been employed in a wide variety of security applications, and is also commonly used to check data integrity. MD5 was designed by Ron Rivest in 1991 to replace an earlier hash function, MD4. An MD5 hash is typically expressed as a 32-digit hexadecimal number.

The Hash

A cryptographic hash function is a hash function, that is, an algorithm that takes an arbitrary block of data and returns a fixed-size bit string, the hash value, such that an change to the data will change the hash value. The data to be encoded is often called the “message,” and the hash value is sometimes called the message digest or simply digest. Java security package java.security provides certain useful classes to generate Hash values. Especially the class java.security.MessageDigest provides applications the functionality of a message digest algorithm, such as MD5 or SHA. Below is an example of generating MD5 Hash value for any input in Java using java.security.MessageDigest.

package net.viralpatel.java.md5; import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class JavaMD5Hash { public static void main(String[] args) { String password = "MyPassword123"; System.out.println("MD5 in hex: " + md5(password)); System.out.println("MD5 in hex: " + md5(null)); //= d41d8cd98f00b204e9800998ecf8427e System.out.println("MD5 in hex: " + md5("The quick brown fox jumps over the lazy dog")); //= 9e107d9d372bb6826bd81d3542a419d6 } public static String md5(String input) { String md5 = null; if(null == input) return null; try { //Create MessageDigest object for MD5 MessageDigest digest = MessageDigest.getInstance("MD5"); //Update input string in message digest digest.update(input.getBytes(), 0, input.length()); //Converts message digest value in base 16 (hex) md5 = new BigInteger(1, digest.digest()).toString(16); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return md5; } }
Code language: Java (java)

Above example is quite straight forward. The main() method calls md5() method to get MD5 hash value of any input. In md5() method we used java.security.MessageDigest class’s object to generate Md5 hash. Note how we used java.math.BigInteger to convert the message digest into hex values of base 16. Alternately, you can also use Apache Commons Codec library to covert any string to Md5 hash. The commons-codec.jar contains class org.apache.commons.codec.digest.DigestUtils that can be used to generate MD5 hash. Following is the code snippet for same:

package net.viralpatel.java.md5; import org.apache.commons.codec.digest.DigestUtils; public class JavaMD5Hash { public static void main(String[] args) { String password = "MyPassword123"; System.out.println( DigestUtils.md5Hex( password ) ); } }
Code language: Java (java)

Thus if your project already uses commons-codec jar then it is advisable to use DigestUtils.md5Hex() method to generate MD5 hash values.

The Salt

The wikipedia definition of salt is:

In cryptography, a salt consists of random bits, creating one of the inputs to a one-way function. The other input is usually a password or passphrase. The output of the one-way function can be stored rather than the password, and still be used for authenticating users. The one-way function typically uses a cryptographic hash function.

Thus basically, salt is a random data string that one can append to the password before hashing it. Consider a scenario where in a system users passwords are stored in database table after hashing them. So the plain text password are hashed using hash algo like Md5 and than stored in database. Now it is possible to perform a dictionary attack based on hash values. A plain hash can be looked up in a lookup table and its corresponding password string can be retrieved. So instead of directly hashing passwords, we append a random string to it before hashing.

String password = "mypassword"; String salt = "Random$SaltValue#WithSpecialCharacters12@$@4&#%^$*"; String hash = md5(password + salt);
Code language: Java (java)

Thus the benefit provided by using a salted password is making a lookup table assisted dictionary attack against the stored values impractical, provided the salt is large enough. That is, an attacker would not be able to create a precomputed lookup table of hashed values (password + salt), because it would take too much space. A simple dictionary attack is still very possible, although much slower since it cannot be precomputed. It is generally advisable to have salt value large and random with lot of special characters. Also application wide single salt value must be used so that users can be authenticated irrespective of when accounts were created. The salt value must be stored outside application data and must be loaded with application.

References

Get our Articles via Email. Enter your email address.

You may also like...

12 Comments

  1. Cristian Rivera says:

    Hello, I am wondering why you would use MD5, an algorithm thats has already been broken instead of something like GrandCentral which creates a password digest based on the time of day using SHA-512. Just a suggestion. http://code.google.com/p/grandcentral/

  2. pradeep says:

    Really useful, thanks to viral patel.

  3. simar says:

    i believe that it
    String hash = md5(password + salt;

    has to be changed to
    String hash = md5(password + salt);

    and usually you have to keep salt somewhere and for more security for each passwod to have a new salt.
    i do preref
    Sting hash = md5(password+salt) + salt;

  4. simar says:

    pay attention to apache.common
    MessageDigest digest = MessageDigest.getInstance(“MD5”);
    this plaform specific and could not work on some.

    better to pay attention to apache.common
    there are useful class: RandomUtilString to generate string (numeric, alphanumeric and so on)
    and as well class DigestUtils with a certain amoutn of supported algorithms and diff method to get hashed string hashed bytes

  5. gli00001 says:

    //Update input string in message digest
    digest.update(input.getBytes(), 0, input.length());
    shouldn’t it be
    input.getBytes().length() ?

  6. Sif says:

    This is horrifyingly bad advice. MD5 is NOT APPROPRIATE for password storage (it never was). Nor are any of the SHA algorithms (the unreleased SHA-3 might become an exception).

    MD5 & the SHA family are horribly unsuited for password storage due to being far too fast. A modern GPU can do 10+ billion MD5 calculations per second. That’s enough guesses to wreck a massive database in no time at all, especially with how intelligent modern cracking tools like oclHashcat are (it’s not just brute forcing all possible combinations… hackers have a better idea how you formulate your passwords than you do!).

    Use bcrypt, scrypt, or PBKDF2. Pretty much every language out there easily supports one or more of those three, usually in their standard library. They’re designed for password storage, widely recommended by actual security experts, and can be configured to be as slow as you deem necessary.

    Likewise, DO NOT HAVE A SINGLE SALT FOR ALL PASSWORDS! You defeat the primary purpose of a salt by doing that. A salt’s primary purpose is NOT to defeat rainbow table attacks or any similar attack. It’s to kill an attacker’s ability to attack multiple hashes simultaneously. A common salt does not do that. Every time you write the password to your database (account creation, user password change) you should salt it with a new random salt, created by a cryptographically secure random number generator (32 – 64 bits should be adequate). And store this salt.

    So, in summary: Do not use MD5/SHA, use a key derivation function designed for passwords (bcrypt, scrypt, pbkdf2 being the most popular and widely supported). Do not have a single site-wide salt, have a *per-user* salt. Seriously, doing the right thing is easy, and will increase your security an absurd amount.

  7. Rajesh Perul says:

    Hi I got an error……

    Method md5(String input) is not work cool with a string that will generate and md5 string with zero at left side.

    (eg:-this method will generat a string “sandeep” to “DCF16D903E5890AABA465B0B1BA51F ” than the actual “00DCF16D903E5890AABA465B0B1BA51F”

    use this method instead..
    String md5(String s) {
    try {
    // Create MD5 Hash
    MessageDigest digest = java.security.MessageDigest.getInstance(“MD5”);
    digest.update(s.getBytes());
    byte messageDigest[] = digest.digest();

    // Create Hex String
    StringBuffer hexString = new StringBuffer();
    for (int i = 0; i < messageDigest.length; i++) {
    String h = Integer.toHexString(0xFF & messageDigest[i]);
    while (h.length() < 2)
    h = "0" + h;
    hexString.append(h);
    }
    return hexString.toString();

    } catch (NoSuchAlgorithmException e) {
    e.printStackTrace();
    }
    return "";
    }

  8. Keyur Bhatt says:

    Hi, nice article.
    I want to know that is there any algorithm available that will generate same result in all programming languages. I am trying to hash string using salt.
    Thank You.

  9. Rakesh says:

    nice tutorial and very useful for encryption.:)

  10. Supriya Murudkar says:

    How can we decrypt the password when the user logs in again and we need to verify if it is a legit user ?

  11. Rakesh Kumar says:

    Hi Viral,

    I follow you arcticles and it is helpful.

    I am facing one issue regarding encryption, if you can help it will be great.

    Java 1.8 generating different encryption using “SHA-512” Bouncy Castle

    The api which is used to generate the encryption follows below:

    public static byte[] test(String input,String key)
    {
    byte[] plainText=null;
    byte[] digest =null;

    Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    String combinedString=input+key;
    MessageDigest messageDigest=null;
    try
    {
    messageDigest = MessageDigest.getInstance(“SHA-512″,”BC”);
    }
    catch (NoSuchAlgorithmException e)
    {
    String[] message={ “SHA-512” };
    throw e1;
    }
    catch (NoSuchProviderException e)
    {
    String[] message={ “BouncyCastle” };
    SomeExcpetion e1=new SomeExcpetion(e,”******”,message);
    throw e1;
    }
    try
    {
    plainText=combinedString.getBytes(“UTF-8”);
    messageDigest.update(plainText);
    }
    catch (UnsupportedEncodingException e)
    {
    String[] message={ “UTF-8″ };
    SomeExcpetion e1=new SomeExcpetion(e,”*****”,message);
    throw e1;
    }
    digest = messageDigest.digest();
    return digest;
    }
    Encryption generated with Java 1.7 edition:

    *****Some Encrypted Text*****v??L?x?xN?

    Encryption generated with Java 1.8 edition:

    *****Some Encrypted Text*****v??L?x?xN?qE?

    Any pointers over this then please guide.

  12. ishwarya says:

    useful, thanks viralpatel.net

Leave a Reply

Your email address will not be published. Required fields are marked *