Java MD5 Hashing & Salting: Secure Your Passwords

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

View Comments

  • 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;

  • 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

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

  • 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.

  • 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 "";
    }

  • 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.

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

Recent Posts

  • Java

Java URL Encoder/Decoder Example

Java URL Encoder/Decoder Example - In this tutorial we will see how to URL encode/decode…

4 years ago
  • General

How to Show Multiple Examples in OpenAPI Spec

Show Multiple Examples in OpenAPI - OpenAPI (aka Swagger) Specifications has become a defecto standard…

4 years ago
  • General

How to Run Local WordPress using Docker

Local WordPress using Docker - Running a local WordPress development environment is crucial for testing…

4 years ago
  • Java

Create and Validate JWT Token in Java using JJWT

1. JWT Token Overview JSON Web Token (JWT) is an open standard defines a compact…

4 years ago
  • Spring Boot

Spring Boot GraphQL Subscription Realtime API

GraphQL Subscription provides a great way of building real-time API. In this tutorial we will…

4 years ago
  • Spring Boot

Spring Boot DynamoDB Integration Test using Testcontainers

1. Overview Spring Boot Webflux DynamoDB Integration tests - In this tutorial we will see…

5 years ago