/*
 * @Description: 数据加密，aes加密数据主体，rsa加密aes密钥，aes密钥前端自己存储
 * @Date: 2020-12-08 11:08:28
 * @LastEditors: gzw
 * @LastEditTime: 2021-11-18 17:17:27
 */
import { cipher as AES, util as UTIL, pki as PKI, md as SHA1 } from 'node-forge';
import uuidv1 from 'uuid/v1';
import { parseTime } from './utils.service';
import { APP_ID, PUBLIC_KEY, PRIVATE_KEY } from '@/config/encrypt.config';

/**
 * @description: 数据加密
 * @param {String} data 数据源
 * @return {String} 加密后的数据base64
 */

export function encryption(data = '') {
  if (!data) return null;
  const key = generateRandomStr(16);
  const iv = key; // 后台约定iv与key一致
  const plaintext = typeof data === 'object' ? JSON.stringify(data) : data;
  const body = encryptDataByAes(plaintext, key, iv); // AES加密数据
  const encryptKey = encryptDataByPb(key); // RSA公钥加密AES密钥
  const signData = generateSign(plaintext);
  return {
    appId: APP_ID,
    body,
    encryptKey,
    ...signData
  };
}

/**
 * @description: AES加密数据，默认CBC, Pki#cs7
 * @param {String} txt 数据源
 * @param {String} key 密钥，16位字符串
 * @param {String} iv 初始化向量
 * @return {String} 加密后的数据base64
 */
function encryptDataByAes(txt, key, iv) {
  const cipher = AES.createCipher('AES-CBC', key);
  cipher.start({ iv });
  cipher.update(UTIL.createBuffer(txt, 'utf8'));
  cipher.finish();
  const ciphertext = cipher.output.getBytes();
  return buffer2Base64(ciphertext);
}

/**
 * @description: 使用RSA公钥加密数据
 * @param {String} txt 数据源
 * @return {String} 加密后的数据base64
 */
function encryptDataByPb(txt) {
  const publicKey = PKI.publicKeyFromPem(PUBLIC_KEY);
  const pbData = publicKey.encrypt(txt);
  return buffer2Base64(pbData);
}

/**
 * @description: RSA私钥+SHA1生成签名
 *                签名组成结构nonce+appid+timestamp+body
 * @param {String} txt 数据源
 * @return {Object} 生成的sign数据，时间戳、Nonce
 */
function generateSign(txt) {
  const timestamp = parseTime('');
  const nonce = generateNonce();
  const privateKey = PKI.privateKeyFromPem(PRIVATE_KEY);
  const md = SHA1.sha1.create();
  md.update(nonce + APP_ID + timestamp + txt, 'utf8');
  let sign = privateKey.sign(md);
  sign = buffer2Base64(sign);
  return {
    timestamp,
    nonce,
    sign
  };
}

/**
 * @description: buffer转base64
 * @param {Buffer} buf buffer源数据
 * @return {String} base64 字符串
 */
function buffer2Base64(buf) {
  return UTIL.encode64(buf);
}

/**
 * @description: 生成nonce(uuid)
 *                规则：以当前时间的uuid作为name，以随机生成的uuid作为namespace，生成最终的uuid
 * @return {String} 生成的uuid
 */
function generateNonce() {
  return uuidv1();
}

/**
 * @description: 生成随机字符串
 * @param {Number} n 位数
 * @return {String} 生成的字符串
 */
function generateRandomStr(n) {
  const len = n || 32;
  const chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz0123456789';
  const maxPos = chars.length;
  let pwd = '';
  for (let i = 0; i < len; i++) {
    pwd += chars.charAt(Math.floor(Math.random() * maxPos));
  }
  return pwd;
}
