主讲人张方雄
crypto模块的目的是为了提供通用的加密和哈希算法。用纯JavaScript代码实现这些功能不是不可能,但速度会非常慢。Nodejs用C/C++实现这些算法后,通过cypto这个模块暴露为JavaScript接口,这样用起来方便,运行速度也快。
前提知识-加密算法介绍
- 什么是加密算法 加密算法很容易理解,就是把明文变成人家看不懂的东西,然后送给自己想要的送到的地方,接收方用配套的解密算法又把密文解开成明文,这样就不怕密文给人家截获而泄密。
- 加密算法的种类 大致分为2类,一种是基于key的,一种不是基于key的。 不基于key的算法就是消息双方都通过一定的加密和解密算法来进行通信,这种算法缺点很明显如果加密算法被破解了就泄露了。
- 基于key的加密算法 key是一个什么东西呢?随便你,可以是一个随机产生的数字,或者一个单词,啥都行,只要你用的算法认为你选来做key的东西合法就行。所以基于key的加密算法又分为2类:对称加密和不对称加密。对称加密算法的原理很容易理解,通信一方用KEK加密明文,另一方收到之后用同样的KEY来解密就可以得到明文。
- 不对称加密算法 不对称加密指双方用不同的KEY加密和解密明文,通信双方都要有自己的公共密钥和私有密钥。举个例子比较容易理解,我们们假设通信双方分别是A,B. A,拥有KEY_A1,KEY_A2,其中KEY_A1是A的私有密钥,KEY_A2是A的公共密钥。 B,拥有KEY_B1,KEY_B2,其中KEY_B1是B的私有密钥,KEY_B2是B的公共密钥。公共密钥和私有密钥的特点是,经过其中任何一把加密过的明文,只能用另外一把才能够解开。也就是说经过KEY_A1加密过的明文,只有KEY_A2才能够解密,反之亦然。
Certificate、Cipher、Decipher、DiffieHellman、ECDH、Hash、Hmac、Sign、Verify
crypto.createCipher()或crypto.createCipheriv()方法用于创建Cipher实例。crypto.createDecipher()或crypto.createDecipheriv()的方法 用于创建Decipher实例。Cipher、Decipher对象不能直接使用new关键字创建。
data | | | inputEncoding outputEncoding 用data更新密码。如果给出了inputEncoding的论证,它的值必须是'utf8', 'ascii', 或者'latin1(ISO-8859-1的别名)',而data参数是使用指定编码的字符串。如果不给出inputEncoding的参数,则data必须是Buffer,TypedArray, 或者DataView。如果data是一个Buffer,TypedArray, 或者 DataView, 那么inputEncoding就被忽略了。
outputEncoding指定了加密数据的输出格式,可以是'latin1', 'base64(使用64个可见字符来表示一个二进制数组,编码后数据大小变成原来的4/3,也即3个字符用4个可见字符来表示)' 或者 'hex(hex也称为base16,使用16个可见字符来表示一个二进制数组,编码后数据大小将翻倍,因为1个字符需要用2个可见字符来表示)'。如果指定了outputEncoding,则返回使用指定编码的字符串。如果没有outputEncoding被提供,会返回Buffer。
cipher.update()方法可以用新数据多次调用,直到cipher.final()被调用。在cipher.final()之后调用cipher.update()将抛出错误。
outputEncoding 返回任何加密的内容。如果 outputEncoding 参数是'latin1', 'base64' 或者 'hex',返回字符串。 如果没有提供 outputEncoding,则返回Buffer。
一旦cipher.final()方法已被调用,Cipher 对象就不能再用于加密数据。如果试图再次调用cipher.final(),将会抛出一个错误。
Decipher.update()与Decipher.final()与Cipher中两个方法类似。
Cipher加密
// 示例
const crypto = require('crypto');
const cipher = crypto.createCipher('aes192', 'a password');
let encrypted = cipher.update('some clear text data', 'utf8', 'hex');
encrypted += cipher.final('hex');
console.log(encrypted);
// Prints: ca981be48e90867604588e75d04feabb63cc007a8f8ad89b10616ed84d815504
Decipher解密
// 示例
const crypto = require('crypto');
const decipher = crypto.createDecipher('aes192', 'a password');
const encrypted =
'ca981be48e90867604588e75d04feabb63cc007a8f8ad89b10616ed84d815504';
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
console.log(decrypted);
// Prints: some clear text data
Hash(也可以叫散列)算法,它是用来对一段数据进行验证前,将该数据模糊化,或者也可以为一大段数据提供一个校验码。
在nodejs中,为了使用该散列算法,我们先要使用 createHash方法创建一个hash对象。
Hmac散列运算消息认证码。运算使用散列算法,以一个密钥和一个消息为输入,生成一个消息摘要作为输出。HMAC运算可以用来验证两段数据是否匹配,以确认该数据没有被篡改。使用createHmac创建一个hmac对象。
update()
更新hash或者hmac的内容,这个方法可以通过新的值被多次调用。
digest()
计算所有需要被哈希化的数据摘要,Hash或者Hamc对象在 digest() 方法调用之后不能再次被使用。多次的调用会引发错误并抛出。
Hash
const crypto = require('crypto');
const hash = crypto.createHash('sha256');
hash.update('some data to hash');
console.log(hash.digest('hex'));
// Prints:
// 6a2da20943931e9834fc12cfe5bb47bbd9ae43489a30726962b576f4e3993e50
Hmac(附加密钥的散列算法)
const crypto = require('crypto');
const hmac = crypto.createHmac('sha256', 'a secret');
hmac.update('some data to hash');
console.log(hmac.digest('hex'));
// Prints:
// 7fd04df92f636fd450bc841c9418e5825c17f33ad9c87c518115a45971f7f77e
Sign类是生成签名的实用工具,crypto.createSign()方法用于创建Sign实例。Sign实例不能直接使用new关键字创建。
Verify类是验证签名的工具,crypto.createVerify()方法用于创建Verify实例。Verify对象不能直接使用new关键字创建。
Sign
// 示例
const crypto = require('crypto');
const sign = crypto.createSign('SHA256');
sign.update('some data to sign');
const privateKey = getPrivateKeySomehow(); // 比如.pem文件数据
console.log(sign.sign(privateKey, 'hex'));
// Prints: the calculated signature
Verify
// 示例
const crypto = require('crypto');
const verify = crypto.createVerify('SHA256');
verify.update('some data to sign');
const publicKey = getPublicKeySomehow(); // 比如.pem文件数据
const signature = getSignatureToVerify(); // 将要验证的签名数据
console.log(verify.verify(publicKey, signature));