文章目录

微信公众号开发为了安全一般把消息使用了加密模式,但是官网只提供的了几个C++、php、Java、Python和C#版,没有Node.js的,后来自己试着用Node.js来加解密,在网上也找了很多参考代码,但是都多多少少有点问题,经过调整后终于可以用了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
var crypto = require('crypto');
var XMLParser = require('xml2js'),
thunkify = require('thunkify');
var parseXML = thunkify(XMLParser.parseString);
var buildXML = new XMLParser.Builder({rootName:'xml',cdata:true,headless:true,renderOpts :{indent:' ',pretty:'true'}});
// please decode the url before initializing this function
function wxCrypto(token,appID, encodingAESKey) {
this.token = token;
this.appID = appID;
this.aesKey = new Buffer(encodingAESKey + '=', 'base64');
this.iv = this.aesKey.slice(0, 16);
}
wxCrypto.prototype.decryptMsg = function *(msgSignature, timestamp, nonce, data) {
var msg_encrypt = data.Encrypt;
//if(data.ToUserName!=this.appID)throw new Error("ToUserName is invalid");
if (this.getSignature(timestamp, nonce, msg_encrypt) != msgSignature)throw new Error('msgSignature is not invalid');
var decryptedMessage = this.decrypt(msg_encrypt);
return yield parseXML(decryptedMessage,{explicitArray:false});
};
wxCrypto.prototype.encryptMsg = function (replyMsg,opts) {
var result = {};
var options = opts||{};
result.Encrypt = this.encrypt(replyMsg);
result.Nonce = options.nonce || parseInt((Math.random() * 100000000000), 10);
result.TimeStamp = options.timestamp || new Date().getTime();
result.MsgSignature = this.getSignature(result.TimeStamp, result.Nonce, result.Encrypt);
return buildXML.buildObject(result);
};
wxCrypto.prototype.encrypt = function (xmlMsg) {
var random16 = crypto.pseudoRandomBytes(16);
var msg = new Buffer(xmlMsg);
var msgLength = new Buffer(4);
msgLength.writeUInt32BE(msg.length, 0);
var corpId = new Buffer(this.appID);
var raw_msg = Buffer.concat([random16,msgLength,msg ,corpId]);//randomString + msgLength + xmlMsg + this.corpID;
//var encoded = PKCS7Encoder(raw_msg);
var cipher = crypto.createCipheriv('aes-256-cbc', this.aesKey, this.iv);
//cipher.setAutoPadding(false);
var cipheredMsg = Buffer.concat([cipher.update(/*encoded*/raw_msg), cipher.final()]);
return cipheredMsg.toString('base64');
};
wxCrypto.prototype.decrypt = function (str) {
var aesCipher = crypto.createDecipheriv("aes-256-cbc", this.aesKey, this.iv);
aesCipher.setAutoPadding(false);
var decipheredBuff = Buffer.concat([aesCipher.update(str, 'base64'), aesCipher.final()]);
decipheredBuff = PKCS7Decoder(decipheredBuff);
var len_netOrder_corpid = decipheredBuff.slice(16);
var msg_len = len_netOrder_corpid.slice(0, 4).readUInt32BE(0);
//recoverNetworkBytesOrder(len_netOrder_corpid.slice(0, 4));
var result = len_netOrder_corpid.slice(4, msg_len + 4).toString();
var appId = len_netOrder_corpid.slice(msg_len + 4).toString();
if (appId != this.appID)throw new Error('appId is invalid');
return result;
};
wxCrypto.prototype.getSignature = function (timestamp, nonce, encrypt) {
var raw_signature = [this.token, timestamp, nonce, encrypt].sort().join('');
var sha1 = crypto.createHash("sha1");
sha1.update(raw_signature);
return sha1.digest("hex");
};
function PKCS7Decoder(buff) {
var pad = buff[buff.length - 1];
if (pad < 1 || pad > 32) {
pad = 0;
}
return buff.slice(0, buff.length - pad);
}
function PKCS7Encoder(buff) {
var blockSize = 32;
var strSize = buff.length;
var amountToPad = blockSize - (strSize % blockSize);
var pad = new Buffer(amountToPad-1);
pad.fill(String.fromCharCode(amountToPad));
return Buffer.concat([buff, pad]);
}
module.exports = wxCrypto;

以上代码就是加解密的模块,其中我把一些XML转换逻辑放到了里面,不喜欢的也可以把他们抽出来

消息解密
1
var message = yield wxCrypto.decryptMsg(query.msg_signature,query.timestamp,query.nonce,messageData);
消息加密
1
2
3
4
5
6
var reply = new Message({
Content:'谢谢关注我们的公众号',
ToUserName:message.FromUserName,
FromUserName:message.ToUserName
});
this.body = wxCrypto.encryptMsg(reply.toXML());
此文是本站原创,转载请标注作者和链接出处!