(1)MD5原理
MD5以512位分組來處理輸入的資訊,且每一分組又被劃分為16個32位子分組,經過了一系列的處理後,算法的輸出由四個32位分組組成,将這四個32位分組級聯後将生成一個128位散列值。
第一步、填充
如果輸入資訊的長度(bit)對512求餘的結果不等于448,就需要填充使得對512求餘的結果等于448。填充的方法是填充一個1和n個0。填充完後,資訊的長度就為N*512+448(bit);
第二步、記錄資訊長度
用64位來存儲填充前資訊長度。這64位加在第一步結果的後面,這樣資訊長度就變為N*512+448+64=(N+1)*512位。
第三步、裝入标準的幻數(四個整數)
标準的幻數(實體順序)是(A=(01234567)16,B=(89ABCDEF)16,C=(FEDCBA98)16,D=(76543210)16)。如果在程式中定義應該是(A=0X67452301L,B=0XEFCDAB89L,C=0X98BADCFEL,D=0X10325476L)。有點暈哈,其實想一想就明白了。
首先清楚整型的位表示方法,其次标準文檔上要求的是:四個幻數在記憶體位址上從低到高為:
A: 01 23 45 67
B: 89 ab cd ef
C: fe dc ba 98
D: 76 54 32 10
采用小端表示法表示為A=0X67452301L,則在位址中就是A=01 23 45 67
小端法和大端法差別如下圖:
第四步、四輪循環運算
1.把消息分以12位一分組進行處理
2.每一個分組進行4輪變換,以上面所說4個标準的幻數為起始變量進行計算,重新輸出4個變量
3.以這4個變量再進行下一分組的運算,如果已經是最後一個分組,則這4個變量為最後的結果,即MD5值
循環的次數是分組的個數(N+1)
(1)将每一512位元組細分成16個小組,每個小組64位(8個位元組)
(2)先認識四個線性函數(&是與,|是或,~是非,^是異或)
F(X,Y,Z)=(X&Y)|((~X)&Z)
G(X,Y,Z)=(X&Z)|(Y&(~Z))
H(X,Y,Z)=XYZ
I(X,Y,Z)=Y^(X|(~Z))
(3)設Mj表示消息的第j個子分組(從0到15),<<< s表示循環左移s位,則四種操作為:
FF(a,b,c,d,Mj,s,ti)表示a=b+((a+F(b,c,d)+Mj+ti)<<<s)
GG(a,b,c,d,Mj,s,ti)表示a=b+((a+G(b,c,d)+Mj+ti)<<<s)
HH(a,b,c,d,Mj,s,ti)表示a=b+((a+H(b,c,d)+Mj+ti)<<<s)
II(a,b,c,d,Mj,s,ti)表示a=b+((a+I(b,c,d)+Mj+ti)<<<s)
(4)四輪運算
第一輪
a=FF(a,b,c,d,M0,7,0xd76aa478)
b=FF(d,a,b,c,M1,12,0xe8c7b756)
c=FF(c,d,a,b,M2,17,0x242070db)
d=FF(b,c,d,a,M3,22,0xc1bdceee)
a=FF(a,b,c,d,M4,7,0xf57c0faf)
b=FF(d,a,b,c,M5,12,0x4787c62a)
c=FF(c,d,a,b,M6,17,0xa8304613)
d=FF(b,c,d,a,M7,22,0xfd469501)
a=FF(a,b,c,d,M8,7,0x698098d8)
b=FF(d,a,b,c,M9,12,0x8b44f7af)
c=FF(c,d,a,b,M10,17,0xffff5bb1)
d=FF(b,c,d,a,M11,22,0x895cd7be)
a=FF(a,b,c,d,M12,7,0x6b901122)
b=FF(d,a,b,c,M13,12,0xfd987193)
c=FF(c,d,a,b,M14,17,0xa679438e)
d=FF(b,c,d,a,M15,22,0x49b40821)
第二輪
a=GG(a,b,c,d,M1,5,0xf61e2562)
b=GG(d,a,b,c,M6,9,0xc040b340)
c=GG(c,d,a,b,M11,14,0x265e5a51)
d=GG(b,c,d,a,M0,20,0xe9b6c7aa)
a=GG(a,b,c,d,M5,5,0xd62f105d)
b=GG(d,a,b,c,M10,9,0x02441453)
c=GG(c,d,a,b,M15,14,0xd8a1e681)
d=GG(b,c,d,a,M4,20,0xe7d3fbc8)
a=GG(a,b,c,d,M9,5,0x21e1cde6)
b=GG(d,a,b,c,M14,9,0xc33707d6)
c=GG(c,d,a,b,M3,14,0xf4d50d87)
d=GG(b,c,d,a,M8,20,0x455a14ed)
a=GG(a,b,c,d,M13,5,0xa9e3e905)
b=GG(d,a,b,c,M2,9,0xfcefa3f8)
c=GG(c,d,a,b,M7,14,0x676f02d9)
d=GG(b,c,d,a,M12,20,0x8d2a4c8a)
第三輪
a=HH(a,b,c,d,M5,4,0xfffa3942)
b=HH(d,a,b,c,M8,11,0x8771f681)
c=HH(c,d,a,b,M11,16,0x6d9d6122)
d=HH(b,c,d,a,M14,23,0xfde5380c)
a=HH(a,b,c,d,M1,4,0xa4beea44)
b=HH(d,a,b,c,M4,11,0x4bdecfa9)
c=HH(c,d,a,b,M7,16,0xf6bb4b60)
d=HH(b,c,d,a,M10,23,0xbebfbc70)
a=HH(a,b,c,d,M13,4,0x289b7ec6)
b=HH(d,a,b,c,M0,11,0xeaa127fa)
c=HH(c,d,a,b,M3,16,0xd4ef3085)
d=HH(b,c,d,a,M6,23,0x04881d05)
a=HH(a,b,c,d,M9,4,0xd9d4d039)
b=HH(d,a,b,c,M12,11,0xe6db99e5)
c=HH(c,d,a,b,M15,16,0x1fa27cf8)
d=HH(b,c,d,a,M2,23,0xc4ac5665)
第四輪
a=II(a,b,c,d,M0,6,0xf4292244)
b=II(d,a,b,c,M7,10,0x432aff97)
c=II(c,d,a,b,M14,15,0xab9423a7)
d=II(b,c,d,a,M5,21,0xfc93a039)
a=II(a,b,c,d,M12,6,0x655b59c3)
b=II(d,a,b,c,M3,10,0x8f0ccc92)
c=II(c,d,a,b,M10,15,0xffeff47d)
d=II(b,c,d,a,M1,21,0x85845dd1)
a=II(a,b,c,d,M8,6,0x6fa87e4f)
b=II(d,a,b,c,M15,10,0xfe2ce6e0)
c=II(c,d,a,b,M6,15,0xa3014314)
d=II(b,c,d,a,M13,21,0x4e0811a1)
a=II(a,b,c,d,M4,6,0xf7537e82)
b=II(d,a,b,c,M11,10,0xbd3af235)
c=II(c,d,a,b,M2,15,0x2ad7d2bb)
d=II(b,c,d,a,M9,21,0xeb86d391)
5)每輪循環後,将A,B,C,D分别加上a,b,c,d,然後進入下一循環。
MD5算法實作代碼:
package internetsafe;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.MessageDigest;
public class MD5 {
static char hexdigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
public static String getMD5(File file) {
FileInputStream fis = null;
try {
MessageDigest md = MessageDigest.getInstance("MD5");
fis = new FileInputStream(file);
byte[] buffer = new byte[2048];
int length = -1;
while ((length = fis.read(buffer)) != -1) {
md.update(buffer, 0, length);
}
byte[] b = md.digest();
return byteToHexString(b);
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static String byteToHexString(byte[] tmp) {
String s;
// 用位元組表示就是 16 個位元組
// 每個位元組用 16 進制表示的話,使用兩個字元,是以表示成 16 進制需要 32 個字元
// 比如一個位元組為01011011,用十六進制字元來表示就是“5b”
char str[] = new char[16 * 2];
int k = 0; // 表示轉換結果中對應的字元位置
for (int i = 0; i < 16; i++) { // 從第一個位元組開始,對 MD5 的每一個位元組轉換成 16 進制字元的轉換
byte byte0 = tmp[i]; // 取第 i 個位元組
str[k++] = hexdigits[byte0 >>> 4 & 0xf]; // 取位元組中高 4 位的數字轉換, >>> 為邏輯右移,将符号位一起右移
str[k++] = hexdigits[byte0 & 0xf]; // 取位元組中低 4 位的數字轉換
}
s = new String(str); // 換後的結果轉換為字元串
return s;
}
public static void main(String arg[]) {
String a = getMD5(new File("d:/a.txt"));
System.out.println("a.txt的摘要值為:" + a);
}
}