1. 简介

MD5(Message-Digest Algorithm 5)是一种广泛使用的哈希算法。尽管由于存在安全漏洞,MD5 已不再推荐用于安全敏感场景,但在一些非加密用途中仍然常见。

本文将介绍如何在 Kotlin 中生成 MD5 哈希值。

2. 理解 MD5 哈希

MD5 是一种哈希函数,能将任意输入数据转换为固定长度的 128 位(16 字节)哈希值,通常表示为一个 32 位的十六进制字符串。该过程是单向的——无法从哈希值还原原始数据。

MD5 的主要特性包括:

  • 定长输出:无论输入多大,输出始终是 128 位。
  • 高效性:计算速度快,适合处理大量数据。
  • 唯一性(理想情况下):不同输入应产生不同哈希,但由于输出空间有限,实际存在冲突可能。

⚠️ 但也要清楚它的局限性和风险:

  • 碰撞漏洞:不同内容可能生成相同哈希,破坏唯一性。
  • 安全性差:因其计算快,容易被暴力破解或彩虹表攻击。

尽管如此,MD5 仍用于以下非安全场景:

  • ✅ 文件完整性校验:比如下载后比对哈希,确认是否被篡改。
  • ✅ 快速校验和(checksum):用于缓存、索引等轻量级场景。

切记:MD5 不可用于密码存储、签名验证等安全相关功能。对于高安全需求,应使用更可靠的算法,如 SHA-256

3. 在 Kotlin 中实现 MD5 哈希

Kotlin 可直接使用 Java 的 MessageDigest 类来实现 MD5 计算。我们可以通过扩展函数的方式,为 String 添加 .md5() 方法:

@OptIn(ExperimentalStdlibApi::class)
fun String.md5(): String {
    val md = MessageDigest.getInstance("MD5")
    val digest = md.digest(this.toByteArray())
    return digest.toHexString()
}

📌 上述代码逻辑如下:

  1. 获取 MD5 实例;
  2. 将字符串转为字节数组并计算摘要;
  3. 使用 Kotlin 1.9 引入的 toHexString() 转为十六进制字符串。

⚠️ 注意:toHexString() 目前仍是实验性 API,需通过 @OptIn(ExperimentalStdlibApi::class) 显式启用。

为了验证正确性,编写一个 JUnit 测试用例:

@Test
fun `Calling extension md5 should return a md5 hash`() {
    val stringToBeHashed = "Hello, Baeldung!"
    val expectedHash = "6469a4ea9e2753755f5120beb51587f8"
    val calculatedHash = stringToBeHashed.md5()

    assertEquals(expectedHash, calculatedHash)
}

✅ 测试通过说明我们的扩展函数工作正常。预期值 "6469a4ea9e2753755f5120beb51587f8" 是预先计算好的标准结果。

💡 踩坑提醒:如果测试失败,请检查字符串编码是否一致(默认 UTF-8),避免因 BOM 或换行符导致哈希不一致。

4. 使用 MD5 验证文件校验和

与字符串类似,我们也可以对文件内容进行 MD5 哈希,常用于验证文件完整性(例如软件包、配置文件传输后是否损坏)。

下面是为 File 类添加的扩展函数:

@OptIn(ExperimentalStdlibApi::class)
fun File.md5(): String {
    val md = MessageDigest.getInstance("MD5")
    val digest = md.digest(this.readBytes())
    return digest.toHexString()
}

📌 核心是调用 readBytes() 一次性读取文件全部内容并计算哈希。

配套测试用例如下,测试文件为 src/test/resources/test_md5.txt,其内容为:

Hello, Baeldung! I'm a file!

对应的测试代码:

@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)
}

✅ 测试通过表明文件哈希计算准确无误。

⚠️ 注意事项:

  • 大文件慎用 readBytes(),可能引发 OOM;
  • 生产环境建议使用流式读取(InputStream + digest.update())分块处理。

5. 总结

本文展示了如何在 Kotlin 中借助 Java 的 MessageDigest 类,简洁地实现字符串和文件的 MD5 哈希计算。

📌 关键要点回顾:

  • 使用扩展函数提升代码可读性和复用性;
  • toHexString() 是 Kotlin 1.9 新增的实验性功能,注意标注 @OptIn
  • 文件哈希适用于完整性校验,但大文件需考虑内存问题;
  • MD5 仅适用于非安全场景,绝不应用于身份认证、密码存储等环节

✅ 安全替代方案:优先选用 SHA-256、SHA-3 等现代哈希算法。

完整示例代码已托管至 GitHub:
https://github.com/Baeldung/kotlin-tutorials/tree/master/core-kotlin-modules/core-kotlin-9


原始标题:Generate an MD5 Hash in Kotlin