Source: encrypt.js

'use strict';

var crypto = require('crypto');
var pkcs7 = require('pkcs7');
var randomEncodingAESKey = require('./randomEncodingAESKey');

/**
 * @module open-service-node-sdk/lib/encrypt
 * @author xuyuanxiang <xuyuanxiang@wosai-inc.com> ({@link http://xuyuanxiang.me})
 * @description 消息加密算法:
 * Base64_Encode(AES_Encrypt[random(16B) + msg_len(4B) + msg + $key])
 * @example
 * const encrypt = require('open-service-node-sdk/lib/encrypt');
 * // 数据加密密钥
 * const encodingAESKey = 'KLN4DMkqdDKnUvLQ501oitOHsrZy6VRXadgdNcu3jgd';
 * // 应用开发商创建应用获取的appId
 * const appId = 'e490e912-4c09-11e7-b114-b2f933d5fe66';
 * // 消息明文
 * const payload = JSON.stringify({ text: 'hello world' });
 * // 加密
 * const encoded = encrypt(encodingAESKey, appId, payload);
 * @param {String} encodingAESKey - 数据加密密钥
 * @param {String} appId - 应用开发商创建应用获取的appId
 * @param {String} clearData - 消息明文
 * @return {String} 密文
 */
module.exports = function encrypt(encodingAESKey, appId, clearData) {
  // 密钥,生成规则:Base64_Decode(数据加密密钥 + “=”)
  var key = new Buffer(encodingAESKey + '=', 'base64');
  // 初始向量大小为16字节,取key前16字节
  var iv = key.slice(0, 16);
  // AES算法,CBC模式
  var encipher = crypto.createCipheriv('aes-256-cbc', key, iv);
  encipher.setAutoPadding(false);

  // 16字节的随机字符串
  var randomStr = randomEncodingAESKey(16);
  var before = new Buffer(randomStr);
  // 4字节的msg长度,网络字节序
  var msgLen = new Buffer(4);
  // msg为消息体明文
  var msg = new Buffer(clearData);
  // 应用开发商创建应用获取的appId
  var after = new Buffer(appId);
  msgLen.writeInt32BE(msg.byteLength, 0);
  // source = random(16B) + msg_len(4B) + msg + appId
  var source = Buffer.concat([before, msgLen, msg, after]);

  // 数据采用PKCS#7填充后进行加密
  var piece1 = encipher.update(pkcs7.pad(source));
  var piece2 = encipher.final();
  // 对明文消息msg加密处理后的Base64编码
  return Buffer.concat([piece1, piece2]).toString('base64');
};