一、哈希函数特点
1.确定性
如果两个哈希值不相同(根据同一函数),那么这两个哈希值的原始输入也是不相同的。
2.散列碰撞
哈希函数的输入和输出不是唯一对应关系的,如果两个哈希值相同,两个输入值很可能是相同的,但也可能不同。
3.不可逆性
哈希函数是一个单向密码体制,即从明文到密文的不可逆映射,只有加密过程没有解密过程。
4.混淆特性
输入一些数据计算出哈希值,然后部分改变输入值,一个具有强混淆特性的哈希函数会产生一个完全不同的哈希值。
二、常用哈希算法
1.MD4
MD4(RFC 1320)是MIT的Ronald L.Rivest在1990年设计的,MD是Message Digest(消息摘要)的缩写。它适用在32位字长的处理器上用高速软件实现——它是基于32位操作数的位操作来实现的。
2.MD5
MD5(RFC 1321)是Rivest于1991年对MD4的改进版本。它对输入仍以512位分组,其输出是4个32位字的级联,与MD4相同。MD5比MD4来得复杂,并且速度较之要慢一点,但更安全,在抗分析和抗差分方面表现更好。
3.SHA-1
SHA1是由NIST NSA设计为同DSA一起使用的,它对长度小于264的输入,产生长度为160bit的散列值,因此抗穷举(brute-force)性更好。SHA-1设计时基于和MD4相同原理,并且模仿了该算法。
三、常见哈希算法原理
散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
比如我们存储70个元素,但我们可能为这70个元素申请了100个元素的空间。70/100=0.7,这个数字称为负载因子。我们之所以这样做,也是为了“快速存取”的目的。我们基于一种结果尽可能随机平均分布的固定函数H为每个元素安排存储位置,这样就可以避免遍历性质的线性搜索,以达到快速存取。但是由于此随机性,也必然导致一个问题就是冲突。所谓冲突,即两个元素通过散列函数H得到的地址相同,那么这两个元素称为“同义词”。这类似于70个人去一个有100个椅子的饭店吃饭。散列函数的计算结果是一个存储单位地址,每个存储单位称为“桶”。设一个散列表有m个桶,则散列函数的值域应为[0,m-1]。
四、哈希冲突
理想中的一个哈希函数,希望达到如果key1≠key2,那hash(key1)≠hash(key2)这种效果,然而在真实的情况下,要想找到一个不同的key对应的哈希值都不一样的哈希函数,几乎是不可能的,即使是MD5或者由美国国家安全局设计的SHA-1算法也无法实现。
事实上,再好的哈希函数都无法避免哈希冲突。为什么呢?这涉及到数学中比较好理解的一个原理:抽屉原理。抽屉原理:桌上有十个苹果,要把这十个苹果放到九个抽屉里,无论怎样放,我们会发现至少会有一个抽屉里面至少放两个苹果。这一现象就是我们所说的“抽屉原理”。
对于哈希表而言,无论设置的存储区域(n)有多大,当需要存储的数据大于n时,那么必然会存在哈希值相同的情况。这就是所谓的哈希冲突。