精英盒子 -> 程序设计 -> 加密系列2:散列算法 [打印本页]

jybox 2012-05-19 03:58

加密系列2:散列算法


散列算法


又叫: 单向加密散列算法HASH(哈希)函数摘要算法

举个栗子


让我们来设想这样的一个场景,在教室中,你和同桌在聊天,周围也都是同学.
你向来对你的银行卡密码严格保密(围观群众:废话),没有人知道,但是你的同桌突然告诉你,他知道你的银行卡密码.
你很慌张,急于确认对方是否真的知道,但周围又都是同学,不能让同桌直接说出来,怎么办呢?


你也许想到,问他“我的银行卡密码最后一位是多少?”
但是呢,如果你的同桌其实不知道你的密码,却蒙对了怎么办,十个数字蒙对一个还是有可能的.
又如果,你的同桌真的说对了,于是周围同学都知道了你的密码的最后一位,你的银行卡密码的安全性一下子下降了若干倍.


其实问题很好解决,你可以问他“我的银行卡密码六个数字相乘在一起是多少?”
这样,你的同桌一通猛算之后报出了答案,你也一通猛算,知道了同桌到底知不知道你的密码.
这样一来,你的同桌必须知道密码中所有的六位数字,才能算出答案.
而你周围的同学,却无法通过这个答案推算出你的密码.

散列函数


我们来思考一下为什么周围的同学无法通过这个结果,推算出的密码.
因为一个数字,可以是多组数字的乘积,例如你同桌报出的答案是5040,那么你的银行卡密码有可能是257463,也可能是422957,还可能是524297...总之,可能性有成千上万种.所以其他人不可能通过这个结果推算出银行卡密码.


当然,我上面的这种方法也有漏洞,虽然无法直接由结果推算出密码,但是却限制了可能的密码的范围,本质上和说出密码最后一位没太大区别.


于是,数学家出现了,他们通过严谨的数学方法创造了一些十分可靠的散列算法,例如比较常见的MD5SHA系列 等等.
例如MD5,这种算法可以由任意长的数据,算出一个32位的散列值 .

下面是几组字符串和对应的散列值
散列函数主要有MD5、SHA系列                  ffcab6ac050c7015de2fc630ca295d8a
MD5                                                            7f138a09169b250e9dcb378140907378
MD5即Message-Digest Algorithm 5             dfd59ae55e55a50dcd6f71e15ed01cd9
MD5即Message-Digest Algorithm               5e7b52ed19e4f7bc429819bc74c85942

可以看到,明文和散列值没有任何规律性可言,这点是经过严格的数学证明的(但是后来的数学家也发现了一些漏洞,我们在后文再讨论这个).

请对比第三条和第四条,即使明文仅仅相差了一个数字,形成的散列值也完全不同了.

性质


再次总结散列函数的性质,散列函数可以将任意长度的数据(明文),生成一个固定长度的散列值.
由于明文的长度是无限的,所以明文的可能性也是无限的,但散列值的长度有限、可能性有限.
所以一个散列值会对应无数个明文.


所以呢,也有可能出现数据明明不同,但却生成了同样的散列值的情况,这种情况被称为散列碰撞 .
散列碰撞是不可避免的,但一个优秀的散列算法应该保证无法(或极其困难)人为构造一个散列碰撞.


所以我们可以认为,一个优秀的散列算法,应该具备以下的性质:

  • 可以将任意长度的数据生成固定长度的散列值,这个散列值可以视为是随机且不可预测的.
  • 同样的数据会生成同样的散列值,不同的数据(即使是很细微的不同)在一定范围内(因为必定会重复嘛)生成不同的散列值.
  • 无法(或极其困难)从散列值计算出明文,无法(或极其困难)人为地构造散列碰撞.




应用



检查数据完整性/真实性


这是散列算法重要的作用之一.
你经常可以看到,在下载软件(游戏)时,网站上都会有类似下面的标语

请用MD5校验工具校验下载到的文件的MD5值,最新客户端的MD5值为xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.


这么做,有两方面目的,一是可以帮助用户判断文件有没有损坏.另一方面是防止用户下载到一些经过黑客修改过的软件.


这就利用了散列算法对同一数据生成同样的散列值,不同数据生成不同的散列值这一性质.

当然,MD5目前已经被发现了一些漏洞,我们在后文探讨.

证明自己拥有数据


这是开头的那个例子的情况.
A知道一些数据,它要向B证明自己知道这些数据,但是出于某些原因,比如:
  • 有其他人在窃听,不能直接传输数据.
  • 这份数据非常大,传输起来非常耗时.

这时A就可以通过散列算法,将这些数据计算出一个散列值,发给B.
B用同样的散列算法计算出这些数据的散列值,和A发来的散列值进行对比,如果一样,则说明A确实拥有这些数据.

防止逆向算出明文


(在目前的大多数网站中)当你注册一个用户的时候,程序会将你设置的密码通过散列算法计算出散列值,保存在数据库中,而不会储存你的明文密码.
当你登录的时候,程序会用同样的散列算法计算出你输入的密码的散列值,和数据库中的散列值进行对比,如果相同,则说明你密码输入正确.


为什么要这样呢?因为事实上,网站并不关心你设置了什么样的密码,它只关心你密码输入的是否正确.
不可避免地,网站也有数据失窃的时候,如果在数据库中储存的是明文的密码,那么得到数据的人便可以随意登录任意用户的帐号了.
而如果数据库中储存的是散列值,那么得到数据的人就没办法了——因为登录时要求你输入的是密码,而不是散列值,而从散列值是无法算出密码的!


我还得废话一句,某些情况下是可以通过一些手段来获得散列值对应的明文的,我们在后文讨论.

标识数据


比如我们在使用迅雷下载文件的时候,迅雷会在它的用户中寻找正在下载同样的文件的用户,互相上传来加快速度.
但是迅雷怎么就知道你们下载的是同一个文件呢?大部分时候,一个文件的文件名在不同的地方都是不一样的啊.


你当然能够猜到,用散列算法呗,同样的数据的散列值是相同的.迅雷通过散列值来表示一个文件,而不是通过文件名.


这样的情况还有很多,例如在QQ上,别人给你发了一张图片,QQ会先发送这个图片的散列值.
然后你的QQ会先在本地找,看看以前收到过这张图片没有,如果有的话就不必传输图片了,没有的话才开始传输这个图片.

表达诚意


如果你有一些计算机基础的话,对前面提到的几点一定不会陌生,但看到这个小标题,你一定傻了——表达诚意是毛啊?


如果你每天收到大量的垃圾邮件,你表示灰常无奈,你需要发信人对你表示出诚意,否则你就不接收.
那么你可以要求发信人发信的时候,带上一段“表达诚意的数据”,使得整封邮件(以及发信时间等信息)加上这段数据后,散列的结果的前N位为0.


因为在散列之前,我们不知道一个明文对应怎样的散列值,所以要得到这个附加到邮件上后,能使得散列的结果前N位为0的数据可谓十分困难.
唯一的办法就是反复更换不同的数据,来进行试验,直到达到要求(前N位为0).
如果N等于6的话,平均需要试验1700万次才能得到这个满足要求的数据,这在一般的计算机上大概需要花费几分钟的时间.


如果发信人真的有诚意,是不会在乎这么几分钟的时间的,而群发广告的家伙却不会有这个诚意——这样的话,他们每天恐怕只能发几百封广告...


PS.这项技术被称为hashcash,但是目前应用并不广泛.

针对散列算法的攻击



通过散列值计算明文


如前面表达诚意一节所说,唯一的办法就是反复试验,直到达到结果为止.
对于网站的登录密码来说,一般密码都在16位以下,甚至10位以下,攻击者可以将这个范围内所有的组合都计算一遍,如果发现哪个密码组合(明文)的散列值和目标散列值一样,那么就说明这个散列值对应这个明文.


事实上现在有很多网站提供这样的在线查询服务.


当然,这种暴力地穷举,也只能对一些比较短小的数据有效.较长的数据,因为组合实在太多样,所以穷举无能为力.

防范穷举


对于用户来说,可以提高密码的复杂度,让攻击者放弃攻击.
例如你的密码有16位,但是攻击者只试验完了10位的密码的组合就放弃了.


对于开发者来说,可以通过在散列算法中加入salt(佐料)来人为地提高穷举的难度.
例如,以前的散列算法是MD5(密码) ,这样在密码很短的情况下很容易被穷举成功.
你可以修改为MD5(用户名+MD5(密码)),这样,被散列的内容被人为地提高到了32个字符或者更多,极大地增加了穷举的难度.


在散列算法中嵌入例如用户名这样的干扰数据,还有一些好处.那就是如果攻击者掌握了整个网站的数据库,那么攻击者不得不为每个用户单独进行一次穷举.
因为有用户名的加入,不同的用户即使密码一样,散列值也不一样,所以攻击者不得不为每个用户单独进行一次穷举.

MD5的碰撞


早在2004年,中国的一位数学家王小云就研究出了人为构造MD5碰撞的方法.


通过这种方法,可以在比较短(至少比穷举短)的时间内,创造一段指定MD5的数据.
可以让经过修改的文件保持原来的MD5值,从而进行恶意攻击等行为.


值得注意的一点,这只是MD5的漏洞,只能说MD5目前不再是一个优秀的散列算法了.  

在此建议使用SHA系列的散列算法,目前该算法还没有发现明显的漏洞,是比较安全的.



jybox 2012-05-19 04:00
怎么排版这么乱啊,我是在MaDe写的....

laoyis 2012-05-19 23:19
挽尊

scxy 2012-05-20 11:29
laoyis:挽尊 (2012-05-19 23:19) 

scxyscxy和scxy都是我...scxyscxy是以前的账号,现在换这个了,别2个都@...

cu2s 2012-05-21 20:49
不错~~~~~~~




Powered by phpwind v8.7 Code ©2003-2011 phpwind
Time 0.040875 second(s),query:5 Gzip enabled