AES-256-GCM es el estándar de cifrado simétrico dominante en aplicaciones modernas. Lo que muchos desconocen es que no necesitas ninguna librería externa para usarlo: el propio navegador expone la Web Crypto API, una implementación nativa, auditada y de alto rendimiento.
En este artículo verás cómo funciona el proceso completo — desde contraseña hasta ciphertext — con código JavaScript real y explicaciones de por qué cada parte es necesaria.
¿Qué significa AES-256-GCM?
AES (Advanced Encryption Standard) es el algoritmo de cifrado simétrico más utilizado en el mundo. Simétrico significa que la misma clave sirve para cifrar y para descifrar. Es el algoritmo que protege tus comunicaciones HTTPS, tu disco duro cifrado y la mayoría de aplicaciones bancarias.
El 256 indica la longitud de la clave en bits. A mayor longitud, mayor seguridad. AES-128 es perfectamente seguro para uso general, pero AES-256 es el estándar para datos sensibles y es el que recomiendan agencias como NIST o NSA para información clasificada.
GCM (Galois/Counter Mode) es el modo de operación del cifrado. Es especialmente valioso porque hace dos cosas a la vez:
- Cifrado: convierte el texto en un bloque ilegible sin la clave
- Autenticación: genera un tag de autenticación que detecta cualquier manipulación del ciphertext
Esta combinación se llama cifrado autenticado (AEAD). Si alguien modifica el ciphertext en tránsito, la operación de descifrado fallará con un error en lugar de devolver datos corruptos silenciosamente.
El problema: contraseña ≠ clave
Una contraseña como "mi-contraseña-2026" es texto arbitrario de longitud variable. AES-256 necesita exactamente 256 bits (32 bytes) generados de forma criptográficamente segura. Aquí entra PBKDF2 (Password-Based Key Derivation Function 2).
PBKDF2 toma tu contraseña y un salt aleatorio y aplica SHA-256 miles de veces para producir una clave de longitud exacta. Las iteraciones (100.000 en nuestro ejemplo) hacen que el proceso sea computacionalmente costoso, lo que frena los ataques de fuerza bruta incluso si el atacante tiene el ciphertext.
Implementación completa en JavaScript
1. Derivar la clave con PBKDF2
async function deriveKey(password, salt) {
const enc = new TextEncoder();
const keyMaterial = await crypto.subtle.importKey(
"raw",
enc.encode(password),
"PBKDF2",
false,
["deriveKey"]
);
return crypto.subtle.deriveKey(
{ name: "PBKDF2", salt, iterations: 100_000, hash: "SHA-256" },
keyMaterial,
{ name: "AES-GCM", length: 256 },
false,
["encrypt", "decrypt"]
);
}
2. Cifrar
async function encrypt(plaintext, password) {
const enc = new TextEncoder();
const salt = crypto.getRandomValues(new Uint8Array(16));
const iv = crypto.getRandomValues(new Uint8Array(12));
const key = await deriveKey(password, salt);
const ciphertext = await crypto.subtle.encrypt(
{ name: "AES-GCM", iv },
key,
enc.encode(plaintext)
);
// Empaqueta salt + iv + ciphertext en un solo buffer Base64
const buf = new Uint8Array(28 + ciphertext.byteLength);
buf.set(salt, 0);
buf.set(iv, 16);
buf.set(new Uint8Array(ciphertext), 28);
return btoa(String.fromCharCode(...buf));
}
El resultado es un string Base64 que lleva incluido el salt (16 bytes) y el IV (12 bytes). No hay estado externo que guardar junto al ciphertext.
3. Descifrar
async function decrypt(b64, password) {
const buf = Uint8Array.from(atob(b64), c => c.charCodeAt(0));
const salt = buf.slice(0, 16);
const iv = buf.slice(16, 28);
const data = buf.slice(28);
const key = await deriveKey(password, salt);
const plaintext = await crypto.subtle.decrypt(
{ name: "AES-GCM", iv },
key,
data
);
return new TextDecoder().decode(plaintext);
}
Si la contraseña es incorrecta o el ciphertext ha sido modificado, crypto.subtle.decrypt lanzará un DOMException. Gestiona siempre ese caso con try/catch.
Por qué este patrón es seguro
Salt aleatorio por operación: aunque cifres el mismo texto con la misma contraseña dos veces, el resultado siempre es diferente. Previene ataques de rainbow table y precomputación.
IV fresco en cada cifrado: el IV (vector de inicialización) garantiza que el mismo plaintext más la misma clave nunca produzca el mismo ciphertext. Reutilizar un IV con la misma clave es una vulnerabilidad crítica que rompe la confidencialidad del cifrado.
Authentication tag de GCM: los últimos 16 bytes del ciphertext son el tag de autenticación. Si modificas cualquier bit del ciphertext, del salt o del IV, el descifrado falla con error. Imposible modificar el mensaje sin que el receptor lo detecte.
Errores comunes que debes evitar
No almacenes la clave derivada en localStorage. Si tienes una vulnerabilidad XSS en tu aplicación, la clave queda expuesta a cualquier script malicioso. Siempre deriva la clave desde la contraseña en el momento de usarla y descártala después.
No uses AES-ECB. Es el modo básico de AES sin IV ni autenticación. Patrones repetidos en el plaintext producen patrones repetidos en el ciphertext, filtrando información sobre el contenido. Nunca uses ECB para datos reales.
No trunces el IV. Un IV de 12 bytes es el tamaño estándar para AES-GCM y es el que optimiza el algoritmo de autenticación interno. Usar otro tamaño introduce complejidad sin ningún beneficio.
Web Crypto API: nativa, sin dependencias
Todo el código anterior funciona en cualquier navegador moderno y también en Node.js 18+, Deno y Bun mediante el mismo objeto global crypto.subtle. Sin npm install, sin vulnerabilidades en librerías de terceros, sin actualizaciones que mantener.
Es la misma implementación criptográfica que usa tu sistema operativo, auditada por los equipos de seguridad de los fabricantes de navegadores. No hay razón para usar librerías como crypto-js en proyectos nuevos.
Pruébalo sin escribir código
Si quieres cifrar texto o archivos ahora mismo sin configurar nada, nuestro encriptador online implementa exactamente este algoritmo: AES-256-GCM con PBKDF2, ejecutado íntegramente en tu navegador. Tus datos nunca salen de tu dispositivo.