目录
- 什么是单向散列函数
- 散列算法的特征
- 散列算法的用途
- 散列算法的分类
- 密码学哈希和非密码学哈希
- 不安全的密码学哈希算法
- 主流的密码学哈希算法
- SHA256散列算法(SHA2算法)
- SHA256算法过程
- SM3散列算法
- 应该使用哪种单向散列函数呢
什么是单向散列函数
单向散列函数( one-way hash function )有一个输入和一个输出,其中输人称为消息( message ),输出称为散列值( hash value )。单向散列函数可以根据消息的内容计算出散列值,而散列值就可以被用来检查消息的完整性。
消息不一定是人类能够读懂的文字,也可以是图像文件或者声音文件。单向散列函
数不需要知道消息实际代表的含义。无论任何消息,单向散列函数都会将它作为单纯的比特序列来处理,即根据比特序列计算出散列值。
散列值的长度和消息的长度无关。无论消息是 1 比特,还是 100MB,甚至是 100GB, 单向散列函数都会计算出固定长度的散列值。以 SHA256 单向散列函数为例,它所计算出的散列值的长度永远是 256 比特( 32 字节 )
散列算法的特征
散列算法具有以下特征:
- 散列算法具有不可逆性,即,无法有效地通过散列值逆推明文。
- 散列算法的明文通常可以很长,而散列值则固定长度。
- 相同的明文产生相同的散列值,如果两个明文的散列值不同,那么这两个明文一定不同。
- 不同的明文大概率产生不同的散列值,但依然有较小的概率产生相同的散列值。这叫哈希碰撞/散列碰撞/哈希冲突/散列冲突。
- 一个明文少许改变部分输入,那么会产生一个完全不同的散列值。这叫雪崩效应,是密码学中混淆与扩散原则的体现。
散列算法的用途
由于散列算法所具备的特征,它常常被用于以下场景:
- 网络传输的校验和: 在网络传输(比如从网站下载资源)过程中,为了避免传输过程中发生数据丢包等问题,网站往往会提供一个对应下载文件的校验和文件,这个校验和文件就是目标文件的散列值,于是在客户端下载完目标文件后,只要用相同算法对下载到本地的文件做一次散列计算,然后与网站提供的校验和文件进行对比,就能确定下载好的文件是否与网站上的文件一致。
- 确保传递消息的真实性与完整性: 类似校验和,发送消息的一方将原消息与其散列值一起发送,接收方通过验证原消息的散列值与接收到的散列值是否一致来确保消息的真实性与完整性。实际的安全网络传输中当然不会如此原始简单,比如tls通信中,在握手完成后的通信中就用到了散列函数来验证消息,但并不是简单的直接使用散列,而是结合握手时协商好的相关密钥对消息做认证码(MAC)验证。
- 电子签名:电子签名一般用于网络中的身份验证,由数字签名算法实现。而数字签名算法中往往需要一个散列函数对签名主体先做一次摘要计算,在提高安全性的同时,也确保了签名内容不会过长。(数字签名的一个特点是签名内容越长,签名就越长。)
保存敏感资料如密码: 在服务端保存用户密码等敏感资料时,可以利用散列的特性进行保存,在无法逆推明文的基础上,可以通过散列计算验证密码是否正确。 - 散列表实现快速查找: 即HashTable,利用key的散列值映射到内存地址从而快速读写value。HashTable的场景,对散列计算速度要求较高,而对散列碰撞的要求相对较低,因此两个不同key计算到同一个内存地址上的概率相对较大。因此HashTable的实现,比如Java的HashMap,对哈希冲突的场景都做了特殊处理(同一地址上用链表或红黑树结构存储)。
散列算法的分类
散列算法一般可以被分为密码学哈希算法和非密码学哈希算法;密码学哈希算法中又可以分为安全的算法和不安全的算法;另外还有一种特殊用途的抗ASIC哈希算法。
密码学哈希和非密码学哈希
散列算法一般被分为密码学哈希和非密码学哈希。
所谓密码学哈希,英文是Cryptographic Hash Function,指的是用于保证密码学安全性的散列算法。所谓保证密码学安全性,是指很难发生哈希碰撞,或者很难被找出散列前的明文,并且散列值表现出随机性。密码学哈希的关键指标是抗碰撞性,也就是发生哈希碰撞的可能性。抗碰撞性越好,发生碰撞的可能性就越低,也就越安全。在使用密码学哈希时,一般都会将密码学哈希不会发生碰撞作为设计前提。
而非密码学哈希,只是尽量避免非恶意输入带来的哈希碰撞,对抗碰撞性的要求并不高。比如检测数据中的意外变化(CRCs, 循环冗余校验),或者HashTable中将不同的对象快速分配到不同的地址空间,这些场景并不要求不能发生碰撞,只要尽量较少碰撞就可以了。
判断一个哈希算法是不是密码学哈希的原则是,看它设计出来的目的是什么,是否是要确保密码学安全性,即拥有足够高的抗碰撞性。
以HashTable为例,它对散列计算的速度要求远大于抗碰撞性要求,所以采用的就是某个很简单的非密码学哈希算法。比如java的HashMap所采用的散列算法,就是遍历对象的每个字节不断乘以一个质数(31)再叠加。
非密码学哈希只能用在数据校验、HashTable等对抗碰撞性要求低的场景,而密码学哈希的应用场景不但有数据校验,还有电子签名、密码保存、数据指纹、伪随机数生成等场景。
不安全的密码学哈希算法
对于密码学哈希,使用时是假设它不会发生碰撞的。但如果一个密码学哈希算法被证明在当下计算机的计算能力内出现碰撞的可能性较高,或出现过碰撞,就会被标记为不安全的密码学哈希算法了,将不再被推荐作为密码学哈希算法使用。比如MD5算法,它最开始是作为密码学哈希被设计出来的,但随着计算机能力的发展,MD5被证明实际出现碰撞的可能性较大,于是MD5就被标记为不安全的密码学哈希算法,实际上只能在很有限的一些场景里作为非密码学哈希来使用。
目前被证明不安全或安全性有争议的密码学哈希算法: MD5、SHA-0系列、SHA-1系列等等。(MD5 的强抗碰撞性已经被攻破,也就是说,现在已经能够产生具备相同散列值的两条不同的消息,因此它也已经不安全了。)
目前认为安全的密码学哈希算法: SHA-2系列(包括SHA-256、SHA-384、SHA-512等)、SHA-3系列(包括SHA3-224、SHA3-256、SHA3-384、SHA3-512等)、SM3等等
主流的密码学哈希算法
目前国际上主流的密码学哈希算法是SHA-2与SHA-3,国内主推的则是国密标准的SM3。以SHA-256为例,256代表其散列值的长度是256位,即32个字节。一般来说,散列值长度越长,抗碰撞性就越好,所以SHA-512拥有比SHA-256更好的抗碰撞性。而在散列值长度相同时,SHA-3系列算法被认为比SHA-2系列拥有更高的安全强度,其碰撞概率更低。SM3的散列值长度固定为256位,在安全强度上与SHA-256相当。
SHA256散列算法(SHA2算法)
SHA256算法是SHA-2系列算法中应用最广泛的一个算法。
SHA-2是Secure Hash Algorithm 2(安全散列算法2)的缩写,它是一个密码学哈希算法集合,由美国国家安全局研发,由美国国家标准与技术研究院(NIST)在2001年发布,属于SHA算法之一,是SHA-1的后继者。SHA-2包含了6个具体的算法:
- SHA-224
- SHA-256
- SHA-384
- SHA-512
- SHA-512/224
- SHA-512/256
这些具体算法之间的区别主要是散列值的长度,迭代计算的次数不尽相同。它们的基本算法过程是一致的,以最常用的SHA256算法为例进行说明。
SHA256算法过程
该过程说明如下:
- 对明文进行补位处理,使明文长度为512的整数倍.
- 将补位后的明文拆分为n个512位的块。
- 对n个块进行迭代,依次对每个块做SHA256压缩运算,最终得到8个散列字(一个字4个字节)。
- 将最终的8个散列字拼接起来,得到最终的散列值,共32个字节,256位。
SM3散列算法
SM3是我国国家标准的商用密码体系中提供的一种密码学哈希算法,首版由国家密码管理局于2010年12月17日发布。目前最新版本为2016年发布的GB/T 32905-2016 信息安全技术 SM3密码杂凑算法。
SM3算法过程与SHA256基本相同,只是核心的压缩函数的具体实现逻辑不同。
该过程说明如下:
- 对明文进行补位处理,使明文长度为512的整数倍。
- 将补位后的明文拆分为n个512位的块。
- 对n个块进行迭代,依次对每个块做SM3压缩运算,最终得到8个散列字(一个字4个字节)。
- 将最终的8个散列字拼接起来,得到最终的散列值,共32个字节,256位。
应该使用哪种单向散列函数呢
- 首先,MD5 是不安全的,因此不应该使用。
- SHA-1 除了用于对过去生成的散列值进行校验之外,不应该被用于新的用途,而是应该迁
移到 SHA-2。 - SHA-2 有效应对了针对 SHA-1 的攻击方法,因此是安全的,可以使用。
- SHA-3 是安全的,可以使用。
- 2013 年发布的《CRYPTREC 密码清单》中,SHA-2 ( SHA-256、 SHA-384、SHA-512 )被
列入了 “电子政府推荐使用的密码清单” 中。