MD5压缩算法心得

    看到网上许多关于MD5算法的文章,大体上都是一个版本,晦涩难懂,看的云里雾里。到现在才理解了些皮毛,写出来给大家分享下。

    MD5算法的全称是Message Digest Algorithm(消息摘要算法第五版),是计算机安全领域广泛使用的一个压缩加密的哈希算法,主要提供消息完整化。知道这个算法可以压缩加密就可以了。

    算法的主要思想就是:讲输入的信息分割成许多分组(长度为L),每个分组有512位(注意是位,MD5中是以位操作的)。然后又将每个分组划分为16个分组,每个分组有32组,经过一些处理后,输出一个128位的散列值。

    首先对输入的信息(假设位长度是BL)进行分组,要确保每个分组都够512位,但是不可能输入的信息的位数每次都是512的倍数,所以就问题来了,如何保证是512的倍数呢?舍弃最后一个分组,如果只有一组呢?舍弃这种办法是行不通了,那就只剩填充了。填充的话,有个规定:填充后的位数对512求余的结果是448,所以信息的位长度变成了N*512+448,也就是N*54+56个字节,N是正整数。填充的规则是在信息的后面添加一个1和若干个0,直到位长度是N*512+448,然后再在后面加上这个信息的原位长度BL的64位二进制表示,现在信息的长度变成了(N+1)*512位。这两步的作用是是信息长度恰好是512的整数倍,同时确保不同的消息在填充后不一样。

      MD5中有4个32位的整数参数,叫做链接变量,分别是

     A = 0x01234567

     B = 0x89abcdef

     C = 0xfedcba98

     D = 0x76543210

     设置好这四个链接变量后,就进入算法的四轮循环运算,循环的次数是L。将上面4个链接变量复制到另外四个变量中:A到a,B到b,C到c,D到d。

     算法主循环有四轮,每轮基本上都很相似,第一轮进行16次操作,每次对abcd中三个做一次函数运算,然后将所得的结果依次加上第四个变量,信息的一个子分组和一个常数。再将结果向右移动一个不定的数,并加上abcd中一个,然后将该结果替换abcd中一个。

     函数运算有且仅有以下四个:

      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)) 
      (&是与,|是或,~是非,^是异或) 


      这些函数是这样设计的:如果X、Y和Z的对应位是独立和均匀的,那么结果的每一位也应是独立和均匀的。函数F是按逐位方式操作:如果X,那么Y,否则Z。函数H是逐位奇偶操作符。 
      设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) 


这四轮(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) 
     常数ti可以如下选择: 在第i步中,ti是4294967296*abs(sin(i))的整数部分,i的单位是弧度。 (2的32次方) 
     所有这些完成之后,将A,B,C,D分别加上a,b,c,d。然后用下一分组数据继续运行算法,最后的输出是A,B,C和D的级联(ABCD每个是32位,加起来刚好是128位)。 

    

     下面贴上MD5算法的Java例子。因为Java中提供了MD5算法的类,所以直接使用即可。

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/*
 * MD5 算法
*/
public class MD5 {

    // 全局数组
    private final static String[] strDigits = { "0", "1", "2", "3", "4", "5",
            "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
    public MD5() {
    }
    // 返回形式为数字跟字符串
    private static String byteToArrayString(byte bByte) {
        int iRet = bByte;
        // System.out.println("iRet="+iRet);
        if (iRet < 0) {
            iRet += 256;
        }
        int iD1 = iRet / 16;
        int iD2 = iRet % 16;
        return strDigits[iD1] + strDigits[iD2];
    }
    // 返回形式只为数字
    private static String byteToNum(byte bByte) {
        int iRet = bByte;
        System.out.println("iRet1=" + iRet);
        if (iRet < 0) {
            iRet += 256;
        }
        return String.valueOf(iRet);
    }
    // 转换字节数组为16进制字串
    private static String byteToString(byte[] bByte) {
        StringBuffer sBuffer = new StringBuffer();
        for (int i = 0; i < bByte.length; i++) {
            sBuffer.append(byteToArrayString(bByte[i]));
        }
        return sBuffer.toString();
    }
    public static String GetMD5Code(String strObj) {
        String resultString = null;
        try {
            resultString = new String(strObj);
            MessageDigest md = MessageDigest.getInstance("MD5");
            // md.digest() 该函数返回值为存放哈希值结果的byte数组
            resultString = byteToString(md.digest(strObj.getBytes()));
        } catch (NoSuchAlgorithmException ex) {
            ex.printStackTrace();
        }
        return resultString;
    }
    public static void main(String[] args) {
        MD5 getMD5 = new MD5();
        System.out.println(getMD5.GetMD5Code("000000"));
    }
}


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。