package com.cm.common.utils;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.StringUtils;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.*;

public class AesUtil {

    private static final String IV_STRING = "16-Bytes--String";
    /**
     * PKCS#7
     */
    public static final String PKCS_7 = "PKCS7Padding";
    /**
     * PKCS#5
     */
    public static final String PKCS_5 = "PKCS5Padding";

    /**
     * AES加密
     *
     * @param encodeRule
     * @param content
     * @return
     * @throws Exception
     */
    public static String aesEncoder(String encodeRule, String content) throws Exception {
        // 1.构造秘钥生成器
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        // 2.根据编码规则构建秘钥生成器
        SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
        random.setSeed(encodeRule.getBytes());
        keyGenerator.init(128, random);
        // 3.产生堆成秘钥
        SecretKey secretKey = keyGenerator.generateKey();
        // 4.对称秘钥原始数组
        byte[] secretKeyByte = secretKey.getEncoded();
        // 5.生成AES秘钥
        SecretKey key = new SecretKeySpec(secretKeyByte, "AES");
        // 6.初始化密码器
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, key);
        // 8.获取加密内容字节数组
        byte[] contentByte = content.getBytes("UTF-8");
        // 9.加密
        return new String(Base64.encodeBase64(cipher.doFinal(contentByte)));
    }

    /**
     * AES解密
     *
     * @param encodeRule
     * @param content
     * @return
     * @throws Exception
     */
    public static String aesDecoder(String encodeRule, String content) throws Exception {
        // 1.构建秘钥生成器
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        // 2.根据编码规则构建秘钥生成器
        SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
        random.setSeed(encodeRule.getBytes());
        keyGenerator.init(128, random);
        // 3.生成对称解密秘钥
        SecretKey secretKey = keyGenerator.generateKey();
        // 4.对称秘钥原始数组
        byte[] secretKeyByte = secretKey.getEncoded();
        // 5.生成AES秘钥
        SecretKey key = new SecretKeySpec(secretKeyByte, "AES");
        // 6.初始化密码器
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.DECRYPT_MODE, key);
        // 7.要解密内容的字节数组
        byte[] contentByte = Base64.decodeBase64(content);
        // 8.解密
        return new String(cipher.doFinal(contentByte), "UTF-8");
    }

    /**
     * 通用aes加密，兼容IOS
     *
     * @param key
     * @param content
     * @return
     * @throws Exception
     */
    public static String aesCommonEncoder(String key, String content) throws Exception {
        byte[] encryptedBytes = aesCommonEncodeDetail(key, content, IV_STRING.getBytes(), PKCS_5);
        return new String(Base64.encodeBase64(encryptedBytes), "UTF-8");
    }

    /**
     * 通用aes加密，兼容IOS
     *
     * @param key
     * @param content
     * @param paddingType
     * @return
     * @throws Exception
     */
    public static byte[] aesCommonEncodeDetail(String key, String content, byte[] ivBytes, String paddingType) throws Exception {
        byte[] byteContent = content.getBytes("UTF-8");
        byte[] enCodeFormat = key.getBytes();
        SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, "AES");
        IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
        if (StringUtils.equals(paddingType, PKCS_7)) {
            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        }
        Cipher cipher = Cipher.getInstance("AES/CBC/" + paddingType);
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
        return cipher.doFinal(byteContent);
    }

    /**
     * aes通用解密，兼容IOS
     *
     * @param key
     * @param content
     * @return
     * @throws Exception
     */
    public static String aesCommonDecoder(String key, String content) throws Exception {
        byte[] encryptedBytes = Base64.decodeBase64(content);
        byte[] keyBytes = key.getBytes();
        byte[] result = aesCommonDecoderDetail(keyBytes, encryptedBytes, IV_STRING.getBytes(), PKCS_5);
        return new String(result, "UTF-8");
    }

    /**
     * aes cbc 通用解密
     *
     * @param keyBytes       秘钥字节数组
     * @param encryptedBytes 密文字节数组
     * @param ivBytes        向量字节数组
     * @param paddingType    填充类型
     * @return
     * @throws Exception
     */
    public static byte[] aesCommonDecoderDetail(byte[] keyBytes, byte[] encryptedBytes, byte[] ivBytes, String paddingType) throws Exception {
        SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
        IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
        Cipher cipher;
        if (StringUtils.equals(paddingType, PKCS_7)) {
            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        }
        cipher = Cipher.getInstance("AES/CBC/" + paddingType);
        cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
        return cipher.doFinal(encryptedBytes);
    }
}
