/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
 */

/*package com.fidufosyga.model;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.spec.KeySpec;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
/**import org.apache.commons.codec.binary.Base64;**/
/*import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.Key;
import java.security.spec.KeySpec;
import java.util.Base64;

public class AESUtilJava {
 
    private static final String IV = "IV_VALUE_16_BYTE"; 
    private static final String PASSWORD = "PASSWORD_VALUE"; 
    private static final String SALT = "SALT_VALUE"; 

    // Clave y IV pre-generados para mejor rendimiento
    private final SecretKey secretKey;
    private final IvParameterSpec ivSpec;

    // Constructor que inicializa clave e IV una sola vez
    public AESUtilJava() throws Exception {
        this.secretKey = generateKey();
        this.ivSpec = new IvParameterSpec(IV.getBytes("UTF-8"));
    }

    // Convierte hexadecimal a Base64
    public String hexToBase64(String hex) {
        try {
            int len = hex.length();
            byte[] bytes = new byte[len / 2];
            for (int i = 0; i < len; i += 2) {
                bytes[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
                        + Character.digit(hex.charAt(i + 1), 16));
            }
            return Base64.getEncoder().encodeToString(bytes);
        } catch (Throwable t) {
            throw new RuntimeException(t);
        }
    }

    // Convierte Base64 a hexadecimal
    public String base64ToHex(String base64) {
        byte[] bytes = Base64.getDecoder().decode(base64);
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            hexString.append(String.format("%02x", b));
        }
        return hexString.toString();
    }

    // Cifra con AES y codifica en Base64
    public String encryptAndEncode(String raw) {
        try {
            Cipher cipher = getCipher(Cipher.ENCRYPT_MODE);
            byte[] encryptedBytes = cipher.doFinal(raw.getBytes("UTF-8"));
            return Base64.getEncoder().encodeToString(encryptedBytes);
        } catch (Throwable t) {
            throw new RuntimeException(t);
        }
    }

    // Decodifica de Base64 y descifra con AES
    public String decodeAndDecrypt(String encrypted) throws Exception {
        byte[] decodedBytes = Base64.getDecoder().decode(encrypted);
        Cipher cipher = getCipher(Cipher.DECRYPT_MODE);
        byte[] decryptedBytes = cipher.doFinal(decodedBytes);
        return new String(decryptedBytes, "UTF-8");
    }

    // Crea el Cipher para cifrar o descifrar
    private Cipher getCipher(int mode) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(mode, secretKey, ivSpec);
        return cipher;
    }

    // Genera la clave AES con PBKDF2 (derivación de clave)
    private SecretKey generateKey() throws Exception {
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        char[] passwordChars = PASSWORD.toCharArray();
        byte[] saltBytes = SALT.getBytes("UTF-8");

        // Mantiene las 65536 iteraciones si querés seguridad fuerte
        KeySpec spec = new PBEKeySpec(passwordChars, saltBytes, 65536, 128);
        SecretKey tmp = factory.generateSecret(spec);
        return new SecretKeySpec(tmp.getEncoded(), "AES");
    }
}*/

package com.fidufosyga.model;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.spec.KeySpec;
import java.util.Base64;

public class AESUtilJava {

    private static final String IV = "IV_VALUE_16_BYTE";  // Cambia esto por el valor real del IV
    private static final String PASSWORD = "PASSWORD_VALUE";  // Cambia esto por la contraseña real
    private static final String SALT = "SALT_VALUE";  // Cambia esto por el valor real de SALT

    private final SecretKey secretKey;
    private final IvParameterSpec ivSpec;
    private final Cipher encryptCipher;
    private final Cipher decryptCipher;

    // Constructor: prepara claves y cifradores una vez
    public AESUtilJava() {
        try {
            this.secretKey = generateKey();
            this.ivSpec = new IvParameterSpec(IV.getBytes(StandardCharsets.UTF_8));

            // Inicializar el Cipher para cifrado y descifrado
            this.encryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            this.encryptCipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);

            this.decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            this.decryptCipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
        } catch (Exception e) {
            throw new RuntimeException("Error inicializando AESUtilJava", e);
        }
    }

    // Cifra texto y lo codifica en Base64
    public String encryptAndEncode(String raw) {
        try {
            byte[] encryptedBytes = encryptCipher.doFinal(raw.getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(encryptedBytes);
        } catch (Exception e) {
            throw new RuntimeException("Error cifrando texto", e);
        }
    }

    // Decodifica Base64 y descifra texto
    public String decodeAndDecrypt(String encrypted) {
        try {
            byte[] decodedBytes = Base64.getDecoder().decode(encrypted);
            byte[] decryptedBytes = decryptCipher.doFinal(decodedBytes);
            return new String(decryptedBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException("Error descifrando texto", e);
        }
    }

    // Método para convertir Hexadecimal a Base64
    public String hexToBase64(String hex) {
        try {
            int len = hex.length();
            byte[] bytes = new byte[len / 2];
            for (int i = 0; i < len; i += 2) {
                bytes[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
                        + Character.digit(hex.charAt(i + 1), 16));
            }
            return Base64.getEncoder().encodeToString(bytes);
        } catch (Throwable t) {
            throw new RuntimeException("Error convirtiendo Hex a Base64", t);
        }
    }

    // Método para convertir Base64 a Hexadecimal
    public String base64ToHex(String base64) {
        try {
            byte[] bytes = Base64.getDecoder().decode(base64);
            char[] hexArray = "0123456789abcdef".toCharArray();
            char[] hexChars = new char[bytes.length * 2];
            for (int j = 0; j < bytes.length; j++) {
                int v = bytes[j] & 0xFF;
                hexChars[j * 2] = hexArray[v >>> 4];
                hexChars[j * 2 + 1] = hexArray[v & 0x0F];
            }
            return new String(hexChars);
        } catch (Throwable t) {
            throw new RuntimeException("Error convirtiendo Base64 a Hex", t);
        }
    }

    // Método privado para generar la clave AES
    private SecretKey generateKey() throws Exception {
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        KeySpec spec = new PBEKeySpec(PASSWORD.toCharArray(), SALT.getBytes(StandardCharsets.UTF_8), 65536, 128);
        SecretKey tmp = factory.generateSecret(spec);
        return new SecretKeySpec(tmp.getEncoded(), "AES");
    }

    // Procesamiento en bloques para evitar el uso excesivo de memoria
    public byte[] processInBlocks(byte[] inputData, int blockSize) {
        byte[] outputData = new byte[0];
        for (int i = 0; i < inputData.length; i += blockSize) {
            int length = Math.min(blockSize, inputData.length - i);
            byte[] block = new byte[length];
            System.arraycopy(inputData, i, block, 0, length);
            // Procesar bloque y agregar a la salida
            byte[] processedBlock = processBlock(block);
            outputData = concatenateArrays(outputData, processedBlock);
        }
        return outputData;
    }

    private byte[] processBlock(byte[] block) {
        try {
            return encryptCipher.doFinal(block);
        } catch (Exception e) {
            throw new RuntimeException("Error procesando bloque de datos", e);
        }
    }

    // Método para concatenar dos arrays de bytes
    private byte[] concatenateArrays(byte[] array1, byte[] array2) {
        byte[] result = new byte[array1.length + array2.length];
        System.arraycopy(array1, 0, result, 0, array1.length);
        System.arraycopy(array2, 0, result, array1.length, array2.length);
        return result;
    }
}


