/*
 * @Description: 数据加密，aes加密数据主体，rsa加密aes密钥，aes密钥前端自己存储
 * @Date: 2020-12-08 11:08:28
 * @LastEditors: gzw
 * @LastEditTime: 2021-07-07 17:44:22
 */
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';
import CryptoJS from 'crypto-js';
import pay from '@/api/pay.api';

/**
 * @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) {
  console.log(message);
  const [{ payPwdSalt }] = await pay.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 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;
}
