Hash加密算法
哈希算法(Hash)又称摘要算法(Digest),它的作用是:对任意一组输入数据进行计算,得到一个固定长度的输出摘要。
哈希算法最重要的特点就是:
- 相同的输入一定得到相同的输出
- 不同的输入大概率得到不同的输出
哈希算法的目的就是为了验证原始数据是否被篡改。
Java字符串的hashCode()
就是一个哈希算法,它的输入是任意字符串,输出是固定的4字节int
整数:
"hello".hashCode(); // 0x5e918d2
"hello, java".hashCode(); // 0x7a9d88e8
"hello, bob".hashCode(); // 0xa0dbae2f
两个相同的字符串永远会计算出相同的hashCode
,否则基于hashCode
定位的HashMap
就无法正常工作。这也是为什么当我们自定义一个class时,覆写equals()
方法时我们必须正确覆写hashCode()
方法。
哈希碰撞
哈希碰撞是指,两个不同的输入得到了相同的输出:
"AaAaAa".hashCode(); // 0x7460e8c0
"BBAaBB".hashCode(); // 0x7460e8c0
那么碰撞能不能避免?答案是不能。碰撞是一定会出现的,因为输出的字节长度是固定的,String
的hashCode()
输出是4字节整数,最多只有4294967296
种输出,但输入的数据长度是不固定的,有无数种输入。所以,哈希算法是把一个无限的输入集合映射到一个有限的输出集合,必然会产生碰撞。
碰撞不可怕,我们担心的不是碰撞,而是碰撞的概率,因为碰撞概率的高低关系到哈希算法的安全性。一个安全的哈希算法必须满足:
- 碰撞概率低
- 不能猜测输出
不能猜测输出是指,输入的任意一个bit的变化会造成输出完全不同,这样就很难从输出反推输入(只能依靠暴力穷举)。假设一种哈希算法有如下规律:
hashA("java001") = "123456"
hashA("java002") = "123457"
hashA("java003") = "123458"
那么很容易从输出123459
反推输入,这种哈希算法就不安全。安全的哈希算法从输出是看不出任何规律的:
hashB("java001") = "123456"
hashB("java002") = "580271"
hashB("java003") = ???
常用的Hash算法
目前常用的几种Hash
加密算法有下面几种,它们的基本原理相同,不同的是输出的固定长度。
算法 | 输出长度(位) | 输出长度(字节) |
---|---|---|
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 |