package com.nantian.sc.cloud.common.gateway.utils;

import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Random;

/**
 * @author hzp
 * @title: ErrorUtil
 * @projectName nt_cms_main
 * @description: AES加、解密算法工具类
 * @date 2022/08/24,0024下午 13:46
 */
public class AesUtil {

//    private static final String ENCODE_RULES = "mjfeng";
//
//    /**
//     * 加密
//     * 1.构造密钥生成器
//     * 2.根据ecnodeRules规则初始化密钥生成器
//     * 3.产生密钥
//     * 4.创建和初始化密码器
//     * 5.内容加密
//     * 6.返回字符串
//     */
//    public static String aesEncode(String content) {
//        try {
//            //1.构造密钥生成器，指定为AES算法,不区分大小写
//            KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
//            //2.根据ecnodeRules规则初始化密钥生成器
//            //生成一个128位的随机源,根据传入的字节数组
//            SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
//            random.setSeed(ENCODE_RULES.getBytes());
//            keyGenerator.init(128, random);
//            //3.产生原始对称密钥
//            SecretKey originalKey = keyGenerator.generateKey();
//            //4.获得原始对称密钥的字节数组
//            byte[] raw = originalKey.getEncoded();
//            //5.根据字节数组生成AES密钥
//            SecretKey key = new SecretKeySpec(raw, "AES");
//            //6.根据指定算法AES自成密码器
//            Cipher cipher = Cipher.getInstance("AES");
//            //7.初始化密码器，第一个参数为加密(Encrypt_mode)或者解密解密(Decrypt_mode)操作，第二个参数为使用的KEY
//            cipher.init(Cipher.ENCRYPT_MODE, key);
//            //8.获取加密内容的字节数组(这里要设置为utf-8)不然内容中如果有中文和英文混合中文就会解密为乱码
//            byte[] byteEncode = content.getBytes("utf-8");
//            //9.根据密码器的初始化方式--加密：将数据加密
//            byte[] byteAES = cipher.doFinal(byteEncode);
//            //10.将加密后的数据转换为字符串
//            //这里用Base64Encoder中会找不到包
//            //解决办法：
//            //在项目的Build path中先移除JRE System Library，再添加库JRE System Library，重新编译后就一切正常了。
//            String aesEncode = new String(new BASE64Encoder().encode(byteAES));
//            //11.将字符串返回
//            return aesEncode;
//        } catch (NoSuchAlgorithmException e) {
//            e.printStackTrace();
//        } catch (NoSuchPaddingException e) {
//            e.printStackTrace();
//        } catch (InvalidKeyException e) {
//            e.printStackTrace();
//        } catch (IllegalBlockSizeException e) {
//            e.printStackTrace();
//        } catch (BadPaddingException e) {
//            e.printStackTrace();
//        } catch (UnsupportedEncodingException e) {
//            e.printStackTrace();
//        }
//        //如果有错就返加nulll
//        return null;
//    }
//
//    /**
//     * 解密
//     * 解密过程：
//     * 1.同加密1-4步
//     * 2.将加密后的字符串反纺成byte[]数组
//     * 3.将加密内容解密
//     */
//    public static String aesDecode(String content) {
//        try {
//            //1.构造密钥生成器，指定为AES算法,不区分大小写
//            KeyGenerator keygen = KeyGenerator.getInstance("AES");
//            //2.根据ecnodeRules规则初始化密钥生成器
//            //生成一个128位的随机源,根据传入的字节数组
//            SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
//            random.setSeed(ENCODE_RULES.getBytes());
//            keygen.init(128, random);
//            //3.产生原始对称密钥
//            SecretKey originalKey = keygen.generateKey();
//            //4.获得原始对称密钥的字节数组
//            byte[] raw = originalKey.getEncoded();
//            //5.根据字节数组生成AES密钥
//            SecretKey key = new SecretKeySpec(raw, "AES");
//            //6.根据指定算法AES自成密码器
//            Cipher cipher = Cipher.getInstance("AES");
//            //7.初始化密码器，第一个参数为加密(Encrypt_mode)或者解密(Decrypt_mode)操作，第二个参数为使用的KEY
//            cipher.init(Cipher.DECRYPT_MODE, key);
//            //8.将加密并编码后的内容解码成字节数组
//            byte[] byteContent = new BASE64Decoder().decodeBuffer(content);
//            /*
//             * 解密
//             */
//            byte[] byteDecode = cipher.doFinal(byteContent);
//            String aesDecode = new String(byteDecode, "utf-8");
//            return aesDecode;
//        } catch (NoSuchAlgorithmException e) {
//            e.printStackTrace();
//        } catch (NoSuchPaddingException e) {
//            e.printStackTrace();
//        } catch (InvalidKeyException e) {
//            e.printStackTrace();
//        } catch (IOException e) {
//            e.printStackTrace();
//        } catch (IllegalBlockSizeException e) {
//            e.printStackTrace();
//        } catch (BadPaddingException e) {
//            e.printStackTrace();
//        }
//        //如果有错就返加nulll
//        return null;
//    }
//
//    /**
//     * 解密
//     * 解密过程：
//     * 1.同加密1-4步
//     * 2.将加密后的字符串反纺成byte[]数组
//     * 3.将加密内容解密
//     */
//    public static String aesDecodeByKey(String content, String aesKey) {
//        try {
//
//            byte[] byteContent = new BASE64Decoder().decodeBuffer(content);
//            SecretKeySpec secretKeySpec = new SecretKeySpec(aesKey.getBytes(), "AES");
//            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
//            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
//
//            /*
//             * 解密
//             */
//            byte[] byteDecode = cipher.doFinal(byteContent);
//            String aesDecode = new String(byteDecode, "utf-8");
//            return aesDecode;
//        } catch (NoSuchAlgorithmException e) {
//            e.printStackTrace();
//        } catch (NoSuchPaddingException e) {
//            e.printStackTrace();
//        } catch (InvalidKeyException e) {
//            e.printStackTrace();
//        } catch (IOException e) {
//            e.printStackTrace();
//        } catch (IllegalBlockSizeException e) {
//            e.printStackTrace();
//        } catch (BadPaddingException e) {
//            e.printStackTrace();
//        }
//        //如果有错就返加nulll
//        return null;
//    }
//
//    /**
//     * 加密
//     * 1.构造密钥生成器
//     * 2.根据ecnodeRules规则初始化密钥生成器
//     * 3.产生密钥
//     * 4.创建和初始化密码器
//     * 5.内容加密
//     * 6.返回字符串
//     */
//    public static String aesEncodeByKey(String content, String aesKey) {
//        Cipher cipher = Cipher.getInstance(ALGORITHMS, PROVIDER);
//        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), KEY_ALGORITHM));
//
//        //调用doFinal
//        // 转base64
//        return Base64.encodeBase64String(cipher.doFinal(content.getBytes(StandardCharsets.UTF_8)));
//    }
    /**
     * 加密算法AES
     */
    private static final String KEY_ALGORITHM = "AES";

    /**
     * key的长度，Wrong key size: must be equal to 128, 192 or 256
     * 传入时需要16、24、36
     */
    private static final int KEY_LENGTH = 16 * 8;

    /**
     * 算法名称/加密模式/数据填充方式
     * 默认：AES/ECB/PKCS5Padding
     */
    private static final String ALGORITHMS = "AES/ECB/PKCS5Padding";

    /**
     * 后端AES的key，由静态代码块赋值
     */
    public static String key;

    /**
     * 不能在代码中创建
     * JceSecurity.getVerificationResult 会将其put进 private static final Map<Provider,Object>中，导致内存缓便被耗尽
     */
    private static final BouncyCastleProvider PROVIDER = new BouncyCastleProvider();

    static {
        key = getKey();
    }

    /**
     * 获取key
     */
    public static String getKey() { //生产16位的强随机Key
        int length = KEY_LENGTH / 8;
        StringBuilder uid = new StringBuilder(length);
        //产生16位的强随机数
        Random rd = new SecureRandom();
        for (int i = 0; i < length; i++) {
            //产生0-2的3位随机数
            switch (rd.nextInt(3)) {
                case 0:
                    //0-9的随机数
                    uid.append(rd.nextInt(10));
                    break;
                case 1:
                    //ASCII在65-90之间为大写,获取大写随机
                    uid.append((char) (rd.nextInt(26) + 65));
                    break;
                case 2:
                    //ASCII在97-122之间为小写，获取小写随机
                    uid.append((char) (rd.nextInt(26) + 97));
                    break;
                default:
                    break;
            }
        }
        return uid.toString();
    }

    /**
     * 加密
     *
     * @param content    加密的字符串
     * @param encryptKey key值
     */
    public static String encrypt(String content, String encryptKey) throws Exception {
        //设置Cipher对象
        Cipher cipher = Cipher.getInstance(ALGORITHMS, PROVIDER);
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), KEY_ALGORITHM));

        //调用doFinal
        // 转base64
        return Base64.encodeBase64String(cipher.doFinal(content.getBytes(StandardCharsets.UTF_8)));

    }

    public static String encryptByte(byte[] content, String encryptKey) throws Exception {
        //设置Cipher对象
        Cipher cipher = Cipher.getInstance(ALGORITHMS, PROVIDER);
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), KEY_ALGORITHM));

        //调用doFinal
        // 转base64
//        return cipher.doFinal(content).toString();
        return Base64.encodeBase64String(cipher.doFinal(content));
    }

    /**
     * 解密
     *
     * @param encryptStr 解密的字符串
     * @param decryptKey 解密的key值
     */
    public static String decrypt(String encryptStr, String decryptKey) throws Exception {
        //base64格式的key字符串转byte
        //底层使用utf-8进行转换，StringUtils.getBytesUtf8()
        byte[] decodeBase64 = Base64.decodeBase64(encryptStr);

        //设置Cipher对象
        Cipher cipher = Cipher.getInstance(ALGORITHMS,PROVIDER);
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), KEY_ALGORITHM));

        //调用doFinal解密
        //同样需要使用utf-8转换回来，StringUtils.newStringUtf8()或者直接new String()
        return new String(cipher.doFinal(decodeBase64),StandardCharsets.UTF_8);
    }


    public static byte[] decryptBytes(String encryptStr, String decryptKey) throws Exception {
        //base64格式的key字符串转byte
        //底层使用utf-8进行转换，StringUtils.getBytesUtf8()
        byte[] decodeBase64 = Base64.decodeBase64(encryptStr);

        //设置Cipher对象
        Cipher cipher = Cipher.getInstance(ALGORITHMS,PROVIDER);
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), KEY_ALGORITHM));

        //调用doFinal解密
        //同样需要使用utf-8转换回来，StringUtils.newStringUtf8()或者直接new String()
        return new String(cipher.doFinal(decodeBase64),StandardCharsets.UTF_8).getBytes(StandardCharsets.UTF_8);
    }

    /**
     * 将二进制转换成16进制
     *
     * @param buf
     * @return
     */
    public static String parseByte2HexStr(byte buf[]) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < buf.length; i++) {
            String hex = Integer.toHexString(buf[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sb.append(hex.toUpperCase());
        }
        return sb.toString();
    }

    /**
     * 将16进制转换为二进制
     *
     * @param hexStr
     * @return
     */
    public static byte[] parseHexStr2Byte(String hexStr) {
        if (hexStr.length() < 1)
            return null;
        byte[] result = new byte[hexStr.length() / 2];
        for (int i = 0; i < hexStr.length() / 2; i++) {
            int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }
}
