package com.friday.tooldriver.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * AES加密和解密工具类
 *
 */
@Slf4j
public class AESUtils {

    // AES密码器
    private static Cipher cipher;
    // 字符串编码
    private static final String KEY_CHARSET = "UTF-8";
    // 算法方式
    private static final String KEY_ALGORITHM = "AES";
    // 算法/模式/填充
    private static final String CIPHER_ALGORITHM_CBC = "AES/CBC/PKCS5Padding";
//    private static final String CIPHER_ALGORITHM_CBC = "AES/CBC/PKCS7Padding";
    // 私钥大小128/192/256(bits)位 即：16/24/32bytes，暂时使用128，如果扩大需要更换java/jre里面的jar包
    private static final Integer PRIVATE_KEY_SIZE_BIT = 128;
    private static final Integer PRIVATE_KEY_SIZE_BIT_256 = 256;
    private static final Integer PRIVATE_KEY_SIZE_BYTE = 16;
    private static final int CACHE_SIZE = 1024;
    public static final String DEFAULT_SECRET_KEY_128 = "1111111111111111";

    /**
     * 加密
     * @param secretKey 密钥：加密的规则 16位
     * @param plainText 明文：要加密的内容
     * @return cipherText 密文：加密后的内容，如有异常返回空串：""
     */
    public static String encrypt(String plainText, String secretKey) {
        if (StringUtils.isBlank(plainText)) {
            return null;
        }
        if (StringUtils.isBlank(secretKey)) {
            secretKey = DEFAULT_SECRET_KEY_128;
        }
        if (secretKey.length() != PRIVATE_KEY_SIZE_BYTE) {
        	log.error("encryptFlag() secretKey length error! secretKey:" + secretKey + ", expect length:" + PRIVATE_KEY_SIZE_BYTE);
            throw new RuntimeException("AESUtil:Invalid AES secretKey length (must be 16 bytes)");
        }
        // 密文字符串
        String cipherText;
        try {
            // 加密模式初始化参数
            initParam(secretKey, Cipher.ENCRYPT_MODE);
            // 获取加密内容的字节数组
            byte[] bytePlainText = plainText.getBytes(KEY_CHARSET);
            // 执行加密FileInputStream
            byte[] byteCipherText = cipher.doFinal(bytePlainText);
            cipherText = Base64.getEncoder().encodeToString(byteCipherText);
        } catch (Exception e) {
        	log.error("encryptFlag() Exception! secretKey:" + secretKey + ", plainText:" + plainText, e);
            throw new RuntimeException("AESUtil:encryptFlag fail!", e);
        }
        return cipherText;
    }

    /**
     * 初始化参数
     * @param secretKey 密钥：加密的规则 16位
     * @param mode 加密模式：加密or解密
     */
    public static void initParam(String secretKey, int mode) {
        if (StringUtils.isBlank(secretKey)) {
            secretKey = DEFAULT_SECRET_KEY_128;
        }
        try {
            // 防止Linux下生成随机key
            SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
            secureRandom.setSeed(secretKey.getBytes());
            // 获取key生成器
            KeyGenerator keygen = KeyGenerator.getInstance(KEY_ALGORITHM);
            keygen.init(PRIVATE_KEY_SIZE_BIT, secureRandom);

            // 获得原始对称密钥的字节数组
            byte[] raw = secretKey.getBytes();

            // 根据字节数组生成AES内部密钥
            SecretKeySpec key = new SecretKeySpec(raw, KEY_ALGORITHM);
            // 根据指定算法"AES/CBC/PKCS5Padding"实例化密码器
            cipher = Cipher.getInstance(CIPHER_ALGORITHM_CBC);
            IvParameterSpec iv = new IvParameterSpec(secretKey.getBytes());
            cipher.init(mode, key, iv);
        } catch (Exception e) {
        	log.error("initParam() Exception! secretKey:" + secretKey + ", mode:" + mode);
            throw new RuntimeException("AESUtil:initParam fail!", e);
        }
    }

    public static void main(String[] args) {
        System.out.print("加密密文"+ AESUtils.encrypt("admin1","xRBdjOhCsuB2|KHZ"));
    }
}
