散列函数的应用及其安全性
一、散列函数的具体应用
HASH函数必须具备两个基本特征:单向性 和 碰撞约束。
单向性是指:操作方向的不可逆性,在HASH函数中是指 只能从输入推导出输出,而不能从输出计算出输入。
碰撞约束是指:不能找到一个输入使其输出结果等于一个已知的输出结果或者不能同时找到两个不同的输入使其输出结果完全一致。
一个函数只用同时严格的具备了这样的特性,我们才能认可这样的一个HASH。
目前常用的HASH函数主要有两个系列,MD 和 SHA系列。MD系列主要包括 MD2,MD4,MD5,不幸的是这一系列的hash函数都已经被证实是不够安全的了.SHA系列正是因此而生,其包含SHA1 和 SHA2(SHA224, SAH256, SHA384,SHA512)系列。其中224,256,384,512都是指其输出的位长度,而SHA1是160位长(注意我们应该避免使用SHA0,那是SHA的初始版本,后来经过调整,升级为SHA0,我们在使用的时候应该使用SHA1).
HASH的应用:
数据校验
HASH函数有类似数据冗余校验类似的功能,但是它比简单的冗余校验碰撞的概率要小得多,顾而在现在密码学中总是用HASH来做关键数据的验证。
单向性的运用
利用HASH函数的这个特点,我们能够实现口令,密码等安全数据的安全存储。密码等很多关键数据我们需要在数据库中存储,但是在实际运用的过程中,只是作比较操作,顾而我们可以比较HASH结果。这一点相信在银行等系统中有所运用,否则我们真的要睡不着觉了:)
碰撞约束以及有限固定摘要长度
数字签名正是运用了这些特点来提高效率的。我们知道非对称加密算法速度较低,通过HASH处理我们可以使其仅仅作用于HASH摘要上,从而提高效率。
可以运用HASH到随机数的生成和密码,salt值等的衍生中
因为HASH算法能够最大限度的保证其唯一性,故而可以运用到关键数据的衍生中(从一个随机的种子数产生,并且不暴露种子本身秘密)。
二、散列函数的安全性以及目前安全散列函数的发展。
抗碰撞性:抗碰撞性(Collision-Resistant):找出任意两个不同的x,x' \in X,使得h(x)=h(x')是困难的(计算不可行);也称强抗碰撞性(Strong Collision-Resistant )。相对的,也有弱抗碰撞性(Weak Collision-Resistant )这个概念。
弱抗碰撞性:当给定某条消息的散列值时,单向散列函数必须确保要找到和该条消息具有相同散列值的另外一条消息是非常困难的。
生日攻击(Birthday Attack):
生日悖论(Birthday paradox):生日悖论是指,如果一个房间里有23个或23个以上的人,那么至少有两个人的生日相同的概率要大于50%。这就意味着在一个典型的标准小学班级(30人)中,存在两人生日相同的可能性更高。对于60或者更多的人,这种概率要大于99%。从引起逻辑矛盾的角度来说生日悖论并不是一种悖论,从这个数学事实与一般直觉相抵触的意义上,它才称得上是一个悖论。大多数人会认为,23人中有2人生日相同的概率应该远远小于50%。
在考虑所有人的生日都是独立均匀随机分布在365内的话,
![\bar p(n) = 1 \cdot \left(1-\frac{1}{365}\right) \cdot \left(1-\frac{2}{365}\right) \cdots \left(1-\frac{n-1}{365}\right) =\frac{364}{365} \cdot \frac{363}{365} \cdot \frac{362}{365} \cdots \frac{365-n+1}{365}](https://i-blog.csdnimg.cn/blog_migrate/e43b246261930269cefea0eef4a07714.png)
![{ 365! \over 365^n (365-n)! }](https://i-blog.csdnimg.cn/blog_migrate/92065bc09740072f068fd3554f908459.png)
生日攻击原理:
由此我们可以将它用在碰撞,得到不同Message有着相同tag。
假设:取样次数为N,M:M1-Mn,取值在tag:1-B中,并且假设分布随机均匀相互独立。
取样次数n与B的关系,n=1.2*B^0.5(这是生日悖论中最坏的情况。)
证明:M2不等于M1的概率为(B-1)/B,同理可得M3为(B-2)/B,M4为(B-3)/B...Mn为(B-n+1)/B。
因此,其中有碰撞的概率为:1-(1-1/B)(1-2/B).....(1-(k-1)/B)>= (1-e)^(-n^2/2B)
因为n=1.2*B^0.5,因此(1-e)^(-n^2/2B)=1-e^-0.72=0.53>50%
结论,因此使用生日攻击,我们只需2^(n/2)次寻找,就有50%概率能找到相同tag的两个不同Message。
步骤:
1.随机在2^(n/2)信息空间中寻找一个M
2.求出相应的tag
3.寻找是否有碰撞,没有则返回步骤1
破解时间:
理论上而言,若抗碰撞性一直为2^n,而强抗碰撞性因为生日攻击的原因会降至2^(n/2)时间。
![](https://i-blog.csdnimg.cn/blog_migrate/3e88e0f6dc5ee042b7e593c6cd4e5d1d.png)
由此可见,SHA-1已经越来越不安全了,数月或者数年后,2^80将不是一个无法逾越的计算时间。另外,因为计算机多为伪随机,因此现在SHA-1理论上所需的抗碰撞时间仅为2^55时间,但好像并没有人去证实过。
安全散列函数结构:
因为所需的安全散列长度越来越长,因此我们可以使用有限定义域上的散列函数(俗称压缩函数)通过迭代方式拓展为具有无限定义域的散列函数。而最为代表性的就Merkle-Damgard结构
Merkle-Damgard结构:
![](https://i-blog.csdnimg.cn/blog_migrate/a195b4428fd8b8b4bbce9745543c709a.png)
这个结构的好处是,如果压缩函数是抗碰撞的,那经过此结构处理后的散列函数也是抗碰撞的。
MD5算法:
两个不同的输入M和M’,但其Hash值一样,我们就称之为碰撞。
本质上,对于任何一个哈希函数来说,碰撞是无可避免的,从一个规模较大的集合映射到一个规模较小的集合,必然会存在相同映射的情况。所以,对Hash函数而言,应该具有的特性是碰撞阻力,而并非避免碰撞。即,这个碰撞很困难,在实践过程中难以发生。
隐秘性指的是,找不到一种算法,能够由MD5值反推出输入M。换句话说,Hash函数是不可逆的。
MD5算法首先会将原始消息按512bit进行分组,那么最后一组很大概率是不到512bit的,这时候会对最后一组进行补齐,即补满512bit。这个过程称为padding。padding的规则是,在最末一个字节之后补充0x80,其余的部分填充为0x00,padding最后的8字节用来表示需要哈希的消息长度。
非加密hash函数以一个字符串为输入,计算出一个整数作为输出。Hash函数的一个喜人地方是,输出的整数均匀的分布在输出域空间里,即使是对于相似的输入。与加密hash函数不同,非加密hash函数并不要求能抵挡利用碰撞进行的hacker攻击。加密hash函数则有这方面的要求(抵抗碰撞),但是碰撞速率非常慢:SHA-1大约是0.09 bytes/cycle,而最新的非加密hash函数的碰撞率大约为3bytes/cycle。所以在抵御攻击的能力上,破解非加密hash比加密hash大约快33倍。所以非加密hash主要还是用作hash表。
作为有趣的一点,Lua社区目前有一个争论:如果可以的话,当Lua的 hash函数被攻击使得它的hash table 的实现被迫进入O(n)复杂度的最差性能时,该怎么办。例如攻击者不断的传数据给Lua,而Lua则把这些数据放到Lua的hash table里,这样就达到了Dos攻击的目的。Lua的作者有些怀疑这种攻击的现实性(这种Dos攻击是否会比其它的Dos攻击代价小),不过不管怎样他还是计划在hash函数启动时加入随机种子。对于加密hash函数,这也是一种令人感兴趣的可选的增加碰撞难度的方法,但代价是输出不可重现。
三、说明md5算法在验证软件完整性时可能出现的问题。
1、由于可以构造出MD5值相同的软件,黑客会通过构造MD5相同的软件以此来躲避安全软件对恶意程序的查杀。
2、无法保证文件的完整性和正确性。
3、如果将加密的md5值直接保存在数据库,当网站存在注入或其他漏洞时,入侵者极有可能获取用户的密码值。