
package com.pine.common.utils;


import java.security.MessageDigest;
import java.util.Base64;

/**
 * 登录密码工具类<p>
 * 接口传输密码要求，原始密码md5加密，前面拼接上请求Json串字符串，再次md5加密。
 * 数据库密码为明文密码md5加密，再Base64加密
 * Created by Stanny.Xie on 2017/6/23.
 * version 1.0
 */
public class PasswordEncryptorUtils {

    /**
     * 加密字符集
     */
    private static final String CHARSET = "utf-8";

    private static final String hexDigits = "0123456789ABCDEF";

    /**
     * 十六进制字符串转字节码
     *
     * @param hexString
     * @return
     */
    public static byte[] hexStringToBytes(String hexString) {
        if (hexString == null || hexString.equals("")) {
            return null;
        }
        hexString = hexString.toUpperCase();
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] d = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
        }
        return d;
    }

    /**
     * 返回字符在十六进制中的位置
     *
     * @param c
     * @return
     */
    private static byte charToByte(char c) {
        return (byte) hexDigits.indexOf(c);
    }

    /**
     * 字节码数组转十六进制字符串
     *
     * @param codes
     * @return
     */
    public static String bytesToHexString(byte[] codes) {
        StringBuilder stringBuilder = new StringBuilder("");
        if (codes == null || codes.length <= 0) {
            return null;
        }
        for (int i = 0; i < codes.length; i++) {
            int v = codes[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString().toUpperCase();
    }

    /**
     * 利用md5算法加密
     *
     * @param pwdCodes 加密原字节码
     * @return
     * @throws Exception
     */
    private static byte[] md5Encode(byte[] pwdCodes) throws Exception {
        MessageDigest md5Utils = MessageDigest.getInstance("MD5");
        return md5Utils.digest(pwdCodes);
    }

    /**
     * 字符串md5加密
     *
     * @param pwd
     * @return
     * @throws Exception
     */
    private static byte[] md5Encode(String pwd) throws Exception {
        return md5Encode(pwd.getBytes(CHARSET));
    }

    /**
     * 用于md5加密
     *
     * @param pwd 原密码
     * @return md5加密后密码
     * @throws Exception
     */
    public static String md5Encryptor(String pwd) throws Exception {
        if (null == pwd) {
            return "";
        }
        return bytesToHexString(md5Encode(pwd));
    }

    /**
     * 利用Base64加密
     *
     * @param pwdCodes
     * @return
     * @throws Exception
     */
    private static String base64Encode(byte[] pwdCodes) throws Exception {
        return new String(Base64.getEncoder().encode(pwdCodes));
    }

    /**
     * 利用Base64解密
     *
     * @param dbPwd
     * @return
     * @throws Exception
     */
    private static byte[] base64Decode(String dbPwd) throws Exception {
        return Base64.getDecoder().decode(dbPwd.getBytes());
    }

    /**
     * 用于md5密码base64加密
     *
     * @param md5Pwd
     * @return
     * @throws Exception
     */
    public static String base64Encryptor(String md5Pwd) throws Exception {
//        if (StringUtils.isRealEmpty(md5Pwd)) {
//            return null;
//        }
        return base64Encode(hexStringToBytes(md5Pwd));
    }

    /**
     * 用于数据库密码一次Base64解密
     *
     * @param dbPwd 数据库密码
     * @return Base64解密后的密码
     * @throws Exception
     */
    public static String base64Decryptor(String dbPwd) throws Exception {
//        if (StringUtils.isRealEmpty(dbPwd)) {
//            return null;
//        }
        return bytesToHexString(base64Decode(dbPwd));
    }

    /**
     * 登录密码校验
     *
     * @param reqJsonStr 用户请求Json串
     * @param sign   用户输入的密码，加上请求Json串后md5再md5加密后的字符串
     * @param md5Pwd     数据库密码，多次加密后的密码
     * @return 匹配结果
     * @throws Exception
     */
    @Deprecated
    public static boolean passwordsCompare(String reqJsonStr, String sign, String md5Pwd) throws Exception {
        if (null == md5Pwd || null == sign) {
            return false;
        }
        // (请求Json串+base64解码后的数据库密码)再md5加密，与参数密码比较
        if (md5WithSecretKey(reqJsonStr, md5Pwd).equalsIgnoreCase(sign)) {
            return true;
        }
        return false;
    }

    /**
     * 用户输入的密码与数据库密码比较
     * @param inputPwd
     * @param md5Pwd
     * @return
     * @throws Exception
     */
    public static boolean passwordsCompare(String inputPwd, String md5Pwd) throws Exception {
//        if (StringUtils.isRealEmpty(md5Pwd)|| StringUtils.isRealEmpty(inputPwd)) {
//            return false;
//        }
        // 数据库密码需要先Base64解密
        if (base64Decryptor(md5Pwd).equalsIgnoreCase(inputPwd)) {
            return true;
        }
        return false;
    }

    /**
     * 用于密码拼接请求Json串的再次加密
     *
     * @param reqJsonStr 用户请求Json串
     * @param md5Pwd     md5加密后的密码
     * @return
     * @throws Exception
     */
    public static String md5WithSecretKey(String reqJsonStr, String md5Pwd) throws Exception {
        if (null == md5Pwd) {
            return "";
        }
        StringBuffer pwdBuffer = new StringBuffer(reqJsonStr).append("{\"key\":\"").append(md5Pwd).append("\"}");
        return md5Encryptor(pwdBuffer.toString());
    }

    /**
     * 用于明文密码md5+Base64加密，结果保存到数据库
     *
     * @param pwd 原始密码
     * @return Base64加密后的密码
     * @throws Exception
     */
    public static String md5AndBase64Encryptor(String pwd) throws Exception {
        if (null == pwd) {
            return "";
        }
        return base64Encode(md5Encode(pwd));
    }
}
