package com.bootdo.common.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

/**
 * @author 宋显哲
 * @version 1.0.0 创建于 2018/1/18
 **/
public final class AesUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(AesUtil.class);
    private static final String UTF8 = "utf-8";
    //key长16字节
    private static final int KEY_LENGTH = 16;

    /**
     * 方法名称：AES 加密<br>
     * 方法作用：对普通字符串进行AES加密
     *
     * @param content 等待加密的字符串
     * @param key     加/解密 密钥
     * @param iv      加/解密 初始化向量
     * @return 返回加密后的字符串
     * @throws Exception 异常信息
     */
    public static String encrypt(String content, String key, String iv) throws UnsupportedEncodingException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        if (key == null) {
            LOGGER.error("Key为空null");
            return null;
        }

        // 判断Key是否为16位
        if (key.getBytes(UTF8).length != KEY_LENGTH) {
            LOGGER.error("Key长度不是16位");
            return null;
        }

        byte[] raw = key.getBytes();
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        //"算法/模式/补码方式"
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        //使用CBC模式，需要一个向量iv，可增加加密算法的强度
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(iv.getBytes(UTF8)));
        byte[] encrypted = cipher.doFinal(content.getBytes(UTF8));
        //此处使用BAES64做转码功能。
        return Base64.getEncoder().encodeToString(encrypted);
    }

    /**
     * 方法名称：AES 解密<br>
     * 方法作用：对经过Aes加密后的字符串进行解密，
     *
     * @param content 待解密内容字符串
     * @param key     加/解密 密钥
     * @param iv      加/解密 初始化向量
     * @return 返回解密后的内容
     * @throws Exception 异常
     */
    public static String decrypt(String content, String key, String iv) throws Exception {
        try {
            // 判断Key是否正确
            if (key == null) {
                LOGGER.error("Key为空null");
                return null;
            }

            // 判断Key是否为16位
            if (key.getBytes(UTF8).length != KEY_LENGTH) {
                LOGGER.error("Key长度不是16位");
                return null;
            }

            byte[] raw = key.getBytes(UTF8);
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(iv.getBytes(UTF8)));
            byte[] encrypted1 = Base64.getMimeDecoder().decode(content);
            byte[] original = cipher.doFinal(encrypted1);
            return new String(original);
        } catch (Exception ex) {
            LOGGER.error("AES解码异常，异常信息：" + ex.getMessage());
            return null;
        }
    }
}
