在理解哈希函数之前,我们需要先弄明白数学上的一个重要概念,单向散列函数?
什么是单向散列函数?
首先,我们从名字上看,一眼就能看出来单向散列函数有两个关键修饰词,“单向”和“散列”。 其实,在数学上,单向函数和散列函数是两个不同类型的函数。所以,我们要想理解单向散列函数,我们就要先知道什么是单向函数,什么又是散列函数。
什么是单向函数?
单向函数(One-way Function)是正向计算容易,逆向运算困难的函数。也就是说,给定你一个输入,你很容易计算出输出;但是给定你一个输出,你却很难计算出输入是什么。
用一个通俗的例子讲,把盘子打碎是一件很简单的事情,但是把这些碎片再拼接成一个完整的盘子,就是一件非常困难的事情。
但值得注意是:虽然我们强调,单向函数只能正向计算,不能逆向运算。但其实,这只是一个美好的愿望。为什么我这么说?
因为就算把盘子碎片再拼接起来非常困难,但是仅仅就是非常困难而已,无论是手工还是计算机辅助,碎盘子还是可以拼接起来的。只是需要花很长的时间而已。 这也是现在加密算法的基础,如果给定无限时间,任何加密算法都是可以被破解的,但是可能需要两千年,这个放在人类社会中,是不可接受的,于是我们把这种需要很长很长时间才能破解的“加密算法” 认为是不可破解的。
什么是散列函数?
散列函数(Hash Function)是一个可以把任意大小的数据,转行成固定长度的数据的函数。 比如说,无论输入数据是一个字节,或者一万个字节,输出数据都是 16 个字节。我们把转换后的数据,叫做散列值。因为散列函数经常被人们直译为哈希函数,所以我们也可以称散列值为哈希值。通常的,对于给定的输入数据和散列函数,散列值是确定不变的。
哈希碰撞
问题:既然输入数据的大小没有限制,而输出结果的数据长度固定,那么你觉得,会不会存在散列值相同的两个或者 多个数据呢?
答案: 确定存在的。于是我们把这种情况称之为哈希碰撞。
如何解决Hash碰撞
方案一: 我们可以让数据变得更长,散列值越长,存在相同散列值的概率就越小,发生碰撞的可能性就越小。常见的哈希函算法有,MD5,与SHA1,SHA256,其长度变化如下图:
方案二: 一个好的散列函数,它的散列值应该是均匀分布的。也就是说,每一个散列值出现的概率都是一样的。如果不这样的话,一部分散列值出现的概率就会较高,另一部分散列值出现的概率会较低,别人就更容易构造出两个或者多个数据,使得它们具有相同的散列值。这种行为,叫做碰撞攻击。
我们在写代码经常会发现有**“盐值”的参数,他的目的就是为了让散列值的概率分布的更均匀一些。**
什么叫哈希函数?
数学中的单项散列函数,放在编程的世界里面,我们称为哈希函数
哈希函数的特点:
- 逆向运算困难;
- 构造碰撞困难。
哈希函数的代码运用
const crypto = require('crypto');
const dist0 = crypto.createHash('sha256').update('hello block-chain').digest('hex')
const dist1 = crypto.createHash('sha256').update('hello1 block-chain').digest('hex')
const dist2 = crypto.createHash('sha256').update('hello').update(' block-chain').digest('hex')
console.log('dist0', dist0)
console.log('dist1', dist1)
console.log('dist2', dist2)
根据上面的案例我们发现如下特点:
- dist0与dist2,输出的内容一样,根据这个我们可以发现,主要输入内容一样,他们的哈希值就是一样的。
- dist0与dist1,我们只改变了一点点内容,发现输出的哈希值完全不一样,我们把这种情况,称之为“雪崩效应”。
雪崩效应(Avalanche Effect)是密码学算法一个常见的特点,指的是输入数据的微小变换,就会导致输出数据的巨大变化。 严格雪崩效应是雪崩效应的一个形式化指标,我们也常用来衡量均匀分布。严格雪崩效应指的是,如果输入数据的一位反转,输出数据的每一位都有 50% 的概率会发生变化。
哈希函数的实际运用场景
- 安全校验
- 唯一标识
- 数据校验
哈希函数在编程场景中运用是非常多的,这里提供了一篇比较好的文章,感兴趣的可以点进去看看 —— 算法:哈希算法的应用场景