MD5加密原理

目录

简介

MD5 算法底层原理:

第一步:处理原文 

第二步:设置初始值 

第三步:循环处理分组数据

参数及函数

第四步:拼接结果

代码实现:

java 实现MD5加密原理

使用Java自带的MessageDigest工具类实现


简介

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

MD5 算法底层原理:

简单概括起来,MD5 算法的过程分为四步:处理原文,设置初始值,循环处理分组数据,拼接结果。

总体流程如下图所示,表示第i个分组,每次的运算都由前一轮的128位结果值和第i块512bit值进行运算。

第一步:处理原文 

首先,我们计算出原文长度(bit)对 512 求余的结果,如果不等于 448,就需要填充原文使得原文对 512 求余的结果等于 448。填充的方法是第一位填充 1,其余位填充 0。填充完后,信息的长度就是 512*N+448。 

之后,用剩余的位置(512-448=64 位)记录原文的真正长度,把长度的二进制值补在最后。这样处理后的信息长度就是 512*(N+1)。

第二步:设置初始值 

MD5 的哈希结果长度为 128 位,按每 32 位分成一组共 4 组。这 4 组结果是由 4 个初始值 A、B、C、D 经过不断演变得到。MD5 的官方实现中,A、B、C、D 的初始值如下(16 进制):  

A=0x01234567 

B=0x89ABCDEF 

C=0xFEDCBA98 

D=0x76543210   

它们称为链接变量(chaining variable)

第三步:循环处理分组数据

 

一共进行多少次循环呢?由处理后的原文长度决定。

假设处理后的原文长度是 M(bit)

主循环次数 = M / 512

每个主循环中包含 512 / 32 * 4 = 64 次 子循环

每一分组的算法流程如下:

第一分组需要将上面四个链接变量复制到另外四个变量中: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中之一。

参数及函数

1.F非线性函数.官方 MD5 所用到的函数有四种:

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是逐位奇偶操作符。

在主循环下面 64 次子循环中,F、G、H、I 交替使用,第一轮 16 次使用 F,第二轮 16 次使用 G,第三轮 16 次使用 H,第四轮 16 次使用 I。

2.Mj

Mj是第一步处理后的原文。在第一步中,处理后原文的长度是 512 的整数倍。把原文的每 512 位再分成 16 等份,命名为 M0~M15,每一等份长度 32。在 64 次子循环中,每 16 次循环,都会交替用到 M1~M16 之一。

3.ti

一个常量,在 64 次子循环中,每一次用到的常量都是不同的。

常数ti可以如下t选择:

在第i步中,ti是4294967296(2的32次方)*abs(sin(i))的整数部分,i的单位是弧度。

4.<<<S

左移 S 位,S 的值也是常量。

命名规则(s+方法名+第N个数)

SFF1=7;   SFF2=12,   SFF3=17;   SFF4=22;

SGG1=5;  SGG2=9,    SGG3=14;  SGG4=20;

SHH1=4;  SHH2=11,   SHH3=16;  SHH4=23;

SⅡ1=6;   SⅡ2=10,    SⅡ3=15;    SⅡ4=21;

设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 次子循环,可以归纳为下面的四轮:

这四轮(64步)是:

 第一轮:

       FF(a,b,c,d,M0,7,0xd76aa478)     s[0]=7,   K[0] = 0xd76aa478

  FF(a,b,c,d,M1,12,0xe8c7b756)   s[1]=12,  K[1] = 0xe8c7b756

  FF(a,b,c,d,M2,17,0x242070db)

  FF(a,b,c,d,M3,22,0xc1bdceee)

  FF(a,b,c,d,M4,7,0xf57c0faf)

  FF(a,b,c,d,M5,12,0x4787c62a)

  FF(a,b,c,d,M6,17,0xa8304613)

  FF(a,b,c,d,M7,22,0xfd469501)

  FF(a,b,c,d,M8,7,0x698098d8)

  FF(a,b,c,d,M9,12,0x8b44f7af)

  FF(a,b,c,d,M10,17,0xffff5bb1)

  FF(a,b,c,d,M11,22,0x895cd7be)

  FF(a,b,c,d,M12,7,0x6b901122)

  FF(a,b,c,d,M13,12,0xfd987193)

  FF(a,b,c,d,M14,17, 0xa679438e)

  FF(a,b,c,d,M15,22,0x49b40821)

  第二轮:

  GG(a,b,c,d,M1,5,0xf61e2562)

  GG(a,b,c,d,M6,9,0xc040b340)

  GG(a,b,c,d,M11,14,0x265e5a51)

  GG(a,b,c,d,M0,20,0xe9b6c7aa)

  GG(a,b,c,d,M5,5,0xd62f105d)

  GG(a,b,c,d,M10,9,0×02441453)

  GG(a,b,c,d,M15,14,0xd8a1e681)

  GG(a,b,c,d,M4,20,0xe7d3fbc8)

  GG(a,b,c,d,M9,5,0x21e1cde6)

  GG(a,b,c,d,M14,9,0xc33707d6)

  GG(a,b,c,d,M3,14,0xf4d50d87)

  GG(a,b,c,d,M8,20,0x455a14ed)

  GG(a,b,c,d,M13,5,0xa9e3e905)

  GG(a,b,c,d,M2,9,0xfcefa3f8)

  GG(a,b,c,d,M7,14,0x676f02d9)

  GG(a,b,c,d,M12,20,0x8d2a4c8a)

  第三轮:

  HH(a,b,c,d,M5,4,0xfffa3942)

  HH(a,b,c,d,M8,11,0x8771f681)

  HH(a,b,c,d,M11,16,0x6d9d6122)

  HH(a,b,c,d,M14,23,0xfde5380c)

  HH(a,b,c,d,M1,4,0xa4beea44)

  HH(a,b,c,d,M4,11,0x4bdecfa9)

  HH(a,b,c,d,M7,16,0xf6bb4b60)

  HH(a,b,c,d,M10,23,0xbebfbc70)

  HH(a,b,c,d,M13,4,0x289b7ec6)

  HH(a,b,c,d,M0,11,0xeaa127fa)

  HH(a,b,c,d,M3,16,0xd4ef3085)

  HH(a,b,c,d,M6,23,0x04881d05)

  HH(a,b,c,d,M9,4,0xd9d4d039)

  HH(a,b,c,d,M12,11,0xe6db99e5)

  HH(a,b,c,d,M15,16,0x1fa27cf8)

  HH(a,b,c,d,M2,23,0xc4ac5665)

  第四轮:

  Ⅱ(a,b,c,d,M0,6,0xf4292244)

  Ⅱ(a,b,c,d,M7,10,0x432aff97)

  Ⅱ(a,b,c,d,M14,15,0xab9423a7)

  Ⅱ(a,b,c,d,M5,21,0xfc93a039)

  Ⅱ(a,b,c,d,M12,6,0x655b59c3)

  Ⅱ(a,b,c,d,M3,10,0x8f0ccc92)

  Ⅱ(a,b,c,d,M10,15,0xffeff47d)

  Ⅱ(a,b,c,d,M1,21,0x85845dd1)

  Ⅱ(a,b,c,d,M8,6,0x6fa87e4f)

  Ⅱ(a,b,c,d,M15,10,0xfe2ce6e0)

  Ⅱ(a,b,c,d,M6,15,0xa3014314)

  Ⅱ(a,b,c,d,M13,21,0x4e0811a1)

  Ⅱ(a,b,c,d,M4,6,0xf7537e82)

  Ⅱ(a,b,c,d,M11,10,0xbd3af235)

  Ⅱ(a,b,c,d,M2,15,0x2ad7d2bb)

  Ⅱ(a,b,c,d,M9,21,0xeb86d391)

第四步:拼接结果

所有这些完成之后,将A,B,C,D分别加上a,b,c,d。然后用下一分组数据继续运行算法,最后的输出是A,B,C和D的级联。

代码实现:

java 实现MD5加密原理

import java.util.Arrays;
public class MD5 {

    //static final String hexs[]={"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"};
    //标准的幻数
    private static final int A=0x67452301;
    private static final int B=0xefcdab89;
    private static final int C=0x98badcfe;
    private static final int D=0x10325476;


    //下面这些S11-S44实际上是一个4*4的矩阵,在四轮循环运算中用到
    static final int S11 = 7;
    static final int S12 = 12;
    static final int S13 = 17;
    static final int S14 = 22;

    static final int S21 = 5;
    static final int S22 = 9;
    static final int S23 = 14;
    static final int S24 = 20;

    static final int S31 = 4;
    static final int S32 = 11;
    static final int S33 = 16;
    static final int S34 = 23;

    static final int S41 = 6;
    static final int S42 = 10;
    static final int S43 = 15;
    static final int S44 = 21;

    //java不支持无符号的基本数据(unsigned)
    private int [] result={A,B,C,D};//存储hash结果,共4×32=128位,初始化值为(幻数的级联)
    //此重载方法是将传入的字符串加点特色(比如密码加密可以连同将用户名加入一起加密,这样就算密码和别人一样加密后的结果也不一样)
    private byte[] digest(String inputStr ,String salt) {
    	return digest(salt+inputStr);
    }
    private byte[] digest(String inputStr){
        byte [] inputBytes=inputStr.getBytes();//将字符串转化成字节数组
        int byteLen=inputBytes.length;//长度(字节)
        int groupCount=0;//完整分组的个数
        groupCount=byteLen/64;//每组512位(64字节)
        int []groups=null;//每个小组(64字节)再细分后的16个小组(4字节)

        //处理每一个完整分组
        for(int step=0;step<groupCount;step++){
            groups=divGroup(inputBytes,step*64);//处理分组,将每一个完整分组16个小组(16×4)
            trans(groups);//处理分组,核心算法
        }

        //处理完整分组后的尾巴
        int rest=byteLen%64;//512位分组后的余数
        byte [] tempBytes=new byte[64];
        //余数小于<=56,先填充1,0数据,然后最后64位(8字节)储存长度
        if(rest<=56){
        	//将尾巴先存储在临时数组中
            for(int i=0;i<rest;i++)
                tempBytes[i]=inputBytes[byteLen-rest+i];
            if(rest<56){
            	//填充数据(448位之前第一个填充1,后面填充0)
                tempBytes[rest]=(byte)(1<<7);
                for(int i=1;i<56-rest;i++)
                    tempBytes[rest+i]=0;
            }
            //后64位储存原文实际长度(448-512),即8字节
            long len=byteLen<<3;//长度单位是bit 即原文字节数组长度×8
            for(int i=0;i<8;i++){
                tempBytes[56+i]=(byte)(len&0xFF);//每次取长度的低八位存入字节数组
                len=len>>8;//取完移除低八位
            }
            groups=divGroup(tempBytes,0);
            trans(groups);//处理分组
        }else{//余数大于56,需增加一组主循环,目的保证处理后的原文最后64位(8字节)储存长度
            for(int i=0;i<rest;i++)
            	//将尾巴先存储在临时数组中
                tempBytes[i]=inputBytes[byteLen-rest+i];
            //填充数据(第一个填充1,后面填充0)
            tempBytes[rest]=(byte)(1<<7);
            for(int i=rest+1;i<64;i++)
                tempBytes[i]=0;
            groups=divGroup(tempBytes,0);
            trans(groups);//处理分组
            //前56元素填充0
            for(int i=0;i<56;i++)
                tempBytes[i]=0;
            //后64位储存原文实际长度(448-512),即8字节
            long len=(long)(byteLen<<3);
            for(int i=0;i<8;i++){
                tempBytes[56+i]=(byte)(len&0xFF);
                len=len>>8;
            }
            groups=divGroup(tempBytes,0);
            trans(groups);//处理分组
        }
        //System.out.println(Arrays.toString(result));
        //将hash值转换成字节数组
        //int[] result={A,B,C,D};共4×32=128位,每八位转换一个byte类型,储存在一个结果集
        byte[] resultByte = new byte[16];
        for(int i = 0;i<4;i++) {
        	for(int j = 0; j < 4; j++) {
        		//每次取低八位
        		resultByte[i*4+j] = (byte) (result[i] & 0xff);
        		//取完移除
        		result[i]=result[i]>>8;
        	}
        }
        //System.out.println(Arrays.toString(resultByte));
        return resultByte;
    }

    /**
     * 从inputBytes的index开始取512位,作为新的分组
     * 将每一个512位的分组再细分成16个小组,每个小组64位(8个字节)
     * @param inputBytes
     * @param index
     * @return
     */
    private static int[] divGroup(byte[] inputBytes,int index){
        int [] temp=new int[16];
        for(int i=0;i<16;i++){
        	//从byte数组中取四个元素组成一个int类型保存在数组中
        	//b2iu方法是将byte的最高位符号位转化为代表数值位
            temp[i]=b2iu(inputBytes[4*i+index])|
                (b2iu(inputBytes[4*i+1+index]))<<8|
                (b2iu(inputBytes[4*i+2+index]))<<16|
                (b2iu(inputBytes[4*i+3+index]))<<24;
        }
        //最后返回这分组
        return temp;
    }

    /**
     * 这时不存在符号位(符号位存储不再是代表正负),所以需要处理一下
     * @param b
     * @return
     */
    public static int b2iu(byte b){//0x7F + 128=0xff
        return b < 0 ? b & 0x7F + 128 : b;
     }

    /**
     * 主要的操作,四轮循环
     * @param groups[]--每一个分组512位(64字节)
     */
    private void trans(int[] groups) {
        int a = result[0], b = result[1], c = result[2], d = result[3];
        /*第一轮*/
        a = FF(a, b, c, d, groups[0], S11, 0xd76aa478); /* 1 */
        d = FF(d, a, b, c, groups[1], S12, 0xe8c7b756); /* 2 */
        c = FF(c, d, a, b, groups[2], S13, 0x242070db); /* 3 */
        b = FF(b, c, d, a, groups[3], S14, 0xc1bdceee); /* 4 */
        a = FF(a, b, c, d, groups[4], S11, 0xf57c0faf); /* 5 */
        d = FF(d, a, b, c, groups[5], S12, 0x4787c62a); /* 6 */
        c = FF(c, d, a, b, groups[6], S13, 0xa8304613); /* 7 */
        b = FF(b, c, d, a, groups[7], S14, 0xfd469501); /* 8 */
        a = FF(a, b, c, d, groups[8], S11, 0x698098d8); /* 9 */
        d = FF(d, a, b, c, groups[9], S12, 0x8b44f7af); /* 10 */
        c = FF(c, d, a, b, groups[10], S13, 0xffff5bb1); /* 11 */
        b = FF(b, c, d, a, groups[11], S14, 0x895cd7be); /* 12 */
        a = FF(a, b, c, d, groups[12], S11, 0x6b901122); /* 13 */
        d = FF(d, a, b, c, groups[13], S12, 0xfd987193); /* 14 */
        c = FF(c, d, a, b, groups[14], S13, 0xa679438e); /* 15 */
        b = FF(b, c, d, a, groups[15], S14, 0x49b40821); /* 16 */

        /*第二轮*/
        a = GG(a, b, c, d, groups[1], S21, 0xf61e2562); /* 17 */
        d = GG(d, a, b, c, groups[6], S22, 0xc040b340); /* 18 */
        c = GG(c, d, a, b, groups[11], S23, 0x265e5a51); /* 19 */
        b = GG(b, c, d, a, groups[0], S24, 0xe9b6c7aa); /* 20 */
        a = GG(a, b, c, d, groups[5], S21, 0xd62f105d); /* 21 */
        d = GG(d, a, b, c, groups[10], S22, 0x2441453); /* 22 */
        c = GG(c, d, a, b, groups[15], S23, 0xd8a1e681); /* 23 */
        b = GG(b, c, d, a, groups[4], S24, 0xe7d3fbc8); /* 24 */
        a = GG(a, b, c, d, groups[9], S21, 0x21e1cde6); /* 25 */
        d = GG(d, a, b, c, groups[14], S22, 0xc33707d6); /* 26 */
        c = GG(c, d, a, b, groups[3], S23, 0xf4d50d87); /* 27 */
        b = GG(b, c, d, a, groups[8], S24, 0x455a14ed); /* 28 */
        a = GG(a, b, c, d, groups[13], S21, 0xa9e3e905); /* 29 */
        d = GG(d, a, b, c, groups[2], S22, 0xfcefa3f8); /* 30 */
        c = GG(c, d, a, b, groups[7], S23, 0x676f02d9); /* 31 */
        b = GG(b, c, d, a, groups[12], S24, 0x8d2a4c8a); /* 32 */

        /*第三轮*/
        a = HH(a, b, c, d, groups[5], S31, 0xfffa3942); /* 33 */
        d = HH(d, a, b, c, groups[8], S32, 0x8771f681); /* 34 */
        c = HH(c, d, a, b, groups[11], S33, 0x6d9d6122); /* 35 */
        b = HH(b, c, d, a, groups[14], S34, 0xfde5380c); /* 36 */
        a = HH(a, b, c, d, groups[1], S31, 0xa4beea44); /* 37 */
        d = HH(d, a, b, c, groups[4], S32, 0x4bdecfa9); /* 38 */
        c = HH(c, d, a, b, groups[7], S33, 0xf6bb4b60); /* 39 */
        b = HH(b, c, d, a, groups[10], S34, 0xbebfbc70); /* 40 */
        a = HH(a, b, c, d, groups[13], S31, 0x289b7ec6); /* 41 */
        d = HH(d, a, b, c, groups[0], S32, 0xeaa127fa); /* 42 */
        c = HH(c, d, a, b, groups[3], S33, 0xd4ef3085); /* 43 */
        b = HH(b, c, d, a, groups[6], S34, 0x4881d05); /* 44 */
        a = HH(a, b, c, d, groups[9], S31, 0xd9d4d039); /* 45 */
        d = HH(d, a, b, c, groups[12], S32, 0xe6db99e5); /* 46 */
        c = HH(c, d, a, b, groups[15], S33, 0x1fa27cf8); /* 47 */
        b = HH(b, c, d, a, groups[2], S34, 0xc4ac5665); /* 48 */

        /*第四轮*/
        a = II(a, b, c, d, groups[0], S41, 0xf4292244); /* 49 */
        d = II(d, a, b, c, groups[7], S42, 0x432aff97); /* 50 */
        c = II(c, d, a, b, groups[14], S43, 0xab9423a7); /* 51 */
        b = II(b, c, d, a, groups[5], S44, 0xfc93a039); /* 52 */
        a = II(a, b, c, d, groups[12], S41, 0x655b59c3); /* 53 */
        d = II(d, a, b, c, groups[3], S42, 0x8f0ccc92); /* 54 */
        c = II(c, d, a, b, groups[10], S43, 0xffeff47d); /* 55 */
        b = II(b, c, d, a, groups[1], S44, 0x85845dd1); /* 56 */
        a = II(a, b, c, d, groups[8], S41, 0x6fa87e4f); /* 57 */
        d = II(d, a, b, c, groups[15], S42, 0xfe2ce6e0); /* 58 */
        c = II(c, d, a, b, groups[6], S43, 0xa3014314); /* 59 */
        b = II(b, c, d, a, groups[13], S44, 0x4e0811a1); /* 60 */
        a = II(a, b, c, d, groups[4], S41, 0xf7537e82); /* 61 */
        d = II(d, a, b, c, groups[11], S42, 0xbd3af235); /* 62 */
        c = II(c, d, a, b, groups[2], S43, 0x2ad7d2bb); /* 63 */
        b = II(b, c, d, a, groups[9], S44, 0xeb86d391); /* 64 */

        /*加入到之前计算的结果当中*/
        result[0] += a;
        result[1] += b;
        result[2] += c;
        result[3] += d;
        result[0]=result[0]&0xFFFFFFFF;
        result[1]=result[1]&0xFFFFFFFF;
        result[2]=result[2]&0xFFFFFFFF;
        result[3]=result[3]&0xFFFFFFFF;
    }

    /**
     * 下面是处理要用到的线性函数
     */
    private static int F(int x, int y, int z) {
        return (x & y) | ((~x) & z);
    }

    private static int G(int x, int y, int z) {
        return (x & z) | (y & (~z));
    }

    private static int H(int x, int y, int z) {
        return x ^ y ^ z;
    }

    private static int I(int x, int y, int z) {
        return y ^ (x | (~z));
    }

    private static int FF(int a, int b, int c, int d, int x, int s,
            int ac) {
        a += (F(b, c, d)&0xFFFFFFFF) + x + ac;
        //<<<s表示循环左移s位,解决Java中无该运算符
        a = ((a&0xFFFFFFFF)<< s) | ((a&0xFFFFFFFF) >>> (32 - s));
        a += b;
        return (a&0xFFFFFFFF);
    }

    private static int GG(int a, int b, int c, int d, int x, int s,
            int ac) {
        a += (G(b, c, d)&0xFFFFFFFF) + x + ac;
        a = ((a&0xFFFFFFFF) << s) | ((a&0xFFFFFFFF) >>> (32 - s));
        a += b;
        return (a&0xFFFFFFFF);
    }

    private static int HH(int a, int b, int c, int d, int x, int s,
            long ac) {
        a += (H(b, c, d)&0xFFFFFFFF) + x + ac;
        a = ((a&0xFFFFFFFF) << s) | ((a&0xFFFFFFFF) >>> (32 - s));
        a += b;
        return (a&0xFFFFFFFF);
    }

    private static int II(int a, int b, int c, int d, int x, int s,
            long ac) {
        a += (I(b, c, d)&0xFFFFFFFF) + x + ac;
        a = ((a&0xFFFFFFFF) << s) | ((a&0xFFFFFFFF) >>> (32 - s));
        a += b;
        return (a&0xFFFFFFFF);
    }
    //清除缓存,将int[] result={A,B,C,D},还原为初始状态
    public  void reset() {
    	result[0] = A;
    	result[1] = B;
    	result[2] = C;
    	result[3] = D;
    	
    }
    public static void main(String []args){
        MD5 md=new MD5();
        //byte[] bytes = md.digest("123").getBytes();
        System.out.println("----");
        md.reset();
        byte[] digest1 = md.digest("123");
        System.out.println(Arrays.toString(digest1));
        md.reset();
        byte[] digest2 = md.digest("123","francis");
        System.out.println(Arrays.toString(digest2));
    }
}
//结果:
//[32, 44, -71, 98, -84, 89, 7, 91, -106, 75, 7, 21, 45, 35, 75, 112]
//[-115, 112, -101, 75, 100, 97, -82, -10, 20, 82, -102, -125, -40, -125, -58, 75]

使用Java自带的MessageDigest工具类实现

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

public class Md5Test {
	public static void main(String[] args) throws IOException {
		String s = "123";
		String md5 = Md5(s);
		Md5("francis123");
//		File file = new File("D:/0439 - 副本.jpg");
//		Md5(file);
//		System.out.println("完成");
	}
	/**
	 * 
	 * @param str 要加密的字符串
	 * @return
	 */
	public static String Md5(String str) {
		//获取md5对象
		MessageDigest md5 = null;
		try {
			md5 = MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		//将字符串转换为字节数组
		byte[] bytes = str.getBytes();
		//清除默认缓存
		md5.reset();
		//信息摘要对象对字节数组进行摘要,得到摘要字节数组
		byte[] digest = md5.digest(bytes);
		//打印摘要数组信息
		System.out.println("摘要数组长度:"+digest.length);
		System.out.println("摘要数组内容:"+Arrays.toString(digest));
		StringBuffer hexValue = new StringBuffer();
		//把摘要数组的每一个字节转换成16进制
		for (int i = 0; i < digest.length; i++) {
			//将字节数组转换为16进制字符串
			String hexString = Integer.toHexString(digest[i] & 0xff);
			//如果字符长度小于2,先追加一个0
			if(hexString.length() == 1) {
				hexValue.append("0");
			}
			//追加
			hexValue.append(hexString);
		}
		return hexValue.toString();
	}
	public static void Md5(File file) throws IOException {
		MessageDigest md5 = null;
		try {
			md5 = MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}	
		RandomAccessFile raf = new RandomAccessFile(file, "rw");
		byte[] buff = new byte[16];
		int len;
		while(( len = raf.read(buff)) != -1) {
			md5.reset();
			md5.update(buff, 0, len);
			byte[] digest = md5.digest();
			raf.seek(raf.getFilePointer()-len);
			raf.write(digest);
			//raf.seek(raf.getFilePointer()+len-digest.length);
			//raf.skipBytes((int) (raf.getFilePointer()+len-digest.length));
		}
		raf.close();
	}
	//可逆的加密算法,加盐加密
	public static String KL(String str) {
		char[] charArray = str.toCharArray();
		for (int i = 0; i < charArray.length; i++) {
			charArray[i] = (char) (charArray[i] ^ 't');
		}
		String s = new String(charArray);
		return s;
	}
}
//结果:
//摘要数组长度:16
//摘要数组内容:[32, 44, -71, 98, -84, 89, 7, 91, -106, 75, 7, 21, 45, 35, 75, 112]
//摘要数组长度:16
//摘要数组内容:[-115, 112, -101, 75, 100, 97, -82, -10, 20, 82, -102, -125, -40, -125, -58, 75]

对比两个代码结果是一致的,到此基本实现MD5算法原理.

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值