FIPS 203, FIPS 204 y FIPS 205 son los tres estándares de criptografía post-cuántica que NIST aprobó el 13 de agosto de 2024. FIPS 203 define ML-KEM, un mecanismo para acordar una clave secreta; FIPS 204 y FIPS 205 definen ML-DSA y SLH-DSA, dos esquemas de firma digital. Aquí tienes para qué sirve cada uno, qué significan sus conjuntos de parámetros, cuánto ocupan sus claves y firmas y qué calendario propone NIST para retirar RSA y las curvas elípticas. Después lo pruebo todo con OpenSSL 3.5.9 en Docker: claves, firmas, encapsulado, un handshake TLS 1.3 híbrido y OpenSSH. Tienes también la versión en inglés de esta guía.

Puntos clave

  • FIPS 203 (ML-KEM, antes CRYSTALS-Kyber) sustituye al intercambio de claves con RSA o ECDH; FIPS 204 (ML-DSA, antes Dilithium) y FIPS 205 (SLH-DSA, antes SPHINCS+) sustituyen a las firmas RSA, ECDSA y EdDSA.
  • Cada estándar tiene conjuntos de parámetros ligados a categorías de seguridad de NIST: la 1 equivale a romper AES-128, la 3 a AES-192 y la 5 a AES-256.
  • Los tamaños crecen mucho: una clave pública ML-KEM-768 ocupa 1184 bytes frente a 32 de X25519, y una firma SLH-DSA va de 7856 a 49 856 bytes.
  • El borrador NIST IR 8547 propone declarar obsoletos RSA y ECC de 112 bits después de 2030 y prohibir todo RSA y ECC después de 2035.
  • OpenSSL 3.5 trae los tres algoritmos y ofrece por defecto el grupo híbrido X25519MLKEM768 en TLS 1.3; en mi prueba el ClientHello pasó de 281 a 1515 bytes.
  • A 30 de septiembre de 2026, FN-DSA (FIPS 206) y HQC siguen sin borrador publicado en la página del proyecto PQC de NIST.

Qué son FIPS 203, 204 y 205 y qué sustituye cada uno

Los tres estándares cubren las dos operaciones de clave pública que un ordenador cuántico grande rompería: acordar un secreto y firmar. El algoritmo de Shor factoriza enteros y resuelve logaritmos discretos en tiempo polinómico, y eso tumba RSA, Diffie-Hellman y las curvas elípticas. Los algoritmos nuevos se basan en problemas para los que no se conoce ataque cuántico eficiente. El contexto histórico del concurso está en el artículo sobre los estándares NIST PQC.

La distinción que más confunde es la de KEM frente a firma. Un mecanismo de encapsulado de claves (KEM) permite que dos partes compartan un secreto de 32 bytes. Una publica su clave de encapsulado; la otra genera el secreto y lo envía dentro de un texto cifrado que solo la clave de decapsulado abre. Una firma digital hace otra cosa: demuestra quién emitió un mensaje y que nadie lo alteró.

Estándar Algoritmo Basado en Función Sustituye a
FIPS 203 ML-KEM CRYSTALS-Kyber Encapsulado de claves RSA-KEM, DH, ECDH
FIPS 204 ML-DSA CRYSTALS-Dilithium Firma digital RSA, ECDSA, EdDSA
FIPS 205 SLH-DSA SPHINCS+ Firma digital (hash) RSA, ECDSA, EdDSA
FIPS 206 (borrador pendiente) FN-DSA Falcon Firma digital RSA, ECDSA, EdDSA

ML-KEM y ML-DSA se apoyan en retículos modulares (el problema module learning with errors). SLH-DSA solo depende de la seguridad de una función hash, y por eso NIST lo mantiene como alternativa si un día se rompen los retículos.

Qué significan las categorías de seguridad 1, 2, 3 y 5

NIST no describe la seguridad post-cuántica con un número de bits, sino con cinco categorías definidas por un ataque de referencia. El borrador NIST IR 8547 las resume así:

Categoría Ataque de referencia Ejemplo
1 Búsqueda de clave en un cifrado de bloque de 128 bits AES-128
2 Búsqueda de colisiones en un hash de 256 bits SHA-256
3 Búsqueda de clave en un cifrado de bloque de 192 bits AES-192
4 Búsqueda de colisiones en un hash de 384 bits SHA3-384
5 Búsqueda de clave en un cifrado de bloque de 256 bits AES-256

Un parámetro de categoría 3 promete que romperlo cuesta al menos tanto como buscar por fuerza bruta una clave AES-192, con cualquier modelo de computación realista. El sufijo de cada nombre sigue esta lógica: ML-KEM-512 es categoría 1, ML-KEM-768 categoría 3 y ML-KEM-1024 categoría 5.

ML-KEM (FIPS 203): parámetros y tamaños

ML-KEM tiene tres conjuntos de parámetros, y los tres producen el mismo secreto compartido de 32 bytes. Lo que cambia es el tamaño de la clave y del texto cifrado que viaja por la red, según la tabla 3 de FIPS 203:

Parámetros Categoría Clave de encapsulado Clave de decapsulado Texto cifrado
ML-KEM-512 1 800 bytes 1632 bytes 768 bytes
ML-KEM-768 3 1184 bytes 2400 bytes 1088 bytes
ML-KEM-1024 5 1568 bytes 3168 bytes 1568 bytes

ML-KEM-768 es el que usan TLS y OpenSSH en sus grupos híbridos. FIPS 203 da un criterio general para elegir: "When initially establishing cryptographic protections for data, the strongest possible parameter set should be used". El mismo párrafo matiza que algunos parámetros pueden penalizar el rendimiento, así que la elección real mezcla seguridad y ancho de banda.

Un detalle que conviene conocer antes de programar con ML-KEM es el rechazo implícito. Si el texto cifrado llega alterado, la decapsulación no devuelve un error: devuelve un secreto distinto, calculado a partir del texto cifrado y de un valor aleatorio z guardado en la clave privada. El fallo aparece después, cuando las dos partes no consiguen descifrar nada con claves diferentes. Lo compruebo en la parte práctica.

ML-DSA (FIPS 204): parámetros y tamaños

ML-DSA es la firma de uso general de la familia: claves y firmas de pocos kilobytes y una implementación que NIST describe como sencilla. El nombre de cada conjunto indica las dimensiones de la matriz interna, no los bits de seguridad, y por eso ML-DSA-44 es categoría 2 y no categoría 1:

Parámetros Categoría Clave privada Clave pública Firma
ML-DSA-44 2 2560 bytes 1312 bytes 2420 bytes
ML-DSA-65 3 4032 bytes 1952 bytes 3309 bytes
ML-DSA-87 5 4896 bytes 2592 bytes 4627 bytes

Como comparación, en el mismo contenedor una firma Ed25519 ocupó 64 bytes y su clave pública 32. Una cadena de certificados X.509 con ML-DSA multiplica ese peso en cada handshake. FIPS 204 también permite guardar solo una semilla de 32 bytes como clave privada y regenerar el resto al firmar.

SLH-DSA (FIPS 205): firmas grandes con supuestos mínimos

SLH-DSA cambia tamaño de firma por confianza en los supuestos: su seguridad depende solo de SHA-2 o SHAKE. Sus claves públicas son diminutas (32, 48 o 64 bytes) y sus firmas, enormes. FIPS 205 define 12 conjuntos, combinando tres niveles, dos familias de hash (SHA2 y SHAKE) y dos variantes: s, de firma pequeña, y f, de firma rápida.

Parámetros Categoría Clave pública Firma
SLH-DSA-*-128s 1 32 bytes 7856 bytes
SLH-DSA-*-128f 1 32 bytes 17 088 bytes
SLH-DSA-*-192s 3 48 bytes 16 224 bytes
SLH-DSA-*-192f 3 48 bytes 35 664 bytes
SLH-DSA-*-256s 5 64 bytes 29 792 bytes
SLH-DSA-*-256f 5 64 bytes 49 856 bytes

El asterisco vale SHA2 o SHAKE, con los mismos tamaños. Cada clave admite hasta 264 firmas; la nota de FIPS 205 calcula que a 10 000 millones de firmas por segundo harían falta más de 58 años para agotarla. SLH-DSA encaja en firmas de firmware, raíces de confianza o documentos de larga vida, donde se firma poco y se verifica durante décadas. En abril de 2026 NIST publicó el borrador SP 800-230 con conjuntos extra de SLH-DSA para usos que firman un número limitado de mensajes.

Qué falta por llegar: FN-DSA (FIPS 206), HQC y más firmas

La familia no está cerrada, y a 30 de septiembre de 2026 hay tres piezas en camino:

  • FN-DSA (FIPS 206): la firma basada en Falcon, con firmas más cortas y verificación rápida, pero una implementación más delicada. La presentación de NIST en el taller MPTS 2026 la describe como "Under development (hopefully soon)" y la página de noticias del proyecto PQC no lista todavía un borrador publicado
  • HQC: un segundo KEM basado en códigos correctores, no en retículos, elegido el 11 de marzo de 2025 (NIST IR 8545) como respaldo de ML-KEM. Su borrador de estándar figura como "underway" en la misma presentación
  • Firmas adicionales: el 14 de mayo de 2026, NIST IR 8610 pasó nueve candidatos a la tercera ronda del proceso de firmas adicionales, buscando esquemas que no dependan de retículos estructurados

Nada de esto cambia lo que puedes desplegar hoy. ML-KEM, ML-DSA y SLH-DSA son estándares finales, tienen validación FIPS 140 en marcha y ya están en OpenSSL y OpenSSH.

Cuándo dejan de valer RSA y ECC según NIST IR 8547

NIST IR 8547, publicado como borrador en noviembre de 2024, propone el calendario para retirar los algoritmos vulnerables. Hoy sigue siendo un borrador (la página de CSRC lo lista como Initial Public Draft), así que las fechas pueden moverse, pero es el único calendario oficial de NIST sobre la mesa:

Algoritmos Seguridad Propuesta
RSA, ECDSA, EdDSA (firmas) 112 bits Obsoletos después de 2030, prohibidos después de 2035
RSA, ECDSA, EdDSA (firmas) 128 bits o más Prohibidos después de 2035
DH, ECDH, MQV, RSA (claves) 112 bits Obsoletos después de 2030, prohibidos después de 2035
DH, ECDH, MQV, RSA (claves) 128 bits o más Prohibidos después de 2035

Según la tabla 2 de SP 800-57, RSA de 2048 bits y las curvas de 224 a 255 bits dan 112 bits de seguridad; RSA de 3072 bits y P-256 dan 128. El objetivo de 2035 viene del memorando de seguridad nacional NSM-10 de Estados Unidos. Los algoritmos simétricos aprobados con al menos 128 bits, como AES-128 o SHA-256, siguen valiendo. Cómo priorizar la migración está en el artículo sobre qué hacer con los estándares finales de NIST.

Práctica: ML-KEM, ML-DSA y SLH-DSA con OpenSSL 3.5 en Docker

OpenSSL 3.5 fue la primera versión con los tres algoritmos, y es la versión de soporte largo hasta el 8 de abril de 2030. Probé todo el 30 de septiembre de 2026 en un contenedor Alpine 3.23.6 sobre Linux arm64, con OpenSSL 3.5.9 (publicada el 29 de septiembre) y OpenSSH 10.2p1.

Preparar el contenedor y listar los algoritmos

Arranca un contenedor Alpine, instala OpenSSL y OpenSSH y comprueba la versión. Luego lista los KEM disponibles:

docker run --rm -it mirror.gcr.io/library/alpine:3.23 sh
apk add --no-cache openssl openssh
openssl version
openssl list -kem-algorithms | grep -i mlkem

La salida confirma la versión y muestra los tres ML-KEM puros y cuatro grupos híbridos:

OpenSSL 3.5.9 29 Sep 2026 (Library: OpenSSL 3.5.9 29 Sep 2026)
  { 2.16.840.1.101.3.4.4.1, id-alg-ml-kem-512, ML-KEM-512, MLKEM512 } @ default
  { 2.16.840.1.101.3.4.4.2, id-alg-ml-kem-768, ML-KEM-768, MLKEM768 } @ default
  { 2.16.840.1.101.3.4.4.3, id-alg-ml-kem-1024, ML-KEM-1024, MLKEM1024 } @ default
  X25519MLKEM768 @ default
  X448MLKEM1024 @ default
  SecP256r1MLKEM768 @ default
  SecP384r1MLKEM1024 @ default

openssl list -signature-algorithms muestra de la misma forma los tres ML-DSA y los doce SLH-DSA, todos en el proveedor default.

Encapsular y decapsular un secreto con ML-KEM

El flujo de un KEM son cuatro pasos: generar la clave, publicar la parte pública, encapsular con ella y decapsular con la privada. Con openssl pkeyutl queda así:

openssl genpkey -algorithm ML-KEM-768 -out kem.key
openssl pkey -in kem.key -pubout -out kem.pub
openssl pkeyutl -encap -pubin -inkey kem.pub \
  -out kem.ct -secret emisor.ss
openssl pkeyutl -decap -inkey kem.key -in kem.ct -secret receptor.ss
cmp emisor.ss receptor.ss && echo "mismo secreto"
wc -c kem.ct emisor.ss

El emisor obtiene emisor.ss y un texto cifrado de 1088 bytes; el receptor recupera el mismo secreto de 32 bytes. Luego cambié un solo byte del texto cifrado y repetí la decapsulación: openssl terminó con código 0 y devolvió un secreto de 32 bytes distinto (1666f3ae… frente a 5863fcc4…). Es el rechazo implícito de FIPS 203 en acción, y la razón por la que tu protocolo debe confirmar la clave antes de fiarse de ella.

Firmar y verificar con ML-DSA y SLH-DSA

Las firmas post-cuánticas se usan con -rawin, porque el algoritmo procesa el mensaje completo en lugar de un resumen calculado aparte:

openssl genpkey -algorithm ML-DSA-65 -out firma.key
openssl pkey -in firma.key -pubout -out firma.pub
openssl pkeyutl -sign -rawin -inkey firma.key \
  -in msg.txt -out msg.sig
openssl pkeyutl -verify -rawin -pubin -inkey firma.pub \
  -in msg.txt -sigfile msg.sig
wc -c msg.sig

La verificación imprime Signature Verified Successfully y la firma ocupa 3309 bytes. Con un mensaje alterado, openssl sale con código 1 y el error Signature Verification Failure. Para SLH-DSA basta cambiar el nombre del algoritmo, por ejemplo SLH-DSA-SHA2-128s.

Tamaños medidos frente a la especificación

Repetí el flujo con los tres ML-KEM, los tres ML-DSA y cuatro SLH-DSA, y medí la clave pública dentro de su estructura SPKI, el texto cifrado y la firma. Todos los valores coinciden byte a byte con las tablas de FIPS 203, 204 y 205:

Tamaños medidos con OpenSSL 3.5 bytes
ML-KEM-512
Clave pública: 800 bytes
Texto cifrado o firma: 768 bytes
ML-KEM-768
Clave pública: 1184 bytes
Texto cifrado o firma: 1088 bytes
ML-KEM-1024
Clave pública: 1568 bytes
Texto cifrado o firma: 1568 bytes
ML-DSA-44
Clave pública: 1312 bytes
Texto cifrado o firma: 2420 bytes
ML-DSA-65
Clave pública: 1952 bytes
Texto cifrado o firma: 3309 bytes
ML-DSA-87
Clave pública: 2592 bytes
Texto cifrado o firma: 4627 bytes
SLH-DSA-SHA2-128s
Clave pública: 32 bytes
Texto cifrado o firma: 7856 bytes
SLH-DSA-SHA2-128f
Clave pública: 32 bytes
Texto cifrado o firma: 17 088 bytes
SLH-DSA-SHAKE-256s
Clave pública: 64 bytes
Texto cifrado o firma: 29 792 bytes
SLH-DSA-SHAKE-256f
Clave pública: 64 bytes
Texto cifrado o firma: 49 856 bytes
Ver tabla de valores
AlgoritmoClave públicaTexto cifrado o firma
ML-KEM-512800 bytes768 bytes
ML-KEM-7681184 bytes1088 bytes
ML-KEM-10241568 bytes1568 bytes
ML-DSA-441312 bytes2420 bytes
ML-DSA-651952 bytes3309 bytes
ML-DSA-872592 bytes4627 bytes
SLH-DSA-SHA2-128s32 bytes7856 bytes
SLH-DSA-SHA2-128f32 bytes17 088 bytes
SLH-DSA-SHAKE-256s64 bytes29 792 bytes
SLH-DSA-SHAKE-256f64 bytes49 856 bytes

Clave pública dentro de su estructura SPKI. Los diez valores coinciden byte a byte con FIPS 203, 204 y 205.

La clave privada en PKCS#8 pesa más de lo que dice la tabla, y tiene explicación. OpenSSL 3.5 guarda por defecto la semilla y la clave expandida juntas (el formato seed-priv de su documentación). Una clave ML-KEM-768 ocupó 2498 bytes en DER: la semilla (d, z) de 64 bytes, la clave de decapsulado de 2400 y la cabecera ASN.1. En SLH-DSA-128s la clave privada entera ocupa 84 bytes.

El grupo híbrido X25519MLKEM768 en un handshake TLS 1.3

OpenSSL 3.5 ofrece por defecto dos key shares en TLS 1.3, X25519MLKEM768 y X25519, así que un cliente y un servidor actualizados negocian el híbrido sin configurar nada. El grupo combina ML-KEM-768 con X25519: el secreto es seguro mientras resista cualquiera de los dos. Para verlo, levanté un servidor con un certificado ML-DSA-65 autofirmado y me conecté con s_client:

openssl req -x509 -newkey ML-DSA-65 -keyout srv.key -out srv.crt \
  -days 30 -nodes -subj "/CN=pqc.lab"
openssl s_server -accept 4433 -cert srv.crt -key srv.key -www -quiet &
echo | openssl s_client -connect 127.0.0.1:4433 -brief

Estas son las líneas relevantes del resumen de -brief, con las dos piezas post-cuánticas del handshake, el acuerdo de claves y la firma del servidor:

Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Signature type: mldsa65
Negotiated TLS1.3 group: X25519MLKEM768

Con -trace en lugar de -brief se ven los tamaños de cada mensaje. Estos son los que medí, contra un servidor con certificado P-256 para aislar el efecto del grupo, y contra el de ML-DSA-65 para ver el del certificado:

Tamaño de los mensajes del handshake TLS 1.3 bytes
ClientHello (grupos por defecto frente a solo X25519)
Clásico: 281 bytes
Post-cuántico: 1515 bytes
Key share del cliente
Clásico: 32 bytes
Post-cuántico: 1216 bytes
Key share del servidor
Clásico: 32 bytes
Post-cuántico: 1120 bytes
Certificado en DER (P-256 frente a ML-DSA-65)
Clásico: 382 bytes
Post-cuántico: 5506 bytes
Firma de CertificateVerify
Clásico: 71 bytes
Post-cuántico: 3309 bytes
Ver tabla de valores
MensajeClásicoPost-cuántico
ClientHello (grupos por defecto frente a solo X25519)281 bytes1515 bytes
Key share del cliente32 bytes1216 bytes
Key share del servidor32 bytes1120 bytes
Certificado en DER (P-256 frente a ML-DSA-65)382 bytes5506 bytes
Firma de CertificateVerify71 bytes3309 bytes

Medido con openssl s_client -trace.

El key share del cliente son 1184 bytes de clave ML-KEM más 32 de X25519, y el del servidor, 1088 de texto cifrado más 32. Con los grupos por defecto, el cliente además envía un key share X25519 aparte, por si el servidor no conoce el híbrido. Si fuerzas en el cliente -groups MLKEM768 o SecP256r1MLKEM768, un servidor OpenSSL 3.5 con su configuración por defecto corta con alert handshake failure (alerta 40), porque ninguno de los dos está en su lista por defecto. La adopción real de estos grupos en la web está en el artículo sobre criptografía post-cuántica en TLS.

mlkem768x25519-sha256 y firmas ML-DSA en OpenSSH

OpenSSH usa el mismo KEM con otro nombre, mlkem768x25519-sha256, y desde OpenSSH 10.0 (9 de abril de 2025) es el intercambio de claves por defecto. Con OpenSSH 10.2p1 en el contenedor, una conexión a localhost lo confirma:

ssh-keygen -A
/usr/sbin/sshd
ssh -v -o BatchMode=yes localhost true 2>&1 | grep "kex: algorithm"

La línea de depuración muestra kex: algorithm: mlkem768x25519-sha256. Las firmas son otro asunto: la clave de host siguió siendo ssh-ed25519.

OpenSSH 10.3 añadió soporte experimental para una firma compuesta ML-DSA-44 más Ed25519, desactivada por defecto. La probé en Alpine edge con OpenSSH 10.5p1: ssh-keygen -t mldsa44-ed25519 generó una clave pública de 1895 bytes (99 en Ed25519), y con ella como clave de host y de usuario la sesión autenticó con kex: algorithm: mlkem768x25519-sha256 y host key algorithm: ssh-mldsa44-ed25519@openssh.com. La configuración paso a paso para servidores está en la guía para migrar SSH a criptografía post-cuántica.

Preguntas frecuentes

¿Kyber y ML-KEM son lo mismo?

No exactamente. ML-KEM es la versión estandarizada de CRYSTALS-Kyber, y el apéndice C de FIPS 203 enumera los cambios que hacen que, con las mismas entradas, produzca salidas distintas a las de Kyber. Por eso TLS pasó del grupo X25519Kyber768 al X25519MLKEM768. Lo mismo vale para Dilithium frente a ML-DSA y SPHINCS+ frente a SLH-DSA.

¿Qué parámetros elijo para empezar?

ML-KEM-768 para acuerdo de claves, porque es el que usan los grupos híbridos de TLS y OpenSSH. Para firmas, ML-DSA-65 cubre la categoría 3 con firmas de 3309 bytes; SLH-DSA encaja donde firmas poco y quieres depender solo de un hash. FIPS 203 recomienda el parámetro más fuerte que tu sistema admita.

¿Tengo que migrar ya si el ordenador cuántico no existe?

El acuerdo de claves, sí. Un atacante puede guardar hoy tráfico cifrado y descifrarlo cuando exista la máquina, así que el KEM híbrido protege datos que ya estás enviando. Las firmas solo hay que cambiarlas antes de que el ataque sea posible, y el borrador IR 8547 marca 2035 como límite.

Conclusión

FIPS 203 resuelve el acuerdo de claves con ML-KEM, y FIPS 204 y FIPS 205 resuelven la firma con ML-DSA y SLH-DSA. Los tres son definitivos desde agosto de 2024 y ya funcionan en software de uso diario. En mi prueba con OpenSSL 3.5.9 todos los tamaños coincidieron con los documentos de NIST. El coste real está en el ancho de banda: un ClientHello de 1515 bytes y un certificado ML-DSA-65 de 5506.

El plan que sale de aquí tiene tres pasos:

  1. comprueba que tus servidores TLS y SSH usan OpenSSL 3.5 u OpenSSH 10 o posteriores, que negocian el híbrido por defecto
  2. verifica el grupo negociado con openssl s_client -brief y el intercambio SSH con ssh -v
  3. haz inventario de dónde firmas con RSA o ECDSA, porque esa migración es la lenta y el borrador de NIST la cierra en 2035

El estado de la adopción está en el artículo sobre la migración post-cuántica en la práctica.

Fuentes: [1] FIPS 203, Module-Lattice-Based Key-Encapsulation Mechanism Standard[1], [2] FIPS 204, Module-Lattice-Based Digital Signature Standard[2], [3] FIPS 205, Stateless Hash-Based Digital Signature Standard[3], [4] NIST IR 8547 ipd, Transition to Post-Quantum Cryptography Standards[4], [5] Proyecto Post-Quantum Cryptography de NIST CSRC[5], [6] The NIST PQC Project, MPTS 2026[6], [7] NEWS de OpenSSL 3.5[7], [8] Estrategia de versiones de OpenSSL[8], [9] Notas de versión de OpenSSH[9], [10] NIST SP 800-57 Part 1 Rev. 5[10].

Fuentes

  1. FIPS 203, Module-Lattice-Based Key-Encapsulation Mechanism Standard
  2. FIPS 204, Module-Lattice-Based Digital Signature Standard
  3. FIPS 205, Stateless Hash-Based Digital Signature Standard
  4. NIST IR 8547 ipd, Transition to Post-Quantum Cryptography Standards
  5. Proyecto Post-Quantum Cryptography de NIST CSRC
  6. The NIST PQC Project, MPTS 2026
  7. NEWS de OpenSSL 3.5
  8. Estrategia de versiones de OpenSSL
  9. Notas de versión de OpenSSH
  10. NIST SP 800-57 Part 1 Rev. 5