1. Introduction
The MD5 (Message-Digest Algorithm 5) hash is a widely used cryptographic hash function. Although MD5 is not recommended for cryptographic security due to vulnerabilities, it’s still used for other purposes.
In this tutorial, we’ll explore how to generate an MD5 hash in Kotlin.
2. Understanding MD5 Hashing
MD5 is a cryptographic hash function that transforms any input data into a fixed-size, 128-bit (16-byte) hash, typically represented as a 32-character hexadecimal number. This process is one-way, meaning the original data can’t be retrieved from the hash.
There are a few key characteristics to note about this algorithm:
- Fixed-Length Output: Independent of input size, MD5 produces a 128-bit hash.
- Efficiency: Known for its speed, it is suitable for quickly processing large volumes of data.
- Uniqueness: Ideally, each unique input yields a unique hash, but there are limitations due to the output’s fixed size.
We also need to be aware of the limitations and potential vulnerabilities of this algorithm when used in certain ways:
- Collision Vulnerability: Different inputs can produce the same hash, compromising its uniqueness.
- Security Concerns: The speed of MD5 also makes it more vulnerable to brute-force attacks.
Despite its known security vulnerabilities, MD5 is still used for:
- Data Integrity Checks: Verifying if files have been altered during transfer.
- Checksum Operations: Quick hash generation for data indexing.
While efficient, MD5’s security issues limit its use to non-critical applications. For secure hashing needs, algorithms like SHA-256 are recommended due to their robustness against vulnerabilities that affect MD5.
3. Implementing MD5 Hashing in Kotlin
Kotlin has a straightforward way of handling MD5 hashing by utilizing Java’s MessageDigest class. We’ll create an extension function for the String class that will perform the MD5 hashing:
@OptIn(ExperimentalStdlibApi::class)
fun String.md5(): String {
val md = MessageDigest.getInstance("MD5")
val digest = md.digest(this.toByteArray())
return digest.toHexString()
}
This function first obtains an instance of MessageDigest for MD5*,* then computes the digest of our string converted to a ByteArray, before finally converting the resulting MD5 digest ByteArray to a String. We use toHexString() – an experimental function introduced in Kotlin 1.9 – to convert the ByteArray into a more typical representation of the digest: a hexadecimal string. Because this function is still experimental, we must opt-in to use it.
To verify our function, let’s write a JUnit test to ensure it’s working as expected:
@Test
fun `Calling extension md5 should return a md5 hash`() {
val stringToBeHashed = "Hello, Baeldung!"
val expectedHash = "6469a4ea9e2753755f5120beb51587f8"
val calculatedHash = stringToBeHashed.md5()
assertEquals(expectedHash, calculatedHash)
}
This test confirms that our md5() function calculates the MD5 hash of “Hello, Baeldung!” as “6469a4ea9e2753755f5120beb51587f8”, which we computed ahead of time.
4. Verifying a File Checksum With MD5 Hashing
Similarly to what we’ve done with a String in the previous section, we can apply MD5 hashing to a File. Calculating the MD5 hash of a file is a common way to verify the file’s integrity. Computing the MD5 hash of a file specifically means we’re computing the hash of the file’s contents.
Let’s define a function that calculates a file’s MD5 hash in Kotlin:
@OptIn(ExperimentalStdlibApi::class)
fun File.md5(): String {
val md = MessageDigest.getInstance("MD5")
val digest = md.digest(this.readBytes())
return digest.toHexString()
}
Let’s also write a unit test to ensure our new function works. We’ll use test_md5.txt as our example file, which contains:
Hello, Baeldung! I'm a file!
Now, let’s have a look at the test code:
@Test
fun `Calling extension md5 on a file should return a md5 hash`() {
val fileToBeHashed = File("src/test/resources/test_md5.txt")
val expectedHash = "ef948f943cdba8514ed5aab7592a904d"
val calculatedHash = fileToBeHashed.md5()
assertEquals(expectedHash, calculatedHash)
}
This unit test validates that our md5() function hashes our test_md5.txt file to “ef948f943cdba8514ed5aab7592a904d”, which we also computed ahead of time.
5. Conclusion
In this article, we’ve demonstrated a simple and effective way to generate MD5 hashes in Kotlin by borrowing Java’s MessageDigest class. Remember, while MD5 is quick and useful for certain applications, it’s not suitable for security-sensitive operations. For those, we should consider more secure hashing algorithms like SHA-256.
As always, the code used in this article is available over on GitHub.