package cn.gintone.encryptionUtils;


import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Map;

public class SecureHybridDecryptor {
    private static final int GCM_TAG_LENGTH = 128;

    public static String decrypt(String encryptedData, PrivateKey privateKey) throws Exception {
        String[] parts = encryptedData.split(":", 3);
        String encryptedAESKey = parts[0];
        String ivBase64 = parts[1];
        String encryptedText = parts[2];

        // 1. 解密AES密钥
        SecretKey aesKey = decryptAESKey(encryptedAESKey, privateKey);

        // 2. 解密数据
        return decryptWithAES(encryptedText, aesKey, ivBase64);
    }

    public static Object decrypt_Object(String encryptedData, PrivateKey privateKey) throws Exception {
        String[] parts = encryptedData.split(":", 3);
        String encryptedAESKey = parts[0];
        String ivBase64 = parts[1];
        String encryptedText = parts[2];

        // 1. 解密AES密钥
        SecretKey aesKey = decryptAESKey(encryptedAESKey, privateKey);

        // 2. 解密数据
        return decryptWithAES_object(encryptedText, aesKey, ivBase64);
    }

    private static SecretKey decryptAESKey(String encryptedKey, PrivateKey privateKey) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(encryptedKey);
        Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] decryptedKey = cipher.doFinal(keyBytes);
        return new SecretKeySpec(decryptedKey, "AES");
    }

    private static String decryptWithAES(String encryptedData, SecretKey aesKey, String ivBase64) throws Exception {
        byte[] iv = Base64.getDecoder().decode(ivBase64);
        byte[] data = Base64.getDecoder().decode(encryptedData);

        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        GCMParameterSpec spec = new GCMParameterSpec(128, iv);
        cipher.init(Cipher.DECRYPT_MODE, aesKey, spec);

        byte[] decrypted = cipher.doFinal(data);
        return new String(decrypted, StandardCharsets.UTF_8);
    }

    private static Object decryptWithAES_object(String encryptedDataBase64, SecretKey aesKey, String ivBase64) throws Exception {
        // 解码Base64编码的加密数据和IV
        byte[] encryptedData = Base64.getDecoder().decode(encryptedDataBase64);
        byte[] iv = Base64.getDecoder().decode(ivBase64);

        // 使用AES/GCM/NoPadding进行解密
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH, iv);
        cipher.init(Cipher.DECRYPT_MODE, aesKey, spec);

        byte[] decrypted = cipher.doFinal(encryptedData);

        // 将解密后的字节数组反序列化为对象
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decrypted);
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        Object obj = objectInputStream.readObject();
        objectInputStream.close();

        return obj;
    }


    // 解密
    public static PrivateKey loadPrivateKey(String privateKey) throws Exception {
        privateKey = privateKey.replace("-----BEGIN PRIVATE KEY-----", "")
                .replace("-----END PRIVATE KEY-----", "")
                .replaceAll("\\s", "");
        byte[] keyBytes = Base64.getDecoder().decode(privateKey);
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        return kf.generatePrivate(spec);
    }


    // 公钥加密
    public static PublicKey loadPublicKey(String publicKey) throws Exception {
        publicKey = publicKey.replace("-----BEGIN PUBLIC KEY-----", "")
                .replace("-----END PUBLIC KEY-----", "")
                .replaceAll("\\s", ""); // 清理PEM格式
        byte[] keyBytes = Base64.getDecoder().decode(publicKey);
        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        return kf.generatePublic(spec);
    }


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


        String original = "这是一个需要加密的长文本数据，可以超过任意长度限制。";
        for (int i = 0; i < 1000; i ++) {
            original += "这是一个需要加密的长文本数据，可以超过任意长度限制。";
        }

        Map<String, String> keyMap = PemFileGenerator.generateAndSaveKeyPair(1024);
        PublicKey publicKey = loadPublicKey(keyMap.get("publicPem"));
        // 加密
        String encrypted = SecureHybridEncryptor.encrypt_object(original, publicKey);
        System.out.println("加密结果：" + encrypted.substring(0, 100) + "...");

        PrivateKey privateKey = loadPrivateKey(keyMap.get("privatePem"));
        // 解密
        Object decrypted = SecureHybridDecryptor.decrypt_Object(encrypted, privateKey);
        System.out.println("解密结果验证：" + decrypted);
    }
}
