写在前面
最近接触微信支付时,项目中有退款功能。申请退款后设置回调地址,退款结果通知将以HTTP形式通知服务端。通知结果中的req_info为加密信息,在解密过程中留下解题思路。
假设我们有得到了微信回调的XML:
<xml>
<return_code>SUCCESS</return_code>
<appid><![CDATA[wx2421b1c4370ec43b]]></appid>
<mch_id><![CDATA[10000100]]></mch_id>
<nonce_str><![CDATA[TeqClE3i0mvn3DrK]]></nonce_str>
<req_info><![CDATA[m4NnwrtY0jhpDgNp65H1V/0OWMtSoTYhhY89MHbflhmnaHq9ZKjx9ABq6Jpg4SccA876HVy7J9P85NpdvCMNGInZ4fANDRE+YfZe4HeF+bbFj6JETcEFPpE9YW+bTbC0D+gl/otScJfvB2QUK7+EeBGPHN1EWX9zbr2Gw6AUaORdFk3mGxV5dtjuwWQrv5juzkXDs33Z2dUMslO+i3j0cTDHqwS4hptx2j6h2HvzgzltFbjo7nysU+4rArqJvrGW/9r18e1St9XgG21NALqixfaSmqetOR4zLVL4/+z3CEz8cg5r+/4GUOTf3XFmLCZ/wEkRQhKRNVibG0NFfiG3KnqArMJ/dheQHCd7qL+XX/ZV6tj8RLMgL7R6hOiR03Ljyikdxq9M3K9CTYgf03pHJd3geXX1LgXrLxc1flL6NW+zD3ZayGYpr1WpLsSMG7z8W5j1pme6cRj3n2+CwSFnOnOkxaFuLKoJAJIqM3gbC0eN++vY73RKphlI4zZqg6o5s3MXI6ju1yoi/ZQ+XbTg2JttsdbU0aySernKwkt0rYMf0j/Mcvo2axgHbI3w/iTm141WxHUjkQ+ga2X1pOWdGifGhSmMP8oGaA/WD5MAsK1qXX0eFvUWS/PTauCSTWq5Cmr8loA/KL3jgvB0nyR4mfccB+tPy4Ny7kzOlr/VNeb0ULf96R0AWFWCtdt8AmujAP0DYiM5FSmYLI0XRhpSDjnEbBM8+isNE1GlAVR3NzzemwQORihScovpAktbRSN/d3N+NgTjSoVDiJvCOxCs3thX9qt9iwYbA+/X/gv8lza2FZyIzwkQxGRcYl8JWKpXzNW8EWUNVnSLdHvQttDeV3CvgP/x579RGd6whyFYS6AaI0qw7oTjCFh2EHS/VzGvFuv166ZlVIJ4MNvg79O9h63ZOSE1LzVqEsVh8fDCfM2GgJ9aUdl95Djgunit4yIZOdoigR3f/BEHKrYCEham11rYohaAXs4XAXWihsV3WD5j4G/P+txvjAwujvf4HDwzHgFsmSml013U2mUiy+v4zw==]]></req_info>
</xml>
再假设我们有一个key:
2IBtBXdrqC3kCBs4gaceL7nl2nnFadQv
官方版本的解密思路

项目所需依赖:
1/ crypto.JS 2/ xml2js
关于解题方法:
第一步:使用将key(partnerKey 关于如何获得请参考官方解密思路中的第二条)进行md5加密,加密后转换为小写,得到key的加密串。
crypto.createHash('md5').update({partnerKey}, 'utf8').digest('hex').toLowerCase()
* 将{partnerKey}替换为你的数据第二步:使用crypto.JS创建解密,使用createDecipheriv方法
* 关于这个方法:
function createDecipheriv(algorithm: string, key: any, iv: any): Decipher
关于创建解码对象:
let decipher = crypto.createDecipheriv('aes-256-ecb', key, iv);
* 此处的key为第一步md5加密后得到的,iv可为空字符串
设置自动补位:
decipher.setAutoPadding(true);
对req_info中的加密串进行base64解码:
let decoded = decipher.update(req_info, 'base64', 'utf8');
decoded += decipher.final('utf8');
第三步:将解码后的数据从xml转换为json即可得到想要的数据
new Promise((resolve, reject) => {
xml2js.parseString(xml, {trim: true, explicitArray: false, explicitRoot: false}, (err, res) => err ? reject(new Error('XMLDataError')) : resolve(res || {}));
})
封装一波:
1>
import * as crypto from 'crypto'
import * as xml2js from 'xml2js'
export function md5(str) {
return crypto.createHash('md5').update(str, 'utf8').digest('hex');
}
export function parseXML(xml) {
return new Promise((resolve, reject) => {
const opt = {trim: true, explicitArray: false, explicitRoot: false};
xml2js.parseString(xml, opt, (err, res) => err ? reject(new Error('XMLDataError')) : resolve(res || {}));
})
}
export function decrypt(encryptedData, key, iv = '') {
let decipher = crypto.createDecipheriv('aes-256-ecb', key, iv);
decipher.setAutoPadding(true);
let decoded = decipher.update(encryptedData, 'base64', 'utf8');
decoded += decipher.final('utf8');
return decoded;
}2>
async decrypt(partnerKey,req_info){
let key = util.md5(partnerKey).toLowerCase();
let info = util.decrypt(req_info, key);
return await util.parseXML(info);
}