Grover muerde a AES: por qué 128 ha muerto y 256 es tu nueva base
El algoritmo de Grover da un speedup cuadrático sobre la búsqueda de clave por fuerza bruta. AES-128 baja a ~64 bits efectivos. AES-256 se queda en ~128 bits. El arreglo es una línea de config — pero hay que encontrar cada sitio donde vive estado de cifrado.
TL;DR ¶
Un adversario cuántico corriendo el algoritmo de Grover contra un cifrado
simétrico de n bits necesita unas 2^(n/2) operaciones cuánticas para
recuperar la clave. AES-128 cae a ~2⁶⁴ trabajo efectivo — al alcance de
un adversario serio en los 2030s. AES-256 cae a ~2¹²⁸ efectivo — más
allá de cualquier presupuesto proyectado. Mueve cada clave AES-128 a
AES-256 ya. Esta es la actualización PQ más barata que jamás harás.
1. La matemática, comprimida ¶
Grover da un speedup de raíz cuadrada sobre búsqueda no estructurada.
Para un espacio de claves de tamaño 2^n:
- Fuerza bruta clásica:
2^nintentos,~2^npuertas cuánticas. - Cuántico (Grover):
~2^(n/2)iteraciones, cada una costando~O(n)puertas reversibles más una evaluación de oráculo.
Concretamente, para AES:
| Cifrado | Esfuerzo clásico | Esfuerzo Grover | Veredicto |
|---|---|---|---|
| AES-128 | 2¹²⁸ | 2⁶⁴ | Cae en los 2030s |
| AES-192 | 2¹⁹² | 2⁹⁶ | Límite |
| AES-256 | 2²⁵⁶ | 2¹²⁸ | Seguro |
El número 2⁶⁴ es aproximadamente el coste de minar la cadena de Bitcoin dos veces. No trivial — pero predecible, paralelizable, y al alcance de un adversario a nivel estatal hacia finales de los 2020s.
El aviso CNSA 2.0 de la NSA (2022) deja explícitamente AES-128 fuera de las suites aprobadas para "confidencialidad a largo plazo de información de seguridad nacional". El objetivo de migración es AES-256-GCM.
2. Por qué los hashes están mayormente bien ¶
El mismo speedup aplica a preimágenes de hash. El coste de preimagen de SHA-256 baja de 2²⁵⁶ a ~2¹²⁸ bajo Grover — sigue seguro. Los ataques de colisión (cumpleaños) son más duros cuánticamente: Brassard-Høyer-Tapp da raíz cúbica, así que las colisiones de SHA-256 bajan de 2¹²⁸ a ~2⁸⁵.
Ese número de colisión importa para compromisos de larga duración — raíces Merkle en logs append-only, entradas de certificate-transparency, storage deduplicado. Para esos casos, migra a SHA-384 o SHA3-384. SHA-256 está bien para integridad de corta duración (MAC de record TLS, HMAC de tokens de sesión).
3. Migración: cada sitio que escribiste AES-128, séde'lo ¶
La mayoría de equipos tienen AES-128 esparcido en tres sitios:
- Suites de cipher TLS (config del servidor, config del load balancer).
- Cifrado de envelope a nivel de aplicación (llamadas KMS, cifrado de columnas de base de datos, archivos en reposo).
- Cifrado de RPC interno (Wireguard, Tailscale, HMAC + AES custom).
3a. Python (cryptography) ¶
1 # cryptography ≥ 41 2 from cryptography.hazmat.primitives.ciphers.aead import AESGCM 3 import os 4 5 # ANTES: AES-128 — vulnerable a Grover 6 key128 = AESGCM.generate_key(bit_length=128) 7 aead128 = AESGCM(key128) 8 9 # DESPUÉS: AES-256 — seguro frente a Grover 10 key256 = AESGCM.generate_key(bit_length=256) 11 aead256 = AESGCM(key256) 12 13 nonce = os.urandom(12) 14 ct = aead256.encrypt(nonce, b'plaintext', b'associated-data') 15 pt = aead256.decrypt(nonce, ct, b'associated-data')
3b. Node.js ¶
1 const crypto = require('node:crypto'); 2 3 // ANTES: aes-128-gcm 4 function encryptOld(key, plaintext) { 5 const iv = crypto.randomBytes(12); 6 const cipher = crypto.createCipheriv('aes-128-gcm', key, iv); 7 const ct = Buffer.concat([cipher.update(plaintext), cipher.final()]); 8 return { iv, tag: cipher.getAuthTag(), ct }; 9 } 10 11 // DESPUÉS: aes-256-gcm (solo cambian el algoritmo y la longitud de la clave) 12 function encryptNew(key, plaintext) { 13 // key debe ser de 32 bytes 14 const iv = crypto.randomBytes(12); 15 const cipher = crypto.createCipheriv('aes-256-gcm', key, iv); 16 const ct = Buffer.concat([cipher.update(plaintext), cipher.final()]); 17 return { iv, tag: cipher.getAuthTag(), ct }; 18 } 19 20 // Genera una clave fresca de 256 bits 21 const key256 = crypto.randomBytes(32);
3c. PHP (libsodium) ¶
1 <?php 2 // libsodium viene con PHP 7.2+ — incorporado, sin extensión que instalar. 3 // XChaCha20-Poly1305 es un reemplazo casi directo de AES-256-GCM y es la 4 // primitiva simétrica cuántica-segura recomendada en CNSA 2.0. 5 6 // ANTES: openssl AES-128-GCM 7 $key128 = random_bytes(16); 8 $iv = random_bytes(12); 9 $tag = ''; 10 $ct128 = openssl_encrypt('hola', 'aes-128-gcm', $key128, OPENSSL_RAW_DATA, $iv, $tag); 11 12 // DESPUÉS: libsodium XChaCha20-Poly1305 (efectivamente 256 bits, simétrico cuántica-seguro) 13 $key256 = sodium_crypto_aead_xchacha20poly1305_ietf_keygen(); // 32 bytes 14 $nonce = random_bytes(SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES); 15 $ct256 = sodium_crypto_aead_xchacha20poly1305_ietf_encrypt('hola', '', $nonce, $key256);
3d. TLS — Apache / nginx ¶
1 # nginx: quita AES-128, deja solo AEADs AES-256 2 ssl_protocols TLSv1.2 TLSv1.3; 3 ssl_ciphers "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384"; 4 ssl_prefer_server_ciphers off;
1 # Apache mod_ssl 2 SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1 3 SSLCipherSuite TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384 4 SSLHonorCipherOrder off
4. Barrido one-shot por un repo ¶
1 # aes256-migrate.sh — marca cada referencia AES-128 en un árbol. 2 # Conservador: nunca auto-edita, solo lista. Requiere revisión manual. 3 set -eu 4 5 ROOT="${1:-.}" 6 7 echo "=== Referencias AES-128 en $ROOT ===" 8 grep -rnE 'AES[-_]?128[-_]?(GCM|CBC|CTR|ECB)?|aes-128-(gcm|cbc|ctr|ecb)|aes_128' 9 --include='*.{py,js,ts,php,go,rb,java,kt,rs,c,cpp,sh,yaml,yml,conf,nginx,htaccess}' 10 "$ROOT" 2>/dev/null 11 12 echo 13 echo "=== Generadores con bit_length=128 ===" 14 grep -rnE 'bit_lengths*=s*128|key.*=.*16s*[);]|randomBytes(s*16s*)' 15 --include='*.{py,js,ts,php,go,rb,rs}' "$ROOT" 2>/dev/null 16 17 echo 18 echo "=== Configs TLS referenciando suites CBC ===" 19 grep -rnE 'AES.*CBC|CBC-SHA' 20 --include='*.{conf,nginx,htaccess,yaml,yml}' "$ROOT" 2>/dev/null
Hazlo ejecutable y córrelo contra tu repo: chmod +x aes256-migrate.sh && ./aes256-migrate.sh /srv/app. Tría por archivo.
5. Coste de esperar ¶
Un documento cifrado con AES-128 en 2026 será abrible por un adversario a nivel estatal con capacidad cuántica hacia 2032-2034. Si tu política de retención dice "cifrado durante 7 años", la matemática dice que ya llegas tarde.
La migración a AES-256 no rompe ningún protocolo. Sin nuevas dependencias. Sin regresión de rendimiento que valga la pena medir (AES-NI en Intel/AMD hace 256 casi indistinguible de 128 en el throughput que te importa). Esta es la única actualización post-cuántica más barata de toda la pila.
6. Referencias ¶
- Bernstein, Cost analysis of hash collisions: will quantum computers make SHARCS obsolete? (2009)
- Grassl, Langenberg, Roetteler y Steinwandt, Applying Grover's algorithm to AES: quantum resource estimates (2016)
- NSA CNSA 2.0 (2022, actualizado 2024) — exige AES-256-GCM en builds nuevos
- NIST SP 800-131A Rev. 2 — retira AES-128 para casos de uso "de transición"
Migra simétrico primero. No cuesta nada. El trabajo PQ caro (asimétrico, firmas, KEMs) merece tu atención después.
OPS RELACIONADAS
Dentro de la suite PQC de NIST: ML-KEM (FIPS 203), ML-DSA (FIPS 204), SLH-DSA (FIPS 205)
Cuatro años después de nombrar a los finalistas de ronda 3, los estándares están firmados. Aquí está qué hace cada uno, qué parámetro elegir en cada nivel de seguridad, y la llamada mínima en Python y TypeScript.
Q-day: cómo los analistas fijan la ventana entre 2029 y 2034
Los pronósticos convergen en una ventana de cinco años. Comparamos seis estimaciones publicadas lado a lado, mostramos qué asume cada una, y enviamos una calculadora del teorema de Mosca para que derives tu propio plazo de migración.
Cae RSA-2048: el estimado de 20M de qubits ruidosos, redibujado
Gidney y Ekerå dijeron ~20 millones de qubits ruidosos y ~8 horas. Tres años después de mejoras en corrección de errores, el número se mueve — pero no la conclusión. Dónde aterrizan los estimados de 2026.