1. 程式人生 > >java實現md5加密

java實現md5加密

comm 代碼 inf 應用領域 ast center href 攻擊 字符串

java實現md5加密

MD5的全稱是Message-Digest Algorithm 5(信息-摘要算法),在90年代初由MIT Laboratory for Computer Science和RSA Data Security Inc的Ronald L. Rivest開發出來,經MD2、MD3和MD4發展而來。

一.使用md5加密密碼

我們先用java去實現md5加密密碼,再去研究一下md5的原理以及他的優缺點。

1.新建MD5.java文件

package com.creditease.bixin.common.util;

import sun.misc.BASE64Encoder;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * Created by hengyang4 on 2018/6/15.
 */
public class MD5 {

    /*
    * 使用md5進行加密
    *
    * 
*/ public String EncodeByMd5(String str) throws NoSuchAlgorithmException,UnsupportedEncodingException{ //確定計算方法 MessageDigest md5 = MessageDigest.getInstance("MD5"); BASE64Encoder base64Encoder = new BASE64Encoder(); //加密後的字符串 String newstr = base64Encoder.encode(md5.digest(str.getBytes("utf-8")));
return newstr; } /** * 判斷用戶密碼是否正確 * 用戶輸入的密碼 @param newpwd * 數據庫中保存的密碼 @param oldpwd * * **/ public boolean checkPassword(String newpwd,String oldpwd) throws NoSuchAlgorithmException,UnsupportedEncodingException{ if(EncodeByMd5(newpwd).equals(oldpwd)) return true; else return false; } }

2.新建測試類測試該代碼

package com.creditease.bixin.common.util;

import com.creditease.bixin.Application;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;

/**
 * Created by hengyang4 on 2018/6/15.
 */
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
public class MD5Test {

    @Test
    public void md5Test()throws Exception{
        String str = "dog";
        try {
            MD5 md5 = new MD5();
            String newstr = md5.EncodeByMd5(str);
            System.out.println(newstr);
            System.out.println(md5.checkPassword("dog",newstr));
        }catch (NoSuchAlgorithmException e){
            e.printStackTrace();
        } catch (UnsupportedEncodingException e){
            e.printStackTrace();
        }
    }

}

 運行結果:

技術分享圖片

使用的時候發現md5使用起來很簡單也很便利,那麽md5原理是什麽呢

二.md5原理

對MD5算法簡要的敘述可以為:MD5以512位分組來處理輸入的信息,且每一分組又被劃分為16個32位子分組,經過了一系列的處理後,算法的輸出由四個32位分組組成,將這四個32位分組級聯後將生成一個128位散列值。 總體流程如下圖所示, 技術分享圖片 表示第i個分組,每次的運算都由前一輪的128位結果值和第i塊512bit值進行運算。 技術分享圖片MD5算法的整體流程圖 [1] 1.填充 在MD5算法中,首先需要對信息進行填充,使其位長對512求余的結果等於448,並且填充必須進行,即使其位長對512求余的結果等於448。因此,信息的位長(Bits Length)將被擴展至N*512+448,N為一個非負整數,N可以是零。 填充的方法如下: 1) 在信息的後面填充一個1和無數個0,直到滿足上面的條件時才停止用0對信息的填充。 2) 在這個結果後面附加一個以64位二進制表示的填充前信息長度(單位為Bit),如果二 進制表示的填充前信息長度超過64位,則取低64位。 經過這兩步的處理,信息的位長=N*512+448+64=(N+1)*512,即長度恰好是512的整數倍。這樣做的原因是為滿足後面處理中對信息長度的要求。 2. 初始化變量 初始的128位值為初試鏈接變量,這些參數用於第一輪的運算,以大端字節序來表示,他們分別為: A=0x01234567,B=0x89ABCDEF,C=0xFEDCBA98,D=0x76543210。 (每一個變量給出的數值是高字節存於內存低地址,低字節存於內存高地址,即大端字節序。在程序中變量A、B、C、D的值分別為0x67452301,0xEFCDAB89,0x98BADCFE,0x10325476) 3. 處理分組數據 每一分組的算法流程如下: 第一分組需要將上面四個鏈接變量復制到另外四個變量中:A到a,B到b,C到c,D到d。從第二分組開始的變量為上一分組的運算結果,即A = a, B = b, C = c, D = d。 主循環有四輪(MD4只有三輪),每輪循環都很相似。第一輪進行16次操作。每次操作對a、b、c和d中的其中三個作一次非線性函數運算,然後將所得結果加上第四個變量,文本的一個子分組和一個常數。再將所得結果向左環移一個不定的數,並加上a、b、c或d中之一。最後用該結果取代a、b、c或d中之一。 以下是每次操作中用到的四個非線性函數(每輪一個)。 F( X ,Y ,Z ) = ( X & Y ) | ( (~X) & Z ) G( X ,Y ,Z ) = ( X & Z ) | ( Y & (~Z) ) H( X ,Y ,Z ) =X ^ Y ^ Z I( X ,Y ,Z ) =Y ^ ( X | (~Z) ) (&是與(And),|是或(Or),~是非(Not),^是異或(Xor)) 這四個函數的說明:如果X、Y和Z的對應位是獨立和均勻的,那麽結果的每一位也應是獨立和均勻的。 F是一個逐位運算的函數。即,如果X,那麽Y,否則Z。函數H是逐位奇偶操作符。 假設Mj表示消息的第j個子分組(從0到15),常數ti是4294967296*abs( sin(i) )的整數部分,i 取值從1到64,單位是弧度。(4294967296=232) 現定義: 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) 註意:“<<”表示循環左移位,不是左移位。 這四輪(共64步)是: 第一輪
FF(a ,b ,c ,d ,M0 ,7 ,0xd76aa478 )
FF(d ,a ,b ,c ,M1 ,12 ,0xe8c7b756 )
FF(c ,d ,a ,b ,M2 ,17 ,0x242070db )
FF(b ,c ,d ,a ,M3 ,22 ,0xc1bdceee )
FF(a ,b ,c ,d ,M4 ,7 ,0xf57c0faf )
FF(d ,a ,b ,c ,M5 ,12 ,0x4787c62a )
FF(c ,d ,a ,b ,M6 ,17 ,0xa8304613 )
FF(b ,c ,d ,a ,M7 ,22 ,0xfd469501)
FF(a ,b ,c ,d ,M8 ,7 ,0x698098d8 )
FF(d ,a ,b ,c ,M9 ,12 ,0x8b44f7af )
FF(c ,d ,a ,b ,M10 ,17 ,0xffff5bb1 )
FF(b ,c ,d ,a ,M11 ,22 ,0x895cd7be )
FF(a ,b ,c ,d ,M12 ,7 ,0x6b901122 )
FF(d ,a ,b ,c ,M13 ,12 ,0xfd987193 )
FF(c ,d ,a ,b ,M14 ,17 ,0xa679438e )
FF(b ,c ,d ,a ,M15 ,22 ,0x49b40821 )

第二輪
GG(a ,b ,c ,d ,M1 ,5 ,0xf61e2562 )
GG(d ,a ,b ,c ,M6 ,9 ,0xc040b340 )
GG(c ,d ,a ,b ,M11 ,14 ,0x265e5a51 )
GG(b ,c ,d ,a ,M0 ,20 ,0xe9b6c7aa )
GG(a ,b ,c ,d ,M5 ,5 ,0xd62f105d )
GG(d ,a ,b ,c ,M10 ,9 ,0x02441453 )
GG(c ,d ,a ,b ,M15 ,14 ,0xd8a1e681 )
GG(b ,c ,d ,a ,M4 ,20 ,0xe7d3fbc8 )
GG(a ,b ,c ,d ,M9 ,5 ,0x21e1cde6 )
GG(d ,a ,b ,c ,M14 ,9 ,0xc33707d6 )
GG(c ,d ,a ,b ,M3 ,14 ,0xf4d50d87 )
GG(b ,c ,d ,a ,M8 ,20 ,0x455a14ed )
GG(a ,b ,c ,d ,M13 ,5 ,0xa9e3e905 )
GG(d ,a ,b ,c ,M2 ,9 ,0xfcefa3f8 )
GG(c ,d ,a ,b ,M7 ,14 ,0x676f02d9 )
GG(b ,c ,d ,a ,M12 ,20 ,0x8d2a4c8a )

第三輪
HH(a ,b ,c ,d ,M5 ,4 ,0xfffa3942 )
HH(d ,a ,b ,c ,M8 ,11 ,0x8771f681 )
HH(c ,d ,a ,b ,M11 ,16 ,0x6d9d6122 )
HH(b ,c ,d ,a ,M14 ,23 ,0xfde5380c )
HH(a ,b ,c ,d ,M1 ,4 ,0xa4beea44 )
HH(d ,a ,b ,c ,M4 ,11 ,0x4bdecfa9 )
HH(c ,d ,a ,b ,M7 ,16 ,0xf6bb4b60 )
HH(b ,c ,d ,a ,M10 ,23 ,0xbebfbc70 )
HH(a ,b ,c ,d ,M13 ,4 ,0x289b7ec6 )
HH(d ,a ,b ,c ,M0 ,11 ,0xeaa127fa )
HH(c ,d ,a ,b ,M3 ,16 ,0xd4ef3085 )
HH(b ,c ,d ,a ,M6 ,23 ,0x04881d05 )
HH(a ,b ,c ,d ,M9 ,4 ,0xd9d4d039 )
HH(d ,a ,b ,c ,M12 ,11 ,0xe6db99e5 )
HH(c ,d ,a ,b ,M15 ,16 ,0x1fa27cf8 )
HH(b ,c ,d ,a ,M2 ,23 ,0xc4ac5665 )

第四輪
II(a ,b ,c ,d ,M0 ,6 ,0xf4292244 )
II(d ,a ,b ,c ,M7 ,10 ,0x432aff97 )
II(c ,d ,a ,b ,M14 ,15 ,0xab9423a7 )
II(b ,c ,d ,a ,M5 ,21 ,0xfc93a039 )
II(a ,b ,c ,d ,M12 ,6 ,0x655b59c3 )
II(d ,a ,b ,c ,M3 ,10 ,0x8f0ccc92 )
II(c ,d ,a ,b ,M10 ,15 ,0xffeff47d )
II(b ,c ,d ,a ,M1 ,21 ,0x85845dd1 )
II(a ,b ,c ,d ,M8 ,6 ,0x6fa87e4f )
II(d ,a ,b ,c ,M15 ,10 ,0xfe2ce6e0 )
II(c ,d ,a ,b ,M6 ,15 ,0xa3014314 )
II(b ,c ,d ,a ,M13 ,21 ,0x4e0811a1 )
II(a ,b ,c ,d ,M4 ,6 ,0xf7537e82 )
II(d ,a ,b ,c ,M11 ,10 ,0xbd3af235 )
II(c ,d ,a ,b ,M2 ,15 ,0x2ad7d2bb )
II(b ,c ,d ,a ,M9 ,21 ,0xeb86d391 )

所有這些完成之後,將a、b、c、d分別在原來基礎上再加上A、B、C、D。 即a = a + A,b = b + B,c = c + C,d = d + D 然後用下一分組數據繼續運行以上算法。 4. 輸出 最後的輸出是a、b、c和d的級聯。 當你按照我上面所說的方法實現MD5算法以後,你可以用以下幾個信息對你做出來的程序作一個簡單的測試,看看程序有沒有錯誤。
MD5 ("") = d41d8cd98f00b204e9800998ecf8427e
MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661
MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72
MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0
MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b
MD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz") =
f29939a25efabaef3b87e2cbfe641315
MD5 ("8a683566bcc7801226b3d8b0cf35fd97") =cf2cb5c89c5e5eeebef4a76becddfcfd

三.JAVA實現md5原理

public class MD5{
    /*
    *四個鏈接變量
    */
    private final int A=0x67452301;
    private final int B=0xefcdab89;
    private final int C=0x98badcfe;
    private final int D=0x10325476;
    /*
    *ABCD的臨時變量
    */
    private int Atemp,Btemp,Ctemp,Dtemp;
     
    /*
    *常量ti
    *公式:floor(abs(sin(i+1))×(2pow32)
    */
    private final int K[]={
        0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee,
        0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501,0x698098d8,
        0x8b44f7af,0xffff5bb1,0x895cd7be,0x6b901122,0xfd987193,
        0xa679438e,0x49b40821,0xf61e2562,0xc040b340,0x265e5a51,
        0xe9b6c7aa,0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8,
        0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed,0xa9e3e905,
        0xfcefa3f8,0x676f02d9,0x8d2a4c8a,0xfffa3942,0x8771f681,
        0x6d9d6122,0xfde5380c,0xa4beea44,0x4bdecfa9,0xf6bb4b60,
        0xbebfbc70,0x289b7ec6,0xeaa127fa,0xd4ef3085,0x04881d05,
        0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665,0xf4292244,
        0x432aff97,0xab9423a7,0xfc93a039,0x655b59c3,0x8f0ccc92,
        0xffeff47d,0x85845dd1,0x6fa87e4f,0xfe2ce6e0,0xa3014314,
        0x4e0811a1,0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391};
    /*
    *向左位移數,計算方法未知
    */
    private final int s[]={7,12,17,22,7,12,17,22,7,12,17,22,7,
        12,17,22,5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,
        4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,6,10,
        15,21,6,10,15,21,6,10,15,21,6,10,15,21};
     
     
    /*
    *初始化函數
    */
    private void init(){
        Atemp=A;
        Btemp=B;
        Ctemp=C;
        Dtemp=D;
    }
    /*
    *移動一定位數
    */
    private    int    shift(int a,int s){
        return(a<<s)|(a>>>(32-s));//右移的時候,高位一定要補零,而不是補充符號位
    }
    /*
    *主循環
    */
    private void MainLoop(int M[]){
        int F,g;
        int a=Atemp;
        int b=Btemp;
        int c=Ctemp;
        int d=Dtemp;
        for(int i = 0; i < 64; i ++){
            if(i<16){
                F=(b&c)|((~b)&d);
                g=i;
            }else if(i<32){
                F=(d&b)|((~d)&c);
                g=(5*i+1)%16;
            }else if(i<48){
                F=b^c^d;
                g=(3*i+5)%16;
            }else{
                F=c^(b|(~d));
                g=(7*i)%16;
            }
            int tmp=d;
            d=c;
            c=b;
            b=b+shift(a+F+K[i]+M[g],s[i]);
            a=tmp;
        }
        Atemp=a+Atemp;
        Btemp=b+Btemp;
        Ctemp=c+Ctemp;
        Dtemp=d+Dtemp;
     
    }
    /*
    *填充函數
    *處理後應滿足bits≡448(mod512),字節就是bytes≡56(mode64)
    *填充方式為先加一個0,其它位補零
    *最後加上64位的原來長度
    */
    private int[] add(String str){
        int num=((str.length()+8)/64)+1;//以512位,64個字節為一組
        int strByte[]=new int[num*16];//64/4=16,所以有16個整數
        for(int i=0;i<num*16;i++){//全部初始化0
            strByte[i]=0;
        }
        int    i;
        for(i=0;i<str.length();i++){
            strByte[i>>2]|=str.charAt(i)<<((i%4)*8);//一個整數存儲四個字節,小端序
        }
        strByte[i>>2]|=0x80<<((i%4)*8);//尾部添加1
        /*
        *添加原長度,長度指位的長度,所以要乘8,然後是小端序,所以放在倒數第二個,這裏長度只用了32位
        */
        strByte[num*16-2]=str.length()*8;
            return strByte;
    }
    /*
    *調用函數
    */
    public String getMD5(String source){
        init();
        int strByte[]=add(source);
        for(int i=0;i<strByte.length/16;i++){
        int num[]=new int[16];
        for(int j=0;j<16;j++){
            num[j]=strByte[i*16+j];
        }
        MainLoop(num);
        }
        return changeHex(Atemp)+changeHex(Btemp)+changeHex(Ctemp)+changeHex(Dtemp);
     
    }
    /*
    *整數變成16進制字符串
    */
    private String changeHex(int a){
        String str="";
        for(int i=0;i<4;i++){
            str+=String.format("%2s", Integer.toHexString(((a>>i*8)%(1<<8))&0xff)).replace(‘ ‘, ‘0‘);
 
        }
        return str;
    }
    /*
    *單例
    */
    private static MD5 instance;
    public static MD5 getInstance(){
        if(instance==null){
            instance=new MD5();
        }
        return instance;
    }
     
    private MD5(){};
     
    public static void main(String[] args){
        String str=MD5.getInstance().getMD5("");
        System.out.println(str);
    }
}

四.MD5優勢與不足

MD5優勢 Van oorschot和Wiener曾經考慮過一個在散列中暴力搜尋沖突的函數(brute-force hash function),而且他們猜測一個被設計專門用來搜索MD5沖突的機器(這臺機器在1994年的制造成本大約是一百萬美元)可以平均每24天就找到一個沖突。但單從1991年到2001年這10年間,竟沒有出現替代MD5算法的MD6或被叫做其他什麽名字的新算法這一點,我們就可以看出這個瑕疵並沒有太多的影響MD5的安全性。上面所有這些都不足以成為MD5的在實際應用中的問題。並且,由於MD5算法的使用不需要支付任何版權費用的,所以在一般的情況下(非絕密應用領域。但即便是應用在絕密領域內,MD5也不失為一種非常優秀的中間技術),MD5怎麽都應該算得上是非常安全的了。 不足 2004年8月17日的美國加州聖巴巴拉的國際密碼學會議(Crypto’2004)上,來自中國山東大學的王小雲教授做了破譯MD5、HAVAL-128、 MD4和RIPEMD算法的報告,公布了MD系列算法的破解結果。宣告了固若金湯的世界通行密碼標準MD5的堡壘轟然倒塌,引發了密碼學界的軒然大波。(註意:並非是真正的破解,只是加速了雜湊沖撞) 令世界頂尖密碼學家想象不到的是,破解MD5之後,2005年2月,王小雲教授又破解了另一國際密碼SHA-1。因為SHA-1在美國等國際社會有更加廣泛的應用,密碼被破的消息一出,在國際社會的反響可謂石破天驚。換句話說,王小雲的研究成果表明了從理論上講電子簽名可以偽造,必須及時添加限制條件,或者重新選用更為安全的密碼標準,以保證電子商務的安全。 MD5驗證可執行文件不再可靠的消息 MD5破解工程權威網站是為了公開征集專門針對MD5的攻擊而設立的,網站於2004年8月17日宣布:“中國研究人員發現了完整MD5算法的碰撞;Wang,Feng,Lai,Yu公布了MD5、MD4、HAVAL-128、RIPEMD-128幾個 Hash函數的碰撞。這是近年來密碼學領域最具實質性的研究進展。使用他們的技術,在數個小時內就可以找到MD5碰撞。……由於這個裏程碑式的發現,MD5CRK項目將在隨後48小時內結束”。 在2004年8月之前,國際密碼學界對王小雲這個名字並不熟悉。2004年8月,在美國加州聖芭芭拉召開的國際密碼大會上,並沒有被安排發言的王小雲教授拿著自己的研究成果找到會議主席,沒想到慧眼識珠的會議主席破例給了她15分鐘時間來介紹自己的成果,而通常發言人只被允許有兩三分鐘的時間。王小雲與助手展示了MD5、SHA-0及其他相關雜湊函數的雜湊沖撞。所謂雜湊沖撞指兩個完全不同的訊息經雜湊函數計算得出完全相同的雜湊值。根據鴿巢原理,以有長度限制的雜湊函數計算沒有長度限制的訊息是必然會有沖撞情況出現的。可是,一直以來,電腦保安專家都認為要任意制造出沖撞需時太長,在實際情況上不可能發生,而王小雲等的發現可能會打破這個必然性。就這樣,王小雲在國際會議上首次宣布了她及她的研究小組的研究成果——對MD4、MD5、HAVAL-128和RIPEMD等四個著名密碼算法的破譯結果。 在公布到第三個成果的時候,會場上已經是掌聲四起,報告不得不一度中斷。報告結束後,所有與會專家對他們的突出工作報以長時間的掌聲,有些學者甚至起立鼓掌以示他們的祝賀和敬佩。由於版本問題,作者在提交會議論文時使用的一組常數和先行標準不同,在發現這一問題之後,王小雲教授立即改變了那個常數,在很短的時間內就完成了新的數據分析,這段有驚無險的小插曲更證明了他們論文的信服力,攻擊方法的有效性,驗證了研究工作的成功

 

java實現md5加密