赞
踩
进制数 | 零 | 一 | 二 | 三 | 四 | 五 | 六 | 七 | 八 | 九 | 十 | 十一 | 十二 | 十三 | 十四 | 十五 | 十六 | … |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
十进制 | 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”,在内存中的存储是一样的。)
我们先用一个例子来过一下这个过程,然后用文字描述算法细节。
比如加密一个普通的内容为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位):
01101000 01100101 01101100 01101100 01101111 1 (407个0)00101000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [存储]
第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相等
以上计算由一个地方需要说明,就是给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算法的输出。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。