(注意hash有个更常见的名字,叫ha xi,下文统称散列)
如果你找到一个密码,形如:
72efc62e9931b55a60c876eb0f6aa9df
不要以为找错了,心想这什么人用这么变态的密码。
很多网站数据库里存的密码就长这样:这是一个散列。而且是md5散列算法计算出的散列。
散列函数可以把输入的任何数据计算成一个固定长度的数据。
比如
md5(摆烂) =72efc62e9931b55a60c876eb0f6aa9df
md5(摆大烂)=68042465b8de136879a9407cdf8ef986
散列函数有什么特性呢?
- 不可还原: 计算得出的结果不可还原。
- 唯一: 同样的输入会有同样的结果。但是只要略有不同,那么输出的散列也大不相同。所以也被称为”摘要“,”指纹“。
- 碰撞抵抗:因为输入有无穷多种可能,输出长度有限,理论上成熟的算法也会存在不同的输入得出一样的结果(概率很低,比如md5有128bit,也就是存在2的128次方种可能),但是从算法层面要防止人们利用算法缺陷构造出散列一样的输入。(md5就有这种问题)
还是晕的话我举一些应用的例子:
用作文件完整性校验:很多软件下载的页面会给出这个文件的checksum,其实就是把软件当作输入,算出其散列。对比散列我们就能知道我是否下载完整,或者这个软件有没有被人动过手脚。因为只要略有不同那么散列会完全不同。比如系统镜像就经常提供checksum检查系统有没有被篡改,但是你不可能直接根据几十字节的checksum还原出几个G的镜像。
同样,早期杀毒软件其实也是基于病毒样本的散列,计算并对比硬盘里的文件是否和样本库里的散列一致。
网站的数据库用这种方式存储密码,可以防止任何人接触到明文的密码。那怎么登录呢?
我们可以利用唯一性,我们只要再次计算比对用户输入的密码是否和数据库里的散列一致就可以了。若一致则密码正确。而服务器实际上无需得知用户输入的明文密码。其实这也是”零知识证明“。
虚拟货币所谓的挖矿其实也是在计算散列。
有人经常把计算hash的过程称为加密,比如md5加密,其实这不准确。因为这里既没有密钥,md5散列也不可还原。
有人要问,那么我md5是怎么还原成明文的?我看cmd5就能啊?其实cmd5是提前计算了大量的散列存下来,然后直接查找的。
重点提一下md5,md5是有缺陷的。虽然自然碰撞(输入不同但是计算结果相同)的概率很低,但是现在被发现可以被人为构造碰撞。因此用作文件校验并不合适。(有人可以给你下载的操作系统做手脚,但是算出来的md5一样,查不出异常)前缀构造法不破坏第二原像性,依旧可以校验文件。
另一方面,随着计算机算力提升,md5的运算速度很快,这意味着暴力破解的成本很低。甚至这些年的家用CPU让md5计算速度到了每秒几亿次。而显卡,彩虹表,FPGA有能让速度提高好几个数量级。
由此,数据库密码用md5算法处理后保存也不合适。
如果依旧想用md5存储密码的话,考虑加盐和胡椒,进行多次迭代。
更正一下,可实现的哈希碰撞其实指的是可以构造出两份同哈希的文件,然而在一个文件已经固定的情况下是(极其)不太可能找到另一个文件能够生成一样哈希的文件
md5的已被证明的缺陷,由王小云提出,指的是理论md5的碰撞几率和实际几率有出入。设计规范上来说,32位的哈希的碰撞几率应该是可被证明的1/2^128,但事实上并没有这么低
鸽巢原理
不过虽然没有这么完美的低,依旧还是很低的
我听说过md5有前缀碰撞法,但是没有去研究过它的原理。不过看应用是把一个已经固定的文件构造出了一个和它hash一样的文件。
对,指的是两个md5相同的文件/数据,两个文件的前缀相同。但是两个文件的后缀依旧不可控
因为对于32位hash,鸽巢原理,只要生成2^128+1个哈希一定保证有一次碰撞,这个性质对所有哈希算法都适用。但md5的缺陷使得人可以找到一对A B,这对数据的md5相同
我又回头看了一下前缀碰撞,你是对的。
因为我们依旧不能操作原像,因此md5依旧满足第二原像抗性。我以为是已经破坏了第二原像抗性所以举例有误。