package com.trs.project.util;


import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.*;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;

/**
 * DES相关加解密工具
 * 1.1.0.Alpha版本默认为 ECB模式
 *
 * @author Mrsazz
 */
public class GpDESUtils {

    private static Logger logger = LoggerFactory.getLogger(GpDESUtils.class);

    /**
     * 默认密钥
     */
    private static final String DES_KEY = "nmgzzqmy";
    /**
     * 字符集编码
     */
    private static final Charset CHAR_SET = Charset.forName("UTF8");
    /**
     * 模式
     */
    private static final String DES_MODEL = "DES";

    /**
     * 加密字符串（默认密钥）
     *
     * @param code 需要加密的字符串
     * @return 加密后的BASE64编码的字符串
     */
    public static String encrypt(String code) {
        return doEncrypt(code, DES_KEY);
    }

    /**
     * 加密字符串（指定密钥）
     *
     * @param code   需要加密的字符串
     * @param desKey 密钥（注意长度不小于8位）
     * @return 加密后的BASE64编码的字符串
     */
    public static String encrypt(String code, String desKey) {
        return doEncrypt(code, desKey);
    }

    /**
     * DES加密字符串方法
     *
     * @param code
     * @param desKey
     * @return
     */
    private static String doEncrypt(String code, String desKey) {
        byte[] keyByte = desKey.getBytes(CHAR_SET);
        // 创建一个空的八位数组,默认情况下为0
        byte[] byteTemp = new byte[8];
        // 将用户指定的规则转换成八位数组
        for (int i = 0; i < byteTemp.length && i < keyByte.length; i++) {
            byteTemp[i] = keyByte[i];
        }
        DESKeySpec mDesKeySpec = null;
        byte[] encode = new byte[0];
        try {
            mDesKeySpec = new DESKeySpec(desKey.getBytes(CHAR_SET));
            // 创建一个密匙工厂，然后用它把DESKeySpec转换成
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES_MODEL);
            SecretKey secureKey = keyFactory.generateSecret(mDesKeySpec);
            Cipher mCipher = Cipher.getInstance(DES_MODEL);
            mCipher.init(Cipher.ENCRYPT_MODE, secureKey);
            encode = mCipher.doFinal(code.getBytes(CHAR_SET));
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        }
        return new BASE64Encoder().encode(encode);
    }

    /**
     * 解密字符串（默认密钥）
     *
     * @param code 需要解密的BASE64编码的密文
     * @return 解密后的明文字符串
     */
    public static String decrypt(String code) {
        return doDecrypt(code, DES_KEY);
    }

    /**
     * 解密字符串（指定密钥）
     *
     * @param code   需要解密的BASE64编码的密文
     * @param desKey 密钥（注意长度不小于8位）
     * @return 解密后的明文字符串
     */
    public static String decrypt(String code, String desKey) {
        return doDecrypt(code, desKey);
    }

    /**
     * DES解密字符串方法
     *
     * @param code
     * @param desKey
     * @return
     */
    private static String doDecrypt(String code, String desKey) {
        byte[] keyByte = desKey.getBytes(CHAR_SET);
        // 创建一个空的八位数组,默认情况下为0
        byte[] byteTemp = new byte[8];
        // 将用户指定的规则转换成八位数组
        for (int i = 0; i < byteTemp.length && i < keyByte.length; i++) {
            byteTemp[i] = keyByte[i];
        }
        // 创建一个DESKeySpec对象
        DESKeySpec mDesKeySpec = null;
        byte[] decode = new byte[0];
        try {
            mDesKeySpec = new DESKeySpec(desKey.getBytes(CHAR_SET));
            // 创建一个密匙工厂
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES_MODEL);
            // 将DESKeySpec对象转换成SecretKey对象
            SecretKey securekey = keyFactory.generateSecret(mDesKeySpec);
            Cipher mCipher = Cipher.getInstance(DES_MODEL);
            mCipher.init(Cipher.DECRYPT_MODE, securekey);
            decode = mCipher.doFinal(new BASE64Decoder().decodeBuffer(code));
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        }
        return new String(decode, CHAR_SET);
    }

    /**
     * 加密输入流，目前测试最大25M
     *
     * @param inputStream 需要加密的输入流
     * @param desKey      用于DES加密的密钥(目前测试使用的是56位字符串)
     * @return 加密后的输入流
     */
    public static InputStream encryptInputStream(InputStream inputStream, String desKey) {
        byte[] keyByte = null;
        keyByte = desKey.getBytes(StandardCharsets.UTF_8);
        // 创建一个空的八位数组,默认情况下为0
        byte[] byteTemp = new byte[8];
        // 将用户指定的规则转换成八位数组
        for (int i = 0; i < byteTemp.length && i < keyByte.length; i++) {
            byteTemp[i] = keyByte[i];
        }
        Key key = new SecretKeySpec(byteTemp, DES_MODEL);
        Cipher mCipher;
        try {
            mCipher = Cipher.getInstance(DES_MODEL);
            mCipher.init(Cipher.ENCRYPT_MODE, key);
            logger.debug("DES开始加密！");
            CipherInputStream cis = new CipherInputStream(inputStream, mCipher);
            return cis;
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 解密输出流，目前测试最大25M
     *
     * @param filePath 需要解密的输出流
     * @param desKey   用于DES解密的密钥(目前测试使用的是56位字符串)
     * @return 解密后的输出流
     * @throws Exception
     */
    public static InputStream decryptOutputStream(String filePath, String desKey) {
        FileInputStream keyFIS = null;
        byte[] keyByte = new byte[0];
        keyByte = desKey.getBytes(StandardCharsets.UTF_8);
        // 创建一个空的八位数组,默认情况下为0
        byte[] byteTemp = new byte[8];
        // 将用户指定的规则转换成八位数组
        for (int i = 0; i < byteTemp.length && i < keyByte.length; i++) {
            byteTemp[i] = keyByte[i];
        }
        Key key = new SecretKeySpec(byteTemp, DES_MODEL);
        Cipher cipherDecrypt;
        InputStream is = null;
        CipherOutputStream cos = null;
        try {
            logger.debug("开始解密");
            cipherDecrypt = Cipher.getInstance(DES_MODEL);
            cipherDecrypt.init(Cipher.DECRYPT_MODE, key);
            is = new FileInputStream(filePath);
            OutputStream out = new ByteArrayOutputStream();
            cos = new CipherOutputStream(out, cipherDecrypt);
            byte[] buffer = new byte[1024];
            int r;
            while ((r = is.read(buffer)) >= 0) {
                cos.write(buffer, 0, r);
            }
            logger.debug("解密完成");
            return outputStreamToInputStream(out);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != cos) {
                try {
                    cos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    /**
     * outputStream转inputStream
     *
     * @param out
     * @return
     * @throws Exception
     */
    public static ByteArrayInputStream outputStreamToInputStream(OutputStream out) {
        ByteArrayOutputStream baos;
        baos = (ByteArrayOutputStream) out;
        ByteArrayInputStream swapStream = new ByteArrayInputStream(baos.toByteArray());
        return swapStream;
    }

    /**
     * 获取信息的校验码
     *
     * @param message
     * @return
     */
    public static String getDataMac(String message) {
        return DigestUtils.sha256Hex(message);
    }

    public static void main(String[] args) {
        String aaa = "[encoded data, 23696 characters]";

//        System.out.println(decrypt(aaa, "T2UW2J0b4lM="));
        System.out.println(decrypt(aaa, "nmgzzqmy"));
    }
}
