验证数据的完整性

在网上下载东西的时候往往会提供md5验证字符串,这样就可以对下载的东西验证是否数据完整。数据完整性可以保证数据是否被更改过,只要更改一个字节,那么得到的md5就和先前不同。下面用node.js为一段字符串生成一个md5字符串,然后更改一下字符串再次生成一下md5,看看两次的md5值是否一致。

// 导入加密解密库
var crypto = require("crypto");

// 创建一个md5生成工具对象
var md5hash = crypto.createHash("md5");
// 测试用的字符串
var str = "hello world!";
// 把字符串md5生成器,可多此调用。
md5hash.update(str);
// 生成最终的md5值
var hexstr = md5hash.digest("hex");
console.log(hexstr);
// 打印结果 fc3ff98e8c6a0d3087d515c0473f8677

// 第二次生成同样的字符串
// 创建一个md5生成工具对象
// 如果已调用过digest,那么必须重新生成md5hash。
md5hash = crypto.createHash("md5");
// 把字符串md5生成器,可多此调用。
md5hash.update(str);
// 第二次生成最终的md5值
hexstr = md5hash.digest("hex");
console.log(hexstr);
// 打印结果 fc3ff98e8c6a0d3087d515c0473f8677

// 第三次生成
md5hash = crypto.createHash("md5");
// 把字符串md5生成器,可多此调用。
md5hash.update(str);
md5hash.update("leo");
// 第三次生成最终的md5值
hexstr = md5hash.digest("hex");
console.log(hexstr);
// 打印结果 037011eb16e5358f3908372c7f27cda4

仔细看这段代码,会发现为同样的字符串生成的md5值是一样的,第一次和第二次调用md5hash.digest生成的md5值是相同的,第三次多调用了一次update生成的md5就不相同了,也就是说,数据变化造成md5也不相同。

通过上述例子,基本了解了状况,也就是通过某种手段把数据(多大都没关系)通过多次或一次性的加入到md5生成器中,然后调用digest方法得到一小段字符串,这个字符串就可以证明数据的完整性。

node.js 中数据验证的手段有一些,下面把这些手段慢慢道来。

通过 crypto.createHash(algorithm) 和 crypto.createHmac(algorithm, key) 方法可以得到生成器。当然并不只是能生成md5生成器,其实也差不多,无非就是算法不同而已,无论多么复杂,思路要清晰,要记住生成器无非就是生成一小段字符串,用来验证数据完整性而已!

crypto.createHash(algorithm)

这个会得到Hash对象,也就是生成器。algorithm算法,有很多,md5是其中一种,对于我们来说无所谓,随便选择一个即可,要想知道当前node.js版本支持那些算法,可以通过crypto.getHashs() 得到一个数组,看下面我的机器得到了那些算法,这些算法随意挑一个用即可,无所谓,谁又晓得这些算法有什么区别。

var crypto = require("crypto");
console.log(crypto.getHashes());

打印出:

[ 'DSA-SHA1-old',
 'dsa',
 'dsa-sha',
 'dsa-sha1',
 'dsaEncryption',
 'dsaWithSHA',
 'dsaWithSHA1',
 'dss1',
 'ecdsa-with-SHA1',
 'md4',
 'md4WithRSAEncryption',
 'md5',
 'md5WithRSAEncryption',
 'mdc2',
 'mdc2WithRSA',
 'ripemd',
 'ripemd160',
 'ripemd160WithRSA',
 'rmd160',
 'rsa-md4',
 'rsa-md5',
 'rsa-mdc2',
 'rsa-ripemd160',
 'rsa-sha',
 'rsa-sha1',
 'rsa-sha1-2',
 'rsa-sha224',
 'rsa-sha256',
 'rsa-sha384',
 'rsa-sha512',
 'sha',
 'sha1',
 'sha1WithRSAEncryption',
 'sha224',
 'sha224WithRSAEncryption',
 'sha256',
 'sha256WithRSAEncryption',
 'sha384',
 'sha384WithRSAEncryption',
 'sha512',
 'sha512WithRSAEncryption',
 'shaWithRSAEncryption',
 'ssl2-md5',
 'ssl3-md5',
 'ssl3-sha1',
 'whirlpool' ]

my god! 我只认识md5! 其实无所谓,说真的,身为作者的我连md5原理都不懂。不过我会用,这就够了。就好比不懂电的原理,也会开关灯照明一样。忘记这些算法噩梦吧,我们继续。

随意选择一个... 看哪个好看呢,除了md5,我们选择sha算法,管他是怎么算的呢。

// 生成个莫名其妙sha创建器

sha = crypto.createHash("sha");下面丢两端字符串给它。

var crypto = require("crypto");
var sha = crypto.createHash("sha");
sha.update("my name is ")
sha.update("利奥")

然后digest一下,看看生成hex字符串。

var crypto = require("crypto");
var sha = crypto.createHash("sha");
sha.update("my name is ")
sha.update("利奥")
console.log(sha.digest("hex"))

打印出结果:

19985bb2a9a65daad500e4b70727d13497448709

下面把两端update合为一个,字符串内容是一样的,看看sha的结果是否一致。

var crypto = require("crypto");
var sha = crypto.createHash("sha");
sha.update("my name is 利奥")
console.log(sha.digest("hex"))

打印结果与先前一致:

19985bb2a9a65daad500e4b70727d13497448709
crypto.createHmac(algorithm, key)

这个方法得到Hmac对象,谁知道Hmac是啥呢,不过只要知道他的功能和前面介绍的Hash一样就行了,也是用来验证数据完整性的。

这个方法的不同无非就是多了一个key,比如update的数据都一致,就是key不同,那么digest得到的结果也不同。看个完整例子吧。

var crypto = require("crypto");
var sha = crypto.createHmac("sha","lol");
sha.update("my name is 利奥")
console.log(sha.digest("hex"))

得到的结果是:

2ff412ce186bea688c8501569554641bec669c95

下面把key变一下,看看结果

var crypto = require("crypto");
// 变成god
var sha = crypto.createHmac("sha","god");
sha.update("my name is 利奥")
console.log(sha.digest("hex"))

打印结果变成为了

fe95a527cbc60deec342a3d917360e649ef096cc
小结

本节介绍了数据完整性的验证,验证无非就是用一小段字符串,如果字符串相同就说明数据一致。Hash和Hmac对象都是用来生成这种字符串的,区别就是Hmac多了一个key,这就说明,采用Hmac方式只知道验证字符串还不够,还得知道key,才能确定数据是否一致。下一节介绍加密与解密数据。