天天看點

基于Java實作的MD5算法

(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

小端法和大端法差別如下圖:

基于Java實作的MD5算法

第四步、四輪循環運算

1.把消息分以12位一分組進行處理

2.每一個分組進行4輪變換,以上面所說4個标準的幻數為起始變量進行計算,重新輸出4個變量

3.以這4個變量再進行下一分組的運算,如果已經是最後一個分組,則這4個變量為最後的結果,即MD5值

基于Java實作的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);  

    }  
  
}  
           

繼續閱讀