密码学入门(5):单向散列函数
在开始之前,我们先假设一个场景:我们现在想下载一个ubuntu的镜像文件,如何确保我们下载的文件是和原始文件一模一样的呢?下载的过程中可能会因为网络原因,或者其他可能的原因,导致下载的镜像文件不完整,即使是 1 1 1个bit的不同。
其实,我们可能已经接触过单向散列函数了。在下载镜像文件时,在下载页面可能会看到md5、sha256之类的字眼,后面跟了一堆数字和字母的序列。例如:
这里的f8d3ab0faeaecb5d26628ae1aa21c9a13e0a242c381aa08157db8624d574b830
就是单向散列函数生成的散列值。通过计算下载的镜像文件的散列值,再和这串散列值对比,就可以验证文件是否完整了。这是单向散列函数的一个应用。
什么是单向散列函数
单向散列函数(one-way hash function)有一个输入和一个输出,其中输入称为消息(message),输出称为散列值(hash value)。它可以根据消息的内容计算出散列值,而散列值可以用来检查消息的完整性。
单向散列函数的相关术语有很多变体,例如:
- 单向散列函数也称为消息摘要函数(message digest function)、哈希函数或杂凑函数。
- 输入单向散列函数的消息也称为原像(pre-image)。
- 单向散列函数输出的散列值也称为消息摘要(message digest)或者指纹(fingerprint)。
- 完整性也称为一致性。
单向散列函数除了上面说的可以用来验证文件的完整性,还可以用于构造消息认证码、数字签名、构造伪随机数生成器等。
单向散列函数无法解决的问题:单向散列函数能够辨别出“篡改”,但无法辨别出“伪装”。即只能保证消息的完整性,不能对消息进行认证。用于认证的技术包括消息认证码和数字签名,我们将在之后讨论。
单向散列函数的性质
- 根据任意长度的消息计算出固定长度的散列值:无论输入多长的消息( 1 1 1字节、 1 1 1MB、 1 1 1GB、 1 1 1TB或更大),输出的散列值都是固定长度(例如sha256是 256 256 256bit)。
- 能够快速计算出散列值。
- 具备单向性:根据消息计算散列值很容易,但根据散列值计算消息很困难。
- 消息不同散列值也不同:消息中哪怕只有 1 1 1比特的改变,也必须有很高的概率产生不同的散列值。
- 抗碰撞性:两个不同的消息产生同一个散列值的情况称为碰撞(collision)。难以发现碰撞的性质称为抗碰撞性(collision resistance)。
- 雪崩效应:当输入发生最微小的改变(例如,反转一个二进制位)时,也会导致输出的不可区分性改变(输出中每个二进制位有50%的概率发生反转):
MD4、MD5
- MD4是由Rivest于1990年设计的单向散列函数,能够产生 128 128 128比特的散列值。现在已经不安全了。
- MD5是由Rivest于1991年设计的单向散列函数,能够产生 128 128 128比特的散列值。现在也不安全了。
- MD4和MD5中的MD是消息摘要(Message Digest)的缩写。
SHA家族
- SHA-1于1995年发布,是由NIST(National Institute of Standards and Technology)设计的一种能产生 160 160 160比特的散列值的单向散列函数,是MD5的后继者。现在已经被攻破了。
- SHA-2于2001年发布,包括SHA-256、SHA-384、SHA-512等,散列值长度分别为 256 256 256比特、 384 384 384比特和 512 512 512比特。这些单向散列函数合起来统称SHA-2。SHA-2目前没有出现明显的弱点。
- SHA-3与2015年发布,由于对MD5成功的破解,以及对SHA-0和SHA-1出现理论上破解的方法,NIST感觉需要一个与之前算法不同的,可替换的加密散列算法