1、Hash 算法分类
MD5 和 SHA-1 是目前应用最广泛的 Hash 算法且是以 MD4 算法为基础设计的。
1) MD4
MD4(RFC 1320) 是 MIT 的 Ronald L. Rivest 在 1990 年设计的,MD 是 Message Digest 的缩写。
它适用在 32 位字长的处理器上用快速软件实现,是基于 32 位操作数的位操作来实现的。
2) MD5 - message-digest algorithm 5(信息-摘要算法)
MD5(RFC 1321) 是 Rivest 于 1991 年对 MD4 的改进版本号。
它对输入仍以 512 位分组,其输出是 4 个 32 位字的级联,与 MD4 一样。
MD5 比 MD4 得复杂,而且速度较之要慢一点,但更安全,在抗分析和抗差分方面表现更好。
被广泛用于加密和解密技术上,它可以说是文件的“数字指纹”。
任何一个文件,无论是可执行程序、图像文件、临时文件或者其他任何类型的文件,也不管它体积多大,都有且只有一个独一无二的 MD5 信息值,并且如果这个文件被修改过,它的 MD5 值也将随之改变。
因此,我们可以通过对比同一文件的 MD5 值,来校验这个文件是否被“篡改”过。
3) SHA-1
SHA1 是由 NIST NSA 设计为同 DSA 一起使用的,它对长度小于 264 的输入,产生长度为 160bit 的散列值,因此抗穷举(brute-force)性更好。
SHA-1 的设计也是基于 MD4 算法。
2、Hash 算法用途
Hash 算法在信息安全方面的应用主要分为三个方面:
1) 文件校验
通常使用的校验算法有奇偶校验和 CRC 校验,这 2 种校验并没有抗数据篡改的能力,它们一定程度上能检测并纠正传输数据中的信道误码,但却不能防止对数据的恶意破坏。
MD5 Hash 算法的"数字指纹"特性,使它成为眼下应用最广泛的一种文件完整性校验和(Checksum)算法,不少 Unix 系统有提供计算 md5 checksum 的命令。
2) 数字签名
Hash 算法也是现代 password 体系中的一个重要组成部分。
因为非对称算法的运算速度较慢,所以在数字签名协议中,单向散列函数扮演了一个重要的角色,对 Hash 值,又称"数字摘要"进行数字签名。
3) 鉴权协议
例如以下的鉴权协议又被称作挑战 -- 认证模式:
在传输信道是可被侦听,但不可被篡改的情况下,这是一种简单而安全的方法。
4)文件 Hash 值
MD5-Hash 文件的数字文摘通过 Hash 函数计算得到。
无论文件长度怎样,它的 Hash 函数计算结果是一个固定长度的数字。
与加密算法不同,Hash 算法是一个不可逆的单向函数。
以 Hash MD5 为例:
MD5 以 512 位分组来处理输入的信息,且每一分组又被划分为 16 个 32 位子分组,经过了一系列的处理后,算法的输出由四个 32 位分组组成,将这四个 32 位分组级联后将生成一个 128 位散列值,就是说任意长度的二进制数据经过 md5 加密算法的计算,将会得到一个 128 位的二进制数一般转为 32 位 16 进制数来表示。
原文不相同算出的 MD5 一定不相同,原文相同算出 MD5 一定相同。
只能从原文算成密文,密文永远也算不回原文。
算法具有以下特点:
1) 压缩性:任意长度的数据,算出的 MD5 值长度都是固定的;
2) 容易计算:从原数据计算出 MD5 值很容易;
3) 抗修改性:对原数据进行任何改动,哪怕只修改 1 个字节,所得到的 MD5 值都有很大区别;
4) 弱抗碰撞:已知原数据和其 MD5 值,想找到一个具有相同 MD5 值的数据(即伪造数据)是非常困难的;
5) 强抗碰撞:想找到两个不同的数据,使它们具有相同的 MD5 值,是非常困难的。
3、Hash 算法 MD5 原理
3.1、填充数据
在 MD5 算法中,首先需要对信息进行填充,使其位长对 512 求余的结果等于 448,并且填充必须进行,即使其位长对 512 求余的结果等于 448。
因此,信息的位长(Bits Length)将被扩展至 N*512 + 448,N 为一个非负整数,N 可以是零。
填充的方法如下:
1) 在信息的后面填充一个 1 和无数个 0,直到满足上面的条件时才停止用 0 对信息的填充;
2) 在这个结果后面附加一个以 64 位二进制表示的填充前信息长度(单位为 Bit),如果二进制表示的填充前信息长度超过 64 位,则取低 64 位;
3)经过以上两步的处理,信息的位长 = N*512+448+64=(N+1)*512,即长度恰好是 512 的整数倍,这样做的原因是为满足后面处理中对信息长度的要求。
3.2、初始化变量
初始的 128 位值为初试链接变量,这些参数用于第一轮的运算,以大端字节序来表示,他们分别为:
A=0x01234567,B=0x89ABCDEF,C=0xFEDCBA98,D=0x76543210
每一个变量给出的数值是高字节存于内存低地址,低字节存于内存高地址,即大端字节序。
在程序中变量 A、B、C、D 的值分别为 0x67452301,0xEFCDAB89,0x98BADCFE,0x10325476。
3.3、处理分组数据
每一分组的算法流程如下:
第一分组需要将上面四个链接变量复制到另外四个变量中:
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 中之一。
以下是每次操作中用到的四个非线性函数(每轮一个):
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) )
& = And,| = Or,~ = Not,^ = Xor
这四个函数的说明:
如果 X、Y 和 Z 的对应位是独立和均匀的,那么结果的每一位也应是独立和均匀的。
F 是一个逐位运算的函数,即,如果 X,那么 Y,否则 Z。
函数 H 是逐位奇偶操作符。
假设 Mj 表示消息的第 j 个子分组(从 0 到 15),常数 ti 是 4294967296*abs( sin(i) )的整数部分,i 取值从1到64,单位是弧度。
(4294967296=232)现定义:
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 )
所有这些完成之后,将 a、b、c、d 分别在原来基础上再加上 A、B、C、D。
即 a = a + A,b = b + B,c = c + C,d = d + D
然后用下一分组数据继续运行以上算法。
3.4、算法输出
最后的输出是 a、b、c 和 d 的级联。
按照上面所说的方法实现 MD5 算法以后,可以用以下几个信息对你做出来的程序作一个简单的测试:
MD5 ("") = d41d8cd98f00b204e9800998ecf8427e
MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661
MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72
MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0
MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b
MD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz") =
f29939a25efabaef3b87e2cbfe641315
MD5 ("8a683566bcc7801226b3d8b0cf35fd97") =cf2cb5c89c5e5eeebef4a76becddfcfd
3.5、MD5 加密字符串实例
现以字符串“jklmn”为例。
该字符串在内存中表示为:6A 6B 6C 6D 6E(从左到右为低地址到高地址),信息长度为 40 bits, 即 0x28。
对其填充,填充至 448 位,即 56 字节,结果为:
6A 6B 6C 6D 6E 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
剩下 64 位,即 8 字节填充填充前信息位长,按小端字节序填充剩下的 8 字节,结果为:
6A 6B 6C 6D 6E 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 28 00 00 00 00 00 00 00
初始化 A、B、C、D 四个变量。
将这 64 字节填充后数据分成 16个小组(程序中对应为16个数组),即:
M0:6A 6B 6C 6D (这是内存中的顺序,按照小端字节序原则,对应数组M(0)的值为0x6D6C6B6A)
M1:6E 80 00 00
M2:00 00 00 00
.....
M14:28 00 00 00
M15:00 00 00 00
经过“3. 分组数据处理”后,a、b、c、d 值分别为 0xD8523F60、0x837E0144、0x517726CA、0x1BB6E5FE
在内存中为 a:60 3F 52 D8
b:44 01 7E 83
c:CA 26 77 51
d:FE E5 B6 1B
a、b、c、d 按内存顺序输出即为最终结果:603F52D844017E83CA267751FEE5B61B。这就是字符串 “jklmn” 的MD5值。
大多数公司数据库的密码都是这么保存的,在一定程度上保证了用户信息的安全,但这种密码是找不回来的,一旦忘记就需要重置密码。
refer:
https://blog.csdn.net/sinat_32176313/article/details/49401615
https://www.cnblogs.com/mengfanrong/p/4034950.html