package com.nanjing.water.common.security;

import com.nanjing.water.common.enums.ELogger;
import com.nanjing.water.common.util.LoggerUtil;
import org.slf4j.Logger;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.nio.charset.Charset;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.util.UUID;


public final class Des3Util {
    private Des3Util() {
        throw new IllegalStateException("Utility class");
    }

    private static final Logger sysLogger = LoggerUtil.get(ELogger.SYS_ERROR);

    private static final String TITLE = "Des3加密工具";

    //默认加密偏移量
    private static byte[] DEFAULT_IV = { 0x23, (byte)0xf2, (byte)0xa3, (byte)0xc6, 0x3e, 0x2b, (byte)0xe7, 0x28 };
    //加密算法
    private static final String ALGORITHM = "DESede";
    // 加解密统一使用的编码方式
    private static final String DEFAULT_ENCODING = "utf-8";
    //密钥
    public static final String DEFAULT_KEY = "com.ctrip.tour.cq.soa.v1";

    /**
     * 生成加密偏移量
     * @param iv 偏移量
     */
    private static IvParameterSpec IvGenerator(byte[] iv) throws Exception {
        IvParameterSpec result = new IvParameterSpec(iv);
        return result;
    }

    /**
     * 随机生成一个key
     */
    public static String genKey() throws NoSuchAlgorithmException {
        byte[] keyBytes = UUID.randomUUID().toString().getBytes();
        KeyGenerator generator = KeyGenerator.getInstance(ALGORITHM);
        generator.init(new SecureRandom( keyBytes ) );
        SecretKey key = generator.generateKey();
        return Base64Util.encodeStream(key.getEncoded());
    }
    /**
     * 根据明文字符串生成key(key长度必须 大于等于 24)
     */
    public static Key genKey(String key) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException {
        DESedeKeySpec spec = new DESedeKeySpec(key.getBytes());
        SecretKeyFactory keyfactory = SecretKeyFactory.getInstance(ALGORITHM);
        return keyfactory.generateSecret(spec);
    }

    /**
     * 加密以byte[]明文输入,byte[]密文输出
     * @param buffer 待加密的字节码
     * @param key 密钥(key长度必须 大于等于 24)
     * @return 加密后的字节码
     */
    private static byte[] encrypt(byte[] buffer, String key) {
        byte[] result = null;
        try {
            Cipher cipher = Cipher.getInstance(ALGORITHM +"/CBC/PKCS5Padding");
            IvParameterSpec IVSpec = IvGenerator(DEFAULT_IV);
            cipher.init(Cipher.ENCRYPT_MODE, genKey(key), IVSpec);
            byte[] temp = cipher.doFinal(buffer);
            result = Base64Util.encodeToStream(temp);
        } catch (Exception e) {
            sysLogger.error("Des3Util.encrypt", e);
        }
        return result;
    }
    /**
     * 解密以byte[]密文输入,以byte[]明文输出
     * @param buffer 待解密的字节码
     * @param key 密钥(key长度必须是8的倍数)
     * @return 解密后的字节码
     */
    private static byte[] decrypt(byte[] buffer, String key) {
        byte[] result = null;
        try {
            IvParameterSpec IVSpec = IvGenerator(DEFAULT_IV);
            Cipher cipher = Cipher.getInstance(ALGORITHM +"/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, genKey(key), IVSpec);
            byte[] temp = Base64Util.decodeToStream(buffer);
            result = cipher.doFinal(temp);
        } catch (Exception e) {
            sysLogger.error("Des3Util.decrypt", e);
        }
        return result;
    }

    /**
     * 加密String 明文输入密文输出
     * @param str 待加密的明文
     * @param key 密钥(key长度必须 大于等于 24)
     * @return 加密后的字符串
     */
    public static String encrypt(String str, String key) throws Exception {
        byte[] buffer = str.getBytes(Charset.forName(DEFAULT_ENCODING));
        byte[] result = encrypt(buffer, key);
        return new String(result);
    }
    /**
     * 解密String 以密文输入明文输出
     * @param str 需要解密的字符串
     * @param key 密钥(key长度必须 大于等于 24)
     * @return 解密后的字符串
     */
    public static String decrypt(String str, String key) {
        byte[] buffer = str.getBytes(Charset.forName(DEFAULT_ENCODING));
        byte[] result = decrypt(buffer, key);
        return new String(result).trim();
    }

    /**
     * 加密String 明文输入密文输出
     * @param str 待加密的明文
     * @return 加密后的字符串
     */
    public static String encrypt(String str) throws Exception {
        return encrypt(str, DEFAULT_KEY);
    }
    /**
     * 解密String 以密文输入明文输出
     * @param str 需要解密的字符串
     * @return 解密后的字符串
     */
    public static String decrypt(String str) {
        return decrypt(str, DEFAULT_KEY);
    }
}