目录
4 Hash函数
Hash函数是将任意长的消息M映射为较短的、固定长度的一个值H(M),Hash函数也称为哈希函数、散列函数、压缩函数、杂凑函数、指纹函数等。其函数值H(M)为哈希值、散列值、杂凑码、指纹、消息摘要等。(Hash函数H一般是公开的)
4.1 Hash函数满足条件及作用
Hash函数的目的是为需认证的数据产生一个“指纹”,为实现安全认证,需要满足以下安全条件:
单向性:已知x,求H(x)较为容易;但是,已知h,求使得H(x)=h的x在计算上是不可行的。
抗弱碰撞性:已知x,找出y使得H(y)=H(x)在计算上是不可行的。
抗强碰撞性:找出任意两个不同的输入x、y,使得H(y)=H(x)在计算上是不可行的。
Hash函数的作用:
Hash函数应用于消息认证
消息认证是用来验证消息完整性的一种机制或服务,消息认证保证发送方和接收方的信息一致,通常还要保证发送方的身份真实有效。
Hash函数应用于数字签名
消息认证通常用消息认证码(MAC)实现,即带密钥的Hash函数。数字签名与MAC相似,在进行数字签名过程中,用户的私钥加密消息作为Hash的输入,然后输出消息摘要,其他任何知道该用户公钥的人都可以通过数字签名来验证消息的完整性。攻击者只有获得了私钥,才能篡改消息。
Hash函数还可以用于产生单向口令文件,用于入侵检测和病毒检测,用于构建随机函数或者伪随机数发生器。
4.2 哈希碰撞
所谓哈希,就是将不同的输入映射成独一无二的、固定长度的值(哈希值)。但当不同的输入得到了同一个哈希值,就发生了“哈希碰撞”。
在很多网络服务中会使用哈希函数产生一个token,标识用户的身份和权限。但如果两个不同的用户得到了同样的token,就发生了哈希碰撞。而这意味着服务器把这用户A和用户B视为同个人,用户B可以读取和更改用户A的信息,这无疑是一个巨大的安全隐患。
黑客攻击的一种方法,就是设法制造"哈希碰撞",然后入侵系统,窃取信息。
4.2.1 生日攻击
哈希碰撞的概率取决于两个因素(假设哈希函数是可靠的,每个值的生成概率都相同)
(1)取值空间的大小(即哈希值的长度)
(2)整个生命周期中,哈希值的计算次数
数学上有一个问题,叫做"生日问题"(birthday problem):一个班级需要有多少人,才能保证每个同学的生日都不一样?
答案很出人意料。如果至少两个同学生日相同的概率不超过5%,那么这个班只能有7个人。事实上,一个23人的班级有50%的概率,至少两个同学生日相同;50人班级有97%的概率,70人的班级则是99.9%的概率(计算方法见后文)。
这意味着,如果哈希值的取值空间是365,只要计算23个哈希值,就有50%的可能产生碰撞。也就是说,哈希碰撞的可能性,远比想象的高。实际上,有一个近似的公式。
上面公式可以算出,50% 的哈希碰撞概率所需要的计算次数,N 表示哈希的取值空间。生日问题的 N 就是365,算出来是 23.9。这个公式告诉我们,哈希碰撞所需耗费的计算次数,跟取值空间的平方根是一个数量级。
这种利用哈希空间不足够大,而制造碰撞的攻击方法,就被称为生日攻击(birthday attack)。
4.2.2 哈希碰撞公式
至少两个人生日相同的概率,可以先算出所有人生日互不相同的概率,再用 1 减去这个概率。我们把这个问题设想成,每个人排队依次进入一个房间。第一个进入房间的人,与房间里已有的人(0人),生日都不相同的概率是365/365
;第二个进入房间的人,生日独一无二的概率是364/365
;第三个人是363/365
,以此类推。
因此,所有人的生日都不相同的概率,就是下面的公式。
上面公式的 n 表示进入房间的人数。可以看出,进入房间的人越多,生日互不相同的概率就越小。
这个公式可以推导成下面的形式。
那么,至少有两个人生日相同的概率,就是 1 减去上面的公式。
上面的公式,可以进一步推导成一般性的、便于计算的形式。
根据泰勒公式,指数函数 ex 可以用多项式展开。
如果 x 是一个极小的值,那么上面的公式近似等于下面的形式。
现在把生日问题的1/365
代入。
因此,生日问题的概率公式,变成下面这样。
假设 d 为取值空间(生日问题里是 365),就得到了一般化公式。
上面就是哈希碰撞概率的公式。
4.2.3 如何防止哈希碰撞
防止哈希碰撞的最有效方法,就是扩大哈希值的取值空间。
16个二进制位的哈希值,产生碰撞的可能性是 65536 分之一。也就是说,如果有65537个用户,就一定会产生碰撞。哈希值的长度扩大到32个二进制位,碰撞的可能性就会下降到 4,294,967,296 分之一。
更长的哈希值意味着更大的存储空间、更多的计算,将影响性能和成本。开发者必须做出抉择,在安全与成本之间找到平衡。
4.3 Hash函数的主要结构
4.3.1 Merkle-Damgård(MD)结构
Merkle–Damgård结构简称为MD结构,主要用在Hash算法中抵御碰撞攻击。这个结构是一些优秀的hash算法,比如MD5,SHA-1和SHA-2的基础。
MD结构首先对输入消息进行填充,让消息变成固定长度的整数倍(比如512或者1024)。这是因为压缩算法是不能对任意长度的消息进行处理的,所以在处理之前必须进行填充。
通常来说,我们会使用恒定的数据,比如说0来填充整个消息块。
MD结构流程图:
举个例子,假如我们的消息是“HashInput”,压缩块的大小是8字节(64位),那么我们的消息将会被分成两个块,后面一个块使用0来填充,将会得到:“HashInpu t0000000”。
但是这样做往往是不够的,因为通常对于压缩函数来说,会删除掉最后面的额外的0,所以导致填充和不填充最后计算出来的hash值是一样的。
为避免这种情况,必须更改填充常量数据的第一位。由于常量填充通常由零组成,因此第一个填充位将强制更改为“ 1”。也就是“HashInpu t1000000”。
我们还可以对填充进行进一步的增强,比如使用一个额外的block来填充消息的长度。 但是额外的使用一个block往往有点浪费,一个更加节约空间的做法就是,如果填充到最后一个block的0中有住够的空间的话,那么可以消息的长度放在那里。
4.3.2 海绵(Sponge)结构
海绵结构,也称海绵哈希,是当前密码学中一种重要结构,如sha-3采用的是海绵结构。
海绵结构是一类具有有限内部状态的算法,可以将任意有限长的输入消息变成任意长度输出