Hash算法概述
散列算法(Hash Algorithm),又称哈希算法,杂凑算法,是一种从任意文件中创造小的数字「指纹」的方法。与指纹一样,散列算法就是一种以较短的信息来保证文件唯一性的标志,这种标志与文件的每一个字节都相关,而且难以找到逆向规律。因此,当原有文件发生改变时,其标志值也会发生改变,从而告诉文件使用者当前的文件已经不是你所需求的文件。
简单理解为就是把任意长度的数据作为输入,然后通过Hash散列算法得到一个固定长度的输出值,该输出值就是散列值,它是一种数据压缩映射关系。 简单来说就是将做任意长度的消息压缩到某一固定长度的消息摘要的函数。
散列算法特点:
- 正向快速:给定明文和 hash 算法,在有限时间和有限资源内能计算出 hash 值。
- 逆向困难:给定(若干) hash 值,在有限时间内很难(基本不可能)逆推出明文。
- 输入敏感:原始输入信息修改一点信息,产生的 hash 值看起来应该都有很大不同。
- 冲突避免:很难找到两段内容不同的明文,使得它们的 hash 值一致(发生冲突)。即对于任意两个不同的数据块,其hash值相同的可能性极小;对于一个给定的数据块,找到和它hash值相同的数据块极为困难。
Hash算法的分类
1、加法Hash
把输入元素全部加起来构成最后的结果。
static int additiveHash(String key, int prime){
int hash, i;
for (hash = key.length(), i = 0; i < key.length(); i++)
hash += key.charAt(i);
return (hash % prime);
}
2、位运算Hash
利用各种位运算(常见的是移位和异或)来充分的混合输入元素。
uint32_t time33(char const *str, int len) {
unsigned long hash = 0;
for (int i = 0; i < len; i++) {
hash = hash *33 + (unsigned long) str[i];
}
return hash;
}
3、乘法Hash
这种类型的Hash函数利用了乘法的不相关性(乘法的这种性质,最有名的莫过于平方取头尾的随机数生成算法,虽然这种算法效果并不好)。 就是每次hash=hash*n+x
uint32_t time33(char const *str, int len) {
unsigned long hash = 0;
for (int i = 0; i < len; i++) {
hash = hash *33 + (unsigned long) str[i];
}
return hash;
}
jdk5.0里面的String类的hashCode()方法也使用乘法Hash。不过,它使用的乘数是31。
推荐的乘数还有:131, 1313, 13131, 131313等等。
使用这种方式的著名Hash函数还有:
int M_SHIFT = 0;
public int FNVHash(byte[] data){
int hash = (int)2166136261L;
for(byte b : data)
hash = (hash * 16777619) ^ b;
if (M_SHIFT == 0)
return hash;
return (hash ^ (hash >> M_SHIFT)) & M_MASK;
}
4、除法Hash
除法和乘法一样,同样具有表面上看起来的不相关性。不过,因为除法太慢,这种方式几乎找不到真正的应用。需要注意的是,我们在前面看到的hash的 结果除以一个prime的目的只是为了保证结果的范围。
限制一个范围,一般都是与2^n -1 进行与运算
hash=hash & 1111111
如果你需要它限制一个范围的话,运用上面的公式即可,但是会发现hash位数高的部分被截断了,只留下位数低的部分,所以在做除法前,可以使用如下的代码
"hash%prime": hash = hash ^ (hash>>10) ^ (hash>>20)。
这个公式能让hash的后位与前位进行混合,比如0-10位与10-20,20-30 进行亦或操作,让位数低的部分包含位数高的部分的特征
5、查表Hash
int crc32(String key, int hash){
int i;
for (hash=key.length(), i=0; i
hash = (hash >> 8) ^ crctab[(hash & 0xff) ^ k.charAt(i)];
return hash;
}
6、混合Hash
混合Hash算法利用了以上各种方式。各种常见的Hash算法,比如MD5、Tiger都属于这个范围。它们一般很少在面向查找的Hash函数里面使用。(一般用于对文件之类的,生成一个对象的特征,需要加密和安全,比较复杂)
经典散列算法
名称 | 安全性 | 速度 |
SHA-1 | 高 | 慢 |
MD5 | 中 | 快 |
MD4 | 低 | 中 |
1、MD4
MD4(RFC 1320)是 MIT 的 Ronald L. Rivest 在 1990 年设计的,MD 是 Message Digest 的缩写。它适用在32位字长的处理器上用高速软件实现--它是基于 32 位操作数的位操作来实现的。其输出为 128 位。MD4 已证明不够安全。
2、MD5
对MD4的改进版本。它对输入仍以512位分组,其输出是4个32位字的级联(128位),与 MD4 相同。MD5比MD4来得复杂,并且速度较之要慢一点,但更安全,在抗分析和抗差分方面表现更好。MD5 已被证明不具备"强抗碰撞性"。
3、SHA-1
这是一种数据加密算法,该算法的思想是接收一段明文,然后以一种不可逆的方式将它转换成一段(通常更小)密文,也可以简单的理解为取一串输入码(称为预映射或信息),并把它们转化为长度较短、位数固定的输出序列即散列值(也称为信息摘要或信息认证代码)的过程。