MD5 is a cryptographic Message Digest Algorithm, which produces a 128-bit hash value. The hash function takes an arbitrary-sized data and produces a fixed-length hash value. Hashing is a one-way function, it is impossible to get the original message from the hash and no two different strings can have the same hash value. In this article, we will learn about Java MD5 Hashing using MessageDigest, Guava and Apache Commons.
Hashing enables us to validate whether message transmitted over a channel has tampered or not, if the input has changed even a little bit, then the resulting hash will be different. Though MD5 is not considered as a good Cryptographic algorithm due the several vulnerabilities found but its checksum is fair enough for validating the integrity of a file.
Before getting into the coding, Let us first get some basic understanding of checksum
What is checksum?
Have you ever noticed when you are downloading certain files such updates, patches, etc.. from the internet, they will provide checksum or MD5 or SHA256, etc. along with it, which would be a long sequence of shuffled characters those are called checksum for the particular file. Checksum ensures the integrity of a file, which is transmitted over a network.
The checksum is calculated using the hash algorithms such as such MD5, SHA1, SHA256, etc. The checksum of a file gets changed even if the file gets a tiny modification, the user who downloads the file calculates the checksum of the downloaded file and both should be matching, if not then we can assume the file has tampered.
Let’s look into the below example where we have two files, the content of file1 is “Hello World” and the content of file2 is “Hello World.”. All we have added additional in the file2 is a dot (.) but the resulting Checksum is different.
File 1 Checksum: b10a8db164e0754105b7a99be72e3fe5
File 2 Checksum: d7527e2509d7b3035d23dd6701f5d8d0
Let us dig into the code
Java MD5 Hashing Example
1. MD5 Hash using MessageDigest
package com.javainterviewpoint; import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class MD5Example { public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException { String input = "JavaInterviewPoint"; // MessageDigest instance for MD5 MessageDigest md = MessageDigest.getInstance("MD5"); // Update MessageDigest with input text in bytes md.update(input.getBytes(StandardCharsets.UTF_8)); // Get the hashbytes byte[] hashBytes = md.digest(); //Convert hash bytes to hex format StringBuilder sb = new StringBuilder(); for (byte b : hashBytes) { sb.append(String.format("%02x", b)); } // Print the hashed text System.out.println(sb.toString()); } }
- Create a MessageDigest Instance for MD5 hash function by passing “MD5” as a parameter to getInstance() method
MessageDigest md = MessageDigest.getInstance(“MD5”);
- Get the bytes of the input text and pass it to the update() method of the message digest instance.
md.update(input.getBytes(StandardCharsets.UTF_8));
Note: While working with Cryptography always be sure to specify the encoding you want the bytes to represented. Simply if you are using getBytes(), then it will use the encoding which is default to the platform. Not all the Operating system use the same default encoding.
- The digest() method performs the actual hashing and returns the hashed version of the text passed to it.
byte[] hashBytes = md.digest();
- Finally, convert the hashBytes to a hex format
for (byte b : hashBytes) {
sb.append(String.format(“%02x”, b)); }
2. MD5 Hash using Guava
MD5 hashing with Guava is pretty simple than the above method using MessageDigest. We need to add “guava.27.1-jre.jar” (or) if you are running on maven we need to add guava dependency
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>27.1-jre</version>
</dependency>
package com.javainterviewpoint; import java.nio.charset.StandardCharsets; import com.google.common.hash.HashCode; import com.google.common.hash.HashFunction; import com.google.common.hash.Hashing; public class MD5Example_Guava { public static void main(String[] args) { String input = "JavaInterviewPoint"; // Create Instance of HashFunction (MD5) HashFunction hashFunction = Hashing.md5(); // Pass input and charset to hashString() method HashCode hash = hashFunction.hashString(input, StandardCharsets.UTF_8); // Print the hashed text System.out.println(hash); } }
- Get the instance of MD5 HashFunction by calling the static method md5()
HashFunction hashFunction = Hashing.md5();
- Call the hashString() on top of the HashFunction instance passing the input text and the encoding. The hashString() method returns the md5 hash of the text passed to it
HashCode hash = hashFunction.hashString(input, StandardCharsets.UTF_8);
3. MD5 Hash Apache Commons Codec
In order to use Apache Commons Codec, we need to add “commons-codec 1.12.jar” (or) if you are running on maven we need to add the below Apache Commons Codec dependency
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.12</version>
</dependency>
package com.javainterviewpoint; import org.apache.commons.codec.digest.DigestUtils; public class MD5Example_Apache { public static void main(String[] args) { String input = "JavaInterviewPoint"; // Pass input text to md5Hex() method String hash = DigestUtils.md5Hex( input ); // Print the hashed text System.out.println(hash); } }
The md5Hex() method of the DigestUtils class returns the md5 hash of the text passed to it.
String hash = DigestUtils.md5Hex( input );
Getting a File’s MD5 Checksum in Java
In the above code, we have calculated the MD5 Hash for a simple input string. In real world mostly MD5 will be used for calculating the checksum of file be it zip, exe, iso, etc.
For example, if a file is not properly downloaded due to a network issue or tampered, then if you know the checksum of the original file and the run checksum on the file which has been downloaded. If the resulting checksum matches, the file you have is identical if not the file is corrupted or tampered.
Now let’s see the code for Getting a File’s MD5 Checksum.
package com.javainterviewpoint; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class MD5Example_File { public static void main(String[] args) throws NoSuchAlgorithmException, IOException { // MessageDigest instance for MD5 MessageDigest md = MessageDigest.getInstance("MD5"); byte[] fileBytes = Files.readAllBytes(Paths.get("D:\\temp.txt" )); // Get the hashbytes byte[] hashBytes = md.digest(fileBytes); //Convert hash bytes to hexadecimal StringBuilder sb = new StringBuilder(); for (byte b : hashBytes) { sb.append(String.format("%02x", b)); } // Print the hashed text System.out.println(sb.toString()); } }
- Create a MessageDigest Instance for MD5 hash function by passing “MD5” as a parameter to getInstance() method
MessageDigest md = MessageDigest.getInstance(“MD5”);
- Using the readAllBytes() of the Files class to get the fileBytes
byte[] fileBytes = Files.readAllBytes(Paths.get(“D:\\temp.txt” ));
- Pass the fileBytes to the digest() method of the message digest instance, which returns the md5 hash of the file.
byte[] hashBytes = md.digest(fileBytes);
Secure MD5 Hash with Salt
Though MD5 is widely used it is prone to hash collision weakness. Using Lookup tables and Rainbow tables a hacker can easily identify the password, in order to mitigate the issue we can add the salt before hashing.
Salt is a fixed-length secure random string which is added to the password before hashing and hence the hash will be different for the same password.
Now, let’s see how to Secure MD5 Hash with Salt
package com.javainterviewpoint; import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; public class MD5ExampleWithSalt { public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException { String input = "JavaInterviewPoint"; // MessageDigest instance for MD5 MessageDigest md = MessageDigest.getInstance("MD5"); // Generate the random salt SecureRandom random = new SecureRandom(); byte[] salt = new byte[16]; random.nextBytes(salt); // Passing the salt to the digest for the computation md.update(salt); // Update MessageDigest with input text in bytes md.update(input.getBytes(StandardCharsets.UTF_8)); // Get the hashbytes byte[] hashBytes = md.digest(); //Convert hash bytes to hexadecimal StringBuilder sb = new StringBuilder(); for (byte b : hashBytes) { sb.append(String.format("%02x", b)); } // Print the hashed text System.out.println(sb.toString()); } }
We will be creating a new instance for SecureRandom class and the nextByte() method generates the random salt.
SecureRandom random = new SecureRandom();
byte[] salt = new byte[16];
random.nextBytes(salt);
This code generates different hash everytime for the same input text
Run 1: 85a9df6cdbc31b7dd89a2165203e794b
Run 2: f2cc604967e2206f5f1513a4e31839dc
Leave a Reply