package com.zehong.web.controller.api;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;

/**
 * 平台自定义加密算法规则 和示例
 *
 * @Author wangjian
 * @Date 2023/8/15
 * @Version 1.0
 */
public class RsaToClient {

    private String publicKey;
    private String privatekey;

    public RsaToClient(String privateKey, String publicKey) {
        this.privatekey = privateKey;
        this.publicKey = publicKey;
    }

    public RsaToClient() {
    }

    private static final String RSA_ALGORITHM = "RSA";

    /**
     * 生成RSA密钥对
     *
     * @return RSA密钥对
     */
    @Deprecated
    public KeyPair generateKeyPair() throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA_ALGORITHM);
        keyPairGenerator.initialize(2048); // 密钥大小为2048位
        return keyPairGenerator.generateKeyPair();
    }

    /**
     * 使用公钥加密数据
     *
     * @param data      待加密的数据
     * @param publicKey 公钥
     * @return 加密后的数据
     */
    public String encrypt(String data, PublicKey publicKey) throws Exception {
        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encryptedData = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encryptedData);
    }

    /**
     * 公钥字符串 转换为公钥
     *
     * @param publicKeyString
     */
    public  PublicKey generateRSAPublicKey(String publicKeyString) throws NoSuchAlgorithmException, InvalidKeySpecException {
        byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyString);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(keySpec);
        return publicKey;
    }

    /**
     * 对小字符串进行加密 小于245字节的字符串
     *
     * @param data
     */
    public String encrypt(String data, String publicKeyString) throws Exception {
        PublicKey publicKey = generateRSAPublicKey(publicKeyString);
        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encryptedData = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encryptedData);
    }
    public  String encrypt2(byte[] data, String publicKeyString) throws Exception {
        PublicKey publicKey = generateRSAPublicKey(publicKeyString);
        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encryptedData = cipher.doFinal(data);
        return Base64.getEncoder().encodeToString(encryptedData);
    }

    /**
     * 对大字符串进行加密
     */
    public String encryptMaxString(String data, String publicKeyString) throws Exception {
        byte[] bytes = data.getBytes(StandardCharsets.UTF_8);
        Object[] objects = splitByteArr(bytes, 245);
        String codeAll = "";
        //依次加密
        for (int i = 0; i < objects.length; i++) {
            byte[] temp = (byte[]) objects[i];
//            String encryptedData = encrypt(new String(temp, "UTF-8"), publicKeyString);
            String encryptedData = encrypt2(temp, publicKeyString);
            codeAll += "@@" + encryptedData;
        }
        return codeAll;
    }

    /**
     * 使用私钥解密数据
     *
     * @param encryptedData 加密后的数据
     * @param privateKey    私钥
     * @return 解密后的数据
     */
    public String decrypt(String encryptedData, PrivateKey privateKey) throws Exception {
        byte[] decodedData = Base64.getDecoder().decode(encryptedData);
        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] decryptedData = cipher.doFinal(decodedData);
        return new String(decryptedData, StandardCharsets.UTF_8);
    }

    /**
     * 私钥字符串 转换为 私钥对象
     *
     * @param privateKeyString
     */
    public PrivateKey generateRSAPrivateKey(String privateKeyString) throws NoSuchAlgorithmException, InvalidKeySpecException {
        byte[] decode = Base64.getDecoder().decode(privateKeyString);
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(decode);
        return KeyFactory.getInstance("RSA").generatePrivate(pkcs8EncodedKeySpec);
    }

    /**
     * 对加密字符串 进行解密
     *
     * @param encryptedData
     * @param privateKeyString
     */
    public String decrypt(String encryptedData, String privateKeyString) throws Exception {
        PrivateKey privateKey = generateRSAPrivateKey(privateKeyString);
        byte[] decodedData = Base64.getDecoder().decode(encryptedData);
        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] decryptedData = cipher.doFinal(decodedData);
        return new String(decryptedData, StandardCharsets.UTF_8);
    }

    public byte[]  decryptBytes(String encryptedData, String privateKeyString) throws Exception {
        PrivateKey privateKey = generateRSAPrivateKey(privateKeyString);
        byte[] decodedData = Base64.getDecoder().decode(encryptedData);
        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] decryptedData = cipher.doFinal(decodedData);
        return decryptedData;
    }

    /**
     * 对大字符串加密字符串 进行解密
     */
    public String decryptMaxString(String encryptedData, String privateKeyString) throws Exception {
        String decodeAll = "";
        byte[] bytes = new byte[0];
        String[] split = encryptedData.split("@@");
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        for (String s : split) {
            if ("".equals(s) == false) {
                //解密
//                String decryptedData = decrypt(s,privateKeyString);
                byte[] outBytes = decryptBytes(s,privateKeyString);
                out.write(outBytes);
//                decodeAll += decryptedData;
            }
        }
        return  new String(out.toByteArray(), StandardCharsets.UTF_8);
//        return decodeAll;
    }

    public static void main(String[] args) throws Exception {

        ////示例2 现有密钥进行加密 解密
        //企业ID为一  燃气集团 生成 加密 公钥 私钥
        String publicKeyString = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnxZeDNdIm9/HGsm+LuL8NvycGbabVkOr4gJv/LfNkDPItqj2DTGpZgrCKTuPu0G0lTvjIxvoX5yibel3NoPqmohEZ6on3JF4MWt7KocArXaWkcip92Mrk1s32YHHjzo0Db8QJU6Ct2ldCaKshX3RlWrFYDXjOSbMvYA7wc2DZj1Q7q/1kBhSBqTVHc7HWwYYm/OWtBFXLZ6KPvc+snpNEW2iVKoea+t5okz5NzwifJV7+adYQEIPIWerfssQhs6TLQrkMGf1J2IfdMOG1srSIti4Pxla4UGyfqvUxQ+601yGjh/TCeIGSJr8oPj9u6eB2nQ95Ne2CJ/lCWuxd7DzNQIDAQAB";
        String privateKeyString = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCfFl4M10ib38cayb4u4vw2/JwZtptWQ6viAm/8t82QM8i2qPYNMalmCsIpO4+7QbSVO+MjG+hfnKJt6Xc2g+qaiERnqifckXgxa3sqhwCtdpaRyKn3YyuTWzfZgcePOjQNvxAlToK3aV0JoqyFfdGVasVgNeM5Jsy9gDvBzYNmPVDur/WQGFIGpNUdzsdbBhib85a0EVctnoo+9z6yek0RbaJUqh5r63miTPk3PCJ8lXv5p1hAQg8hZ6t+yxCGzpMtCuQwZ/UnYh90w4bWytIi2Lg/GVrhQbJ+q9TFD7rTXIaOH9MJ4gZImvyg+P27p4HadD3k17YIn+UJa7F3sPM1AgMBAAECggEAIsmmWVJ+Wy+M/2ucPe5+zptgmzLWNv/nRy3XRUEAH4djXaYG4A27CEhT+uY+YOlWTsfgvF2u67F5x2UlH3OrSo1/v9dyjgX1bYEeVsdcu5HSDSD/Icy6y6dHyDVb6RMGLPdZ1X6ckPTmVmQPK8W+ndjSPl6qSGYWoV24M4H4ONPYonmQoL7P4DR7jHDbCzqoaBYcrxZT6K52apGKOBqzRrRxlrFPPScvVwaRSXWSYZcN18K9z7yiXwFf1nwBizRGFt6tvchwgYpjxLLON8qcxcLvtcvmrqAqIdIf9HlPOHnkwjgFqNFwXxI48e26gwV2kBJRajrskyusFlbIATv1ZQKBgQDmj27N2Gx08G3dvGQYnTw3rDBbWn7F4ZXe5f6wNAv5kFr/VuIB046u2jQAdWtUmeM5eRd6PeTE4OvX7FuC/o2m/BaKhNWP6No9yzKwuyCNj4dj98G9H5vneOa3RY3F1ma/Bd8hoY6QC/NQDoabp4wFKjYbcD9uHsdLD0S9x405nwKBgQCwpA+HY13A/MVXgTTQ2+A24b+cE5VobOnoJ2ad3NuyYx71CQ4nu9BORSkh6fB2A0DkHY1/wOexi1qILFlwABWZRFKRkwY7+vAJjLlaG5QtvUixWgQ0HvNlWC/e6XfsWJjeKcJmsBlrnfI3uZvxfXveDVlHOfF+e//zKzUTYJzKqwKBgHyDX6K5S7FHmv3R3PjSCZBDZIYhdC9nqamL6iS8pu7rP8l/4WR9HSRe4RCSWRmCVg1W0RAKVv7gPV4J3k37LQLOR1odbLxgU2Rl1YVOOcFZjxO03KNHa8nxKCA35t298RUelacy+avfWFKW1alALcUoS7o7v3W4F4b4wvX+y80fAoGAfmq77mIv++krdseyu/NQkRaZYiMl35lrAcoJB9vDo/SKeEWlyswAdbPLj0j03hDQBTIdTZwKdadNAH30+FInIwyhpyu4335lAgCjuphYQS/hcYQB1Cd+fD5T7E3clNqHdSAf0Awh9UIR0s3UjE0JNE8LYQ1YBvTJpgd7McYIEIcCgYEAsKgI481TPfjrCML0bjZ+d5O8fObFcQup2CzAlXvZtQrM62/Siubwta7IRiZK6yeMbU4uWeZxNBdPIE8Dd5HBFRHiJiD8uB3gdq91YxQYmbu1i37MxueAAlGGpD6Ds5OZZ6+PZZw2SGcUMgY2Y06eqVyxfbdCWuA8sQ4oxyb8DmI=";

        RsaToClient rsa = new RsaToClient(privateKeyString, publicKeyString);
        System.out.println("publickey=" + publicKeyString);
        System.out.println("privateKey=" + privateKeyString);

        //封装员工证书模型
//        WorkCertModel model = new WorkCertModel();
//        model.setApprovalNumber("冀7823478247977");
//        model.setCertProfessionType("特种设备作业人员(市场监督管理总局颁发)");
//        model.setApprovalDate("2004-05-22");
//        model.setAssessGroup("省住建厅");
//        model.setWorkerCode("workcode");
//        model.setCertificateLevel("1");
//        model.setCertSendDate("2004-05-22");
//        model.setCertDateEnd("2004-07-22");
//        model.setCertificateCode("3000550001");
//
////        组装加密数据结构 (这里根据接口参数进行调整组装格式)
//        List<WorkCertModel> list = new ArrayList<>();
//        list.add(model);
//        WorkerCertDirectDTO dd = new WorkerCertDirectDTO();
//        dd.setList(list);
//        String jsonObj = JSONObject.toJSONString(dd);
        String Str = "[{\"codeExtsys\":\"54-130274-100096\",\"eqEightNum\":\"1\",\"eqFiveNum\":\"0\",\"eqFourNum\":\"1\",\"eqNineNum\":\"0\",\"eqOneNum\":\"1\",\"eqSevenNum\":\"0\",\"eqSixNum\":\"1\",\"eqTenNum\":\"0\",\"eqThreeNum\":\"1\",\"eqTwoNum\":\"0\",\"gasType\":\"030100\",\"gcState\":\"100200\",\"gcTypeSecond\":\"130100\",\"lastRefillDate\":\"2022-06-15\",\"name\":\"唐山海港宏声家电维修部\",\"point\":\"118.138649 39.636066\",\"region\":\"130274\",\"sceneModels\":[{\"code\":\"110100\"}],\"startDate\":\"2019-11-04\",\"workplace\":\"海港港欣华府东侧底商\"}]";
//        String Str = "[{\"codeExtsys\":\"54-130274-100193\",\"eqEightNum\":\"1\",\"eqFiveNum\":\"0\",\"eqFourNum\":\"1\",\"eqNineNum\":\"0\",\"eqOneNum\":\"1\",\"eqSevenNum\":\"0\",\"eqSixNum\":\"1\",\"eqTenNum\":\"0\",\"eqThreeNum\":\"1\",\"eqTwoNum\":\"0\",\"gasType\":\"030300\",\"gcState\":\"100200\",\"gcTypeSecond\":\"130100\",\"lastRefillDate\":\"2023-03-14\",\"name\":\"唐山东冶实业有限责任公司\",\"point\":\"118.130318 39.617767\",\"region\":\"130274\",\"sceneModels\":[{\"code\":\"110500\"}],\"startDate\":\"2017-11-18\",\"workplace\":\"乐亭县临港产业聚集区\"}]";
//        String Str = "[{\"codeExtsys\":\"54-130274-100214\",\"eqEightNum\":\"1\",\"eqFiveNum\":\"0\",\"eqFourNum\":\"1\",\"eqNineNum\":\"0\",\"eqOneNum\":\"1\",\"eqSevenNum\":\"0\",\"eqSixNum\":\"1\",\"eqTenNum\":\"0\",\"eqThreeNum\":\"1\",\"eqTwoNum\":\"0\",\"gasType\":\"030300\",\"gcState\":\"100200\",\"gcTypeSecond\":\"130100\",\"lastRefillDate\":\"2022-09-09\",\"name\":\"唐山市荣辉货物运输有限公司\",\"point\":\"118.42598 39.789928\",\"region\":\"130274\",\"sceneModels\":[{\"code\":\"110100\"}],\"startDate\":\"2021-06-13\",\"workplace\":\"唐山海港开发区12号路\"}]";

        Str += Str + Str;
        //加密
        //11130200001 企业ID=1的 企业CODE 这个月header参数是对应的
        String data = "11130281007@" + Str;
        System.out.println("data=" + data);
        System.out.println("数据" + Str);


        //   加密的算法有长度限制 不再采用配合其他加密算法来解决了 直接切断处理加密
        String encryptedData = rsa.encryptMaxString(data, publicKeyString);
        System.out.println("加密后的数据:" + encryptedData);

        //解密
        String decryptedData = rsa.decryptMaxString(encryptedData, privateKeyString);
        System.out.println("解密后的数据:" + decryptedData);

    }

    /**
     * 将byte数组按照指定大小分割成多个数组
     *
     * @param bytes   要分割的byte数组
     * @param subSize 分割的块大小  单位:字节
     * @return 指定大小的byte数组
     */

    public static Object[] splitByteArr(byte[] bytes, int subSize) {
        int count = bytes.length % subSize == 0 ? bytes.length / subSize : bytes.length / subSize + 1;

        List<List<Byte>> subAryList = new ArrayList<List<Byte>>();

        for (int i = 0; i < count; i++) {
            int index = i * subSize;
            List<Byte> list = new ArrayList<Byte>();
            int j = 0;
            while (j < subSize && index < bytes.length) {
                list.add(bytes[index++]);
                j++;
            }
            subAryList.add(list);
        }

        Object[] subAry = new Object[subAryList.size()];

        for (int i = 0; i < subAryList.size(); i++) {
            List<Byte> subList = subAryList.get(i);
            byte[] subAryItem = new byte[subList.size()];
            for (int j = 0; j < subList.size(); j++) {
                subAryItem[j] = subList.get(j);
            }
            subAry[i] = subAryItem;
        }
        return subAry;
    }

}