对MD5散列密码的一些思考

xsjswt | 2015-01-08 10:00

《应用密码学 -算法、协议与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勿怪,如有需要可以自行修改回来。)