1.5 哈希算法
哈希(Hash)算法又常称为指纹(Fingerprint)或摘要(Digest)算法,是非常基础也非常重要的一种算法。哈希算法可以将任意长度的二进制明文映射为较短的(通常是固定长度的)二进制串(哈希值),并且不同的二进制明文很难映射为相同的二进制串。
消息摘要是指采用单向哈希函数将需要计算摘要的数据提取摘要后生成一串固定长度的密文,这一串密文又称为数字指纹。数字指纹有固定的长度,并且不同的明文提取摘要生成的密文结果总是不同的,但是同样的明文产生的摘要是一致的。由于生成摘要的明文没有任何限制,但是得到的摘要却是定长的,因此必然有一些明文会产生相同的摘要,这种现象称为“碰撞”。为了避免这种情况的产生,哈希函数必须具备很好的抗碰撞性,这意味着在现有的计算资源(包括时间、空间、资金等)下,找到一个碰撞是不可行的。
消息摘要算法有一个特性,就是在输入消息的过程中,如果消息发生了细微的改变,如改变输入消息二进制数据中的一位,最后都会导致输出结果大相径庭。因此,消息摘要算法对于检测消息或密钥等信息对象中的微小变化非常有用。从中可以归纳出消息摘要算法的如下三个特点。
• 消息摘要算法的输入长度是任意的,输出长度是固定的。
• 对消息摘要算法给定输入,计算输出是很容易的。
• 给定消息摘要算法H,找到两个不同的输入,输出为同一个值在计算上不可行。
• 常见的消息摘要算法:MD5、SHA、SHA256、SHA512、SM3等。
在本书中,经常会看到SHA256这个消息摘要算法,这个算法是在比特币系统和以太坊中大量使用的消息摘要算法。SHA256对任意的输入产生定长的32B,256bit的输出,为了更方便地展示,一般采用Hex编码的方式来对结果进行编码。以123为例,对其使用SHA256计算后,用Hex编码得到的结果是a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3。
消息摘要算法并不是一种加密算法,不能用于对信息的保护,但是消息摘要算法常用于对密码的保存。例如,用户登录网站需要通过用户名和密码来进行验证,如果网站后台直接保存了密码的明文,一旦发生了数据泄露,后果不堪设想,因为大多数用户都倾向于在多个网站使用相同的密码。为了避免这种情况的出现,可以利用哈希算法的特性,网站后台不直接保存明文密码,而保存用户密码的哈希值,这样当用户登录时比较密码最终的哈希值即可,如果一致,则证明登录密码是正确的,即使发生了数据泄露也很难根据单向哈希值推算出用户原始的登录密码。
但是,有时因为用户口令的强度太低,只使用一些简单的字符串,如123456,攻击者可以通过对这些口令提前计算哈希值,得到口令和哈希值的一种映射关系来达到破解的目的。为了提高安全性,网站一般会通过加盐(Salt)的方式来计算哈希值,不直接保存用户密码的哈希值,而将密码加上一段随机字符(盐)再计算哈希值,这样把哈希值和盐分开保存可以极大地提高安全性。
消息摘要算法可以用于验证数据的完整性,但仅在数据的摘要与数据本身分开传输的情况下可以验证。否则攻击者可以同时修改数据和摘要,从而轻易地避开检测。消息验证码(Message Authentication Code,MAC)或密钥哈希值(Keyed Hash)是增加了身份验证来扩展摘要函数的密码学函数,只有拥有了摘要密钥,才能生成合法的MAC。
MAC通常与密文一起使用。加密通信可以确保通信的机密性,却无法保证通信消息的完整性,如果攻击者Mallory的能力非常强大,以至于可以修改Alice和Bob通信中的密文,他就可以诱导Bob接收并相信伪造的信息。但是,当MAC和密文一起发送时,Bob就可以确认收到的消息未遭到篡改。
任何消息摘要算法都可以作为MAC的基础,其中一个基础是基于摘要的消息验证码(Hash based Message Authentication Code,HMAC)。HMAC的本质是将摘要密钥和消息以一种安全的方式交织在一起的函数。在本书的第8章数字钱包章节中可以看到HMAC-SHA512这样的消息验证码,它表明基于摘要的消息验证码是以SHA512摘要函数为基础的。