hash算法原理之md5过程

MD5加密过程

  • 十进制是逢十进一
  • 二进制是逢二进一
  • 十六进制是逢十六进一
进制数 十一 十二 十三 十四 十五 十六
十进制 0 1 2 3 4 5 6 7 8 9 10 11 12 13
二进制 0 1 10 11 100 101 110 111
十六进制 0 1 2 3 4 5 6 7 8 9 A B C D E F 10

字节序的概念

计算机的存储单位为字节,一个字节对应8个二进制位,共可以表示2^8也就是256种状态。若表示数的话,最多只能表示256个数。
如一个字节可以表示非负整数的0~255,而表示更大的数,则需要占用多个字节,如表示256至少需要两个字节。
256的二进制形式为 00000001 00000000。这样在计算机存储上就存在一个问题:是先存储00000001这个字节,还是先存储00000000这个字节呢?实际上,采用这两种存储方式的都有,取决于CPU架构和编译器。这就引出了字节序的概念。

小端字节序(Little Endian):低位字节存放在低内存地址,高位字节存放在高内存地址端。
大端字节序(Big Endian):高位字节存放在低内存地址,低位字节存放在高内存地址端。

256作为无符号数在计算机内存中的存储:

字节序 低地址 ————> 高地址
小端 00000000 00000001
大端 00000001 00000000

接下来这篇文章的所有关于存储的描述都是基于小端字节序的,内存地址都是从左往右从低到高的,而且带[存储]字样。(这很关键)
如:00000001 00000010 [存储] 表示的是十六进制的0x201,十进制的513,二进制的1000000001b
(一个数以0x开头意味着这个数是采用的十六进制,以b结尾意味着采用二进制)


任何计算机文件都是可以看作一串二进制位。

例如:一个最普通的内容为hello的ASCII文本文件,在计算机中的存储是这样的:

01101000 01100101 01101100 01101100 01101111 [存储]
(这和UTF-8编码的字符串”hello”,在内存中的存储是一样的。)


下面进入正题:MD5算法描述

MD5算法就像一个函数,任意一个二进制串都可以作为自变量进入这个“函数”,然后会出来一个固定为128位的二进制串。

我们先用一个例子来过一下这个过程,然后用文字描述算法细节。
比如加密一个普通的内容为hello的ASCII文本文件,这个文件由40个二进制位存储在计算机上:

01101000 01100101 01101100 01101100 01101111 [存储]

算法开始:

进行二进制位补充。具体这样补充:

从这40位的后面开始,先补充一个1位,再补充0位,一直到总共448位长度(也就是补充407个0位)。接着在后面写入原始信息长度与2^64的模。也就是40mod(2^64)=40,40转化为2进制为101000,用64存储就是:

00101000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [存储]

二进制位补充完成。
得到内容(共512位):

扫描二维码关注公众号,回复: 1010971 查看本文章

01101000 01100101 01101100 01101100 01101111 1 (407个0)00101000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [存储]

然后对这个512个位平均分成16组,每组32个位:

第1组:01101000 01100101 01101100 01101100
第2组:01101111 10000000 00000000 00000000

第32组:00000000 00000000 00000000 00000000

然后使用四个常数进行运算,分别是:
A=0x67452301,B=0xefcdab89,C=0x98badcfe,D=0x10325476。
A: 00000001 00100011 01000101 01100111 [存储]
B: 10001001 10101011 11001101 11101111 [存储]
C: 11111110 11011100 10111010 10011000 [存储]
D: 01110110 01010100 00110010 00010000 [存储]

一共进行64轮运算:

先说明运算符:

=赋值运算符: i=0意味着把0赋值给i,也就是让i的值为0
&按位与运算符:1010b & 1100b的值为1000b
or按位或运算符:1010b or 1100b的值为1110b
^按位异或运算符:1010b ^ 1100b的值为0110b
~按位取反运算符:~1010b的值为0101b
<<按位循环左移运算符:1100b << 3的值为0110b
mod是取模运算符:33 mod 16 的值为1
i==64是判断i是否和64相等

Created with Raphaël 2.1.2 Start i=0,a=A,b=B,c=C,d=D i==64 A=A+a B=B+b C=C+c D=D+d end i<16 f=(b&c) or (~b&d) g=i t=((a+f+第i组+k[i])<<s[i])+b a=d d=c c=b b=t i<32 f=(b&d) or (~d&c) g=(5*i+1)mod 16 i<48 f=b^c^d g=(3*i+5) mod 16 f=c^(~d or b) g=(7*i) mod 16 yes no yes no yes no yes no

以上计算由一个地方需要说明,就是给t赋值计算的时候,不考虑进位,每个数都是由32位二进制串表示,加的时候若有进位则进位丢失,得到的t也用32位二进制串表示。
以上数还有两个没有提到,k[i]和s[i]:

s[i]取值为以下数组的第i+1个数
{ 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 }
如s[0]==7,s[3]=22...

k[i]取值为以下数组的第i+1个数
{ 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 }

进行完这些运算后,A,B,C,D的值都获得了更新
A: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx [存储]
B: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx [存储]
C: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx [存储]
D: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx [存储]
把这四个数A -> B -> C -> D按照从低内存到高内存排列起来,共128位,这就是MD5算法的输出。

猜你喜欢

转载自blog.csdn.net/xuejianbest/article/details/80391237