任何形式的网络服务都存在安全风险,如何将风险降到最低是互联网普遍关注的问题。通常,网络安全措施的实现方法有数据加密、数字签名、身份认证、防火墙和入侵检测等。其中数据加密是防止未经授权的用户访问敏感信息的手段,而研究数据加密的科学我们称之为密码学(Cryptography)。
密码学有着悠久而光辉的历史,古代的军事家已经用密码传递军事情报了,而现代计算机的应用和计算机科学的发展又为这一古老的科学注入了新的活力。现代密码学是经典密码学的进一步发展和完善。由于加密和解密此消彼长的斗争永远不会停止,这门科学还在迅速发展之中。
鉴于目前全球网络处理的数据量大幅增加,计算机科学家一直在寻找加速数据访问并确保数据安全交换的方法。当前常用的一种安全加密技术哈希(Hash)函数,也称散列函数。今天我们来详细聊聊散列函数。
什么是散列函数
散列函数,首先我们先来看下散列。散列的释义是切碎或打乱某些东西,也是关于散列函数的一种描述。没错,将数据 “打乱”,转换成其他数值。并且无论数据输入多长,输出值总是相同的长度。
散列函数将任意长度的字符串转换为固定长度的字符串,这个固定长度的字符串称为散列值。散列值是一段数据唯一的、紧凑的表示形式。如果对一段明文只更改其中的一个字母,随后的散列变换都将产生不同的散列值。因为找到散列值相同的两个不同的输入在计算上是不可能的,所以数据的散列值可以检验数据的完整性。
在上面的散列函数示例中,所有不同的密码在存储到数据库之前都被转换为固定长度的字符串。这些输出字符串无法转换到原来的实际密码。
散列值是散列函数和算法计算出来的结果。散列值是唯一的,就像人的指纹一样。如果采用小写字母 “a” 到 “f” 和数字 “0” 到 “9” 并定义一个长度为 64 个字符的散列值,则有 1.1579209e+77 个可能的输出值,即 70 后面跟 24 个零!这表明即使使用较短的字符串,仍然可以生成一个长度可以接受的指纹。
使用 SHA256 函数生成的散列值始终具有相同的长度,无论输入字符串中字符的数量和类型如何。
SHA256-Hash for:apple
3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b
SHA256-Hash for:pear
97cfbe87531abe0c6bac7b21d616cb422faaa158a9f2ae7e8685c79eb85fc65e
SHA256-Hash for:plum
0467255695084cc12ffe0c55105907f74a9c189314b9fe87b878eb6fee787b99
SHA256-Hash for:strawberry
5e737f891db1175442a39fde73e51d781a545506d71c95477a6deb5988bd7f9a
上面示例中的散列值只需几行 PHP 代码即可生成:
<?php
echo hash('sha256', 'apple');
?>
散列函数可以用于计算机科学的许多领域。例如:
- 服务器和浏览器之间的通信加密,并为互联网应用程序和数据缓存生成会话 ID
- 保护敏感数据,例如密码、付款订单等
- 向电子邮件中添加数字签名
- 通过查找功能定位相同或相似的数据集
散列函数的设计特点
哈希的核心是一个数学函数,它对两个固定大小的数据块进行运算以创建哈希代码。该散列函数构成散列算法的一部分。每个数据块的大小因算法而异。通常,块大小从 128 位到 512 位。下图演示了哈希函数:
散列算法涉及上述散列函数的轮次,如分组密码。每轮采用固定大小的输入,通常是最新消息块和上一轮输出的组合。重复此过程所需的轮数以散列整个消息。哈希算法的示意图如下图所示:
因为,第一个消息块的哈希值成为第二个哈希操作的输入,其输出改变第三个操作的结果,依此类推。这种效应称为散列的雪崩效应。雪崩效应导致两条消息的散列值大相径庭,即使只有一位数据不同,结果也完全不同。
正确理解哈希函数和算法的区别:
- 哈希函数通过对两块固定长度的二进制数据进行运算生成哈希码。
- 散列算法是使用散列函数的过程,指定消息将如何分解以及如何将先前消息块的结果链接在一起。
散列函数的设计具有以下属性:
单向性
一旦生成散列值,就不可能将其转换回原始数据。例如,在上面的示例中,一定无法将“$P$Hv8rpLanTSYSA/2bP1xN.S6Mdk32.Z3” 转换回 “susi_562#alone”。
无碰撞/无冲突
对于无冲突的散列函数,没有两个字符串可以映射到相同的输出散列值。换句话说,每个输入字符串都必须生成唯一的输出字符串。这种类型的散列函数也称为密码散列函数。在上面的哈希函数示例中,没有相同的哈希值产生,即输出字符串之间没有 “冲突” 。
速度快如闪电
如果散列函数计算散列值的时间太长,则也没有多大用处。因此,散列函数必须非常快。在数据库中,散列值存储在散列表中以确保快速访问。
流行的散列函数
接下来,我们来简单看看有哪些流行的散列函数。
消息摘要(MD)
多年来,MD5 一直是最受欢迎和广泛使用的哈希函数。
- MD 系列包括散列函数 MD2、MD4、MD5 和 MD6。它被采纳为 Internet 标准 RFC 1321。它是一个 128 位的散列函数。
- MD5 摘要已广泛用于软件领域,以保证传输文件的完整性。例如,文件服务器通常会为文件提供预先计算的 MD5 校验和,以便用户可以将下载文件的校验和与其进行比较。
- 2004 年,MD5 发现了冲突。据报道,使用计算机集群的分析攻击仅在一个小时内就成功了。这种碰撞攻击导致 MD5 受损,因此不再推荐使用。
安全散列函数(SHA)
HA 系列包含四种 SHA 算法;SHA-0、SHA-1、SHA-2 和 SHA-3。虽然来自同一个家庭,但结构不同。
- 最初的版本是 SHA-0,一个 160 位的散列函数,由美国国家标准技术研究院(NIST)于 1993 年发布。在当时它并没有很流行。1995 年,SHA-1 出现了,用来纠正一些 SHA-0 的缺点。
- SHA-1 是现有 SHA 散列函数中使用最广泛的。它用于多种广泛使用的应用程序和协议,包括安全套接字层(SSL)的安全性。
- 2005 年,发现了一种在实际时间范围内找到 SHA-1 冲突的方法,这使得 SHA-1 的能力受到质疑。
- SHA-2 系列还有四种 SHA 变体,SHA-224、SHA-256、SHA-384 和 SHA-512,具体取决于其哈希值中的位数。
- SHA-2 是一个强大的哈希函数。虽然有很大的不同,但它的基本设计仍然遵循 SHA-1 的设计。因此,NIST 呼吁新的竞争性哈希函数的设计。
- 2012 年 10 月,NIST 选择 Keccak 算法作为新的 SHA-3 标准。Keccak 提供了许多优点,例如高效的性能和良好的攻击抵抗力。
RIPEMD
RIPEMD 是 RACE Integrity Primitives Evaluation Message Digest 的缩写。这种散列函数由开放研究社区设计,通常被称为欧洲散列函数族。
- 该家族包括 RIPEMD、RIPEMD-128 和 RIPEMD-160。该算法还存在 256 位和 320 位版本。
- 原始 RIPEMD(128 位)基于 MD4 中使用的设计原则,被发现其提供的安全性有缺陷。RIPEMD 128 位版本作为快速修复替代品出现,以修复原始 RIPEMD 上的漏洞。
- RIPEMD-160 是改进版本,也是该系列中使用最广泛的版本。256 位和 320 位版本减少了意外碰撞的可能性,但与 RIPEMD-128 和 RIPEMD-160 相比安全性并没有更高。
Whirlpool
这是一个 512 位哈希函数。
- 它源自高级加密标准(AES)的修改版本。其中一位设计师是 AES 的共同创建者 Vincent Rijmen。
- Whirlpool 已经发布三个版本:即 WHIRLPOOL-0、WHIRLPOOL-T 和 WHIRLPOOL。
散列函数的应用
基于其密码学特性,散列函数有如下应用场景:
密码存储
散列函数为密码存储提供保护。
- 大多数登录过程都没有将密码以明文形式存储,而是将密码的散列值存储在文件中。
- 密码文件由形式为 (user id, h(P)) 的对表组成。
- 登录过程如下图所示:
- 入侵者只能看到密码的散列值,即使他得到了密码。既不能直接使用散列值登录,也不能从散列值中推导出密码,因为散列函数具有单向性。
数据完整性检查
数据完整性检查是散列函数最常见的应用。它用于生成数据文件的校验和。应用程序可以向用户保证数据的准确性。该过程如下图所示:
完整性检查可帮助用户检测原始文件所做的任何更改。但是,它不对原创性提供任何保证。攻击者无需修改文件数据,而是可以更改整个文件并一起计算新的哈希值,将其发送给接收方。此完整性检查应用程序仅在用户确定文件的原创性时才有用。
哈希函数和网站
使用 SSL 加密的数据传输,当 Web 服务器收到请求时,它会将服务器证书发送到用户的浏览器。然后使用散列函数生成会话 ID,并将其发送到服务器进行解密和验证。如果服务器批准会话 ID,则建立加密的 HTTPS 连接并可以交换数据。所有交换的数据包也都是加密的。
哈希值还用于加密缓存数据,以防止未经授权的用户使用缓存访问登录和付款等敏感数据。使用 SFTP 协议的 FTP 服务器和客户端之间的通信也以类似的方式工作。
数字签名
电子邮件通过专门设计用于传输此类消息的服务器发送。使用散列函数生成的密钥也用于向消息添加数字签名。
在电子邮件中添加数字签名就像在手写的信件上签名——签名一次,这个签名就是独一无二的。
发送带有数字签名的电子邮件的步骤是:
- 小美(发件人)将她的消息转换为哈希值并使用她的私钥加密哈希值。这个加密的哈希值就是数字签名。
- 小美将电子邮件和数字签名发送给收件人小帅。
- 小帅使用相同的散列函数生成消息的散列值。他还使用小美的公钥解密散列值并比较两个散列值。
- 如果这两个哈希值匹配,小帅就知道小美的消息在传输过程中没有被篡改。
注意,数字签名证明了消息的完整性,但实际上并没有对其进行加密。如果要发送机密数据,那么最好对其进行加密并使用数字签名。
散列函数用于提高互联网通信的安全性,现在已经开发了许多高度复杂的标准。然而,黑客们也意识到了这一点,并不断想出更高级的黑客技术来破解它。技术不断变革,将来还会有什么样的高级加密算法出现呢?未来,让我们拭目以待!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。