最近在做微信接入,在采用明文消息与微信服务器进行通信时,毫无压力,改成密文后,微信提供了各种语言版本的demo,but 没有nodejs。(复制一下,语文偏科,凑字数)。
做微信加密消息主要下面几个方面的内容:
-
加密前明文结构
-
16字节的随机字符串
-
消息长度的网络子节序
-
加密方式
-
加密算法
-
填充块计算方式
-
加密实现
1. 加密前明文结构: random(16B)+ msg_len(4B) + msg + $AppId;
说明:random(16B)为16字节的随机字符串;msg_len为msg长度,占4个字节(网络字节序),$AppId为公众账号的AppId
2. 16字节随机字符串:没啥说的直接拼接就好了
var randomPrefix = function(n) {
var _str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
var buf = new Buffer(n);
for (var i = 0; i < n; i++) {
buf[i] = _str.charCodeAt(Math.floor(Math.random() * _str.length));
}
return buf;
};
3. 网络子节序:网络子节序根据消息主体长度而生成
var htonl = function(n) {
var buf = new Buffer(4);
buf[0] = (n & 0xFF000000) >> 24;
buf[1] = (n & 0x00FF0000) >> 16;
buf[2] = (n & 0x0000FF00) >> 8;
buf[3] = (n & 0x000000FF) >> 0;
return buf;
};
4.加密方式:Base64_Encode(AES_Encrypt [random(16B)+ msg_len(4B) + msg + $AppId]);
5.加密算法:AES采用CBC模式,秘钥长度为32个字节,数据采用PKCS#7填充;PKCS#7:K为秘钥字节数(采用32),buf为待加密的内容,N为其字节数。Buf需要被填充为K的整数倍。在buf的尾部填充(K-N%K)个字节,每个字节的内容是(K- N%K);
6.填充块计算方式: 消息体长度 /32 ,
var padding = function(n) {
var len = n % 32;
if (len == 0) {
len = 32;
} else {
len = 32 - len;
}
var buf = new Buffer(len);
for (var i = 0; i < len; i++) {
buf[i] = len;
}
return buf;
};
7.加密实现:
1.加密采用crypto库,
2.加密方式:aes-256-cbc,
3.key:
var encodingAESKey = new Buffer("YfWVs4vtcNf6FPFRqzJ2VT6LCmpppePaRyGJjt7Rlcr" + "=", 'base64');
4.IV:
encodingAESKey.slice(0, 16);
5. 创建加密对象方法:createCipheriv,
var cipher = crypto.createCipheriv('aes-256-cbc', encodingAESKey, encodingAESKey.slice(0, 16));
6. 取消自动填充
cipher.setAutoPadding(false);
7.加密并返回结果
cipher.update(Buffer.concat([preBuf, netBuf, msgBuf, corpBuf, paddingBuf]), "binary", 'base64') + cipher.final('base64'); // 解密数据
8.整体加密代码
var encrypt = function(msg) {
var msgBuf = new Buffer(msg, "utf-8"),
msgBufLength = msgBuf.length,
preBuf = randomPrefix(16),
netBuf = htonl(msgBufLength),
corpBuf = new Buffer(corpId, "utf-8"),
corpBufLength = corpBuf.length,
paddingBuf = padding(20 + msgBufLength + corpBufLength);
var cipher = crypto.createCipheriv('aes-256-cbc', encodingAESKey, encodingAESKey.slice(0, 16));
cipher.setAutoPadding(false); // 取消自动填充
return cipher.update(Buffer.concat([preBuf, netBuf, msgBuf, corpBuf, paddingBuf]), "binary", 'base64') + cipher.final('base64'); // 解密数据
};
欢迎加入node.js交流群:572416249
原文:http://my.oschina.net/lvyuely/blog/598421