package com.crm.rely.backend.util;


import com.google.common.base.Strings;
import sun.misc.BASE64Decoder;

import java.io.IOException;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/**
 * @program: cwg-my-base
 * @description:
 * @author: houn
 * @create: 2019-11-21 19:44
 */

public class SignUtil {
    private static final String KEY_ALGORITHM = "RSA";
    private static final String PUBLIC_KEY = "publicKey";
    private static final String PRIVATE_KEY = "privateKey";
    private static final int KEY_SIZE = 1024;

    private static String CHARSET_ENCODING = "UTF-8";
    private static String ALGORITHM_SHA256withRSA = "SHA256withRSA";

    private static String ALGORITHM_SHA1withRSA = "SHA1withRSA";


    /**
     * 签名 SHA256withRSA
     *
     * @param privateKeyString 私钥
     * @param value            明文
     * @return
     */
    public static String signSHA256withRSA(String privateKeyString, String value) {
        return sign(privateKeyString, value, ALGORITHM_SHA256withRSA);
    }

    /**
     * 签名 SHA256withRSA
     *
     * @param privateKey 私钥
     * @param value      明文
     * @return
     */
    public static String signSHA256withRSA(PrivateKey privateKey, String value) {
        return sign(privateKey, value, ALGORITHM_SHA256withRSA);
    }

    /**
     * 签名 SHA1withRSA
     *
     * @param privateKeyString
     * @param value
     * @return
     */
    public static String signSHA1withRSA(String privateKeyString, String value) {
        return sign(privateKeyString, value, ALGORITHM_SHA1withRSA);
    }

    /**
     * 签名 SHA1withRSA
     *
     * @param privateKey 私钥
     * @param value      明文
     * @return
     */
    public static String signSHA1withRSA(PrivateKey privateKey, String value) {
        return sign(privateKey, value, ALGORITHM_SHA1withRSA);
    }

    public static String sign(String privateKeyString, String value, String algorithm) {
        PrivateKey privateKey = restore(privateKeyString);
        return sign(privateKey, value, algorithm);
    }

    public static String sign(PrivateKey privateKey, String value, String algorithm) {
        if (Strings.isNullOrEmpty(algorithm)) {
            algorithm = ALGORITHM_SHA256withRSA;
        }
        try {
            // 进行签名服务
            Signature signature = Signature.getInstance(algorithm);
            signature.initSign(privateKey);
            signature.update(value.getBytes(CHARSET_ENCODING));
            byte[] signedData = signature.sign();
            return Base64.getEncoder().encodeToString(signedData);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 验签
     *
     * @param publicKeyString 公钥
     * @param plain_text      明文
     * @param signedString    签名
     */
    public static boolean verifySignSHA256withRSA(String publicKeyString, String plain_text, String signedString) {

        return verifySign(publicKeyString, plain_text, signedString, ALGORITHM_SHA256withRSA);
    }

    public static boolean verifySignSHA1withRSA(String publicKeyString, String plain_text, String signedString) {
        return verifySign(publicKeyString, plain_text, signedString, ALGORITHM_SHA1withRSA);
    }

    public static boolean verifySign(String publicKeyString, String plain_text, String signedString, String algorithm) {
        PublicKey publicKey = restorePublicKey(publicKeyString, algorithm);
        byte[] signed = getBytes(signedString);
        return verifySign(publicKey, plain_text, signed, algorithm);
    }

    /**
     * 验签
     *
     * @param publicKeyString 公钥
     * @param plain_text      明文
     * @param signed          签名
     */
    public static boolean verifySignSHA256withRSA(String publicKeyString, String plain_text, byte[] signed) {
        return verifySign(publicKeyString, plain_text, signed, ALGORITHM_SHA256withRSA);
    }

    public static boolean verifySignSHA1withRSA(String publicKeyString, String plain_text, byte[] signed) {

        return verifySign(publicKeyString, plain_text, signed, ALGORITHM_SHA1withRSA);
    }

    public static boolean verifySign(String publicKeyString, String plain_text, byte[] signed, String algorithm) {
        PublicKey publicKey = restorePublicKey(publicKeyString, algorithm);
        return verifySign(publicKey, plain_text, signed, algorithm);
    }

    /**
     * 验签
     *
     * @param publicKey    公钥
     * @param plain_text   明文
     * @param signedString 签名
     */
    public static boolean verifySignSHA256withRSA(PublicKey publicKey, String plain_text, String signedString) {

        return verifySign(publicKey, plain_text, signedString, ALGORITHM_SHA256withRSA);
    }

    public static boolean verifySignSHA1withRSA(PublicKey publicKey, String plain_text, String signedString) {

        return verifySign(publicKey, plain_text, signedString, ALGORITHM_SHA1withRSA);
    }

    public static boolean verifySign(PublicKey publicKey, String plain_text, String signedString, String algorithm) {

        byte[] signed = getBytes(signedString);
        return verifySign(publicKey, plain_text, signed, algorithm);
    }

    /**
     * 验签
     *
     * @param publicKey  公钥
     * @param plain_text 明文
     * @param signed     签名
     */
    public static boolean verifySignSHA256withRSA(PublicKey publicKey, String plain_text, byte[] signed) {

        return verifySign(publicKey, plain_text, signed, ALGORITHM_SHA256withRSA);
    }

    public static boolean verifySignSHA1withRSA(PublicKey publicKey, String plain_text, byte[] signed) {

        return verifySign(publicKey, plain_text, signed, ALGORITHM_SHA1withRSA);
    }

    public static boolean verifySign(PublicKey publicKey, String plain_text, byte[] signed, String algorithm) {

        try {
            Signature sign = Signature.getInstance(algorithm);
            sign.initVerify(publicKey);
            sign.update(plain_text.getBytes(CHARSET_ENCODING));
            return sign.verify(signed);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * bytes[]换成16进制字符串
     *
     * @param src
     * @return
     */
    public static String bytesToHexString(byte[] src) {

        HexUtil.bytes2Hex(src);
        StringBuilder stringBuilder = new StringBuilder("");
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    /**
     * 生成密钥对
     *
     * @return
     */
    public static Map<String, byte[]> generateKeyBytes(int keySize) {

        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator
                    .getInstance(KEY_ALGORITHM);
            keyPairGenerator.initialize(keySize);
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
            RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
            Map<String, byte[]> keyMap = new HashMap<String, byte[]>();
            keyMap.put(PUBLIC_KEY, publicKey.getEncoded());
            keyMap.put(PRIVATE_KEY, privateKey.getEncoded());
            return keyMap;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 还原公钥
     *
     * @param keyBytes
     * @return
     */
    public static PublicKey restorePublicKey(byte[] keyBytes, String algorithm) {
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);
        try {
            KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM);
            PublicKey publicKey = factory.generatePublic(x509EncodedKeySpec);
            return publicKey;
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static PublicKey restorePublicKeySHA256withRSA(String key) {

        return restorePublicKey(key, ALGORITHM_SHA256withRSA);
    }

    public static PublicKey restorePublicKeySHA1withRSA(String key) {

        return restorePublicKey(key, ALGORITHM_SHA1withRSA);
    }

    public static PublicKey restorePublicKey(String key, String algorithm) {
        if (Strings.isNullOrEmpty(algorithm)) {
            algorithm = ALGORITHM_SHA256withRSA;
        }
        byte[] keyBytes = getBytes(key);

        return restorePublicKey(keyBytes, algorithm);
    }

    /**
     * 还原私钥
     *
     * @param keyBytes
     * @return
     */
    public static PrivateKey restorePrivateKeySHA256withRSA(byte[] keyBytes) {

        return restorePrivateKey(keyBytes);
    }

    public static PrivateKey restorePrivateKeySHA1withRSA(byte[] keyBytes) {

        return restorePrivateKey(keyBytes);
    }

    public static PrivateKey restorePrivateKey(byte[] keyBytes) {
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(
                keyBytes);
        try {
            KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM);
            PrivateKey privateKey = factory
                    .generatePrivate(pkcs8EncodedKeySpec);
            return privateKey;
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static PrivateKey restorePrivateKeySHA256withRSA(String key) {

        return restore(key);
    }

    public static PrivateKey restorePrivateKeySHA1withRSA(String key) {

        return restore(key);
    }

    public static PrivateKey restore(String key) {

        byte[] keyBytes = getBytes(key);

        return restorePrivateKey(keyBytes);
    }

    private static byte[] getBytes(String value) {

        byte[] valueBytes = null;
        try {
            valueBytes = (new BASE64Decoder()).decodeBuffer(value);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return valueBytes;
    }

    public static void genKeyPair(int keySize) throws NoSuchAlgorithmException {
        // KeyPairGenerator类用于生成公钥和私钥对，基于RSA算法生成对象
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
        // 初始化密钥对生成器，密钥大小为96-1024位
        keyPairGen.initialize(keySize, new SecureRandom());
        // 生成一个密钥对，保存在keyPair中
        KeyPair keyPair = keyPairGen.generateKeyPair();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); // 得到私钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); // 得到公钥
        String publicKeyString = new String(Base64.getEncoder().encodeToString(publicKey
                .getEncoded()));
        // 得到私钥字符串
        String privateKeyString = new String(Base64.getEncoder().encodeToString((privateKey
                .getEncoded())));
        // 将公钥和私钥保存到Map
        System.out.println("pub:" + publicKeyString);
        System.out.println("pri:" + privateKeyString);
    }

    public static void main(String[] args) {


//        try {
//            genKeyPair(KEY_SIZE);
//        } catch (NoSuchAlgorithmException e) {
//            e.printStackTrace();
//        }
        generateKeyBytes(2048).forEach((k, v) -> {
            System.out.println(k);

            System.out.println(Base64.getEncoder().encodeToString(v));
        });


//        String signString = "amount=1400.00&buyerId=76534&buyerName=张三&merId=168038&notifyUrl=https://my.icitywealth"
//        +
//                ".com/PayAnx/Notify&payType=00&seqId=CWH20240418163831087_182288&transDate=20240418&transTime
//                =163831" +
//                "&version=2.0";
//        String priKey =
//                "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKfDHPP9P3QVyjvq3I7Daa3bSWsk4wYbviMWFw0QIwUnBXp37LwDAMp/Ai2WBPwXRRBC8foKRhxDZJ1GRZIZ+yILjbwNfkN6BiEhVe8GH+LfePzlcxJaI3Zz2yOKja7Tni2+8p62bZiK1ntb2OhXT0Dibsd4u5VWauf/+UK4HofZAgMBAAECgYBv/IsDRHZrI3CQdsMseb291Lg50bHKjhJqkYBps+/srJO3oP5isw6AHjByBcbmERKFPGsTInCSxVoQsqwWT0mX57TTp8S6zXDTxTXr6wBDq9vlJJsqOHdCUAUAGnW3/5roEl5JDIltU7/Vek/I4FZHmPsqzCp2kEM6XwntWBmFQQJBANF0C2A6q1IbYDt53ZgP2JFqWJZqDR+Oz5+4X+8nLOk0hokPtmIcYn699n21Y9TorvC5/SZqPX2Fr2sUGNk7bj0CQQDNCzp+Et6q+UgzWX+Zqx4zMFF+Gr8Ity8Pc94tSMQ4Jy4GrzqQdUshP6vf0Q9tjNcvjd26zFpt8Hbak07LcVXNAkEA0WLc7Ho6Qn6zmUGe0SEmM1jI7rVeISo3TUiYPxA+yXOE+wgGH9aYcHOfMtRe1L04Bdcox3p1tkIqtzUEEkZjUQJBAKyBct+Yvo83lN/mvyyow4qrbxRaKjiJ7WThxZ1xp+vaQqXLDMl2dRPu/ooZ2BIBuRTAFTjQLpBqC4SPBG6y1k0CQEfU5tPLGJh+UhxeivUh0EyMaPIKhkGfcgYTpVbAV68UK9JXHRB5ZkNHlUlNwZDcOiBdBTMvtnRwofv17crdmdE=";
//
//        String sign = SignUtil.signSHA1withRSA(priKey, signString);
//        System.out.println(sign);
//
//        String pubKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnwxzz/T90Fco76tyOw2mt20lrJOMGG74jFhcNECMFJwV6d" +
//                "+y8AwDKfwItlgT8F0UQQvH6CkYcQ2SdRkWSGfsiC428DX5DegYhIVXvBh" +
//                "/i33j85XMSWiN2c9sjio2u054tvvKetm2YitZ7W9joV09A4m7HeLuVVmrn//lCuB6H2QIDAQAB";
//
//        System.out.println(SignUtil.verifySignSHA1withRSA(pubKey, signString, sign));

    }

}