package com.hotent.base.util;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.security.Security;
import java.util.HashMap;
import java.util.Map;

public class RestAesUtil {
    /**
     * AES128 算法
     * CBC 模式
     * PKCS7Padding 填充模式
     * CBC模式需要添加偏移量参数iv，必须16位
     * 密钥 sessionKey，必须16位
     * 介于java 不支持PKCS7Padding，只支持PKCS5Padding 但是PKCS7Padding 和 PKCS5Padding 没有什么区别
     * 要实现在java端用PKCS7Padding填充，需要用到bouncycastle组件来实现
     */
    private final String sessionKey = "9e839853592f45f7";
    // 偏移量 16位
    private final String iv = "Qing195GUY86Hong";

    // 算法名称
    final String KEY_ALGORITHM = "AES";
    // 加解密算法/模式/填充方式
    final String algorithmStr = "AES/CBC/PKCS7Padding";
    
    private Map<String, Cipher> cipherMap = new HashMap<String, Cipher>();
    // 加解密 密钥 16位

//    byte[] ivByte;
//    byte[] keybytes;
//    private Key key;
//    private Cipher cipher;
    boolean initialized = false;
    
    private static RestAesUtil INSTANCE;
    
    public static RestAesUtil getInstance() {
        if (INSTANCE == null) {
            synchronized (RestAesUtil.class) {
                if (INSTANCE == null) {
                    INSTANCE = new RestAesUtil();
                }
            }
        }
        return INSTANCE;
    }

//    private RestAesUtil() {
//        super();
//        init();
//    }
    
    public void initialize() {
        if (initialized)
            return;
        Security.addProvider(new BouncyCastleProvider());
        initialized = true;
    }
    
//    public void init() {
//        // 如果密钥不足16位，那么就补足.  这个if 中的内容很重要
//        keybytes = sessionKey.getBytes();
//        ivByte = iv.getBytes();
////        int base = 16;
////        if (keybytes.length % base != 0) {
////            int groups = keybytes.length / base + (keybytes.length % base != 0 ? 1 : 0);
////            byte[] temp = new byte[groups * base];
////            Arrays.fill(temp, (byte) 0);
////            System.arraycopy(keybytes, 0, temp, 0, keybytes.length);
////            keybytes = temp;
////        }
//        // 初始化
//        Security.addProvider(new BouncyCastleProvider());
//        // 转化成JAVA的密钥格式
//        key = new SecretKeySpec(keybytes, KEY_ALGORITHM);
//        try {
//            // 初始化cipher
//            cipher = Cipher.getInstance(algorithmStr, "BC");
//        } catch (NoSuchAlgorithmException e) {
//            // TODO Auto-generated catch block
//            e.printStackTrace();
//        } catch (NoSuchPaddingException e) {
//            // TODO Auto-generated catch block
//            e.printStackTrace();
//        } catch (NoSuchProviderException e) {
//            // TODO Auto-generated catch block
//            e.printStackTrace();
//        }
//    }
    
    /**
     * 加密方法
     *
     * @param content
     *            要加密的字符串
     * @param keyBytes
     *            加密密钥
     * @return
     */
    public synchronized String encrypt(String content) {
        try {
            byte[] encryptedText = null;
            byte[] contentByte = content.getBytes();
            initialize();
            // 如果密钥不足16位，那么就补足.
            byte[] keybytes = sessionKey.getBytes();
            byte[] ivByte = iv.getBytes();
            
            Cipher cipher = null;
            // 初始化cipher 避免大量实例化时候发生Cipher not initialized 异常
            if(cipherMap.get("cipher_enc")==null) {
                // 初始化cipher
                cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
                // 转化成JAVA的密钥格式
                Key key = new SecretKeySpec(keybytes, "AES");
                cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(ivByte));
                cipherMap.put("cipher_enc", cipher);
            } else {
                cipher = cipherMap.get("cipher_enc");
            }
            encryptedText = cipher.doFinal(contentByte);
            return new String(Hex.encode(encryptedText));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 解密方法
     *
     * @param encryptedData
     *            要解密的字符串
     * @param keyBytes
     *            解密密钥
     * @return
     */
    public synchronized String decrypt(String encryptedData) {
        try {
            byte[] encryptedText = null;
            byte[] encryptedDataByte = Hex.decode(encryptedData);
            initialize();
            // 如果密钥不足16位，那么就补足.
            byte[] keybytes = sessionKey.getBytes();
            byte[] ivByte = iv.getBytes();
            
            Cipher cipher = null;
            // 初始化cipher 避免大量实例化时候发生Cipher not initialized 异常
            if(cipherMap.get("cipher")==null) {
                // 初始化cipher
                cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
                // 转化成JAVA的密钥格式
                Key key = new SecretKeySpec(keybytes, "AES");
                cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(ivByte));
                cipherMap.put("cipher", cipher);
            }else {
                cipher = cipherMap.get("cipher");
            }
            encryptedText = cipher.doFinal(encryptedDataByte);
            return new String(encryptedText);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static void main(String[] args) {
        //AesUtil aes = new AesUtil();
        RestAesUtil aes = RestAesUtil.getInstance();
//        //加密字符串
//        JSONObject obj = new JSONObject();
//        obj.put("name","冯智涌");
//        obj.put("idCard","140121199110196016");
//        obj.put("phoneNum","18834822027");
//        obj.put("timeStr","1641286091");
//        
//        String content = obj.toJSONString();
//        System.out.println("加密前的：" + content);
//        // 加密方法
//        long startTime = System.currentTimeMillis();
//        String enc = aes.encrypt(content);
//        System.out.println("加密后的内容：" + enc);
//        long endTime = System.currentTimeMillis();
//        float excTime = (float)(endTime-startTime)/1000;
//        System.out.println("执行时间："+excTime+"s");
        // 解密方法
        //String enc = "88ECAE0CA19A35FFE4EA0DA2F9CFA70E211D313685AF56D7D97493EFA1B37A2999D05820EA29168D0BCD776670218F2E334F80619788D8FC94FAC4683DCECE3DC160C18CE86F453D22F6E945C1515DEB3A63BC59A0CCDF2493A07F084C4C9BF8F301F53AD96BDDB4EB976145ECCA4918";
        //String enc = "23AA272AF49D17514BEB523500F781B6DF7AF3E8ACF5C45850FCF3247BA9C45355CD6B25CC92600A0162E5CFB8205EF2BA069D4B2269BF33C3BAE71C7D6749A716AF9F74E2BA540664348FF746E5CE91301808EF8C9339F81B1623060ABDE80BF0087F07037C2770B633290720BF950BFDE875C2CDC8030269872D45AC298902B2AE984A5D307265B3E5EBCFD23C20DC";
        //String enc = "C481FC238DD9B3AC946DBFF7F43EE53BAA1E7913B991DA487224870815A959B3C8FC57421F76515A40B1E331C1D9A83C06BA8B2602A0101FC53693778D642DB30DA96C339EE44BD7EB3003975D54BB3E216F1B46CB4897419628931C62C5957F2F4F446BEB3AF76A170857DC0E34A9B0";
        String enc = "99F0E85A57ECB745F83B46DB0D37AADA3AF3F764CD7CF12E99CD295B1FC6DDBFCCB7C6BFDB2AB234D05507637FA0B6E4CCDA00C44C98E84B019F1B98B9EF0E4A3D6FDF9BE33E643AFBB1F54CF271FBCC60388B77C7693E3C87CFA4A7D7F99C3A3FDF99BE4C8A87E099694D4C7F88FC21C54CC10201C61AB2D27C02B5D32E680F3063A3BDBE3EB911C583245C2D642D40";
        
        long startTime_2 = System.currentTimeMillis();
        String dec = aes.decrypt(enc);
        System.out.println("解密后的内容：" + dec);
        long endTime_2 = System.currentTimeMillis();
        float excTime_2 = (float)(endTime_2-startTime_2)/1000;
        System.out.println("执行时间："+excTime_2+"s");

    }
}