Encriptar y desencriptar AES-256 | Java

La seguridad en un sistema es muy importante por muy pequeño que sea, es por tal motivo que se requiere de complejos algoritmos que nos ayuden a evitar ataques por fuerza bruta (envío simultáneo de contraseñas con la esperanza de que alguna funcione) o cualquier otro método.

Quizá uno de los más conocidos sea AES - 256 que fue inventado por el gobierno de los Estados Unidos y actualmente no ha podido ser hackeado, este funciona con un método de cifrado donde el receptor como el emisor conoce la llave para descifrarlo, veamos la implementación del cifrado:
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.security.spec.KeySpec;
import java.util.Base64;

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;

public class Encrypt implements Serializable {
    // Asegúrate de añadir la clave de 32 dígitos para encriptar con AES 256
    private static final String secretKeyAES = "alexastudillo32digitosclaveaes25";
    private static final String saltAES = "alex1234";
    
    public Encrypt() {
    }
    
    public String getAES(String data) {
        try {
            byte[] iv = new byte[16];
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
            SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
            KeySpec keySpec = new PBEKeySpec(secretKeyAES.toCharArray(), saltAES.getBytes(), 65536, 256);
            SecretKey secretKeyTemp = secretKeyFactory.generateSecret(keySpec);
            SecretKeySpec secretKey = new SecretKeySpec(secretKeyTemp.getEncoded(), "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
            return Base64.getEncoder().encodeToString(cipher.doFinal(data.getBytes("UTF-8")));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    
    public String getAESDecrypt(String data) {
        byte[] iv = new byte[16];
        try {
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
            SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
            KeySpec keySpec = new PBEKeySpec(secretKeyAES.toCharArray(), saltAES.getBytes(), 65536, 256);
            SecretKey secretKeyTemp = secretKeyFactory.generateSecret(keySpec);
            SecretKeySpec secretKey = new SecretKeySpec(secretKeyTemp.getEncoded(), "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
            return new String(cipher.doFinal(Base64.getDecoder().decode(data)));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
Los dos primeros parámetros son la llave (secretKeyAES) y la sal (saltAES) que deben ser los mismos tanto para encriptar como desencriptar, en este ejemplo usamos los mismos para todo los cifrados pero estos parámetros deben ser generados aleatoriamente de al menos 25 dígitos para cada usuario y no ser el mismo.
Veamos una pequeña explicación de lo que realizamos en las líneas de código:
  • Primero creamos un vector de bytes de tamaño 16 que será nuestro vector de inicialización que es un bloque de bits que es utilizado por varios modos de operación para hacer aleatorio el proceso de encriptación y por lo tanto generar distintos textos cifrados incluso cuando el mismo texto claro es encriptado varias veces, sin la necesidad de regenerar la clave, ya que es un proceso lento.
  • Luego inicializamos una clase IvParameterSpec que simplemente especifica el vector de inicialización a usar.
  • Instanciamos una clase SecretKeyFactory con el nombre del algoritmo que necesitamos; como su nombre nos dice es una fábrica de claves secretas y en este ejemplo la usamos para generar una clave secreta.
  • Inicializamos una PBEKeySpec pasándole como parámetros: la key en un array de caracteres, la sal como un array de bytes, el recuento de iteraciones (65536), y por último la longitud de la clave que se derivará (256).
  • Creamos una SecretKey usando la clase SecretKeyFactory y pasando el cifrado basado en contraseña (PBEKeySpec)
  • Inicializamos una clase SecretKeySpec (especifica una clave secreta de forma independiente del proveedor) pasando como parámetro la clave anterior generada en forma de bytes y el algoritmo que usamos.
  • Finalmente hacemos uso de la clase Cipher del paquete crypto que proporciona la funcionalidad de un cifrado criptográfico para cifrado y descifrado, obtenemos la instancia del algoritmo, después usamos el método init con el modo ya sea descifrado o cifrado, la especificación de la llave secreta y la especificación del vector de inicialización.

Comentarios

  1. Buenas tardes, está genial, ¿ por casualidad sabrá el mismo equivalente pero en C# ?, tengo algunas rutinas que he encontrado, pero ninguna me genera las mismas claves de cifrado como en Java, y en consecuencia no tengo como resultado los mismos textos cifrados. Muchas gracias.

    ResponderEliminar
  2. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  3. La aplicación no abre que puedo hacer

    ResponderEliminar

Publicar un comentario

Entradas populares