哈希函数(SHA-256、MD-5 等)基础入门
为什么要使用哈希函数?
确定性地扰乱数据
无论输入大小如何,输出大小都相同。
它们是如何运作的?
**免责声明**
本文将对哈希函数进行基础介绍。我假设大多数读者来此是为了了解哈希函数的用途和基本工作原理。我的目标是进行概括性的解释,因此我会省略证明和实现细节,而着重讲解其高层次的原理。
为什么要使用哈希函数?
哈希函数在互联网上被广泛用于安全地存储密码、查找重复记录、快速存储和检索数据等等。例如,Qvault使用哈希值将主密码扩展为私钥。
_更多用途列表请参见:[_ https://en.wikipedia.org/wiki/Hash\_function#Uses ]( https://en.wikipedia.org/wiki/Hash_function#Uses )
我想重点介绍哈希函数的几个重要特性,可以说是最重要的特性。
- 哈希函数以确定性的方式对数据进行扰乱。
- 无论输入是什么,哈希函数的输出大小始终相同。
- 无法从加密数据中恢复原始数据(单向函数)
确定性地扰乱数据
想象一下魔方。
我一开始把魔方打乱。如果我随意转动魔方,最后得到的成品会和最初的状态完全不同。而且,如果我重新开始,重复同样的步骤,就能得到完全相同的结果。虽然结果看起来是随机的,但实际上并非如此。这就是“确定性”的含义。
确定性对于安全存储密码至关重要。例如,假设我的密码是“iLoveBitcoin”。
我可以用哈希函数来打乱它:
iLoveBitcoin → “2f5sfsdfs5s1fsfsdf98ss4f84sfs6d5fs2d1fdf15”
现在,即使有人看到加密后的密码,他们也无法得知我的原始密码!这一点至关重要,因为这意味着作为网站开发者,我只需要存储用户密码的哈希值(加密后的数据)即可验证用户身份。用户注册时,我会对密码进行哈希处理并将其存储在数据库中。用户登录时,我只需对用户输入的密码进行哈希处理,然后比较两个哈希值。由于每次输入的密码都会生成相同的哈希值,因此这种方法每次都有效。
如果网站以明文(未加密)形式存储密码,这将造成巨大的安全漏洞。如果有人入侵该网站的数据库,找到所有以明文密码存储的电子邮件地址,他们就可以利用这些密码组合在其他网站上尝试登录。
无论输入大小如何,输出大小都相同。
如果我对一个单词进行哈希运算,输出结果将具有一定的长度(以 SHA-256 这种特定的哈希函数为例,长度为 256 位)。如果我对一本书进行哈希运算,输出结果的长度也相同。
这是另一个重要的特性,因为它能节省计算时间。一个经典的例子是使用哈希值作为数据映射中的键。数据映射是计算机科学中用于存储数据的一种简单结构。
当程序将数据存储在映射表中时,会为映射表指定一个键和一个值。当程序想要访问某个值时,只需提供相应的键即可获取对应的值。数据映射表的优点在于能够快速找到数据。键就像一个地址,计算机可以立即找到它,而无需花费数小时搜索数百万条记录。
因为键就像地址一样,不能太大。如果我想把书存储在数据映射表中,我可以对书的内容进行哈希处理,并将哈希值用作键。作为程序员,我可以直接使用哈希值来查找书的内容,而无需尝试按书名、作者等信息对成千上万条记录进行排序。
它们是如何运作的?
这就是撰写本文的真正挑战所在。我将力求做到极其简洁,省略实际的实现细节,只让读者对计算机在对数据进行哈希处理时的实际操作有一个基本的了解。
让我们一起来看看我为了演示而临时编写的一个算法示例,LANEHASH:
- 我们首先需要一些数据进行哈希处理。
iLoveBitcoin
- 我将字母和数字转换成 1 和 0(计算机中的所有数据都以 1 和 0 的形式存储,不同的 1 和 0 的组合代表不同的字母)。
iLoveBitcoin→ 100010100000101111
- 此时,我们将按照预先设定的步骤对数据进行转换。这些步骤可以是任意的,重要的是,无论何时使用 LANEHASH,我们都需要遵循相同的步骤,以确保算法的确定性。
- 我们将左侧的前四个比特移到右侧。
1000 10100000101111 → 10100000101111 1000
- 我们将其他所有部分分开。
1 0 1 0 0 0 0 0 1 0 1 1 1 1 1 0 0 0 → 110011110 & 000001100
- 我们将这两部分转换成十进制数。十进制是我们学校都学过的“标准”数字系统。(所有二进制数据实际上都是数字,你可以很容易地在网上找到二进制如何转换成十进制的方法。)
110011110 → 414
000001100→ 12
- 我们将这两个数相乘。
414 * 12 = 4968
- 我们将这个数平方。
4968 ^ 2 = 24681024
- 我们将该数字转换回二进制。
24681024 →1011110001001101001000000
- 我们从右侧切掉 9 位,正好得到 16 位。
1011110001001101 001000000 → 1011110001001101
- 我们将二进制数据转换回英文。
1011110001001101 → “8sj209dsns02k2”
如你所见,如果开头使用同一个单词,最终结果也总是相同的。但是,即使只改变一个字母,结果也会发生巨大的变化。
**免责声明**
在进行英文与二进制数据互转换的过程中,我并没有遵循任何固定的模式。请不要因此感到困惑。二进制数据与英文数据之间有很多不同的转换方法,我只是不想在本文中过多赘述。以下是一些相关的参考资料:
https://en.wikipedia.org/wiki/ASCII
https://en.wikipedia.org/wiki/Unicode
谢谢
Lane 的推特账号:@wagslane
Dev.to 上的 Lane:wagslane
下载 Qvault:https://qvault.io
请为我们的 GitHub 仓库点赞:https://github.com/q-vault/qvault
这篇文章《哈希函数(SHA-256、MD-5 等)的(非常)基础介绍》最初发表在Qvault上。
文章来源:https://dev.to/bootdotdev/very-basic-intro-to-hash-functions-sha-256-md-5-etc-399j

