1. 安裝庫文件
npm install crypto
2. 代碼示例
import * as crypto from 'crypto';
const ALGORITHM = 'aes-256-cbc';
const RANDOM_BYTES_SIZE = 16;
const MSG_LENGTH_SIZE = 4;
const BLOCK_SIZE = 32;
class WxCrypto {
private data: { appId: string; token: string; key: Buffer; iv: Buffer };
constructor({ appId, encodingAESKey, token }: { appId: string; encodingAESKey: string; token: string }) {
const key = Buffer.from(encodingAESKey + '=', 'base64');
const iv = key.slice(0, 16);
this.data = { appId, token, key, iv };
}
encrypt(msg:string) {
let { appId, key, iv } = this.data
let randomBytes = crypto.randomBytes(RANDOM_BYTES_SIZE) // 生成指定大小的隨機數(shù)據(jù)
let msgLenBuf = Buffer.alloc(MSG_LENGTH_SIZE) // 申請指定大小的空間,存放消息體的大小
let offset = 0 // 寫入的偏移值
msgLenBuf.writeUInt32BE(Buffer.byteLength(msg), offset) // 按大端序(網(wǎng)絡(luò)字節(jié)序)寫入消息體的大小
let msgBuf = Buffer.from(msg) // 將消息體轉(zhuǎn)成 buffer
let appIdBuf = Buffer.from(appId) // 將 APPID 轉(zhuǎn)成 buffer
let totalBuf = Buffer.concat([randomBytes, msgLenBuf, msgBuf, appIdBuf]) // 將16字節(jié)的隨機數(shù)據(jù)、4字節(jié)的消息體大小榴鼎、若干字節(jié)的消息體伯诬、若干字節(jié)的APPID拼接起來
let cipher = crypto.createCipheriv(ALGORITHM, key, iv) // 創(chuàng)建加密器實例
cipher.setAutoPadding(false) // 禁用默認的數(shù)據(jù)填充方式
totalBuf = this.PKCS7Encode(totalBuf) // 使用自定義的數(shù)據(jù)填充方式
let encryptdBuf = Buffer.concat([cipher.update(totalBuf), cipher.final()]) // 加密后的數(shù)據(jù)
return encryptdBuf.toString('base64') // 返回加密數(shù)據(jù)的 base64 編碼結(jié)果
}
decrypt(encryptedMsg: string): string {
const { key, iv } = this.data;
const encryptedMsgBuf = Buffer.from(encryptedMsg, 'base64');
const decipher = crypto.createDecipheriv(ALGORITHM, key, iv);
decipher.setAutoPadding(false);
const decryptedBuf = Buffer.concat([decipher.update(encryptedMsgBuf), decipher.final()]);
const msgSize = decryptedBuf.readUInt32BE(RANDOM_BYTES_SIZE);
const msgBufStartPos = RANDOM_BYTES_SIZE + MSG_LENGTH_SIZE;
const msgBufEndPos = msgBufStartPos + msgSize;
const msgBuf = decryptedBuf.slice(msgBufStartPos, msgBufEndPos);
return msgBuf.toString();
}
genSign(params: { timestamp: string | string[]; nonce: string | string[]; encrypt: string }): string {
const { token } = this.data;
const { timestamp, nonce, encrypt } = params;
const rawStr = [token, timestamp, nonce, encrypt].sort().join('');
const signature = crypto.createHash('sha1').update(rawStr).digest('hex');
return signature;
}
PKCS7Decode(buf: Buffer): Buffer {
const padSize = buf[buf.length - 1];
return buf.slice(0, buf.length - padSize);
}
PKCS7Encode(buf: Buffer): Buffer {
const padSize = BLOCK_SIZE - (buf.length % BLOCK_SIZE);
const fillByte = padSize;
const padBuf = Buffer.alloc(padSize, fillByte);
return Buffer.concat([buf, padBuf]);
}
}
export default WxCrypto;
- 使用方法
let wx = new WxCrypto(this.weixinOpenPlatform)
/* 解密消息內(nèi)容,并返回xml */
const decryptedXml = wx.decrypt(Encrypt);
// 加密消息
let createTime = (new Date().getTime() / 1000).toFixed(0);
const encryptedReply = wx.encrypt(replyMessage) // 加密消息xml
let signature = wx.genSign({ timestamp: createTime, nonce, encrypt: encryptedReply }) //生成加密簽名
//消息回復(fù)模版
let data = `<xml><Encrypt><![CDATA[${encryptedReply}]]></Encrypt><MsgSignature><![CDATA[${signature}]]></MsgSignature><TimeStamp>${createTime}</TimeStamp><Nonce><![CDATA[${nonce}]]></Nonce></xml>`
- weixinOpenPlatform配置文件定義
weixinOpenPlatform: {
appId: 'xxxxxxx',
appSecret: 'xxxxxx',
token: 'xxxxx,
encodingAESKey: 'xxxxx',
},