Java的MessageDigest 類 能夠提供MD5算法或SHA算法用於計算出信息的摘要;它接收任意大小的信息,並輸出計算後的固定長度的哈希值。這個輸出的哈希值就是咱們所說的信息摘要。java
MD5算法獲得的摘要是固定長度爲 128 bit 的二進制串(一堆0和1,一共128個),爲了更友好的表示摘要,通常都將 128位的二進制串 轉爲 32個16進制位
或 16個16進制位
以下:git
欄目1 | 欄目2 |
---|---|
原始信息 | 1234567890 |
16位小寫摘要 | f82d132f9bb018ca |
16位大寫摘要 | F82D132F9BB018CA |
32位小寫摘要 | e807f1fcf82d132f9bb018ca6738a19f |
32位大寫摘要 | E807F1FCF82D132F9BB018CA6738A19F |
MD5算法獲得的摘要固定長度爲 128 bit
也就是32個16進制位(32位摘要),那麼怎麼獲得16位的摘要呢? 其實從上面的表格中能夠看出,16位的摘要是32位摘要值的中間部分,即32位摘要中第8~24位的部分。算法
public static MesageDigest getInstance(String algorithm);
複製代碼
算法名不區分大小寫,因此下面的寫法都是正確的:數據庫
MesageDigest getInstance("MD5");
MesageDigest getInstance("md5");
MesageDigest getInstance("mD5");
複製代碼
該步驟就是調用下面的某個方法來完成信息的傳遞。數組
public void update(byte input);
public void update(byte[] input);
public void update(byte[] input, int offset, int len);
複製代碼
最後調用下面的某個方法來計算摘要。bash
public byte[] digest();
public byte[] digest(byte[] input);
public int digest(byte[] buf,int offset,int len);
複製代碼
爲了更友好的表示摘要,通常都將 128位的二進制串 轉爲 32個16進制位
或 16個16進制位
,並以字符串的形式表示。app
摘要通常以字符串的形式展現,因此在WEB應用中,用於表示密碼的MD5摘要的數據庫字段通常設置爲String password
函數
雖然字段名的字面意思表示帳戶密碼,但實際上只是帳戶密碼的MD5摘要,參考 摘要與加密的區別(以MD5算法爲例)。工具
實現MD5通用工具類的方法有不少,下面我用清晰明瞭的代碼去實現MD5Util通用工具類。post
import java.security.MessageDigest;
public class MD5Util {
private static final String hexDigits[] = {"0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
/**
* 將1個字節(1 byte = 8 bit)轉爲 2個十六進制位
* 1個16進制位 = 4個二進制位 (即4 bit)
* 轉換思路:最簡單的辦法就是先將byte轉爲10進制的int類型,而後將十進制數轉十六進制
*/
private static String byteToHexString(byte b) {
// byte類型賦值給int變量時,java會自動將byte類型轉int類型,從低位類型到高位類型自動轉換
int n = b;
// 將十進制數轉十六進制
if (n < 0)
n += 256;
int d1 = n / 16;
int d2 = n % 16;
// d1和d2經過訪問數組變量的方式轉成16進制字符串;好比 d1 爲12 ,那麼就轉爲"c"; 由於int類型不會有a,b,c,d,e,f等表示16進制的字符
return hexDigits[d1] + hexDigits[d2];
}
/**
* 將字節數組裏每一個字節轉成2個16進制位的字符串後拼接起來
*/
private static String byteArrayToHexString(byte b[]) {
StringBuffer resultSb = new StringBuffer();
for (int i = 0; i < b.length; i++){
resultSb.append(byteToHexString(b[i]));
}
return resultSb.toString();
}
/**
* MD5算法,統一返回大寫形式的摘要結果,默認固定長度是 128bit 即 32個16進制位
* String origin :須要進行MD5計算的字符串
* String charsetname :MD5算法的編碼
*/
private static String MD5_32(String origin, String charsetname) {
String resultString = null;
try {
// 1,建立MessageDigest對象
MessageDigest md = MessageDigest.getInstance("MD5");
// 2,向MessageDigest傳送信息;傳入的信息須要轉化爲指定編碼的字節數組
md.update(origin.getBytes( charsetname ));
// 3,計算摘要
byte[] bytesResult = md.digest();
// 第2步和第3步能夠合併成下面一步
// byte[] bytesResult = md.digest(origin.getBytes(charsetname));
// 4,將字節數組轉換爲16進制位
resultString = byteArrayToHexString( bytesResult );
} catch (Exception e) {
e.printStackTrace();
}
// 統一返回大寫形式的字符串摘要
return resultString.toUpperCase();
}
/**
* 獲取 16位的MD5摘要,就是截取32位結果的中間部分
*/
private static String MD5_16(String origin, String charsetname) {
return MD5_32(origin, charsetname).substring(8,24);
}
public static void main(String[] args){
String origin = "1234567890";
// 默認MD5計算獲得128 bit的摘要,即32個 16進制位
String result_32 = MD5_32(origin, "utf-8");
System.out.println(result_32); // E807F1FCF82D132F9BB018CA6738A19F
// 獲取16位的摘要
String result_16 = MD5_16(origin, "utf-8");
System.out.println(result_16); // F82D132F9BB018CA
}
}
複製代碼
在不少時候,咱們常常看到相似下面的寫法:
byte[] bytesResult = md.digest(origin.getBytes(charsetname));
複製代碼
在這種寫法中並無代碼顯式地調用update方法,但跟下面的寫法是同樣的,實際上也調用了update方法:
// 2,向MessageDigest傳送信息;傳入的信息須要轉化爲指定編碼的字節數組
md.update(origin.getBytes( charsetname ));
// 3,計算摘要
byte[] bytesResult = md.digest();
複製代碼
查看該digest(byte[] input)
方法的源碼,能夠看到該方法其實就是將第2步和第3步封裝成一個函數而已。
public byte[] digest(byte[] input) {
update(input);
return digest();
}
複製代碼