在用网盘传东西的时候,突然发现传某些几个G的文件竟然几秒钟就传到网盘上去了,刚开始还以为是传送发生了错误,然后又重复传了几次还是一样。然后上网一查,看到知乎上的一个提问的讨论查了些网上的资料才明白其中原理。
对于网盘服务器上的每一个文件,服务器上都存有一个相应的唯一的特征值,然后当你从客户端传文件到网盘上时,会先计算你要传的文件的特征值,然后与服务器中存的对比,发现相同特征值则表明你要传的文件在服务器上已经存在,这时就实现秒传了。
那这个唯一的特征值是如何计算的呢?不部分是用MD5算法。
MD5算法功能就是对于你传入的一个任意长度的数据(其实根据算法的原理应该小于2的64次方bit,这个在目前的文件来说已经是无穷大了),然后经过处理,产生一个“唯一”的128位的信息。而且这个过程是不可逆的,也即你不能通过这个128位信息反推出原数据。
1、MD5算法的历史
1992年8月Ronald L. Rivest在向IETF提交了一份重要文件,描述了这种算法的原理,由于这种算法的公开性和安全性,在90年代被广泛使用在各种程序语言中,用以确保资料传递无误等。MD5由MD4、MD3、MD2改进而来,主要增强算法复杂度和不可逆性
MD5较老,散列长度通常为128位,随着计算机运算能力提高,找到“碰撞”是可能的。因此,在少数安全要求高的场合不使用MD5。
2004年,中国数学家王小云证明MD5数字签名算法可以产生碰撞。2007年,Marc Stevens,Arjen K. Lenstra和Benne de Weger进一步指出通过伪造软件签名,可重复性攻击MD5算法。研究者使用前缀碰撞法(chosen-prefix collision),使程序前端包含恶意程序,利用后面的空间添上垃圾代码凑出同样的MD5 哈希值。
2、MD5算法的原理 (摘自: http://blog.csdn.net/forgotaboutgirl/article/details/7258109)
MD5算法过程:
对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)。有点晕哈,其实想一想就明白了。
第四步、四轮循环运算:循环的次数是分组的个数(N+1)
1)将每一512字节细分成16个小组,每个小组64位(8个字节)
2)先认识四个线性函数(&是与,|是或,~是非,^是异或)
G(X,Y,Z)=(X&Z)|(Y&(~Z))
H(X,Y,Z)=X^Y^Z
I(X,Y,Z)=Y^(X|(~Z))
3)设Mj表示消息的第j个子分组(从0到15),<<<s表示循环左移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,然后进入下一循环。
3、MD5算法的java实现 (摘自: http://blog.csdn.net/forgotaboutgirl/article/details/7258109)
1 /************************************************ 2 * MD5 算法 3 * @author 我行我素 4 * @Date 2007-07-01 5 *************************************************/ 6 public class MD5 { 7 8 static final String hexs[]={"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"}; 9 //标准的幻数 10 private static final long A=0x67452301L; 11 private static final long B=0xefcdab89L; 12 private static final long C=0x98badcfeL; 13 private static final long D=0x10325476L; 14 15 16 //下面这些S11-S44实际上是一个4*4的矩阵,在四轮循环运算中用到 17 static final int S11 = 7; 18 static final int S12 = 12; 19 static final int S13 = 17; 20 static final int S14 = 22; 21 22 static final int S21 = 5; 23 static final int S22 = 9; 24 static final int S23 = 14; 25 static final int S24 = 20; 26 27 static final int S31 = 4; 28 static final int S32 = 11; 29 static final int S33 = 16; 30 static final int S34 = 23; 31 32 static final int S41 = 6; 33 static final int S42 = 10; 34 static final int S43 = 15; 35 static final int S44 = 21; 36 37 //java不支持无符号的基本数据(unsigned) 38 private long [] result={A,B,C,D};//存储hash结果,共4×32=128位,初始化值为(幻数的级联) 39 40 public static void main(String []args){ 41 MD5 md=new MD5(); 42 System.out.println("md5(abc)="+md.digest("abc")); 43 } 44 45 private String digest(String inputStr){ 46 byte [] inputBytes=inputStr.getBytes(); 47 int byteLen=inputBytes.length;//长度(字节) 48 int groupCount=0;//完整分组的个数 49 groupCount=byteLen/64;//每组512位(64字节) 50 long []groups=null;//每个小组(64字节)再细分后的16个小组(4字节) 51 52 //处理每一个完整 分组 53 for(int step=0;step<groupCount;step++){ 54 groups=divGroup(inputBytes,step*64); 55 trans(groups);//处理分组,核心算法 56 } 57 58 //处理完整分组后的尾巴 59 int rest=byteLen%64;//512位分组后的余数 60 byte [] tempBytes=new byte[64]; 61 if(rest<=56){ 62 for(int i=0;i<rest;i++) 63 tempBytes[i]=inputBytes[byteLen-rest+i]; 64 if(rest<56){ 65 tempBytes[rest]=(byte)(1<<7); 66 for(int i=1;i<56-rest;i++) 67 tempBytes[rest+i]=0; 68 } 69 long len=(long)(byteLen<<3); 70 for(int i=0;i<8;i++){ 71 tempBytes[56+i]=(byte)(len&0xFFL); 72 len=len>>8; 73 } 74 groups=divGroup(tempBytes,0); 75 trans(groups);//处理分组 76 }else{ 77 for(int i=0;i<rest;i++) 78 tempBytes[i]=inputBytes[byteLen-rest+i]; 79 tempBytes[rest]=(byte)(1<<7); 80 for(int i=rest+1;i<64;i++) 81 tempBytes[i]=0; 82 groups=divGroup(tempBytes,0); 83 trans(groups);//处理分组 84 85 for(int i=0;i<56;i++) 86 tempBytes[i]=0; 87 long len=(long)(byteLen<<3); 88 for(int i=0;i<8;i++){ 89 tempBytes[56+i]=(byte)(len&0xFFL); 90 len=len>>8; 91 } 92 groups=divGroup(tempBytes,0); 93 trans(groups);//处理分组 94 } 95 96 //将Hash值转换成十六进制的字符串 97 String resStr=""; 98 long temp=0; 99 for(int i=0;i<4;i++){ 100 for(int j=0;j<4;j++){ 101 temp=result[i]&0x0FL; 102 String a=hexs[(int)(temp)]; 103 result[i]=result[i]>>4; 104 temp=result[i]&0x0FL; 105 resStr+=hexs[(int)(temp)]+a; 106 result[i]=result[i]>>4; 107 } 108 } 109 return resStr; 110 } 111 112 /** 113 * 从inputBytes的index开始取512位,作为新的分组 114 * 将每一个512位的分组再细分成16个小组,每个小组64位(8个字节) 115 * @param inputBytes 116 * @param index 117 * @return 118 */ 119 private static long[] divGroup(byte[] inputBytes,int index){ 120 long [] temp=new long[16]; 121 for(int i=0;i<16;i++){ 122 temp[i]=b2iu(inputBytes[4*i+index])| 123 (b2iu(inputBytes[4*i+1+index]))<<8| 124 (b2iu(inputBytes[4*i+2+index]))<<16| 125 (b2iu(inputBytes[4*i+3+index]))<<24; 126 } 127 return temp; 128 } 129 130 /** 131 * 这时不存在符号位(符号位存储不再是代表正负),所以需要处理一下 132 * @param b 133 * @return 134 */ 135 public static long b2iu(byte b){ 136 return b < 0 ? b & 0x7F + 128 : b; 137 } 138 139 /** 140 * 主要的操作,四轮循环 141 * @param groups[]--每一个分组512位(64字节) 142 */ 143 private void trans(long[] groups) { 144 long a = result[0], b = result[1], c = result[2], d = result[3]; 145 /*第一轮*/ 146 a = FF(a, b, c, d, groups[0], S11, 0xd76aa478L); /* 1 */ 147 d = FF(d, a, b, c, groups[1], S12, 0xe8c7b756L); /* 2 */ 148 c = FF(c, d, a, b, groups[2], S13, 0x242070dbL); /* 3 */ 149 b = FF(b, c, d, a, groups[3], S14, 0xc1bdceeeL); /* 4 */ 150 a = FF(a, b, c, d, groups[4], S11, 0xf57c0fafL); /* 5 */ 151 d = FF(d, a, b, c, groups[5], S12, 0x4787c62aL); /* 6 */ 152 c = FF(c, d, a, b, groups[6], S13, 0xa8304613L); /* 7 */ 153 b = FF(b, c, d, a, groups[7], S14, 0xfd469501L); /* 8 */ 154 a = FF(a, b, c, d, groups[8], S11, 0x698098d8L); /* 9 */ 155 d = FF(d, a, b, c, groups[9], S12, 0x8b44f7afL); /* 10 */ 156 c = FF(c, d, a, b, groups[10], S13, 0xffff5bb1L); /* 11 */ 157 b = FF(b, c, d, a, groups[11], S14, 0x895cd7beL); /* 12 */ 158 a = FF(a, b, c, d, groups[12], S11, 0x6b901122L); /* 13 */ 159 d = FF(d, a, b, c, groups[13], S12, 0xfd987193L); /* 14 */ 160 c = FF(c, d, a, b, groups[14], S13, 0xa679438eL); /* 15 */ 161 b = FF(b, c, d, a, groups[15], S14, 0x49b40821L); /* 16 */ 162 163 /*第二轮*/ 164 a = GG(a, b, c, d, groups[1], S21, 0xf61e2562L); /* 17 */ 165 d = GG(d, a, b, c, groups[6], S22, 0xc040b340L); /* 18 */ 166 c = GG(c, d, a, b, groups[11], S23, 0x265e5a51L); /* 19 */ 167 b = GG(b, c, d, a, groups[0], S24, 0xe9b6c7aaL); /* 20 */ 168 a = GG(a, b, c, d, groups[5], S21, 0xd62f105dL); /* 21 */ 169 d = GG(d, a, b, c, groups[10], S22, 0x2441453L); /* 22 */ 170 c = GG(c, d, a, b, groups[15], S23, 0xd8a1e681L); /* 23 */ 171 b = GG(b, c, d, a, groups[4], S24, 0xe7d3fbc8L); /* 24 */ 172 a = GG(a, b, c, d, groups[9], S21, 0x21e1cde6L); /* 25 */ 173 d = GG(d, a, b, c, groups[14], S22, 0xc33707d6L); /* 26 */ 174 c = GG(c, d, a, b, groups[3], S23, 0xf4d50d87L); /* 27 */ 175 b = GG(b, c, d, a, groups[8], S24, 0x455a14edL); /* 28 */ 176 a = GG(a, b, c, d, groups[13], S21, 0xa9e3e905L); /* 29 */ 177 d = GG(d, a, b, c, groups[2], S22, 0xfcefa3f8L); /* 30 */ 178 c = GG(c, d, a, b, groups[7], S23, 0x676f02d9L); /* 31 */ 179 b = GG(b, c, d, a, groups[12], S24, 0x8d2a4c8aL); /* 32 */ 180 181 /*第三轮*/ 182 a = HH(a, b, c, d, groups[5], S31, 0xfffa3942L); /* 33 */ 183 d = HH(d, a, b, c, groups[8], S32, 0x8771f681L); /* 34 */ 184 c = HH(c, d, a, b, groups[11], S33, 0x6d9d6122L); /* 35 */ 185 b = HH(b, c, d, a, groups[14], S34, 0xfde5380cL); /* 36 */ 186 a = HH(a, b, c, d, groups[1], S31, 0xa4beea44L); /* 37 */ 187 d = HH(d, a, b, c, groups[4], S32, 0x4bdecfa9L); /* 38 */ 188 c = HH(c, d, a, b, groups[7], S33, 0xf6bb4b60L); /* 39 */ 189 b = HH(b, c, d, a, groups[10], S34, 0xbebfbc70L); /* 40 */ 190 a = HH(a, b, c, d, groups[13], S31, 0x289b7ec6L); /* 41 */ 191 d = HH(d, a, b, c, groups[0], S32, 0xeaa127faL); /* 42 */ 192 c = HH(c, d, a, b, groups[3], S33, 0xd4ef3085L); /* 43 */ 193 b = HH(b, c, d, a, groups[6], S34, 0x4881d05L); /* 44 */ 194 a = HH(a, b, c, d, groups[9], S31, 0xd9d4d039L); /* 45 */ 195 d = HH(d, a, b, c, groups[12], S32, 0xe6db99e5L); /* 46 */ 196 c = HH(c, d, a, b, groups[15], S33, 0x1fa27cf8L); /* 47 */ 197 b = HH(b, c, d, a, groups[2], S34, 0xc4ac5665L); /* 48 */ 198 199 /*第四轮*/ 200 a = II(a, b, c, d, groups[0], S41, 0xf4292244L); /* 49 */ 201 d = II(d, a, b, c, groups[7], S42, 0x432aff97L); /* 50 */ 202 c = II(c, d, a, b, groups[14], S43, 0xab9423a7L); /* 51 */ 203 b = II(b, c, d, a, groups[5], S44, 0xfc93a039L); /* 52 */ 204 a = II(a, b, c, d, groups[12], S41, 0x655b59c3L); /* 53 */ 205 d = II(d, a, b, c, groups[3], S42, 0x8f0ccc92L); /* 54 */ 206 c = II(c, d, a, b, groups[10], S43, 0xffeff47dL); /* 55 */ 207 b = II(b, c, d, a, groups[1], S44, 0x85845dd1L); /* 56 */ 208 a = II(a, b, c, d, groups[8], S41, 0x6fa87e4fL); /* 57 */ 209 d = II(d, a, b, c, groups[15], S42, 0xfe2ce6e0L); /* 58 */ 210 c = II(c, d, a, b, groups[6], S43, 0xa3014314L); /* 59 */ 211 b = II(b, c, d, a, groups[13], S44, 0x4e0811a1L); /* 60 */ 212 a = II(a, b, c, d, groups[4], S41, 0xf7537e82L); /* 61 */ 213 d = II(d, a, b, c, groups[11], S42, 0xbd3af235L); /* 62 */ 214 c = II(c, d, a, b, groups[2], S43, 0x2ad7d2bbL); /* 63 */ 215 b = II(b, c, d, a, groups[9], S44, 0xeb86d391L); /* 64 */ 216 217 /*加入到之前计算的结果当中*/ 218 result[0] += a; 219 result[1] += b; 220 result[2] += c; 221 result[3] += d; 222 result[0]=result[0]&0xFFFFFFFFL; 223 result[1]=result[1]&0xFFFFFFFFL; 224 result[2]=result[2]&0xFFFFFFFFL; 225 result[3]=result[3]&0xFFFFFFFFL; 226 } 227 228 /** 229 * 下面是处理要用到的线性函数 230 */ 231 private static long F(long x, long y, long z) { 232 return (x & y) | ((~x) & z); 233 } 234 235 private static long G(long x, long y, long z) { 236 return (x & z) | (y & (~z)); 237 } 238 239 private static long H(long x, long y, long z) { 240 return x ^ y ^ z; 241 } 242 243 private static long I(long x, long y, long z) { 244 return y ^ (x | (~z)); 245 } 246 247 private static long FF(long a, long b, long c, long d, long x, long s, 248 long ac) { 249 a += (F(b, c, d)&0xFFFFFFFFL) + x + ac; 250 a = ((a&0xFFFFFFFFL)<< s) | ((a&0xFFFFFFFFL) >>> (32 - s)); 251 a += b; 252 return (a&0xFFFFFFFFL); 253 } 254 255 private static long GG(long a, long b, long c, long d, long x, long s, 256 long ac) { 257 a += (G(b, c, d)&0xFFFFFFFFL) + x + ac; 258 a = ((a&0xFFFFFFFFL) << s) | ((a&0xFFFFFFFFL) >>> (32 - s)); 259 a += b; 260 return (a&0xFFFFFFFFL); 261 } 262 263 private static long HH(long a, long b, long c, long d, long x, long s, 264 long ac) { 265 a += (H(b, c, d)&0xFFFFFFFFL) + x + ac; 266 a = ((a&0xFFFFFFFFL) << s) | ((a&0xFFFFFFFFL) >>> (32 - s)); 267 a += b; 268 return (a&0xFFFFFFFFL); 269 } 270 271 private static long II(long a, long b, long c, long d, long x, long s, 272 long ac) { 273 a += (I(b, c, d)&0xFFFFFFFFL) + x + ac; 274 a = ((a&0xFFFFFFFFL) << s) | ((a&0xFFFFFFFFL) >>> (32 - s)); 275 a += b; 276 return (a&0xFFFFFFFFL); 277 } 278 }