MD5 (Message Digest Algorithm 5) 是廣泛使用的雜湊函數,產生 128 位 (16 字節) 的雜湊值,通常表示為 32 位十六進制字串。雖然 MD5 已被證明存在碰撞漏洞,不適合用於數位簽名、SSL 證書等高安全性場景,但因其計算速度快、實現簡單,仍常用於檔案完整性校驗、非核心業務密碼雜湊、緩存鍵生成等場景。
以下代碼採用單例模式封裝 java.security.MessageDigest,提供線程安全的 MD5 計算工具類:
package com.example.security;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MD5Util {
private static final char[] HEX_CHARS =
{'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
private static final ThreadLocal<MessageDigest> MD5_DIGEST = ThreadLocal.withInitial(() -> {
try {
return MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("MD5 算法不可用", e);
}
});
/**
* 計算字串的 MD5 值 (UTF-8 編碼)
*/
public static String encode(String input) {
if (input == null) return "";
return encode(input.getBytes(java.nio.charset.StandardCharsets.UTF_8));
}
/**
* 計算位元組陣列的 MD5 值
*/
public static String encode(byte[] data) {
MessageDigest digest = MD5_DIGEST.get();
digest.reset(); // 重置狀態,確保線程安全
byte[] hashBytes = digest.digest(data);
return bytesToHex(hashBytes);
}
/**
* 位元組陣列轉十六進制字串 (大寫)
*/
private static String bytesToHex(byte[] bytes) {
char[] result = new char[bytes.length * 2];
for (int i = 0; i < bytes.length; i++) {
int v = bytes[i] & 0xFF;
result[i * 2] = HEX_CHARS[v >>> 4];
result[i * 2 + 1] = HEX_CHARS[v & 0x0F];
}
return new String(result);
}
// 測試主方法
public static void main(String[] args) {
String test = "my name is zhangli";
System.out.println("原文: " + test);
System.out.println("MD5: " + encode(test));
// 輸出範例: 7A3F... (32位大寫十六進制)
}
}
| 設計點 | 說明 |
|---|---|
| ThreadLocal 包裝 MessageDigest | MessageDigest 非線程安全,使用 ThreadLocal 讓每個執行緒擁有獨立實例,避免同步開銷。 |
| digest.reset() | 每次計算前重置內部狀態,防止上次殘留數據影響結果。 |
| 位運算轉十六進制 | 使用 & 0xFF 取無符號值,>> 4 取高 4 位,& 0x0F 取低 4 位,效率高於取模運算。 |
| 指定 UTF-8 編碼 | 避免平台預設編碼導致跨平台結果不一致。 |
PBKDF2WithHmacSHA256) 等慢速雜湊算法,並加入隨機鹽值。<dependency>
<groupId>org.mindrot</groupId>
<artifactId>jbcrypt</artifactId>
<version>0.4</version>
</dependency>
public class PasswordUtil {
// 加密 (自動生成鹽值,成本因子 12)
public static String hash(String plain) {
return BCrypt.hashpw(plain, BCrypt.gensalt(12));
}
// 驗證
public static boolean check(String plain, String hashed) {
return BCrypt.checkpw(plain, hashed);
}
}
MD5 作為輕量級雜湊工具在非安全關鍵路徑仍有價值,但務必認清其安全邊界。本文提供的 MD5Util 採用 ThreadLocal 實現高效線程安全,適合高併發場景下的檔案校驗、緩存鍵生成等用途。涉及用戶認證時,請堅定選擇 BCrypt 等專業慢速雜湊方案。