记⼀次在node.js中使⽤crypto的createCipheriv⽅法进⾏加密时
所遇到的坑
  Node.js的提供了⼀组包括对OpenSSL的哈希、HMAC、加密、解密、签名,以及验证等⼀整套功能的封装。具体的使⽤⽅法可以参考这篇⽂章中的描述:。
  本⽂重点介绍在使⽤createCipheriv⽅法时所遇到的坑。对应的解密算法createDecipheriv应该是⼀样的问题。
  按照⽂档中的描述,createCipheriv⽅法接受三个参数:algorithm⽤于指定加密算法,如aes-128-ecb、aes-128-cbc等;key是⽤于加密的密钥;iv参数可选,⽤于指定加密时所⽤的向量。注意这⾥的密钥必须是8/16/32位,如果加密算法是128,则对应的密钥是16位,如果加密算法是256,则对应的密钥是32位。代码如下:
const crypto = require("crypto");
function encrypt (key, iv, data) {
let decipher = ateCipheriv('aes-128-cbc', key, iv);
// decipher.setAutoPadding(true);
return decipher.update(data, 'binary', 'base64') + decipher.final('base64');
}
function decrypt (key, iv, crypted) {
crypted = new Buffer(crypted, 'base64').toString('binary');
let decipher = ateDecipheriv('aes-128-cbc', key, iv);
return decipher.update(crypted, 'binary', 'utf8') + decipher.final('utf8');
}
  下⾯是测试结果:
let key = '123456789abcdefg';
console.log('加密的key:', key);
let iv = 'abcdefg123456789';
console.log('加密的iv:', iv);
let data = "This is an example";
console.log("需要加密的数据:", data);
let crypted = encrypt(key, iv, data);
console.log("数据加密后:", crypted);
let dec = decrypt(key, iv, crypted);
console.log("数据解密后:", dec);
  以上加密和解密的算法在node.js中运⾏没有问题。但如果服务端⽤的不是node.js,⽽是Java、C#或者C语⾔编写的服务,则⽤node.js 加密之后的结果在服务端验证⽆法通过。究其原因可能是因为node.js在实现createCipheriv的算法上与其它语⾔有差异,⽽这个差异也可能体现在编码格式上。在上述node.js代码中,⽆论如何修改encrypt函数中update()和final()⽅法的参数,例如改为"utf8"、"hex",或者将传⼊的参数改为buffer等,虽然得出的加密结果会有区别,但是服务端验证都会失败。
  在多次尝试失败后,我们只能认定node.js中的crypto模块与其它语⾔中的实现存在差异。所以我们不得已选择其它的开源包来替换node.js中的crypto模块。经过尝试,包是个不错的选择。按照⽂档中的描述,我们将上⾯node.js中的encrypt函数修改为:
const aesjs = require('aes-js');
function encrypt (key, iv, data) {
let aesCbc = new aesjs.ModeOfOperation.cbc(aesjs.Bytes(key), aesjs.Bytes(iv));
let encryptedBytes = pt(aesjs.Bytes(data));
return aesjs.utils.hex.fromBytes(encryptedBytes);
}
function decrypt (key, iv, crypted) {
let aesCbc = new aesjs.ModeOfOperation.cbc(aesjs.Bytes(key), aesjs.Bytes(iv));
let encryptedBytes = aesCbc.decrypt(aesjs.Bytes(crypted));
return aesjs.utils.utf8.fromBytes(encryptedBytes);
}
  上⾯这段代码要求加密的数据是16位,测试结果如下:
let key = '123456789abcdefg';
console.log('加密的key:', key);
let iv = 'abcdefg123456789';
console.log('加密的iv:', iv);
let data = "Thisisanexample.";
console.log("需要加密的数据:", data);
let crypted = encrypt(key, iv, data);js代码加密软件
console.log("数据加密后:", crypted);
let dec = decrypt(key, iv, crypted);
console.log("数据解密后:", dec);
  采⽤aes-js计算得到的加密结果可以通过服务端的验证。