package com.ho.common.tools.util;

import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.SecureUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.util.StringUtils;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * @author fancl
 * @desc: AES工具类
 * @date 2022/11/15
 */
@Slf4j
public class AESEncryptUtil {

    /**
     * 编码
     */
    private static final String ENCODING = "UTF-8";
    /**
     * 算法
     */
    private static final String ALGORITHM = "AES";
    /**
     * AES：加密方式   CBC：工作模式   PKCS5Padding：填充模式
     */
    private static final String CBC_PKCS5_PADDING = "AES/CBC/PKCS5Padding";
    /**
     * 加密方法
     *
     * @param data 要加密的数据
     * @param aesKey  加密key
     * @param iv  偏移量
     * @return 加密的结果
     * @throws Exception
     */
    public static String encrypt(String data, String aesKey, String iv) {
        if(data==null|| StringUtils.isEmpty(data)){
            return data;
        }
        /*
         * 新建一个密码编译器的实例，由三部分构成，用"/"分隔，分别代表如下
         * 1. 加密的类型(如AES，DES，RC2等)
         * 2. 模式(AES中包含ECB，CBC，CFB，CTR，CTS等)
         * 3. 补码方式(包含nopadding/PKCS5Padding等等)
         * 依据这三个参数可以创建很多种加密方式
         */
        try {
            Cipher cipher = Cipher.getInstance(CBC_PKCS5_PADDING);
            //偏移量
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes(ENCODING));
            //加密秘钥
            SecretKeySpec keySpec = new SecretKeySpec(aesKey.getBytes(ENCODING), ALGORITHM);
            //初始化密码编译器
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivParameterSpec);
            //生成加密后的密文
            byte[] bytes = cipher.doFinal(data.getBytes(ENCODING));
            //将密文Base64转码返回
            return Base64.encodeBase64String(bytes);
        }catch (Exception e){
            log.error("参数加密失败 ,{}",e);
            return null;
        }
    }

    /**
     * 解密方法
     *
     * @param data 要解密的数据
     * @param aesKey  解密key
     * @param iv  偏移量
     * @return 解密的结果
     * @throws Exception
     */
    public static String decrypt(String data, String aesKey, String iv) {
        if(data==null|| StringUtils.isEmpty(data)){
            return data;
        }
        try {
            Cipher cipher = Cipher.getInstance(CBC_PKCS5_PADDING);
            //偏移量
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes(ENCODING));
            //加密秘钥
            SecretKeySpec keySpec = new SecretKeySpec(aesKey.getBytes(ENCODING), ALGORITHM);
            //初始化密码编译器
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivParameterSpec);
            byte[] bytes = cipher.doFinal(Base64.decodeBase64(data));
            return new String(bytes,ENCODING);
        }catch (Exception e){
            log.error("参数解密失败  ,{}",e);
            return data;
        }
    }


    /**
     * 生成默认的 key 和 iv,key = iv iv 的长度必须是16位
     **/
    public static String generateKeyAndIv() {
        String uid = SecureUtil.md5(String.valueOf(System.currentTimeMillis()));
        // 盐加密
        String salt = IdUtil.randomUUID();
        uid = SecureUtil.md5(uid + salt);
        return uid.substring(16);
    }


}
