这个HASH算法不是大学里数据结构课里那个HASH表的算法。这里的HASH算法是密码学的基础,比较常用的有MD5和SHA,最重要的两条性质,就是不可逆和无冲突。
所谓不可逆,就是当你知道x的HASH值,无法求出x;
所谓无冲突,就是当你知道x,无法求出一个y, 使x与y的HASH值相同。
这两条性质在数学上都是不成立的。因为一个函数必然可逆,且由于HASH函数的值域有限,理论上会有无穷多个不同的原始值,它们的hash值都相同。MD5和SHA做到的,是求逆和求冲突在计算上不可能,也就是正向计算很容易,而反向计算即使穷尽人类所有的计算资源都做不到。
我觉得密码学的几个算法(HASH、对称加密、公私钥)是计算机科学领域最伟大的发明之一,它授予了弱小的个人在强权面前信息的安全(而且是绝对的安全)。举个例子,只要你一直使用https与国外站点通讯,并注意对方的公钥没有被篡改,G**W可以断开你的连接,但它永远不可能知道你们的传输内容是什么。
顺便说一下,王小云教授曾经成功制造出MD5的碰撞,即md5(a) = md5(b)。这样的碰撞只能随机生成,并不能根据一个已知的a求出b(即并没有破坏MD5的无冲突特性)。但这已经让他声名大噪了
作者:蒋又新
链接:https://www.zhihu.com/question/20820286/answer/16319538
hash(散列、杂凑)函数,是将任意长度的数据映射到有限长度的域上。直观解释起来,就是对一串数据m进行杂糅,输出另一段固定长度的数据h,作为这段数据的特征(指纹)。
也就是说,无论数据块m有多大,其输出值h为固定长度。到底是什么原理?将m分成固定长度(如128位),依次进行hash运算,然后用不同的方法迭代即可(如前一块的hash值与后一块的hash值进行异或)。如果不够128位怎么办?用0补全或者用1补全随意,算法中约定好就可以了。
原问题回答完毕。但是既然要说hash算法,不妨说的更透彻些。
=================分割线==========
由于用途的不同,hash在数据结构中的含义和密码学中的含义并不相同,所以在这两种不同的领域里,算法的设计侧重点也不同。
预备小知识:
抗碰撞能力:对于任意两个不同的数据块,其hash值相同的可能性极小;对于一个给定的数据块,找到和它hash值相同的数据块极为困难。
抗篡改能力:对于一个数据块,哪怕只改动其一个比特位,其hash值的改动也会非常大。
在用到hash进行管理的数据结构中,比如hashmap,hash值(key)存在的目的是加速键值对的查找,key的作用是为了将元素适当地放在各个桶里,对于抗碰撞的要求没有那么高。换句话说,hash出来的key,只要保证value大致均匀的放在不同的桶里就可以了。但整个算法的set性能,直接与hash值产生的速度有关,所以这时候的hash值的产生速度就尤为重要,以JDK中的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; }
很简洁的一个乘加迭代运算,在不少的hash算法中,使用的是异或+加法进行迭代,速度和前者差不多。
在密码学中,hash算法的作用主要是用于消息摘要和签名,换句话说,它主要用于对整个消息的完整性进行校验。举个例子,我们登陆知乎的时候都需要输入密码,那么知乎如果明文保存这个密码,那么黑客就很容易窃取大家的密码来登陆,特别不安全。那么知乎就想到了一个方法,使用hash算法生成一个密码的签名,知乎后台只保存这个签名值。由于hash算法是不可逆的,那么黑客即便得到这个签名,也丝毫没有用处;而如果你在网站登陆界面上输入你的密码,那么知乎后台就会重新计算一下这个hash值,与网站中储存的原hash值进行比对,如果相同,证明你拥有这个账户的密码,那么就会允许你登陆。银行也是如此,银行是万万不敢保存用户密码的原文的,只会保存密码的hash值而而已。
在这些应用场景里,对于抗碰撞和抗篡改能力要求极高,对速度的要求在其次。一个设计良好的hash算法,其抗碰撞能力是很高的。以MD5为例,其输出长度为128位,设计预期碰撞概率为,这是一个极小极小的数字——而即便是在MD5被王小云教授破解之后,其碰撞概率上限也高达,也就是说,至少需要找次才能有1/2的概率来找到一个与目标文件相同的hash值。而对于两个相似的字符串,MD5加密结果如下:
MD5("version1") = "966634ebf2fc135707d6753692bf4b1e";
MD5("version2") = "2e0e95285f08a07dea17e7ee111b21c8";
可以看到仅仅一个比特位的改变,二者的MD5值就天差地别了。
到这里,读者估计会问,有没有可能找到这么一个算法,如果输出长度为128位,那么把这128位“充分利用到”,让它可以有种不同的hash值,而且分布均匀,抗篡改能力也特别高,一点点改动就会让hash值面目全非,一点都不浪费(这里的表述非常不严格)?稍微严格一点表述,就是:有没有这样一个算法,使得对于任何一个给定的输入,此算法都会输出一个固定的均匀随机的输出?
答案是密码学家们也至今没有构造出着这样一个算法,但是倾向于这个算法存在,而且有不少的密码学算法构造和这个假设有关。这个假设的名字叫做随机预言机(Random Oracle)。
在密码学中,hash算法有不少有意思的改进思路,以应付不同的使用场景。例如师兄
前一段时间让我写着玩的变色龙Hash(ChameleonHash),它有一个有趣的特性。在普通情况下,ChameleonHash可以当做普通hash算法使用,从明文(用m表示)得到的hash值(用h表示)抗碰撞能力依然特别强;但是如果使用者在计算这个hash值的时候预先计算一个值(用s表示)并保存,那么通过这个值很容易计算出另一个hash值也为h的明文m’ !也就是说,如果你保留这个值的话,hash算法的抗碰撞能力完全被解除了。
这意味着,如果某个网站想要作恶的话,那么它可以很容易的替换他们自己的hash算法为ChameleonHash,方便地伪造出一个密钥来窃取用户的所有数据,而这个公司完全可以在对外宣传的时候,依然声称对用户信息严格保密——《教网站如何优雅地耍流氓》。
作者:之幽
链接:https://www.zhihu.com/question/26762707/answer/40119521
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/119364.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...