目录
什么是Hash算法
任意长度的输入经过Hash算法转化为一定长度的输出。就像读很多本书,最终总结成一本摘要,
看书的操作可以理解为hash算法,总结一本摘要可以理解为hash值,所以hash算法也称为摘要算法或者散列算法。
Hash算法的特点
不可逆,不能通过hash值计算出原本的值。
效率高,hash算法通常能够快速的得到结果。
冲突少,优秀的hash算法应具备的条件。
Hash算法有哪些
目前流行的Hash算法包括MD5、SHA-1 和 SHA-2。
MD4(RFC 1320)是MIT的Ronald L. Rivest在1990年设计的,MD是Message Digest的缩写,其输出为128位,MD4已被证明不够安全。
MD5(RFC 1321)是Rivest于1991年对MD4的改进版本。它对输入仍以512位分组,其输出是128位。MD5比MD4复杂,计算速度要慢一点,但是更安全一些。MD5已被证明不具备"强抗碰撞性"。
SHA(Secure Hash Algorithm)是一个Hash函数族,由NIST(National Institute of Standards and Technology)于1993年发布第一个算法。
SHA-1在1995年面世,它的输出为长度160位的hash值,因此抗穷举性更好。设计时基于和MD4 相同原理,并且模仿了该算法,SHA-1已被证明不具"强抗碰撞性"。
SHA-2为了提高安全性,NIST还设计出了SHA-224、SHA-256、SHA-384和SHA-512算法(统称为 SHA-2),跟SHA-1算法原理类似。SHA-3相关算法也已被提出。
Hash应用
密码学及数字签名
登陆知乎时需要输入密码,知乎如果明文保存这个密码,黑客就很容易窃取到登录的密码,特别不安全。然后知乎就想了一个方法,使用hash算法生成一个密码的签名,知乎后台只保存这个签名值。由于hash算法是不可逆的,黑客即便拿到这个签名也没用。在网站登陆界面上输入密码,知乎后台会重新计算一下这个hash值,与网站中储存的原hash值进行比对,如果相同,证明你拥有这个账户的密码,就会允许登陆。
文件完整性校验
//两段字节串,注意它们有细微差别
a = bytearray.fromhex("0e306561559aa787d00bc6f70bbdfe3404cf03659e704f8534c00ffb659c4
c8740cc942feb2da115a3f4155cbb8607497386656d7d1f34a42059d78f5a8dd1ef")
b = bytearray.fromhex("0e306561559aa787d00bc6f70bbdfe3404cf03659e744f8534c00ffb659c4
c8740cc942feb2da115a3f415dcbb8607497386656d7d1f34a42059d78f5a8dd1ef")
//输出MD5
print(hashlib.md5(a).hexdigest())
print(hashlib.md5(b).hexdigest())
//a和b输出结果都为:
cee9a457e790cf20d4bdaa6d69f01e41
cee9a457e790cf20d4bdaa6d69f01e41
文件内容a和b有细微的修改,得到的hash值应该不一样才对,所以MD5在数年前就已经不被推荐作为应用中的散列算法方案,取代它的是SHA家族算法,也就是安全散列算法(Secure Hash Algorithm,缩写为SHA) 。
JAVA中基于Hash的数据结构
HashMap是对Array与Link的折衷处理,Array与Link可以说是两个速度方向的极端,Array注重于数据的获取,而添加/删除的效率非常低,Link由于是每个对象都保持着下一个对象的指针,查找某个数据需要遍历之前所有的数据,效率比较低,在修改操作中比较快。
JDK1.8HashMap中Hash值的计算
static final int hash(Object key) {
int h;
//计算hashCode
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
Java中几个常用的哈希码(hashCode)算法
Object类的hashCode:返回的是经过处理后的内存地址,由于每个对象的内存地址都不一样,所以哈希码也不一样。这个是native方法,取决于JVM的内部设计,一般是某种C地址的偏移。
String类的hashCode:根据字符串的内容返回哈希码,只要字符串的内容相同,返回的哈希码也相同,JDK1.8中的String.hashCode()如下:
public int hashCode() {
int h = hash;
//hash default value : 0
if (h == 0 && value.length > 0) {
//value : char storage
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
Integer等包装类,返回的哈希码就是Integer对象里包含的那个整数的数值。
Integer n=new Integer(100);
//n.hashCode的值就是100
由此可见,两个一样大小的Integer对象,返回的哈希码也一样 。
什么是Hash冲突
当Key值利用Hash算法定位到数组的某个位置,该位置已经有值时,就会产生冲突,称为Hash冲突。
如何解决Hash冲突
链地址法:利用链表解决。
开放地址法:向下线性或者随机探测不冲突的地址。
再Hash法:通过多个hash算法重新定位。