hashcode 每个人都不陌生,我从接触计算机就开始听说这个名词,但是对其理解,其实一直限于知道有这个东西,大体上是干嘛的,从来没有细致的去思考过它存在的意义。直到研究一个加密 IM 的项目,去思考和学习加密相关的知识,对 hashcode 才慢慢熟悉起来,对其相关的知识也有了一些了解。本篇主要讲自己在接触 hashcode 过程中的一些感悟和思考。秉承习惯,用白话来描述,尽量避免专业词汇。
Hash 是什么(不同输入,定长输出)
先把 hash 作为一个函数来说:hash 函数是对输入数据,输出一个定长的编号,就是输入的可能是一个视频文件,可能是图片,可能是 text 文本,也可能是一个字母 a,b,c 。不管输入是什么,输入的根本都是二进制的 0和1 的一个序列。无论输入的 0 和1 的序列是怎样的顺序,多长,经过 hash 函数计算都会输出一个定长的编号。而这个编号就称为 hashcode。
我的理解是:互联网庞杂的数据需要管理,所以需要对其编号,每个文件都有一串定长的数与之对应起来。相当于给每个人一个身份证号码。既然是类似身份证号码,所以要保证不能有两个人拥有同一个身份证号码吧。所以 hash 函数要保证两个不同的输入,输出的编号也是不一样的。**即不同的输入,经过 hash 函数计算产生不同的 hashcode。**(由于工程实现一一对应比较困难,可能存在不同输入,产生相同的 hashcode ,这种现象叫碰撞,好的 hash 函数应该把碰撞概率尽可能的降低)
hashcode 校验文件完整性(输入敏感)
由上面的条件,可以做到对输入数据进行编号,我们可以 hashcode 来作为一个文件的 id。通常称 hashcode 为一个文件的指纹。即这个指纹就代表是这个文件。如果文件被改动,那文件也就变为另外一个 0 和 1的序列,那它的 hashcode 也应该被改变,才能符合我们上面说的一个文件对应一个 hashcode 的情况。为了强化这种改变,hash 函数一般应该设计为对输入敏感,即输入微小改动会引起输出的 hashcode 面目全非,改动很大。这样 hashcode 就拥有了校验文件完整性的功能。我们传输文件时,附加上文件的 hashcode ,接收方就可以对接收到的文件进行 hash 计算,得出其 hashcode ,对比传过来的 hashcode 是否一致,来判断传输过程中文件完整性是否被破坏。这种机制只能保证文件完整性,并不能保证文件有没有被替换,如果文件和 hashcode 同时替换,这种机制下是无法保证的。** hash 函数的输入敏感性是保证消息完整性的核心,即输入微小改变,产生 hashcode会发生很大改变**
防止从 hashcode 推测输入内容(单向性)
在保证完整性的同时怎么保证文件和 hashcode 没有被一起替换掉呢?因为上面说的 hash 的输入敏感性,如果我们在文件的二进制序列前面加一串字符,再对文件进行 hash ,然后我们和接收方约定了在文件前面加这串字符。接收方收到文件,就可以在文件前面加这串字符,再进行 hash 计算 的到 hashcode ,对比和传输过来的hashcode 是否一致。这样就能够保证传输过程中无法把 hashcode 和文件同时替换掉而不被感知。
因为替换文件后无法算出符合既定规则的 hashcode ,在接收方完整性校验无法通过。但是这里有一个前提,就是通过 hashcode 和文件,无法推算出前面添加了字符串,更无法推出这一串字符是什么。这就要求 hash 过程是单向的,即不能通过 hashcode 知道输入是什么。所以 hash 函数又要求具有单向性,即可以通过输出产生确定的 hashcode ,但是通过 hashcode 不能推算出输入的内容。
由以上内容可以得知:hash函数具有的性质:
+ 不同输入,定长输出;
+ 输入敏感,输入微小改变,输出改变很大;
+ 单向性,可以由输入计算输出 hashcode,无法从 hashcode 计算出输入。
Hash 与数字签名
数字签名,即数字化的签名,我们先来看生活中签名一份租房合同来举例。
+ 签名不能被别人伪造,房东如果随便搞一份合同,随便找个人签你的名字,就来找你收房租,你肯定不会交,而是说,这根本就不是我签的,这是伪造的,不是我的笔迹。
+ 签名不能抵赖,你签了合同,白纸黑字。总不能抵赖住了房不交房租,说不是你签的吧,你的名字,你的笔迹,在合同上呢。
+ 签名对应的合同不能被篡改,改了要能看出来。本来合同上写着 每月 1000元租金。如果你把自己那份合同改成了每月100元,或者房东把自己的合同改成每月10000元,对质公堂的时候一定要能看出来是谁篡改了合同。(这也就是为什么收据,合同,欠款条啥的,都用大写字:壹仟元整。不是为了装逼,而是防止随便改动,加个0或者少个0不留痕迹)
数字签名,既然能作为一种签名自然也要具备这些性质:防伪造,防抵赖,防篡改
数字签名的这些性质怎样来实现呢?
我们在前面说过,hash 是输入敏感性,即输入微小改动会引起输出很大变化,很难找到两个不同的输入,拥有相同的输出。而且输入不同对应定长输出 hashcode。根据这个特性可以知道,一份洋洋洒洒几千字的合同,上面的字可以和一串 hashcode 对应起来,内容改动 hashcode 就会改动,只要算出这个 hashcode 是对的,说明这个合同就是和 hashcode 是配套的,没有被篡改。
但是 hashcode 只能用来验证完整性,保证合同不被篡改。如果要签名防抵赖,防伪造确是无法做到的。这时候就需要有一种机制来保证有以下条件才能实现防伪造,和防抵赖:
1. 防伪造:
+ 必需有一种标记,只有自己能造出来,别人无法产生。
+ 对每个合同的来说标记都是不同的,这个标记要和被标记的合同绑定起来,标记带有合同的信息,合同细微变化,标记也会随之变化
2. 防抵赖:
+ 大家必需都能检验这个标记。
+ 每做标记的人有专属自己的公开的确定的方式来让大家验证。
非对称加密公私钥和 hash 结合起来,完美的解决了这个上面的场景。关于公私钥本篇不再展开讲述,不了解的自行搜索。这里只说一个性质:
+ 用私钥加密的数据,用公钥可以解密,而且以现在的算力,无法从公钥计算出私钥
我们可以根据公私钥加密的这种性质结合 hash 来制作出上面的这种标记(签名)。
1. 对合同文件做 hash 计算生成 hashcode ,又称为文件的摘要 digest ,又称为文件的指纹
2. 用私钥加密 hashcode 生成加密数据,即文件的签名。
3. 用公钥可以解密签名,解密后的 hashcode 和文件计算出的 hashcode 一致,则说明文件内容没有被篡改
4. 把公钥和个人信息交给第三方来公证,绑定在一起,这样私钥所生成签名的文件,就代表私钥持有人的签名,可以防抵赖。
网友评论