MD5算法原理

什么是MD5算法

MD5讯息摘要演算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码杂凑函数,可以产生出一个128位元(16位元组)的散列值(hash value),用于确保信息传输完整一致。

MD5功能

输入任意长度的信息,经过处理,输出为128位的信息(数字指纹);
不同的输入得到的不同的结果(唯一性);

MD5属不属于加密算法

认为不属于的人是因为他们觉得不能从密文(散列值)反过来得到原文,即没有解密算法,所以这部分人认为MD5只能属于算法,不能称为加密算法;
认为属于的人是因为他们觉得经过MD5处理后看不到原文,即已经将原文加密,所以认为MD5属于加密算法;我个人支持前者,正如认为BASE64算法只能算编码一样。

MD5算法是否可逆?

MD5不可逆的原因是其是一种散列函数,使用的是hash算法,在计算过程中原文的部分信息是丢失了的。

不过有个地方值得指出的是,一个MD5理论上的确是可能对应无数多个原文的,因为MD5是有限多个的而原文可以是无数多个。比如主流使用的MD5将任意长度的“字节串映射为一个128bit的大整数。也就是一共有2^128种可能,大概是3.4*10^38,这个数字是有限多个的,而但是世界上可以被用来加密的原文则会有无数的可能性。

不过需要注意的一点是,尽量这是一个理论上的有限对无限,不过问题是这个无限在现实生活中并不完全成立,因为一方面现实中原文的长度往往是有限的(以常用的密码为例,一般人都在20位以内),另一方面目前想要发现两段原文对应同一个MD5(专业的说这叫杂凑冲撞)值非常困难,因此某种意义上来说,在一定范围内想构建MD5值与原文的一一对应关系是完全有可能的。所以对于MD5目前最有效的攻击方式就是彩虹表,具体详情你可以通过谷歌了解。

MD5相当于超损压缩。

MD5用途

1.防止被篡改:
1)比如发送一个电子文档,发送前,我先得到MD5的输出结果a。然后在对方收到电子文档后,对方也得到一个MD5的输出结果b。如果a与b一样就代表中途未被篡改。
2)比如我提供文件下载,为了防止不法分子在安装程序中添加木马,我可以在网站上公布由安装文件得到的MD5输出结果。
3)SVN在检测文件是否在CheckOut后被修改过,也是用到了MD5.

2.防止直接看到明文:
现在很多网站在数据库存储用户的密码的时候都是存储用户密码的MD5值。这样就算不法分子得到数据库的用户密码的MD5值,也无法知道用户的密码。(比如在UNIX系统中用户的密码就是以MD5(或其它类似的算法)经加密后存储在文件系统中。当用户登录的时候,系统把用户输入的密码计算成MD5值,然后再去和保存在文件系统中的MD5值进行比较,进而确定输入的密码是否正确。通过这样的步骤,系统在并不知道用户密码的明码的情况下就可以确定用户登录系统的合法性。这不但可以避免用户的密码被具有系统管理员权限的用户知道,而且还在一定程度上增加了密码被破解的难度。)

3.防止抵赖(数字签名):
这需要一个第三方认证机构。例如A写了一个文件,认证机构对此文件用MD5算法产生摘要信息并做好记录。若以后A说这文件不是他写的,权威机构只需对此文件重新产生摘要信息,然后跟记录在册的摘要信息进行比对,相同的话,就证明是A写的了。这就是所谓的“数字签名”。

MD5安全性

普遍认为MD5是很安全,因为暴力破解的时间是一般人无法接受的。实际上如果把用户的密码MD5处理后再存储到数据库,其实是很不安全的。因为用户的密码是比较短的,而且很多用户的密码都使用生日,手机号码,身份证号码,电话号码等等。或者使用常用的一些吉利的数字,或者某个英文单词。如果我把常用的密码先MD5处理,把数据存储起来,然后再跟你的MD5结果匹配,这时我就有可能得到明文。比如某个MD5破解网站http://www.cmd5.com/default.aspx,所以现在大多数网站密码的策略是强制要求用户使用数字大小写字母的组合的方式提高用户密码的安全度。

MD5实现

  • 十进制是逢十进一
  • 二进制是逢二进一
  • 十六进制是逢十六进一

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

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

 

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

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

任何计算机文件都是可以看作一串二进制位。
例如:一个最普通的内容为hello的ASCII文本文件,在计算机中的存储是这样的:

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

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位):

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相等
 

以上计算由一个地方需要说明,就是给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算法的输出。
 


来自博客:

https://blog.csdn.net/u012611878/article/details/54000607

https://blog.csdn.net/xuejianbest/article/details/80391237

 

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 终极编程指南 设计师:CSDN官方博客 返回首页