对MD5散列密码的一些思考
《应用密码学 -算法、协议与C源码》是一本很好的密码学协议入门、科普书
作者并没有一开始就介绍算法的数学原理、算法如何工作这样的细节
而是从一开始就在说一个问题,使用什么算法,往往并不是最需要考量的,最需要考量的你使用这个算法的方式、方法、协议
所以作者其实一开始就一直在说密码学协议,我觉得这本书的精华部分也是这部分,很多东西我的语言组织能力很差,表述不好,大家自己去看。
那么对于MD5散列密码这个问题,我是这样思考的
1. 首先要明白,MD5设计之初,没有考虑过输入是纯ascii字符。ascii字符的最高位一定是0,不要和我说谁谁谁的密码都是中文什么什么的;然后考虑到可以从键盘输入的字符,其实并不到128个;然后从这两个前提条件,可以导出一个非常明显的猜想:
用MD5去做的密码的散列,在MD5的第一轮中,除掉padding,大约有1/8的输入位是可以预测的
这会对MD5本身带来多大的影响
2. 多轮MD5是否可以抵消1中提出的这个问题
大家稍微简单的看一下各种算法,现代密码算法基本都是由相似的轮组成的。
比如DES在设计之初,为什么是16轮。具体的细节论证我不知道,但是可以在《应》一书中直接看到结论,因为16轮的DES抗差分和线性分析是最强的。
至于3DES,看不同的实现方式(EEE方式),《应》一书中有一个最低的保守的结论:
a. 三次DES使用同一组密钥,安全性不高于单次DES
b. 三次DES使用两个密钥(EDE方式),安全性不低于单次DES
c. 三次DES使用三个密钥(任意方式),安全性不低于单次DES
为什么MD5选择的是16轮,也是有算法设计之初考量的。为什么不选择多余16轮或者少于16轮。我相信,是因为多余16轮的MD5并不比16轮更安全。
所以这,多重MD5应该并不比单重MD5在数学上更安全
然后我们抛开理论。实践中,我们是如何使用多重MD5的?
md5($m.$salt),得到的字符串再去MD5一次,然后如此往复
大家注意啊,注意啊,注意啊,是字符串再去MD5一次
还记得1中提出的这个问题么,ascii啊ascii啊ascii啊
其实,我们能做得更好,因为,md5散列后的字符串其实只是0-9a-f的超小的ascii合集
更可怕的是,长度是确定的,32位
这意味着什么
明文空间的高度可预测性,导致密文空间的极度塌缩
同时,稍微看过MD5实现的都知道,MD5初始化的时候有一个padding。
密文长度的确定,意味着,padding也是确定的,这导致在MD5的第一轮中,超过一半的输入是已知的(32个字节是上一次MD5的结果的字符表示,32个字节是完全已知的padding;且不论那32个字节其实只是0-9a-f;所以超过一半输入是已知的,这个结论是成立的。)
所以,有一个非常明显的猜想:
就算是要做到 @Knight 在 http://zone.wooyun.org/content/17741 中提到的
如果要用一个超级大硬盘硬盘秒破一重以上不带salt的MD5,根本用不到16EB的磁盘,何况我们还没考量到MD5的冲突率
3. 那正确的、或者我们能做的是什么
a. 希望科学家们,能设计一种设计之初就考虑了输入就是纯ascii的单向散列
b. 如果一定想用多次计算来增加攻击者的成本,应该这么做
i. 不要多次使用md5
ii. 在中间参杂几次一些超级慢的算法,rsa之类的,密钥泄露也不怕,要明白,我们的目的是拖时间,不是减弱安全性,所以用rsa之类的超级慢,又无可奈何的算法是一个很棒的想法。一次rsa抵得上几百次甚至几千次的散列
iii. 不要把散列结果用ascii引用送入下一次迭代;而应该把结果转化成一个超级大整数的ascii表示。虽然这样还是ascii,不过毕竟比直接送32位或者64位或者128位0-9a-f的ascii字符串强多了;好吧好吧,起码padding是不好预测的
c. md5其实是一个非常老的算法了,为什么不试试新的算法
==============
本来标题叫做“MD5散列密码不等于MD5的安全性”,但是扯到最后,觉得还是不要这么装逼吧
安全有时候不是一拍脑袋的事情,我们以为不存储明文就是安全了,其实后来出了cmd5;
那我们就加盐多次散列吧,其实呢,说不好这样反而可能更方便构造彩虹表。
末了,顺便问一句,大(wa)家(jue)抢(ji)到(ji)回(shu)家(na)票(jia)没(qiang)
——-
(GaRY编辑:因为加精华,也为了方便后续大家整理,修改了标题,内容未做改动。请xsjswt勿怪,如有需要可以自行修改回来。)