package com.rf.psychological.security;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;

/**
 * @Description:RSA加密工具
 * @Author: zsf
 * @Date: 2022/10/30
 */
@Slf4j
public class RSAUtils {


    /**
     * 加密算法
     */
    private final static String ALGORITHM_RSA = "RSA";

    private final static String publicKeyStr = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCEgTUtj3dn6YK8MGyIbqp9kSMpC0N8TgXjNp4+NAy7U2ifW8Aislg0BNR+sBkVls/7zS8FCwoNmjR4l/fUSqjA+yxSqlfWaXaNR2MARHCRNQm40dT923dE7QUhi7zSvwT5gaYUi0HB2IKpKVi9hgFKs0YwfKqZC2L2VRh1+3t8owIDAQAB";

    public final static String privateKeyStr = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAISBNS2Pd2fpgrwwbIhuqn2RIykLQ3xOBeM2nj40DLtTaJ9bwCKyWDQE1H6wGRWWz/vNLwULCg2aNHiX99RKqMD7LFKqV9Zpdo1HYwBEcJE1CbjR1P3bd0TtBSGLvNK/BPmBphSLQcHYgqkpWL2GAUqzRjB8qpkLYvZVGHX7e3yjAgMBAAECgYB6dMrHk1of329iKkJziArqRvK+oNk6jQTl6nkuNX46tSfwdqPHrRjU4k3b0zUrfZgzNnoo5/3fek7Z0GBKgsEXWu5xp1hDjWgUUjzpzhRtpZaxzQ7AXZ9kWJSkFTfXiJX6DRGExLKTqcZbDN36bgVCX259jT5ic4lrm0ZmEU+gaQJBAMZPxgbux1Z69W0H9XH5KqLrXJWDvg6nCPH3yzNTvUcB5cCv78+JyGs6VzYixLY0UD6fk/qOR4Nir6cgl4PevGcCQQCrDM7A7iADFEUa42VuMeFzNQW4R9fMx9cUlwueEkoEkc+aE9QWIqFEw9nha6EBeXcOe6e9YdqGIRIVYAFukphlAkAaIQqrgSyclWje68yILtdSTgaN4KTbE2EXWJnacm8e+v4FrGjBhJr2neI9zMj0ZOIpzibWPYbopckVETNFecSDAkAOj6GOJPdOq8wSNOdukQp7LzlUbbE+OojhtNYFV9M7Plpo6GU2mS4XV4DVwr7LDFcJQZeO9KSQpIIQlcKpcgtNAkAih8OTRXaXmzU+SBEf2/xcMtVhIKKAomkIppMeNkXX+99yH8Kb9qOOgSKSUUxPhig4m1Zgc8wUYFHuUVbAi8p1";



    public final static String publicKeyStrLX = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCkvzVXZo0OnvWDiBLUDEDeUwy9tGM30K8/QKymHrnUkfDE/T0f5G4SK6MTWU0HKun45vA0/Xeh5eAbyewVcnR8WZFSmrlV6YTe55z10L584etmiaqRHpGFJVR85ryI3Hj8LvnjAJpQoVKIzOjhfMAwmGW/oOUwYAV7y2paeV1XSwIDAQAB";

    private final static String privateKeyStrLX = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAKS/NVdmjQ6e9YOIEtQMQN5TDL20YzfQrz9ArKYeudSR8MT9PR/kbhIroxNZTQcq6fjm8DT9d6Hl4BvJ7BVydHxZkVKauVXphN7nnPXQvnzh62aJqpEekYUlVHzmvIjcePwu+eMAmlChUojM6OF8wDCYZb+g5TBgBXvLalp5XVdLAgMBAAECgYAJgyDJUxqB5Zu3ZHvx0mNMcu8hZPD1oA7+T/WoAc4o/+Qu+5Az7zSLyAk6bMWNzGSGAo+L/7aQmn0+HYKMGnevPi3dDnVewjGaPpsw9Y5iwoAENSGeT5RjrJl/WgPntZzfveR2W4KYeYpoqmjvTOakz5ELv0tLU8IPnG4TB4ewgQJBAPpkitf9EECzuTuR23bvNv5z9C0NcjP5sqYm/4WzmioZs+V6fc/e9sa5iQf5Z8Dy4+3GxydyMHRO7TTqWsBIPYkCQQCob6xoL73XVoeer6pENHX/bCsc5WmGSJVFdTSd+R7DYaBR33IugKEEE7VLl65hA9j3FDFHuKP59jGZXNsU6C0zAkBWySBiimDmvCQ4pG5Xw8Pg39nC/8UUhLhJ5HxuH/kQHIaAxDr1IIeSC16Wd/hhJQ6hLGN8pZRry6tlytCXkrJZAkBCo9Q5cFISxXhozyV1ULAyu1AfYaCrcUIlteZ4bdy+/nwYiGg7f8a0vztmSf/DAGux7bpFnwa5Wa9r9vHyxp1DAkApEIotMOKXrCGY3btAxj9GmEuhV3fxzeVTnEooPhCu7wRbWXJhMwdrG9QgX2t7PZRiS8f4gCdgtsbdA8XRozfS";

    public static List<String> getRSAKeyString(int modulus) throws NoSuchAlgorithmException {
        List<String> keyList = new ArrayList<>(2);
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM_RSA);
        keyPairGenerator.initialize(modulus);

        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        String publicKey = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
        String privateKey = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
        log.info(publicKey);
        log.info(privateKey);
        keyList.add(publicKey);
        keyList.add(privateKey);



        return keyList;
    }


    public static RSAPublicKey   getPublicKey(String publicKey) throws Exception{
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA);
        byte[] keyBytes = Base64.getDecoder().decode(publicKey);
        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        return (RSAPublicKey) keyFactory.generatePublic(spec);
    }

    public static RSAPrivateCrtKey getPrivateKey(String privateKey) throws Exception{
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA);
        byte[] keyBytes = Base64.getDecoder().decode(privateKey);
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
        return (RSAPrivateCrtKey) keyFactory.generatePrivate(spec);
    }


//    /**
//     * 公钥加密
//     *
//     * @param data
//     * @param publicKey
//     * @return
//     * @throws Exception
//     */
/*    public static String encryptByPublicKey(String data, RSAPublicKey publicKey)
            throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM_RSA);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        // 模长n转换成字节数
        int modulusSize = publicKey.getModulus().bitLength() / 8;
        // PKCS Padding长度为11字节，所以实际要加密的数据不能要 - 11byte
        int maxSingleSize = modulusSize - 11;
        // 切分字节数组，每段不大于maxSingleSize
        byte[][] dataArray = splitArray(data.getBytes(), maxSingleSize);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        // 分组加密，并将加密后的内容写入输出字节流
        for (byte[] s : dataArray) {
            out.write(cipher.doFinal(s));
        }
        // 使用Base64将字节数组转换String类型
        return Base64.getEncoder().encodeToString(out.toByteArray());
    }*/

/*    public static String encryptByPublicKey2(String data)
            throws Exception {
        RSAPublicKey publicKey = RSAUtils.getPublicKey(publicKeyStr);
        Cipher cipher = Cipher.getInstance(ALGORITHM_RSA);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        // 模长n转换成字节数
        int modulusSize = publicKey.getModulus().bitLength() / 8;
        // PKCS Padding长度为11字节，所以实际要加密的数据不能要 - 11byte
        int maxSingleSize = modulusSize - 11;
        // 切分字节数组，每段不大于maxSingleSize
        byte[][] dataArray = splitArray(data.getBytes(), maxSingleSize);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        // 分组加密，并将加密后的内容写入输出字节流
        for (byte[] s : dataArray) {
            out.write(cipher.doFinal(s));
        }
        // 使用Base64将字节数组转换String类型
        return Base64.getEncoder().encodeToString(out.toByteArray());
    }*/

    public static String encryptByPublicKey3(String data,String publicKeyStr)
            throws Exception {
        RSAPublicKey publicKey = RSAUtils.getPublicKey(publicKeyStr);
        Cipher cipher = Cipher.getInstance(ALGORITHM_RSA);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        // 模长n转换成字节数
        int modulusSize = publicKey.getModulus().bitLength() / 8;
        // PKCS Padding长度为11字节，所以实际要加密的数据不能要 - 11byte
        int maxSingleSize = modulusSize - 11;
        // 切分字节数组，每段不大于maxSingleSize
        byte[][] dataArray = splitArray(data.getBytes(), maxSingleSize);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        // 分组加密，并将加密后的内容写入输出字节流
        for (byte[] s : dataArray) {
            out.write(cipher.doFinal(s));
        }
        // 使用Base64将字节数组转换String类型
        return Base64.getEncoder().encodeToString(out.toByteArray());
    }

//    /**
//     * 私钥解密
//     *
//     * @param data
//     * @param privateKey
//     * @return
//     * @throws Exception
//     */
    /*public static String decryptByPrivateKey(String data, RSAPrivateKey privateKey)
            throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM_RSA);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        // RSA加密算法的模长 n
        int modulusSize = privateKey.getModulus().bitLength() / 8;
        byte[] dataBytes = data.getBytes();
        // 之前加密的时候做了转码，此处需要使用Base64进行解码
        byte[] decodeData = Base64.getDecoder().decode(dataBytes);
        // 切分字节数组，每段不大于modulusSize
        byte[][] splitArrays = splitArray(decodeData, modulusSize);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        for(byte[] arr : splitArrays){
            out.write(cipher.doFinal(arr));
        }
        return new String(out.toByteArray());
    }*/

    /*public static String decryptByPrivateKey2(String data)
            throws Exception {
        RSAPrivateCrtKey privateKey = RSAUtils.getPrivateKey(privateKeyStr);

        Cipher cipher = Cipher.getInstance(ALGORITHM_RSA);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        // RSA加密算法的模长 n
        int modulusSize = privateKey.getModulus().bitLength() / 8;
        byte[] dataBytes = data.getBytes();
        // 之前加密的时候做了转码，此处需要使用Base64进行解码
        byte[] decodeData = Base64.getDecoder().decode(dataBytes);
        // 切分字节数组，每段不大于modulusSize
        byte[][] splitArrays = splitArray(decodeData, modulusSize);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        for(byte[] arr : splitArrays){
            out.write(cipher.doFinal(arr));
        }
        return new String(out.toByteArray());
    }*/

    public static String decryptByPrivateKey3(String data,String privateKeyStr)
            throws Exception {
        RSAPrivateCrtKey privateKey = RSAUtils.getPrivateKey(privateKeyStr);

        Cipher cipher = Cipher.getInstance(ALGORITHM_RSA);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        // RSA加密算法的模长 n
        int modulusSize = privateKey.getModulus().bitLength() / 8;
        byte[] dataBytes = data.getBytes();
        // 之前加密的时候做了转码，此处需要使用Base64进行解码
        byte[] decodeData = Base64.getDecoder().decode(dataBytes);
        // 切分字节数组，每段不大于modulusSize
        byte[][] splitArrays = splitArray(decodeData, modulusSize);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        for(byte[] arr : splitArrays){
            out.write(cipher.doFinal(arr));
        }
        return new String(out.toByteArray());
    }



    /**
     * 按指定长度切分数组
     *
     * @param data
     * @param len 单个字节数组长度
     * @return
     */
    private static byte[][] splitArray(byte[] data,int len){

        int dataLen = data.length;
        if (dataLen <= len) {
            return new byte[][]{data};
        }
        byte[][] result = new byte[(dataLen-1)/len + 1][];
        int resultLen = result.length;
        for (int i = 0; i < resultLen; i++) {
            if (i == resultLen - 1) {
                int slen = dataLen - len * i;
                byte[] single = new byte[slen];
                System.arraycopy(data, len * i, single, 0, slen);
                result[i] = single;
                break;
            }
            byte[] single = new byte[len];
            System.arraycopy(data, len * i, single, 0, len);
            result[i] = single;
        }
        return result;
    }

    public static void main(String[] args) throws Exception {
        // 使用字符串生成公钥、私钥完成加解密
        List<String> keyStringList = RSAUtils.getRSAKeyString(1024);
        String pukString = keyStringList.get(0);
        String prkString = keyStringList.get(1);
        System.out.println("公钥:" + pukString);
        System.out.println("私钥:" + prkString);
        /*JSONObject jsonObject = new JSONObject();
        jsonObject.put("userName","lingxi");
        jsonObject.put("institutionNo","10031");
        jsonObject.put("password","e10adc3949ba59abbe56e057f20f883e");
        String  message = jsonObject.toString();*/
        // 生成公钥、私钥
        /*RSAPublicKey puk = RSAUtils.getPublicKey(publicKeyStr);
        RSAPrivateCrtKey prk = RSAUtils.getPrivateKey(privateKeyStr);
        String encryptedMsg = "TVMh35d2egfeAMgLUYoK6oQlW0DRTo6O6H+RmwBrr2uigE5rFnYC4J1gtAgACgyDqh7oIhvkfRUaj77+wXBHAa1lQ9dVtc5/EGO7/VhqgHn9b4DsCdv40wLfXbwg85O+j48QeUtm5dFat7Nn4zduCsvrNUNI8RQJlzD2z4kIH2Eo/n6jtBAHJSnTc7Q3YyaEAFozwaZSOpKbu/HkX8Q2woI+8U78JDcTxOy2teblbEAu2QewIswKsbXpCyyxu1HQLjyNm0lVSdVahvaCg9x2cJ1FL01p0fTURHEoFuMxWPWhO8QKolxX3zeZuromzC2MzcGvhKg20O6X3JWCb2kzglaNkMlH5AoAhTfoe55V5Ita4rZ3KC2U6AfDYjMz2tTTBzdkfxet7KnD3Yx/6nnwbhHb32rfn7/eT+uEmdO36cB9TH4PAY2zXYdzlhwA5KuT5TR2DxlvOiDH7Hk6NhRNwnWBqX5cdSFy7YWyPVsRllIlqmj7v8xYLHxqciNNK0/R";//RSAUtils.encryptByPublicKey2(message);

        String decryptedMsg = RSAUtils.decryptByPrivateKey2(encryptedMsg);
        log.info(decryptedMsg);*/
        /*System.out.println("string key ! message ==  decryptedMsg ? " + message.equals(decryptedMsg));
        String enMsg = RSAUtils.encryptByPublicKey3(message,RSAUtils.publicKeyStr);
        log.info(enMsg);
        String encStr = RSAUtils.decryptByPrivateKey3("Qew9gDqXjtuzaLqemYDpr24k3B5YzWMXgaVwyfq7r9i4LFAuXcf73OfuEzuWOc0f0TwhLg1y/IfY1zStShtHsdmbbpplEUtQaLHFAcmwwhnjd78DTloRIWt5kGYPNE9jbFE+D4gLOqHId0lGEOeqNuhkgKSZBNJksFmQZibfXLowPXxVtE9Iv3uLMHUYoy/w/8t3Ry00+dcmvCI1658GlEMhkw6UItGvENtcxCp/MsxmwQrzifAlXp33WDhcdyf8TyznEQ8LZryRESy1Do8OgGl/3jE33Wg657CNBXHHyqdNyRmG2He5/DMgRxTU9Vhi0TtNwjbcY8ZKJnX8DtzVOxnL6nBbAN9bVkcqGzlLX6JH1cL7swquJqx5nqr1UexXrbcXo0LMAgGDl/zrMxtM4K+BGZSkhO1/NtfcSHBaL6srSZ+NezOa1BXjzvbDEJBjtzn/1kGfD9Zql1YXnYV7kB23/fVTCRTs14EPGeftHd/H1R/eICdyHM3frg9vDkc7",RSAUtils.privateKeyStrLX);
log.info(encStr);*/
    }


}
