package com.kym.common.utils;

import org.apache.commons.codec.digest.DigestUtils;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;


/**
 * MD5加密算法类
 *
 * @author yaopeng
 * @date 2015年5月29日 上午11:22:56
 */
public class EncryptUtil {
    /**
     * md5盐值
     */
    private static final String SALT = "M33ab";
    /**
     * 十六进制下数字到字符的映射数组
     */
    private final static String[] HEX_DIGITS = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};

    /**
     * 8位偏移量
     */
    private static final String IV = "97812367";

    /**
     * aes des加密key
     */
    public static final String DEFAULT_KEY = "MTIzNzg5YWNk";

    private EncryptUtil() {
    }

    /**
     * 对字符串进行MD5加密
     */
    public static String encodeByMD5(String content) {
        try {
            if (null != content) {
                return DigestUtils.md5Hex(content);
          /*      //创建具有指定算法名称的信息摘要
                MessageDigest md = MessageDigest.getInstance("MD5");
                //使用指定的字节数组对摘要进行最后更新，然后完成摘要计算
                byte[] results = md.digest(content.getBytes(StandardCharsets.UTF_8));
                //将得到的字节数组变成字符串返回
                String resultString = byteArrayToHexString(results);
                return resultString.toUpperCase();*/
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    /**
     * 对字符串进行HmacSHA1加密
     *
     */
    public static String encodeByHmacSHA1(String content) {
        try {
            if (null != content) {
                SecretKey secretKey = new SecretKeySpec(content.getBytes(), "HmacSHA1");
                Mac mac = Mac.getInstance(secretKey.getAlgorithm());
                mac.init(secretKey);
                byte[] results = mac.doFinal();
                //将得到的字节数组变成字符串返回
                String resultString = byteArrayToHexString(results);
                return resultString.toUpperCase();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    /**
     * 对字符串进行HmacSHA256加密
     *
     */
    public static String encodeByHmacSHA256(String content) {
        try {
            if (null != content) {
                SecretKey secretKey = new SecretKeySpec(content.getBytes(), "HmacSHA256");
                Mac mac = Mac.getInstance(secretKey.getAlgorithm());
                mac.init(secretKey);
                byte[] results = mac.doFinal();
                //将得到的字节数组变成字符串返回
                String resultString = byteArrayToHexString(results);
                return resultString.toUpperCase();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    /**
     * 对字符串进行HmacMD5加密
     *
     */
    public static String encodeByHmacMD5(String content) {
        try {
            if (null != content) {
                SecretKey secretKey = new SecretKeySpec(content.getBytes(), "HmacMD5");
                Mac mac = Mac.getInstance(secretKey.getAlgorithm());
                mac.init(secretKey);
                byte[] results = mac.doFinal();
                //将得到的字节数组变成字符串返回
                String resultString = byteArrayToHexString(results);
                return resultString.toUpperCase();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    /**
     * 对字符串进行SHA1加密
     */
    public static String encodeBySHA1(String content) {
        try {
            if (null != content) {
                //创建具有指定算法名称的信息摘要
                MessageDigest md = MessageDigest.getInstance("SHA-1");
                md.reset();
                //使用指定的字节数组对摘要进行最后更新，然后完成摘要计算
                byte[] results = md.digest(content.getBytes(StandardCharsets.UTF_8));
                //将得到的字节数组变成字符串返回
                String resultString = byteArrayToHexString(results);
                return resultString.toUpperCase();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    /**
     * 字符串SHA-256加密
     */
    public static String encodeBySHA256(String content) {
        MessageDigest messageDigest = null;
        try {
            if (null != content) {
                messageDigest = MessageDigest.getInstance("SHA-256");
                byte[] bytes = content.getBytes();
                messageDigest.update(bytes);
                byte[] disestBytes = messageDigest.digest();
                char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
                char[] chars = new char[disestBytes.length * 2];
                int index = 0;
                for (byte b : disestBytes) {
                    chars[index++] = hexDigits[b >>> 4 & 0xf];
                    chars[index++] = hexDigits[b & 0xf];
                }
                return new String(chars);
            }
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * aes加密
     *
     * @param key     密钥
     */
    public static String encodeByAes(String content, String key) {
        if (null != content) {
            KeyGenerator kgen = null;
            try {
                kgen = KeyGenerator.getInstance("AES");


                SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
                random.setSeed(key.getBytes());
                kgen.init(128, random);

                SecretKey secretKey = kgen.generateKey();
                byte[] enCodeFormat = secretKey.getEncoded();
                SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, "AES");
                Cipher cipher = Cipher.getInstance("AES");
                byte[] byteContent = content.getBytes(StandardCharsets.UTF_8);
                cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
                byte[] bytes = cipher.doFinal(byteContent);
                return byteArrayToHexString(bytes);
            } catch (NoSuchAlgorithmException | InvalidKeyException | NoSuchPaddingException | BadPaddingException | IllegalBlockSizeException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * aes 解密
     *
     * @param key     密钥
     */
    public static String decodeByAes(String content, String key) {
        if (null != content) {
            try {
                byte[] byteRresult = new byte[content.length() / 2];
                for (int i = 0; i < content.length() / 2; i++) {
                    int high = Integer.parseInt(content.substring(i * 2, i * 2 + 1), 16);
                    int low = Integer.parseInt(content.substring(i * 2 + 1, i * 2 + 2), 16);
                    byteRresult[i] = (byte) (high * 16 + low);
                }
                KeyGenerator kgen = KeyGenerator.getInstance("AES");
                SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
                random.setSeed(key.getBytes());
                kgen.init(128, random);

                SecretKey secretKey = kgen.generateKey();
                byte[] enCodeFormat = secretKey.getEncoded();
                SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, "AES");
                Cipher cipher = Cipher.getInstance("AES");
                cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
                byte[] result = cipher.doFinal(byteRresult);
                return new String(result);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }


    public static String encodeByDes(String content, String key) {
        if (null != content) {
            if (key.length() < 8) {
                throw new IllegalArgumentException("des encrypt key length less than 8!");
            }
            try {
                DESKeySpec dks = new DESKeySpec(key.getBytes(StandardCharsets.UTF_8));
                SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
                Key secretKey = keyFactory.generateSecret(dks);
                //加密算法模式
                Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
                IvParameterSpec iv = new IvParameterSpec(IV.getBytes(StandardCharsets.UTF_8));
                cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
                byte[] bytes = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
                return Base64.getEncoder().encodeToString(bytes);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }


    public static String decodeByDes(String content, String key) {
        if (null != content) {
            if (key.length() < 8) {
                throw new IllegalArgumentException("des decrypt key length less than 8!");
            }
            try {
                DESKeySpec dks = new DESKeySpec(key.getBytes(StandardCharsets.UTF_8));
                SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
                Key secretKey = keyFactory.generateSecret(dks);
                Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
                IvParameterSpec iv = new IvParameterSpec(IV.getBytes(StandardCharsets.UTF_8));
                cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
                return new String(cipher.doFinal(Base64.getDecoder().decode(content.getBytes(StandardCharsets.UTF_8))), StandardCharsets.UTF_8);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }


    /**
     * DES加密文件
     *
     * @param srcFile  待加密的文件
     * @param destFile 加密后存放的文件路径
     * @return 加密后的文件路径
     */
    public static void encodeFileByDes(String key, String srcFile, String destFile) {
        if (key.length() < 8) {
            throw new IllegalArgumentException("des encrypt key length less than 8!");
        }
        try {
            DESKeySpec dks = new DESKeySpec(key.getBytes(StandardCharsets.UTF_8));
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            Key secretKey = keyFactory.generateSecret(dks);
            IvParameterSpec iv = new IvParameterSpec(IV.getBytes(StandardCharsets.UTF_8));
            Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
            InputStream is = new FileInputStream(srcFile);
            OutputStream out = new FileOutputStream(destFile);
            CipherInputStream cis = new CipherInputStream(is, cipher);
            byte[] buffer = new byte[1024];
            int r;
            while ((r = cis.read(buffer)) > 0) {
                out.write(buffer, 0, r);
            }
            cis.close();
            is.close();
            out.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }


    /**
     * DES解密文件
     *
     * @param srcFile  已加密的文件
     * @param destFile 解密后存放的文件路径
     * @return 解密后的文件路径
     */
    public static void decodeFileByDes(String key, String srcFile, String destFile) {
        if (key.length() < 8) {
            throw new IllegalArgumentException("des encrypt key length less than 8!");
        }
        try {
            File file = new File(destFile);
            if (!file.exists()) {
                file.getParentFile().mkdirs();
                file.createNewFile();
            }
            DESKeySpec dks = new DESKeySpec(key.getBytes(StandardCharsets.UTF_8));
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            Key secretKey = keyFactory.generateSecret(dks);
            IvParameterSpec iv = new IvParameterSpec(IV.getBytes(StandardCharsets.UTF_8));
            Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
            InputStream is = new FileInputStream(srcFile);
            OutputStream out = new FileOutputStream(destFile);
            CipherOutputStream cos = new CipherOutputStream(out, cipher);
            byte[] buffer = new byte[1024];
            int r;
            while ((r = is.read(buffer)) >= 0) {
                cos.write(buffer, 0, r);
            }
            cos.close();
            is.close();
            out.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * 转换字节数组为十六进制字符串
     *
     * @param b 字节数组
     */
    private static String byteArrayToHexString(byte[] b) {
        StringBuilder sbr = new StringBuilder();
        for (byte value : b) {
            sbr.append(byteToHexString(value));
        }
        return sbr.toString();
    }

    /**
     * 将一个字节转化成十六进制形式的字符串
     *
     * @param b 字节数
     */
    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0) {
            n = 256 + n;
        }
        int d1 = n / 16;
        int d2 = n % 16;
        return HEX_DIGITS[d1] + HEX_DIGITS[d2];
    }

    public static String encryptPassword(String pwd) {
        return encodeByMD5(encodeByMD5(pwd) + SALT);
    }
}
