Criptografía en Java: cifrado y hash – guía completa
La criptografía es la base fundamental de la seguridad en las aplicaciones modernas. Java tiene una infraestructura potente y flexible integrada para trabajar con cifrado y hash: Java Cryptography Architecture (JCA) y Java Cryptography Extension (JCE). Estas bibliotecas permiten implementar tanto cifrado simétrico (AES) como asimétrico (RSA), así como hash criptográfico (SHA-256). En este artículo analizaremos los conceptos clave y escribiremos ejemplos funcionales en Java puro (sin dependencias externas).
Conceptos básicos y arquitectura JCA/JCE
JCA proporciona un marco para trabajar con operaciones criptográficas. La idea clave son los proveedores (providers), que implementan algoritmos específicos. Por defecto, el JDK incluye el proveedor SUN (para hashes) y SunJCE (para cifrado). Las clases principales se encuentran en los paquetes javax.crypto y java.security.
- Cipher — clase principal para cifrado y descifrado.
- KeyGenerator — generación de claves simétricas.
- KeyPairGenerator — generación de pares de claves para cifrado asimétrico.
- MessageDigest — cálculo de resúmenes hash.
- SecretKeySpec — representación de una clave simétrica a partir de un arreglo de bytes.
Cifrado simétrico: AES
AES (Advanced Encryption Standard) es el algoritmo simétrico más popular. Utiliza la misma clave para cifrar y descifrar. El modo recomendado es GCM (cifrado autenticado) o CBC con PKCS5Padding. A continuación, un ejemplo de cifrado de una cadena usando AES-256/GCM.
import javax.crypto.Cipher;import javax.crypto.KeyGenerator;import javax.crypto.SecretKey;import javax.crypto.spec.GCMParameterSpec;import java.security.SecureRandom;import java.util.Base64;
public class AESGCMExample { private static final int AES_KEY_SIZE = 256; private static final int GCM_IV_LENGTH = 12; private static final int GCM_TAG_LENGTH = 128;
public static SecretKey generateKey() throws Exception { KeyGenerator keyGen = KeyGenerator.getInstance("AES"); keyGen.init(AES_KEY_SIZE, SecureRandom.getInstanceStrong()); return keyGen.generateKey(); }
public static String encrypt(String plaintext, SecretKey key) throws Exception { byte[] iv = new byte[GCM_IV_LENGTH]; SecureRandom.getInstanceStrong().nextBytes(iv); Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH, iv); cipher.init(Cipher.ENCRYPT_MODE, key, spec); byte[] cipherText = cipher.doFinal(plaintext.getBytes()); byte[] encrypted = new byte[iv.length + cipherText.length]; System.arraycopy(iv, 0, encrypted, 0, iv.length); System.arraycopy(cipherText, 0, encrypted, iv.length, cipherText.length); return Base64.getEncoder().encodeToString(encrypted); }
public static String decrypt(String encryptedData, SecretKey key) throws Exception { byte[] decoded = Base64.getDecoder().decode(encryptedData); byte[] iv = new byte[GCM_IV_LENGTH]; System.arraycopy(decoded, 0, iv, 0, iv.length); byte[] cipherText = new byte[decoded.length - iv.length]; System.arraycopy(decoded, iv.length, cipherText, 0, cipherText.length); Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH, iv); cipher.init(Cipher.DECRYPT_MODE, key, spec); return new String(cipher.doFinal(cipherText)); }
public static void main(String[] args) throws Exception { SecretKey key = generateKey()