什么是单向散列函数
单向散列函数(one-way hash function)有一个输入和一个输出,其中输入称为消息(message),输出称为散列值(hash value)。单向散列函数可以根据消息的内容计算出散列值,而散列值就可以被用来检查消息的完整性。
散列值的长度和消息的长度无关。无论是1比特,还是100MB,甚至100GB,单向散列函数都会计算出固定长度的散列值。以SHA-256单向散列函数为例,它所计算出的散列值的长度永远都是256比特(32字节)。所以,很容易处理和使用。
单向散列函数的性质
- 根据任意长度的消息计算出固定长度的散列值
- 能够快速就算出散列值
- 消息不同散列值不同
术语
单向散列函数 也称为消息摘要函数(message digest function)、哈希函数或者咋凑函数。
输入单向散列函数的消息也称为原像(pre-image)。
单向散列函数输出的散列值也称为消息摘要(message digest)或者指纹(fingerprint)
单向散列函数的实际应用
检查软件是否被篡改
基于口令的加密
单向散列函数也被用于基于口令的加密(password based encryption ,PBE)。
PBE的原理是将口令和盐(salt,通过伪随机数生成器产生的随机值)混合后计算其散列值,然后将这个散列值用作加密的密钥。通过这样的方式能够防御口令的字典攻击。
消息认证码
使用单向散列函数可以构造消息认证码。
消息认证码是将“发送者和接收者之间的共享密钥”和“消息”进行混合计算出的散列值。使用消息认证码可以检测并防止通信过程中的错误、篡改以及伪装。
数字签名
在进行数字签名时也会使用单向散列函数。
数字签名是现实社会中的签名和盖章这样的行为在数字世界中的实现。数字签名的处理过程非常耗时,因此一般不会对整个消息内容直接施加数字签名,而是先通过单向散列函数计算出消息的散列值,然后在对这个散列值施加数字签名。
伪随机数生成器
使用单向散列函数可以构造伪随机数生成器。
密码技术中所使用的伪随机生成树需要具备“事实上不可能根据过去的随机数列预测未来的随机数列”这样的性质。为了保证不可预测性,可以利用单向散列函数的单向性。
一次性口令
使用单向散列函数可以构造一次性口令(one-time password)。一次性口令经常被用于服务器对客户端的合法认证。在这种方式中,通过使用单向散列函数可以保证口令只在通信链路上传送一次(one-time),因此即便被窃取了,也无法使用。
单向散列函数例子
- MD4、MD5
- SHA-1、SHA-256、SHA-384、SHA-512
- SHA-3
应该选择哪种单向散列函数
- 首先MD5是不安全的,因此不应该使用。
- SHA-1除了用于对过去生成散列值进行校验外,不应该被用于新的用途,而是应该迁移到SHA-2。
- SHA-2有效应对了SHA-1的攻击方法,因此是安全的,可以使用。
- SHA-3 是安全的,可以使用。
- 和对称密码一样,我们不应该使用任何自制算法。
对散列函数的攻击
暴力破解
任何文件中都或多或少存在具有一定的冗余性。利用文件的冗余性生产具有相同散列值的另一个文件,这就是一种针对单向散列函数的攻击。
在对密码进行暴力破解时,我们就是按照顺序改变密钥,如0、1、2、3…然后分别用这些密钥进行解密的,对单向散列函数进行暴力破解也是如此,即每次都稍微改变一下消息的值,然后对这些消息求散列值。
现在我们在寻找的是一条具备特定散列值的消息,具备相同散列值的另一条不同的消息。这相当于一种试图破解单向散列函数的“弱碰撞性”的攻击 。在这种情况下,暴力破解需要尝试的次数,可以根据散列值的长度计算出来,以SHA3-512为例,由于它的散列值长度为512比特,因此最多只需要尝试2^512次就能找到目标消息了,如此多的尝试次数在现实中是不可能完成的。
由于尝试次数纯粹是由散列值的长度决定的,因此散列值的长度越长的单向散列函数,其抵御暴力破解的能力也就越强。
找出具有指定散列值的消息的攻击方式分为两种,即“原像攻击”和“第二原像攻击”。原像攻击(Pre-Image Attack)是指定一个散列值,找出具有该散列值的任意消息;第二原像攻击(Second Pre-Image Attack)是指定一条消息1,找出另外一条消息2,消息2的散列值和消息1相同。
生日攻击
要找到散列值相同的两条消息,而散列值则可以是任意值。这样的攻击,一般称为生日攻击(birthday attack)或是冲突攻击(collision attack),这是一种试图破解单向散列函数的“强碰撞性”攻击。
我们以512比特的散列值为例,对单向散列函数进行暴力破解所需要的尝试次数2^512 次,而对同一单向散列函数进行生日攻击所需要尝试的次数2^256次,因此和暴力破解相比,生日攻击所尝试的次数要少的多。
单向散列函数无法解决的问题
单向散列函数能够辨别出“篡改”,但无法辨别出“伪装”。
当我们不仅需要确认文件的完整性,同时还需要确认这个文件是否真的属于他的,我们还需要认证。
参考资料
该系列的主要内容来自《图解密码技术第三版》