哈希算法(Hash)又称摘要算法(Digest),它的作用是:对任意一组输入数据进行计算,得到一个固定长度的输出摘要。
Java
字符串的hashCode()
就是一个哈希算法,它的输入是任意字符串,输出是固定的4字节int整数:
1 | "hello".hashCode(); // 0x5e918d2 |
两个相同的字符串永远会计算出相同的hashCode
,否则基于hashCode
定位的HashMap
就无法正常工作。这也是为什么当我们自定义一个class
时,覆写equals()
方法时我们必须正确覆写hashCode()
方法。
哈希碰撞
哈希碰撞是指,两个不同的输入得到了相同的输出:
1 | "AaAaAa".hashCode(); // 0x7460e8c0 |
String
的hashCode()
输出是4字节
整数,最多只有4294967296
种输出,但输入的数据长度是不固定的,有无数种输入。所以,哈希算法是把一个无限的输入集合映射到一个有限的输出集合,必然会产生碰撞。
常见哈希算法
算法 | 输出长度(位) | 输出长度(字节) |
---|---|---|
MD5 | 128 bits | 16 bytes |
SHA-1 | 160 bits | 20 bytes |
RipeMD-160 | 160 bits | 20 bytes |
SHA-256 | 256 bits | 32 bytes |
SHA-512 | 512 bits | 64 bytes |
根据碰撞概率,哈希算法的输出长度越长,就越难产生碰撞,也就越安全。
MD5
1 | import java.math.BigInteger; |
使用MessageDigest
时,我们首先根据哈希算法获取一个MessageDigest
实例,然后,反复调用update(byte[])
输入数据。当输入结束后,调用digest()
方法获得byte[]
数组表示的摘要,最后,把它转换为十六进制的字符串。
运行上述代码,可以得到输入HelloWorld
的MD5
是68e109f0f40ca72a15e05cc22786f8e6
。
或者不反复调用 update
,直接
1 | md.update("HelloWorld".getBytes("UTF-8")); |
结果还是一样。
SHA-1
SHA-1
也是一种哈希算法,它的输出是160 bits
,即20字节
。SHA-1
是由美国国家安全局开发的,SHA
算法实际上是一个系列,包括SHA-0
(已废弃)、SHA-1
、SHA-256
、SHA-512
等。
在Java
中使用SHA-1
,和MD5
完全一样,只需要把算法名称改为”SHA-1
“:
1 | import java.math.BigInteger; |
类似的,计算SHA-256
,我们需要传入名称”SHA-256
“,计算SHA-512
,我们需要传入名称”SHA-512
“。Java标准库
支持的所有哈希算法可以在这里查到。
注意:MD5
因为输出长度较短,短时间内破解是可能的,目前已经不推荐使用。