Nothing Type in Kotlin

Encode String security using MD5 algorithm in Java

The MD5 Message-Digest Algorithm is a widely used cryptographic hash function that produces a 128-bit (16-byte) hash value. It’s very simple and straight forward; the basic idea is to map data sets of variable length to data sets of a fixed length. In order to do this, the input message is split into chunks of 512-bit blocks.


A padding is added to the end so that it’s length can be divided by 512. Now these blocks are processed by the MD5 algorithm, which operates in a 128-bit state, and the result will be a 128-bit hash value. After applying MD5, generated hash is typically a 32-digit hexadecimal number.

Here, the password to be encoded is often called the “message” and the generated hash value is called the message digest or simply “digest”.
public class SimpleMD5Example
{
    public static void main(String[] args)
    {
        String passwordToHash = "password";
        String generatedPassword = null;
        try {
            // Create MessageDigest instance for MD5
            MessageDigest md = MessageDigest.getInstance("MD5");
            //Add password bytes to digest
            md.update(passwordToHash.getBytes());
            //Get the hash's bytes
            byte[] bytes = md.digest();
            //This bytes[] has bytes in decimal format;
            //Convert it to hexadecimal format
            StringBuilder sb = new StringBuilder();
            for(int i=0; i< bytes.length ;i++)
            {
                sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
            }
            //Get complete hashed password in hex format
            generatedPassword = sb.toString();
        }
        catch (NoSuchAlgorithmException e)
        {
            e.printStackTrace();
        }
        System.out.println(generatedPassword);
    }
}

Console output:

5f4dcc3b5aa765d61d8327deb882cf99


Although MD5 is a widely spread hashing algorithm, is far from being secure, MD5 generates fairly weak hashes. It’s main advantages are that it is fast, and easy to implement. But it also means that it is susceptible to brute-force and dictionary attacks. Rainbow tables with words and hashes generated allows searching very quickly for a known hash and getting the original word.

Also, It is not collision resistant: this means that different passwords can eventually result in the same hash.

Still, if you are using MD5 hash then consider adding some salt to your security.

Making MD5 more secure using salt

Keep in mind, adding salt is not MD5 specific. You can add it to other algorithms also. So, please focus on how it is applied rather than its relation with MD5.

Wikipedia defines salt as random data that are used as an additional input to a one-way function that hashes a password or pass-phrase. In more simple words, salt is some randomly generated text, which is appended to password before obtaining hash.

The original intent of salting was primarily to defeat pre-computed rainbow table attacks that could otherwise be used to greatly improve the efficiency of cracking the hashed password database. A greater benefit now is to slow down parallel operations that compare the hash of a password guess against many password hashes at once.
Important: 
We always need to use a SecureRandom to create good Salts, and in Java, the SecureRandom class supports the “SHA1PRNG” pseudo random number generator algorithm, and we can take advantage of it.

Let’s see how this salt should be generated.

private static byte[] getSalt() throws NoSuchAlgorithmException
{
    //Always use a SecureRandom generator
    SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
    //Create array for salt
    byte[] salt = new byte[16];
    //Get a random salt
    sr.nextBytes(salt);
    //return salt
    return salt;
}
SHA1PRNG algorithm is used as cryptographically strong pseudo-random number generator based on the SHA-1 message digest algorithm. Note that if a seed is not provided, it will generate a seed from a true random number generator (TRNG).

Now, lets look at the modified MD5 hashing example:

public class SaltedMD5Example
{
    public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchProviderException
    {
        String passwordToHash = "password";
        byte[] salt = getSalt();
       
        String securePassword = getSecurePassword(passwordToHash, salt);
        System.out.println(securePassword); //Prints 83ee5baeea20b6c21635e4ea67847f66
       
        String regeneratedPassowrdToVerify = getSecurePassword(passwordToHash, salt);
        System.out.println(regeneratedPassowrdToVerify); //Prints 83ee5baeea20b6c21635e4ea67847f66
    }
   
    private static String getSecurePassword(String passwordToHash, byte[] salt)
    {
        String generatedPassword = null;
        try {
            // Create MessageDigest instance for MD5
            MessageDigest md = MessageDigest.getInstance("MD5");
            //Add password bytes to digest
            md.update(salt);
            //Get the hash's bytes
            byte[] bytes = md.digest(passwordToHash.getBytes());
            //This bytes[] has bytes in decimal format;
            //Convert it to hexadecimal format
            StringBuilder sb = new StringBuilder();
            for(int i=0; i< bytes.length ;i++)
            {
                sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
            }
            //Get complete hashed password in hex format
            generatedPassword = sb.toString();
        }
        catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return generatedPassword;
    }
   
    //Add salt
    private static byte[] getSalt() throws NoSuchAlgorithmException, NoSuchProviderException
    {
        //Always use a SecureRandom generator
        SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "SUN");
        //Create array for salt
        byte[] salt = new byte[16];
        //Get a random salt
        sr.nextBytes(salt);
        //return salt
        return salt;
    }
}
Important: 
Please note that now you have to store this salt value for every password you hash. Because when user login back in system, you must use only originally generated salt to again create the hash to match with stored hash. If a different salt is used (we are generating random salt), then generated hash will be different.

Also, you might heard of term crazy hashing and salting. It generally refer to creating custom combinations like:
salt+password+salt => hash
Do not practice these things. They do not help in making hashes further secure anyhow. If you want more security, choose a better algorithm.

Comments