NodeJS開發(fā)微信記錄(1)---安全模式AES加解密

總算通過了叠荠,在網(wǎng)上找了很多人的實(shí)現(xiàn)方法,都有這樣那樣的問題扫责。本人對加密完全是小白一個(gè)榛鼎,微信官方的加密解密技術(shù)方案看了很久才勉強(qiáng)弄明白,總結(jié)一下需要注意的地方鳖孤。

  1. 數(shù)據(jù)使用 PKCS#7填充者娱,填充規(guī)則看文檔。通俗一點(diǎn)的解釋是你用來加密的 buf 必須是 32 位的整數(shù)倍苏揣,如果加密前的buf長度不是整數(shù)倍怎么辦呢黄鳍?就要給它補(bǔ)上,補(bǔ) (32 - N%32) 個(gè) (32-N%32)平匈, 比如你長度是 30框沟,后面就要2個(gè)02,29就是補(bǔ)3個(gè) 03增炭。這里有個(gè)問題是 crypto 模塊默認(rèn)是自動填充的忍燥,而且填充的內(nèi)容規(guī)則不同,需要自己來實(shí)現(xiàn)填充規(guī)則隙姿,而且要設(shè)置 setAutoPadding(false)梅垄。下面代碼有實(shí)現(xiàn),可以參考输玷。
  2. 解密格式為 'aes-256-cbc' ,官方說法是‘AES采用CBC模式队丝,秘鑰長度為32個(gè)字節(jié)(256位)’靡馁,琢磨了很久。用通俗一點(diǎn)的說法是机久,
  3. 下面代碼中奈嘿,消息加密的方法,傳入的參數(shù)是明文回復(fù)的消息文本 <xml>...</xml>吞加,返回的是一段字符串文本裙犹,需要自己包裝,最后回復(fù)給用戶的內(nèi)容是 <xml><ToUserName><![CDATA[toUser]]</ToUserName> <Encrypt><![CDATA[ 加密方法返回的字符串文本 ]]</Encrypt> </xml>衔憨,解密的方法則相反叶圃,傳入的是加密字符串文本,返回的是加密前的 xml 消息文本践图,和官方文檔中的消息格式說明是一樣的掺冠。
'use strict'
/**
 * WxCrypt 微信消息加解密的方法
 * @return new WxCrypt(wxConfig)
 * 返回一個(gè)單例即可,不需要重復(fù)引用
 */
const crypto = require('crypto');
const wxConfig = {
// 傳入配置信息
  token: 'xxx', 
  appid: 'xxx',
  msg_signature: 'xxx',
  encodingAESKey: 'xxx'
}
class WxCrypt {
    constructor(opts){
        //初始化需要用到的屬性
        this.token = opts.token;
        this.appid = opts.appid;
        this.msg_signature = opts.msg_signature; //query 傳進(jìn)來簽名
        this.aesKey = new Buffer(opts.encodingAESKey + '=', 'base64');
        this.IV = this.aesKey.slice(0, 16)
    }
    encrypt (xmlMsg) {
        /*
         *@params String xmlMsg 格式化后的 xml 字符串
         *@return String 加密后的字符串 填入到 Encrypt 節(jié)點(diǎn)中
         * 參照官方文檔 需要返回一個(gè)buf: 隨機(jī)16字節(jié) + xmlMsg.length(4字節(jié))+xmlMsg+appid码党。
         * buf的字節(jié)長度需要填充到 32的整數(shù)德崭,填充長度為 32-buf.length%32, 每一個(gè)字節(jié)為 32-buf.length%32
         */
        let random16 = crypto.pseudoRandomBytes(16);
        let msg = new Buffer(xmlMsg);
        let msgLength = new Buffer(4);
        msgLength.writeUInt32BE(msg.length, 0);

        let corpId = new Buffer(this.appid);

        let raw_msg = Buffer.concat([random16,msgLength,msg ,corpId]);
        let cipher = crypto.createCipheriv('aes-256-cbc', this.aesKey, this.IV);
        cipher.setAutoPadding(false);//重要,autopadding填充的內(nèi)容無法正常解密
       raw_msg = this.PKCS7Encode(raw_msg);

        let cipheredMsg = Buffer.concat([cipher.update(/*encoded*/raw_msg), cipher.final()]);

        return cipheredMsg.toString('base64');   
    }

    decrypt(text) {
          /*
           *@params String text 需要解密的字段(Encrypt節(jié)點(diǎn)中的內(nèi)容)
           * @return String msg_content 返回消息內(nèi)容(xml字符串)
           */
        
          let plain_text;
          let decipher = crypto.Decipheriv('aes-256-cbc', this.aesKey, this.IV)
// crypto.Decipheriv == crypto.createDecipheriv 兩個(gè)方法是一樣的
           decipher.setAutoPadding(false);//重要
            
          let decipheredBuff = Buffer.concat([decipher.update(text, 'base64'), decipher.final()])
          decipheredBuff = this.PKCS7Decode(decipheredBuff)

            
        let len_netOrder_corpid = decipheredBuff.slice(16) 
        //切割掉16個(gè)隨機(jī)字符揖盘,剩余為 (4字節(jié)的 msg_len) + msg_content(長度為 msg_len ) + msg_appId 
        let msg_len = len_netOrder_corpid.slice(0, 4).readUInt32BE(0)
        let msg_content = len_netOrder_corpid.slice(4, msg_len+4).toString('utf-8')
      //  let msg_appId =len_netOrder_corpid.slice(msg_len+4).toString('utf-8')
    
        return msg_content
    }
    PKCS7Decode(buff) {
        /*
         *去除尾部自動填充的內(nèi)容
         */
        let padContent = buff[length -1]
            if(padContent<1 || padContent >32){
                    padContent = 0
            }
        let padLen = padContent;//根據(jù)填充規(guī)則眉厨,填充長度 = 填充內(nèi)容,這一步賦值可以省略
        return buff.slice(0, buff.length - padLen)
    }
    PKCS7Encode(buff) {
      let blockSize = 32;
      let needPadLen = 32 - buff.length % 32
      if( needPadLen == 0) {
          needPadLen = blockSize
      }
      let pad = new Buffer(needPadLen)
      pad.fill(needPadLen)
      let newBuff = Buffer.concat([buff, pad])
      return newBuff
    }
 }
var wxCrypt = new WxCrypt(wxConfig);
module.exports = wxCrypt;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末兽狭,一起剝皮案震驚了整個(gè)濱河市憾股,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌箕慧,老刑警劉巖服球,帶你破解...
    沈念sama閱讀 211,348評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異颠焦,居然都是意外死亡斩熊,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評論 2 385
  • 文/潘曉璐 我一進(jìn)店門伐庭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來粉渠,“玉大人,你說我怎么就攤上這事似忧≡眩” “怎么了丈秩?”我有些...
    開封第一講書人閱讀 156,936評論 0 347
  • 文/不壞的土叔 我叫張陵盯捌,是天一觀的道長。 經(jīng)常有香客問我蘑秽,道長饺著,這世上最難降的妖魔是什么箫攀? 我笑而不...
    開封第一講書人閱讀 56,427評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮幼衰,結(jié)果婚禮上靴跛,老公的妹妹穿的比我還像新娘。我一直安慰自己渡嚣,他們只是感情好梢睛,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著识椰,像睡著了一般绝葡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上腹鹉,一...
    開封第一講書人閱讀 49,785評論 1 290
  • 那天藏畅,我揣著相機(jī)與錄音,去河邊找鬼功咒。 笑死愉阎,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的力奋。 我是一名探鬼主播榜旦,決...
    沈念sama閱讀 38,931評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼景殷!你這毒婦竟也來了章办?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,696評論 0 266
  • 序言:老撾萬榮一對情侶失蹤滨彻,失蹤者是張志新(化名)和其女友劉穎藕届,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體亭饵,經(jīng)...
    沈念sama閱讀 44,141評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡休偶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了辜羊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片踏兜。...
    茶點(diǎn)故事閱讀 38,625評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖八秃,靈堂內(nèi)的尸體忽然破棺而出碱妆,到底是詐尸還是另有隱情,我是刑警寧澤昔驱,帶...
    沈念sama閱讀 34,291評論 4 329
  • 正文 年R本政府宣布疹尾,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏纳本。R本人自食惡果不足惜窍蓝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望繁成。 院中可真熱鬧吓笙,春花似錦、人聲如沸巾腕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽尊搬。三九已至侮穿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間毁嗦,已是汗流浹背亲茅。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留狗准,地道東北人克锣。 一個(gè)月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像腔长,于是被迫代替她去往敵國和親袭祟。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 本文主要介紹移動端的加解密算法的分類捞附、其優(yōu)缺點(diǎn)特性及應(yīng)用巾乳,幫助讀者由淺入深地了解和選擇加解密算法。文中會包含算法的...
    蘋果粉閱讀 11,470評論 5 29
  • 這篇文章主要講述在Mobile BI(移動商務(wù)智能)開發(fā)過程中鸟召,在網(wǎng)絡(luò)通信胆绊、數(shù)據(jù)存儲、登錄驗(yàn)證這幾個(gè)方面涉及的加密...
    雨_樹閱讀 2,355評論 0 6
  • 之前的項(xiàng)目中接觸過一些加密的方法欧募,也沒有太仔細(xì)的進(jìn)行記錄和研究压状。最近在寫SDK時(shí),加密模塊的占比相當(dāng)之大跟继;借此時(shí)機(jī)...
    大雄記閱讀 10,976評論 20 63
  • 最近种冬,看了一部電影,《白日夢想家》舔糖。 《白日夢想家》是由本·斯蒂勒自導(dǎo)自演娱两,《當(dāng)幸福來敲門》的編劇史蒂夫·...
    生活旅行家東子閱讀 558評論 0 0
  • 初步描繪,等到彩色鉛筆到手后金吗,繼續(xù)修改十兢。我覺得世界應(yīng)該有色彩趣竣,而不是單一的黑白。期待我的下一步吧纪挎!
    史嘯雲(yún)歪閱讀 361評論 0 1