/*
 * @Description: 数据加密，aes加密数据主体，rsa加密aes密钥，aes密钥前端自己存储
 * @Date: 2020-12-08 11:08:28
 * @LastEditors: gzw
 * @LastEditTime: 2021-06-08 15:07:07
 */
// perf forge.js较大，后期需要替换为其他库，以减小体积
const forge = require("./forge.min");
const CryptoJS = require("./crypto.min");
import { desSalt } from "../api/pay.api";
import uuidv1 from "uuid/v1";
import { parseTime } from "./index";
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: 数据加密
 * @message {String} message 数据源
 * @return {String} 加密后的数据16进制
 */
export async function encryptByDESModeEBC(message) {
  const [{ payPwdSalt }] = await desSalt();
  var keyHex = CryptoJS.enc.Utf8.parse(payPwdSalt);
  var encrypted = CryptoJS.DES.encrypt(message, keyHex, {
    mode: CryptoJS.mode.ECB,
    padding: CryptoJS.pad.Pkcs7
  });
  return encrypted.ciphertext.toString().toLocaleUpperCase();
}

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

/**
 * @description: 使用RSA公钥加密数据
 * @param {String} txt 数据源
 * @return {String} 加密后的数据base64
 */
function encryptDataByPb(txt) {
  const publicKey = forge.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 = forge.pki.privateKeyFromPem(PRIVATE_KEY);
  const md = forge.md.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 forge.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;
}
