为什么要有单向散列函数
- 作为接收者,如果将得到的密文正确解密,看到了明文。是否意味着这次加密传输是完全安全和正确的?可以肯定的说,不是。
这里面有很多原因,其中一个理由是:我们如何判定,我们看到的这个明文,就是发送者发送的明文?如何判定没有被篡改过? - 我们假设一个例子:
- A发送两个消息给B。 第一个消息是让B汇款给C,第二个消息是让B汇款给D。
- 攻击者截获了第一个消息,并保存C对应的字节。
- 当攻击者截获第二段时,将D替换成C。
- 假设密钥没变,B看到的明文就是汇款给C两次,而且B完全无法察觉这是被篡改过的。
- 所以我们需要一种技术来校验文件是否被篡改,保证消息的完整性,或者叫一致性。实现这种功能的技术叫做“单向散列函数”。
什么是单向散列函数
- 单向散列函数有一个输入和一个输出,输入被称为消息,输出被称为散列值。
- 消息的类型不受限制,可以是声音或者图片或者人类无法读懂的消息。因为单向散列函数会将任何输入作为单纯的比特序列来处理,即根据比特序列计算出散列值。
- 输入有可能书很巨大的文件,如果单向散列值计算出的散列值跟文件长度相关,那么在实际使用中可能会出现效率问题。所以,无论输入是多长,计算出的散列值长度固定,也被称为指纹。
- 根据上面的信息,可以得出:比对两份文件的散列值,就能比对出两份文件是否相同,从而保证了文件的完整性。
单向散列值的性质
- 根据任意长度的消息计算出固定长度的散列值
- 能够快速计算出散列值
-
消息不同散列值也不同
- 碰撞。就是如果两份不同的输入,却产生相同的散列值,则称为"碰撞"。
- 抗碰撞性。难以发现碰撞的性质称为"抗碰撞性"。
- 弱抗碰撞性。当给定某条消息的散列值时,单向散列函数必须确保要找到和该条消息具有相同散列值的另外一条消息是非常困难的。单向散列函数都必须具备弱抗碰撞性。
-
强抗碰撞性。指要找到散列值相同的两条不同的消息是非常困难的,这里的散列值可以是任意值。
密码技术中所使用的单向散列函数,必须同时具备"抗弱碰撞性"和"抗强碰撞性"。
- 具备单向性。指的是无法通过散列值反推出消息的性质。
相关术语
因为单向散列函数里有很多术语指的其实是一个东西,所以有必要做出说明。
- 单向散列函数 = 消息摘要函数 = 哈希函数 = 杂凑函数
- 输入的消息 = 原像(pre-image)
- 输出的散列值 = **消息摘要(message digest) = 指纹(fingerprint)
- 完整性 = 一致性
- 散列的英文就是hash,古法语的意思为"斧子",后引申为"剁碎的肉末"。这里的意思估计就是把消息剁碎而无法还原的意思吧。
单向散列函数的实际应用
-
检测软件是否被篡改。
这个上面讲解由来的时候已经介绍到了,一般具体的做法是软件发布者将散列值公开发布到网上,使用软件的人就可以根据这个来判断获得的软件是否已经被篡改。 -
基于口令的加密。
PBE(Password Based Encryption)基于口令的加密,是将口令和salt(随机数)混合后计算其散列值,作为加密的密钥。这样可以抵御针对口令的字典攻击。 -
消息认证码。
消息认证码是将"发送者和接收者之间的共享密钥"和"消息"进行混合计算出的散列值。使用消息认证码可以检测并防止通信过程中的错误、篡改以及伪装。在SSL/TLS中得到了运用。 -
数字签名。
数字签名非常的耗时,所以不会对整个消息进行数字签名。一般先计算出消息的散列值,然后再针对散列值进行数字签名。 -
伪随机数生成器。
伪随机数需要具备"事实上不可能根据过去的随机数列预测未来的随机数列"这样的性质。为了保证不可预测性,可以利用单向散列函数的单向性。 -
一次性口令。
一次性口令通常被用于服务器对客户端的合法性认证。这种方式中,通过使用单向散列函数可以保证口令只在通信链路上传送一次,因此即使窃听者窃取了口令,也无法使用。
单向散列函数使用的算法
-
MD4、MD5。
这两种都是产生128比特的散列值。MD5的强抗碰撞性已经被攻破,所以不再是安全的。 -
SHA-1、SHA-256、SHA-384、SHA-512。
SHA-1产生上限为接近264比特的散列值。
SHA-256、SHA-384、SHA-512分别产生256比特、384比特和512比特的散列值。这些合称为SHA-2。
SHA-1的强抗碰撞性已经被攻破,不再安全。SHA-2目前还未被攻破。 -
RIPEMD-160。
RIPEMD-160是欧盟所设计的RIPEMD的修订版,散列值为160比特。
RIPEMD已经被攻破,RIPEMD-160还未被攻破。 -
AHS与SHA-3*
NIST在SHA-1被攻破的背景下开始着手准备下一代的SHA-3标准,2012年此标准已经晚成选型。
单向散列函数SHA-1
整体流程
-
填充。
将消息填充处理,使其长度为512比特的整数倍。 -
计算W0 - W79。
将每个512比特分组计算得出80个32比特的值(W0 - W79)。 -
分组处理。
针对输入分组进行80个步骤的处理,计算出5个32比特的值(A-E),作为SHA-1的内部状态。 - 单步处理。
详细处理过程
说实话太复杂,暂时也用不上,此处省略。。。。。很多字。
对单向散列函数的攻击
-
暴力破解
- 攻击场景是:A向B发送一条消息,内容是"A向B要求支付金额为1百万元。",攻击者截获此消息后,想要篡改此消息而不会被B发现。
- 这种攻击场景实际上就是破解弱抗碰撞性,就是针对某一特定的消息找到与其相同的散列值的消息进行替换。
- 使用暴力破解法,从文档文件的冗余性入手。即在不改变文档意思的前提下能够对文件内容进行修改的程度。例如:
想要修改成B给A1亿元。可以列举出相同意思的多份修改后的消息:
A向B要求支付金额为1亿元。
A向B要求支付金额为1000000000元。
..........
只要找到一份跟原文相同的散列值即可。
-
生日攻击
- 攻击场景是:编写消息的人是攻击者。攻击者首先生成两份散列值相同,但内容不同的文件。其中一份要B支付1百万的合同给了A,A生成散列值后发送给B。攻击者截获此报文后,替换成散列值相同的要B支付1亿元的合同。这样就达成了攻击。
- 这种攻击场景的实质是要破解强抗碰撞性,即只要任何两份文档存在相同的散列值时,即可达成攻击。
- 攻击的概率计算涉及到生日攻击方法。
- 所谓的生日攻击就是:随机选出N个人,其中任意两个人的生日相同的概率大于二分之一,请问N为多少?
- 这个问题的解题诀窍是,不要正向的去想先选定一个人,再找另外一个人的生日和他相同。这就完全改变了题目的意思,是任意而不是特定,只要选中一个人就是特定。解题的技巧是,先计算N个人的生日全都不一样的概率,再用1去减去那个概率即可,这个过程没有选定任何一个生日,这才是任意。
- 任意N个人的生日不一样的组合数量计算很简单,365一直乘到(365-N+1)即可。所有的可能性组合数量是365的N次方。上下一除就是N个人生日不一样的概率。1减去这个概率就是任意两人生日相同的概率,要大于二分之一的话,N为23。
- 将生日问题转化成一般问题:假设一年为Y天,那么N人中生日相同的概率大于二分之一,N至少为多少?
当Y非常大时,结果类似等于 N = 根号Y - 找出任意散列值相同的文件的概率大于二分之一,其中Y天数就是散列值的组合数量。假设散列值的比特长度为M ,则N = 2的M次方开平方根。
- 假设160比特的散列值,暴力破解需要2160次,而生日攻击只需要280次。
单向散列函数无法解决的问题
单向散列函数只能解决篡改问题,无法解决伪装问题。也就是说此技术无法判断出,发送消息的人是否是正确的。