Java實(shí)現(xiàn)MD5加密的四種方式
MD5介紹
MD5(Message-Digest Algorithm 5)是一種廣泛使用的哈希算法,其輸出結(jié)果是一個(gè)128位的二進(jìn)制數(shù),通常以32位十六進(jìn)制數(shù)的形式表示。因此,MD5的輸出結(jié)果可以表示為一個(gè)32位的字符串。
MD5算法常用于數(shù)據(jù)完整性驗(yàn)證、密碼加密等場(chǎng)景,通常將輸入的數(shù)據(jù)經(jīng)過(guò)MD5處理后,得到一個(gè)32位的摘要(digest),該摘要作為數(shù)據(jù)的唯一表示,可以用于驗(yàn)證數(shù)據(jù)的完整性或作為密碼的加密存儲(chǔ)。需要注意的是,由于MD5算法本身存在安全性問(wèn)題,已經(jīng)不再推薦用于密碼加密等安全場(chǎng)景,而應(yīng)該使用更加安全的算法,如SHA-2、bcrypt等。
MD5(Message Digest Algorithm 5)是一種哈希函數(shù),而不是對(duì)稱加密算法。MD5 用于產(chǎn)生一個(gè)稱為消息摘要(Message Digest)的固定大小的哈希值,通常是 128 位。MD5 不是加密算法,因?yàn)楣V凳遣豢赡娴?,即無(wú)法從哈希值還原出原始數(shù)據(jù)。
對(duì)稱加密算法是一種使用相同密鑰進(jìn)行加密和解密的算法,例如 DES(Data Encryption Standard)、AES(Advanced Encryption Standard)等。與對(duì)稱加密不同,哈希函數(shù)通常是單向的,只能從原始數(shù)據(jù)計(jì)算出哈希值,而無(wú)法從哈希值還原出原始數(shù)據(jù)。
安全性:MD5 已經(jīng)被認(rèn)為不再安全,因?yàn)樗菀资艿脚鲎补?。?duì)于需要安全性的應(yīng)用(如密碼存儲(chǔ)),建議使用更強(qiáng)的散列算法(如 SHA-256)和適當(dāng)?shù)陌踩珜?shí)踐(如加鹽)。
性能:雖然 MD5 在性能上表現(xiàn)良好,但現(xiàn)代安全需求通常需要更強(qiáng)的散列算法。
MD5(Message Digest Algorithm 5)是一種廣泛使用的加密散列函數(shù),主要用于生成數(shù)據(jù)的唯一摘要值(哈希值)。MD5 的底層實(shí)現(xiàn)涉及多個(gè)復(fù)雜的步驟和算法。以下是 MD5 的底層工作原理和關(guān)鍵概念:
- 基本概念
散列函數(shù):MD5 是一種散列函數(shù),用于將任意長(zhǎng)度的輸入數(shù)據(jù)(消息)映射為固定長(zhǎng)度的輸出(128 位,或 16 字節(jié))的哈希值。
不可逆性:MD5 生成的哈希值理論上無(wú)法逆推出原始輸入數(shù)據(jù)。
固定長(zhǎng)度:無(wú)論輸入數(shù)據(jù)的長(zhǎng)度如何,MD5 總是生成一個(gè) 128 位的哈希值。 - MD5 的步驟
MD5 的底層算法包括以下主要步驟: - 初始化
MD5 使用四個(gè) 32 位的初始常量(A、B、C、D)作為計(jì)算的起始值:
( A = 0x67452301 )
( B = 0xEFCDAB89 )
( C = 0x98BADCFE )
( D = 0x10325476 )
這些常量用于初始化 MD5 的內(nèi)部狀態(tài)。 - 填充
將輸入數(shù)據(jù)填充到 512 位的倍數(shù)。填充過(guò)程包括:
填充位:在輸入數(shù)據(jù)的末尾添加一個(gè) 1 位的標(biāo)志位,表示數(shù)據(jù)結(jié)束。
填充零:在標(biāo)志位后添加零,直到數(shù)據(jù)長(zhǎng)度接近 512 位。
附加長(zhǎng)度:在數(shù)據(jù)末尾附加原始數(shù)據(jù)的長(zhǎng)度(以位為單位),以 64 位表示。填充后的數(shù)據(jù)總長(zhǎng)度為 512 位的倍數(shù)。 - 數(shù)據(jù)分塊
將填充后的數(shù)據(jù)分成 512 位的塊,每個(gè)塊被進(jìn)一步分成 16 個(gè) 32 位的子塊(總共 64 個(gè)字節(jié))。 - 處理每個(gè)數(shù)據(jù)塊
對(duì)于每個(gè) 512 位的數(shù)據(jù)塊,執(zhí)行以下步驟:
擴(kuò)展:將 16 個(gè) 32 位子塊擴(kuò)展為 64 個(gè) 32 位的子塊,使用非線性函數(shù)進(jìn)行處理。
輪次:MD5 使用 64 輪的運(yùn)算,每一輪使用不同的非線性函數(shù)(F、G、H、I)和常量(T[i])。每輪的運(yùn)算包括:
非線性函數(shù):F(x, y, z)、G(x, y, z)、H(x, y, z)、I(x, y, z)
常量:T[i] 是一組預(yù)定義的常量,與輸入數(shù)據(jù)和輪次相關(guān)。
位運(yùn)算:使用位移和按位與、或、異或等運(yùn)算來(lái)更新內(nèi)部狀態(tài)(A、B、C、D)。
數(shù)據(jù)混合:將數(shù)據(jù)塊與當(dāng)前的內(nèi)部狀態(tài)進(jìn)行混合。 - 輸出
將最后一個(gè)數(shù)據(jù)塊的處理結(jié)果(A、B、C、D)連接起來(lái),生成 128 位(16 字節(jié))的哈希值。 - MD5 算法的詳細(xì)步驟
填充:
在原始消息末尾添加 1 位的 1。
添加足夠的 0,使得消息長(zhǎng)度(包括填充的部分)為 448 位(512 位的前 448 位),即還需填充 0 到 64 位數(shù)據(jù)塊的長(zhǎng)度。
添加 64 位的消息長(zhǎng)度,作為填充的最后部分,確保最終消息長(zhǎng)度為 512 位的倍數(shù)。
初始化變量:
初始化 A、B、C、D 為常量值。
處理數(shù)據(jù)塊:
將每個(gè)數(shù)據(jù)塊分成 16 個(gè) 32 位的子塊,使用特定的非線性函數(shù)和常量進(jìn)行處理。
進(jìn)行 64 輪的運(yùn)算,更新 A、B、C、D 的值。
輸出結(jié)果:
將 A、B、C、D 的最終值轉(zhuǎn)換為 128 位的哈希值,通常以 16 進(jìn)制表示。 - MD5 的應(yīng)用
數(shù)據(jù)完整性檢查:通過(guò)比較文件的 MD5 哈希值,可以檢測(cè)文件是否被篡改。
密碼存儲(chǔ):在數(shù)據(jù)庫(kù)中存儲(chǔ)密碼的 MD5 哈希值,而不是明文密碼(注意:不建議僅使用 MD5 存儲(chǔ)密碼,因?yàn)樗驯蛔C明不夠安全)。 - 安全性
雖然 MD5 曾被廣泛使用,但由于其安全性問(wèn)題,如碰撞攻擊(即不同的輸入可以產(chǎn)生相同的哈希值),它已不再被認(rèn)為是安全的。對(duì)于需要更高安全性的應(yīng)用,建議使用更強(qiáng)的哈希函數(shù),如 SHA-256 或 SHA-3。
總結(jié)
MD5 是一種將輸入數(shù)據(jù)映射到固定長(zhǎng)度哈希值的散列函數(shù)。其底層實(shí)現(xiàn)包括數(shù)據(jù)填充、分塊、處理和最終輸出四個(gè)主要步驟。盡管 MD5 在許多應(yīng)用中曾被廣泛使用,但由于安全性問(wèn)題,現(xiàn)如今建議使用更安全的哈希算法。
Java 中實(shí)現(xiàn) MD5 加密方式
這三種方法都能有效地生成 MD5 哈希。選擇適合你項(xiàng)目需求的方式,如果已經(jīng)使用了 Apache Commons Codec 或 Guava,可以直接利用它們的功能;如果只是簡(jiǎn)單的 MD5 加密需求,使用 MessageDigest 是最直接的方法。
在 Java 中實(shí)現(xiàn) MD5 加密可以通過(guò)多種方式。
方法一:使用 MessageDigest
這是最基本的方式,使用 Java 內(nèi)置的 MessageDigest 類。
示例代碼:
import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class MD5UsingMessageDigest { public static String md5(String input) { try { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] messageDigest = md.digest(input.getBytes()); StringBuilder hexString = new StringBuilder(); for (byte b : messageDigest) { String hex = Integer.toHexString(0xff & b); if (hex.length() == 1) { hexString.append('0'); } hexString.append(hex); } return hexString.toString(); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } } public static void main(String[] args) { String input = "Hello, World!"; System.out.println("MD5 Hash: " + md5(input)); } }
方法二:使用 Apache Commons Codec
Apache Commons Codec 是一個(gè)流行的庫(kù),提供了便捷的工具類進(jìn)行編碼和解碼。
示例代碼:
首先,確保在項(xiàng)目中添加 Apache Commons Codec 的依賴:
<dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.15</version> <!-- 檢查最新版本 --> </dependency>
然后可以使用以下代碼:
import org.apache.commons.codec.digest.DigestUtils; public class MD5UsingCommonsCodec { public static void main(String[] args) { String input = "Hello, World!"; String md5Hash = DigestUtils.md5Hex(input); System.out.println("MD5 Hash: " + md5Hash); } }
方法三:使用 Guava
Google 的 Guava 庫(kù)也提供了簡(jiǎn)單的 MD5 加密功能。
示例代碼:
首先,確保在項(xiàng)目中添加 Guava 的依賴:
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>31.0.1-jre</version> <!-- 檢查最新版本 --> </dependency>
然后可以使用以下代碼:
import com.google.common.hash.Hashing; import java.nio.charset.StandardCharsets; public class MD5UsingGuava { public static void main(String[] args) { String input = "Hello, World!"; String md5Hash = Hashing.md5() .hashString(input, StandardCharsets.UTF_8) .toString(); System.out.println("MD5 Hash: " + md5Hash); } }
方法四:SPRING核心包
import org.springframework.util.DigestUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class HashController { @GetMapping("/md5") public String getMD5(@RequestParam String input) { return DigestUtils.md5DigestAsHex(input.getBytes()); } }
MD5Util
package com.maxvision.common.util; import lombok.extern.slf4j.Slf4j; import java.security.MessageDigest; @Slf4j public class MD5Util { private static String byteArrayToHexString(byte[] b) { StringBuilder resultSb = new StringBuilder(); for (byte value : b) { resultSb.append(byteToHexString(value)); } return resultSb.toString(); } private static String byteToHexString(byte b) { int n = b; if (n < 0) { n += 256; } int d1 = n / 16; int d2 = n % 16; return HEX_DIGITS[d1] + HEX_DIGITS[d2]; } /** * 用UTF8編碼進(jìn)行MD5加密 * * @param origin 原字符串 * @return 加密后字符串 */ public static String md5Encode(String origin) { return md5Encode(origin, "UTF-8"); } public static String md5Encode(String origin, String charsetname) { String resultString = null; try { resultString = origin; MessageDigest md = MessageDigest.getInstance("MD5"); if (charsetname == null || "".equals(charsetname)) { resultString = byteArrayToHexString(md.digest(resultString.getBytes())); } else { resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname))); } } catch (Exception ignored) { } return resultString; } private static final String[] HEX_DIGITS = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"}; }
以上就是Java實(shí)現(xiàn)MD5加密的四種方式的詳細(xì)內(nèi)容,更多關(guān)于Java MD5加密的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Swagger2不被SpringSecurity框架攔截的配置及說(shuō)明
這篇文章主要介紹了Swagger2不被SpringSecurity框架攔截的配置及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03springboot掃描自定義的servlet和filter代碼詳解
本文是一篇根據(jù)作者工作經(jīng)歷總結(jié)出來(lái)的關(guān)于springboot掃描自定義的servlet和filter代碼詳解的文章,小編覺(jué)得非常不錯(cuò),這里給大家分享下,和朋友們一起學(xué)習(xí),進(jìn)步。2017-10-10SpringMVC使用@PathVariable接收參數(shù)過(guò)程解析
這篇文章主要介紹了SpringMVC使用@PathVariable接收參數(shù)過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10TraceIdPatternLogbackLayout日志攔截源碼解析
這篇文章主要為大家介紹了TraceIdPatternLogbackLayout日志攔截源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11詳解Spring 基于 Aspect 注解的增強(qiáng)實(shí)現(xiàn)
本篇文章主要介紹了詳解Spring 基于 Aspect 注解的增強(qiáng)實(shí)現(xiàn),非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-04-04groovy腳本定義結(jié)構(gòu)表一鍵生成POJO類
這篇文章主要為大家介紹了groovy腳本定義結(jié)構(gòu)表一鍵生成POJO類示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03