Haorui: 先举个例子吧。假如有一天老板要你在设备上测试某一个软件版本。于是你就开始从美国的服务器上下载这个软件版本。下载的时候才发现软件非常大,有好几个G,网速又很慢。这个下去,搞不好要下三天两夜呢。这时候,Michael哥过来说,Lauren,我里有这个软件版本,前几天下的,你拷过去好了。
Lauren: 挺好,我就用Michael哥的。
Haorui: 慢着,这里有一个问题,Michael哥给你的软件会不会有问题呢?比如Michael在软件里面植入一个病毒。一旦你使用这个带病毒的软件,它就会自动联网,把设备上的数据全部发出去。
Lauren: 啊!有这么严重吗?Michael哥是好人,他不会这么干的。
Haorui: OK,也许你说的是对的。但是要注意哦,相对于机器而言,人是不可靠的。还有一种可能,Henry在昨天攻击了Michael的电脑,在Michael不知情的情况下,植入一个软件木马到你要的版本上。一旦带木马的软件版本被执行,你的设备就被攻击者远程控制了。
Lauren: 啊!Michael哥的软件不能用呀,从服务器上下载又很慢。这个怎么办呢?不行,Henry也是好人,他也不会干坏事的。
Haorui: OK, 攻击者可以不是Henry,也许是Bjorn,Tony。总之世上总有坏人,你说对吧。
Lauren: 哪怎么办呢?我总感觉你在忽悠我,你说的都是非常小的概率事件。Michael的软件99.99%是原版的。关键是……
Haorui: 关键是什么?
Lauren: 关键是我要找一种方式来验证Michael哥的软件是否可靠。
Haorui: You got it。问题的关键是你要有一种方式验证Michael哥的软件是原版的。前面我们学习的对称与非对称密码系统,可以解决信息的机密性。而今天我们要讨论的是消息的完整性,及消息没有被恶意篡改。这是一个重要的安全问题。有什么技术手段可以做到呢?
Lauren: 我想到一种办法,用CRC校验。每次在服务器上放软件的时候,同时计算一个CRC值放在一起。现在我计算一下Michael哥软件的CRC值,再与服务器是的CRC值比一下,如果是一致的,说明Michael哥的软件是没有问题的。见图7.1我设计的流程图。
Haorui: 看起来不错,你的方案从流程上可以实现。但是Michael可能比你想像的更聪明。Michael在植入病毒的时候,考虑了这个问题,他会对病毒作一些修改,调整,使整个软件的CRC值与服务器上的CRC值一样。这样你就没有办法了。
Lauren: 看来用CRC不行,应该设计一个算法,让Michael哥哪怕改了一个比特位我们都可以发现。
Haorui: 这个就是今天要讲的哈希函数,或者说单向散列函数。通过它计算出来的值叫哈希值或者叫消息的摘要,或是消息的指纹。看看专业的流程如下, 图7.2.
把CRC替换成Hash函数就可以了。首先在你的本地计算Michael哥的软件的Hash值,然后与服务器上的对比。就可以确定软件的完整性。Hash值在这里实际代表这个软件,只要你修改软件的哪怕一个比特位,它的Hash值都不一样。这就是为什么说叫它消息的指纹。Hash算法是非常重要的密码学组件,在很多协议中广泛使用。
Lauren: 明白,也就是说,每次放软件到服务上,也需要计算一个Hash值放在一起,以方便将来验证。
Haorui: 是的。
Lauren: 那么我刚才说的CRC检验与Hash函数算法有啥区别呢?也就是Hash函数有还有啥特点呢?
Haorui: 对于Hash函数的输入,任何长度的文件都可以,输出是一个固定长度的Hash值,根据不同的Hash算法,长度从32位到512位不等,而且Hash函数的计算速度要快。还有一点就是单向性,及给定一个Hash值,通过计算得出消息原文是不可能的。类于模运算,xmod 100 = 5,实际上是你是无法知道x的值,它的解是一个集合。
但最主要的特点就是,刚才己经讲了,不同的文件所产生的Hash值是不同的。
Lauren: 这个不可能完全做到。比如一个100M的文件,计算出的Hash值为128位。一定存在很多个文件也可以得到相同的Hash值。
Haorui: 是的。但是给定一个消息及消息的Hash值,去计算另一个与之具有相同的Hash值的消息是非常困难的。及设hash_val= Hash(mesage1), hash_val和message1是己知的,求解Hash(mesage1)= Hash(mesage2)中的message2?合格的Hash函数要保证你是不无法通过计算得出的,专业上这叫弱抗碰撞性。还有一个概念叫强抗碰撞性,及要找到两个Hash值相同的消息在计算上不可行的。密码学要使用的Hash函数必须具备这弱抗碰撞性和强抗碰撞性。
Lauren: 明白了,Hash函数算法长啥样?
Haorui: 不同的Hash算法实现不一样。看具体的标准吧。常用的单向散列函数有SHA1、SHA256、SHA384、MD4、MD5等。