在介绍MD5原理前,先说一些计算机基础知识。
1.数组
数组是计算机存储数据最原始的一种数据类型。在日常生活照经常会遇到。考虑如下一种情况:
A班级有13个学生,假设每个学生都有一个学号,为了方便说明,我们用0,1,2,3...12 对这13个学生进行编号。
这其实就是一个最简单的数组,如下图
如果我们用C#实现伪代码,类似如下:
这样,如果需要获取“学生5”的信息,直接用数组下标 students[5] 即可获得学生信息。
2.数据映射
在上面,利用数组存储学生是好的,但是有缺陷,因为数组是从0开始的,如果班级里有4个学生,为6,7,9,12,可以看到学号不是从0开始,而且又不连续,
为了存储四个学生,仍然需要开辟13个存储空间,这导致大量的空间被浪费。
为此,可以采用算法压缩空间。最容易想到的是取余数。
6,7,9,12共4个数,也就意味着最多只要4个空间,所以,利用除法求余数计算位置。
我们小学学过的 6除以4等于1余2,写成6÷4=1...2,在计算机里通常使用/表示除法,用%表示求余数),所以可以得到
6%4=2 7%4=3 9%4=1 12%4=0
这样,可以认为学生学号x通过一个简单的函数y=f(x)映射转换,就转换为存储位置。
3.不可逆
在上面映射里,你可能发现数据是可能冲突的,例如学生7和学生11经过求余
7%4=3 11%4=3
两个不同的学生经过映射后,得到了同一个数字3,所以,根据3你推导不出学生的学号是7还是11.
更通俗的解释为:a=2,b=8,那么 a+b=10,但是给你10,你推导不出a=2,b=8。因为a,b可以有很多种组合。
在MD5加密里,经常听到MD5是一种不可逆算法,如果我们把上面例子中,学生学号理解为密码的明文,存储地址理解为MD5加密的密文,就可能出现:
MD5(123456)=e10adc3949ba59abbe56e057f20f883e MD5(abcdef)=e10adc3949ba59abbe56e057f20f883e
123456和abcdef 加密后,其密文一样。
再想象一种情况:一个网站宣传说用户登录网站时,密码采用了MD5加密。这表示网站是把你的密码加密后存放到SQL数据库里。万一有一天黑客下载到了SQL数据库, 他可能看到
张三 e10adc3949ba59abbe56e057f20f883e 男 18岁 李四 e10adc3949ba59abbe56e057f20f883e 男 20岁
这样黑客虽然下载了数据库,但是仍然看不到用户的密码。可以最大限度减少用户的损失。
这很重要,因为很多用户怕麻烦,他们的密码设置都是一样的,你登录QQ的密码通常和你登录邮件的密码是一样的。 你的工行银行取款密码可能和农行取款密码也是一样的!
3.哈希表
在上面介绍里,使用学生号作为学生编号,但是,这种编号不容易人的读取,一个最好的方式是使用“学生姓名”作为学生编号的标志。这种“键-值”模式就是哈希表最原始的方式。
哈希表其实是Hash的音译过来的。
假如对学生信息进行存储时,采用的Hash函数为:姓名的每个字的拼音开头大写字母的ASCII码之和。
Hash(张三)=ASCII(Z)+ASCII(S)=90+83=173; Hash(李四)=ASCII(L)+ASCII(S)=76+83=159; Hash(王五)=ASCII(W)+ASCII(W)=87+87=174; Hash(张帅)=ASCII(Z)+ASCII(S)=90+83=173;
当然,这种设计可能会有冲突, 例如张三和张帅的Hash值都是174,所以在构造Hash函数时应尽量考虑关键字的分布特点来避免冲突。
哈希函数也被成为散列函数。
4.MD5算法
MD5消息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码哈希函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。
这段话来自百科给的定义,文字很短,但是你一看到MD5的定义是:Hash函数、散列值基本上也就大致了解了MD5的意思了。
关于MD5的详细算法很复杂,详细见网上百科介绍。这里,我们可以自己定义一个自定义的MD5算法:
(1)姓名拼音的首字母 (2)取首字母的ASCII码 (3)对ASCII 使用100求余。 (4)因为余数在0-99之间,要求余数必须是2位数字,如果不够2位,则前面补0.
现在利用上面的1-4条,给你一个汉字“张”,和给你一段文本“今天是周几”你都可以生成自定义的MD5,而且,不管是1个字还是100个字,其最终生成的密码都是2位。
这就是MD5的压缩性
任意长度的数据,其MD5值都固定是一个32位长度的十六进制字符串。
你能详细出,全世界的文字是无限的,而32位固定长度能存放的信息是有线的,所以,这就说MD5力量上是可以破解的。
5.MD5的作用
对原数据做一丁点的改动,MD5值就会有巨大的变动,利用这个特性,可以对数据进行保护。
例如:你编写了一个软件让用户可以下载。此时,你可以用“姓名+最后修改时间”作为MD5的明文进行加密,然后把MD5公开。
假如黑客获取了你的软件并且修改他,这就会导致最后修改时间的改变,只要数据有一点点变动,MD5就会出现巨大波动。
当你最终客户下载软件后,可以比较MD5,看看软件本身的MD5和公布的MD5是否一样,如果不一样,就表示数据被修改过。
在很多网站里,都会提供MD5,下图显示的是Android Studio下载的页面,其旁边提供有MD5值
当你下载好软件后,可以在右键-属性-数字签名-高级 里看到其值。
备注:下面显示的sha256加密,其作用和MD5一样。
6.密码对撞
虽然根据MD5无法推算出明文,但是黑客可以利用数据字典对撞破解密码。什么意思呢?
我们以常规的密码为例: 10个数字加上26个大小写字母,考虑密码是区分大小写的,一共是 62个字符。
这样,你登录QQ,假设你的密码为1位,那么总共只有62种可能,黑客通过MD5算把这62个情况都存储起来:
1 c4ca4238a0b923820dcc509a6f75849b 2 c81e728d9d4c2f636f067f89cc14862c 3 eccbc87e4b5ce2fe28308fd9f2a7baf3 ... Z 21c2e59531c8710156d34a3c30ac81d5
如前面所述,当黑客获取你数据库里加密后的MD5后,他只要把你MD5密文和他的数据字典比较,就能获取你的密码明文。
获取明文后,他就可以登录你的QQ,登录你的邮箱,像你的好友要钱等等。
也正因为此,很多系统在设计时,通常有3个要求:(1)密码至少6位 (2)密码至少包含字母,数字,特殊字符 (3)登录次数有限制,例如你登录超过3次,系统自动锁定你的账户,禁止你再登录。通过这3个办法,防止黑客破解你的系统。
因为,我们使用的密码都是英文,很多用户都喜欢用英语单词作为密码,熟不知英语词典的那些单词的MD5都被黑客算出来了,所以,设置自己密码时,应该要包含字母和数字。
过去曾经认为MD5是不可破解的,但是一方面随着超级计算机运算速度越来越快,例如2018年最新公布的中国太湖之光计算机,每秒运算一千万亿次,已经有科学院成功破解了MD5,所以,对于保密性极强的系统,已经不采用MD5加密了,而采用安全性更高的sha256加密。但是对于普通小型网站,从运算性能和安全综合考量,仍多采用MD5加密。
7.密码加盐
在有些系统里,例如ATM取款机,其密码限制了只能使用0-9这10个数字,安全性降低了,为了提高安全,可以对密码进行加盐。
秘密加盐可以见到理解为对密码二次加密。
因为ATM初始密码只能是0-9这10个数字,假如一个ATM取款密码是123456,通过一个函数salt()对明文进行简单加密,例如 salt(123456)=12!3ad。 然后再对加盐后的密码加密成MD5。 MD5(12!3ad)=e21bc87e4b5ce2fe2830w348fd9f2a7b,最后再把这个MD5存放到数据库。
加盐的主要目的,是让密码更难破解。