CAPÍTULO 65 · PARTE VI

Cifrado simétrico, modos y AEAD

Distingue bloque, modo y contrato AEAD; explica nonce, AAD, límites por clave, fallo autenticado y las consecuencias operativas del reuse.

Nivel N2 · Estado published

El cifrado simétrico suele resumirse como «la misma clave cifra y descifra». Esa frase describe quién posee el secreto, pero omite casi todo lo que hace seguro o inseguro a un sistema real. AES transforma bloques; un modo enlaza esas transformaciones; un esquema AEAD define qué bytes se ocultan, qué contexto se autentica, cómo se usa un nonce y qué ocurre cuando la verificación falla.

La unidad correcta de análisis no es el nombre del algoritmo. Es el contrato completo (algoritmo, clave, nonce, AAD, formato, límites, estado y manejo de errores). Una implementación puede usar AES-256 correctamente y aun filtrar patrones, aceptar modificaciones, repetir un keystream o entregar plaintext manipulado.

Primitiva, modo y protocolo son capas distintas

FIPS 197 especifica AES-128, AES-192 y AES-256. Los tres transforman bloques de 128 bits; el sufijo nombra la longitud de clave, no el tamaño de bloque. La actualización de 2023 mejoró la presentación del estándar sin cambiar el algoritmo. NIST FIPS 197

Un block cipher puede modelarse como una familia de permutaciones: para cada clave K, E_K asigna cada bloque de 128 bits a otro bloque y D_K invierte la operación. Eso no responde cómo cifrar un archivo de 37 bytes, cómo evitar que dos mensajes iguales produzcan la misma salida, cómo autenticar metadata ni cómo detectar manipulación.

Un modo de operación convierte la primitiva en un mecanismo para mensajes. SP 800-38A define ECB, CBC, CFB, OFB y CTR como modos de confidencialidad. Que estén especificados no significa que todos sean una opción apropiada para un protocolo nuevo. NIST decidió revisar SP 800-38A, limitar la aprobación de ECB a usos expresamente permitidos y desarrollar mejor guía sobre autenticación; la revisión futura no debe citarse como si ya hubiera reemplazado al texto final. NIST SP 800-38A

El protocolo añade representación, selección de clave, nonce o IV, AAD, versionado, límites, respuesta a error y lifecycle. La biblioteca criptográfica puede implementar una primitive segura y la aplicación violar el contrato en la llamada siguiente.

Esta separación evita una inferencia frecuente: «usa AES» no demuestra confidencialidad del sistema. Falta saber el modo, y aun «AES-GCM» no demuestra nonce uniqueness, key isolation, AAD correcta, límites respetados ni plaintext retenido hasta verificar.

Por qué estudiar ECB, CBC y CTR

Los modos históricos son útiles porque hacen visibles clases de fallo que reaparecen en protocolos modernos. No se estudian para recomendar composiciones manuales cuando existe una AEAD mantenida.

ECB cifra cada bloque de manera independiente. Dos bloques plaintext iguales bajo la misma clave producen el mismo ciphertext. El adversario observa igualdad y estructura; además puede reordenar bloques sin que ECB proporcione una señal de autenticidad. El problema no es que AES haya dejado de ser una permutación fuerte, sino que el modo conserva relaciones que el mensaje necesitaba ocultar.

CBC combina cada bloque plaintext con el ciphertext anterior antes de aplicar el block cipher. Requiere un IV apropiado para el perfil y padding cuando la longitud no completa un bloque. Alterar un bloque ciphertext modifica el plaintext correspondiente y afecta al siguiente. Si el receptor distingue padding válido de inválido mediante respuesta, timing o efecto, puede aparecer un padding oracle: el adversario aprende plaintext mediante consultas adaptativas aunque nunca recupere K ni rompa AES.

«Cifrar y luego devolver el error exacto» transforma una diferencia interna en interfaz de ataque. Ocultar el texto del error no basta si cambian status, longitud, conexión, logs visibles o latencia. La solución normal no es diseñar un parche casero para CBC, sino usar una construcción autenticada y una API que no libere datos antes de validar.

CTR cifra valores de contador y combina el keystream resultante con plaintext mediante XOR. No requiere padding y permite paralelismo. Su obligación crítica es no repetir el mismo bloque de contador bajo la misma clave. Si se reutiliza keystream, C1 xor C2 = P1 xor P2; estructura o plaintext conocido puede revelar el otro mensaje. CTR tampoco autentica: cambiar bits del ciphertext cambia bits correspondientes del plaintext de forma predecible.

Estas propiedades producen una regla pedagógica: confidencialidad sin integridad no convierte bytes manipulados en fallo seguro. El consumidor puede interpretar un plaintext modificado como comando, longitud, rol o dirección. La autenticación no es un accesorio posterior.

AEAD como interfaz y propiedad conjunta

Authenticated Encryption with Associated Data combina confidencialidad del plaintext con integridad/autenticidad de ciphertext y associated data bajo una sola interfaz. RFC 5116 modela dos operaciones. RFC 5116

Seal(K, N, P, A) -> C

Open(K, N, C, A) -> P o FAIL

Aquí K es la clave, N el nonce, P el plaintext y A la associated data. La representación C suele incluir o acompañarse de un authentication tag. Los detalles exactos pertenecen al algoritmo y al protocolo; no se deben adivinar ni cambiar de orden informalmente.

La propiedad conjunta importa. Un API AEAD reduce el espacio para elegir «encrypt then MAC», «MAC then encrypt» o «encrypt and MAC» sin análisis. Eso no vuelve imposible el mal uso: la aplicación todavía puede repetir nonces, omitir contexto de AAD, usar claves fuera de propósito, truncar tags o procesar salida no verificada.

Un tag válido no autoriza el contenido ni evita replay. Demuestra que ciphertext, nonce y AAD encajan bajo la clave y el algoritmo, dentro de su security bound. El receptor todavía comprueba identidad contextual, frescura, transición de estado, permisos e idempotencia, como en el capítulo anterior.

AAD: visible, pero ligada al ciphertext

Associated data se autentica sin cifrarse. Puede transportar version, algorithm profile, key-id, tenant, sender, receiver, sequence number, content type, routing metadata o longitud. El adversario puede verla; no debería poder modificarla sin que Open falle.

La selección no es «headers frente a body», sino «qué contexto necesita quedar ligado al plaintext». Si un ciphertext de tenant A puede copiarse a tenant B y ambos comparten una clave, omitir tenant de AAD permite una reinterpretación cross-context. Si method y path cambian el significado de un request, autenticar sólo el body deja el contrato incompleto.

La AAD necesita framing inequívoco. Concatenar tenant || path || version sin longitudes o encoding puede hacer que tuplas distintas produzcan los mismos bytes. Se fija una codificación canónica, orden, tipos, domain label y versión. El receptor reconstruye exactamente los mismos bytes antes de llamar Open.

AAD no es almacenamiento confidencial. Un número de cuenta, identidad o clasificación colocados allí pueden filtrarse aunque la verificación sea perfecta. Cuando metadata también debe ocultarse, se rediseña el envelope: parte pasa al plaintext cifrado y sólo el contexto mínimo necesario queda fuera.

Tampoco toda metadata externa puede incluirse. Longitud de transporte, dirección IP observada o timestamp local quizá cambien entre saltos. Debe distinguirse contexto estable autenticado por el emisor de evidencia observada por intermediarios.

Nonce, IV y unicidad por clave

Nonce significa «number used once», pero no todos los mecanismos llaman igual ni exigen lo mismo. Algunos perfiles requieren unicidad, otros impredecibilidad y algunos ambas propiedades para componentes distintos. IV, nonce y salt no son sinónimos intercambiables.

Para las AEAD nonce-based de RFC 5116, distintas invocaciones de encryption bajo una clave deben usar nonces distintos según el contrato del algoritmo. El nonce normalmente no es secreto y puede almacenarse junto al ciphertext. La obligación es sobre el par (K,N): repetir N después de cambiar K no repite el mismo par; mantener K y restaurar el contador sí. RFC 5116, §3.1

Un contador monotónico puede ser excelente en un solo escritor con persistencia fiable. Falla si:

La reserva debe ocurrir antes de publicar el ciphertext. Un diseño puede asignar a cada emisor un prefijo único y usar un contador persistente dentro de ese namespace, o separar claves por emisor. Si el estado puede retroceder, se rekeyea antes de volver a cifrar o se usa un monotonic state externo que la snapshot no restaure.

Nonces aleatorios no eliminan el análisis: introducen probabilidad de colisión y requieren dimensionar número de mensajes, múltiples escritores y vida de clave. «96 bits aleatorios» no equivale a garantía absoluta de unicidad. El perfil decide si random es aceptable y cuál es el límite operacional.

GCM: rápido, autenticado y sensible al reuse

NIST SP 800-38D define Galois/Counter Mode como AEAD para un approved block cipher y GMAC como su especialización de autenticación. GCM combina counter-mode encryption con un authenticator polinómico. AAD se incorpora a la autenticación sin cifrarse. NIST SP 800-38D

AES-GCM es eficiente y ampliamente acelerado, pero su nonce contract es estricto. Repetir el mismo (K,N) reutiliza counter keystream y relaciona plaintexts; además degrada la autenticidad porque las ecuaciones del authenticator comparten material. No debe resumirse como «sólo filtra XOR»: el daño puede alcanzar confidencialidad e integridad.

La longitud de tag pertenece al perfil. RFC 5116 define sus perfiles GCM con tag de 128 bits. La publicación vigente SP 800-38D contempla otras longitudes bajo condiciones; NIST decidió en 2024 revisarla y eliminar soporte para tags menores de 96 bits. Esa decisión anuncia el contenido previsto, no crea todavía una revisión final. El sistema usa el valor exigido por su protocolo y biblioteca, no una longitud negociable por input no confiable.

GCM tiene límites por clave sobre número y longitud de mensajes, AAD, tags fallidos y estrategia de IV. Esos límites no se deducen de «AES-256». Se toma el bound del perfil aplicable, se agrega volumen entre replicas y usuarios que comparten clave, se monitorea y se rota antes de agotarlo.

ChaCha20-Poly1305 y Ascon-AEAD128

RFC 8439 combina el stream cipher ChaCha20 con el authenticator Poly1305 en una AEAD. Usa una clave de 256 bits y nonce de 96 bits que no debe repetirse para la misma clave. Si se repite, se reutilizan tanto el keystream como la one-time Poly1305 key; RFC 8439 explica la pérdida resultante. RFC 8439

ChaCha20-Poly1305 no es «GCM sin AES». Tiene primitiva, límites, layout y test vectors propios. La selección suele depender del protocolo, soporte de biblioteca, plataforma y aceleración. No se implementa ChaCha ni Poly1305 a mano para evitar una dependencia.

NIST publicó SP 800-232 como final en agosto de 2025 e incluye Ascon-AEAD128 para dispositivos restringidos. Es una opción estandarizada con diseño permutation-based; no reemplaza automáticamente AES-GCM o ChaCha20-Poly1305 en cualquier entorno. Interoperabilidad, certificación, side-channel implementation y ecosistema siguen siendo decisiones del perfil. NIST SP 800-232

Enumerar algoritmos no crea crypto agility. Una aplicación necesita un conjunto pequeño permitido, identifiers autenticados, parámetros fijos, test vectors, estrategia de migration y capacidad de retirar suites. Un campo algorithm controlado por el ciphertext no puede habilitar una opción legacy por sí solo.

Misuse resistance reduce daño; no elimina obligaciones

RFC 8452 especifica AES-GCM-SIV, una AEAD nonce-misuse-resistant. Si un nonce se repite, evita el fallo catastrófico de GCM y revela al menos igualdad cuando plaintext y AAD coinciden. La encryption requiere dos pasadas y el documento es IRTF Informational, no IETF Standards Track. RFC 8452

«Misuse-resistant» no significa «nonce optional» ni «reuse recomendado». RFC 8452 recomienda nonces aleatorios y dice expresamente que la propiedad sirve como defensa cuando ocurre el error. El reuse deliberado filtra patrones y consume bounds de manera distinta.

RFC 9771 afina el vocabulario. Nonce-misuse resilience protege mensajes correctamente cifrados con nonces frescos pese a otros reuses; nonce-misuse resistance conserva propiedades para mensajes que no comparten un nonce repetido más de una vez, según el modelo. Una etiqueta no debe transportarse entre algoritmos sin análisis. RFC 9771, §4.3.7

Elegir un modo resistente puede ser apropiado cuando múltiples encryptors o rollback hacen difícil garantizar unicidad. No sustituye key management, domain separation, AAD correcta, límites ni detección operacional de reuse.

Open entrega plaintext o FAIL

Durante decryption, algunas implementaciones pueden calcular bytes plaintext antes de terminar la verificación. Esos bytes no son todavía salida autenticada. No deben llegar a un parser con efectos, escribirse como archivo visible, mostrarse al usuario ni usarse para elegir rutas.

La frontera segura es transaccional: Open devuelve plaintext completo si el tag valida, o FAIL sin plaintext consumible. RFC 8452 exige no liberar plaintext no autenticado y advierte que tamaños grandes crean presión de memoria. Streaming seguro necesita una construcción y API cuyo contrato cubra release; partir un mensaje grande en records AEAD autenticados independientemente no es lo mismo que entregar fragments de una sola apertura antes del tag.

El fallo debe borrar o volver inaccesible cualquier buffer temporal y no producir efectos parciales. La aplicación limita ciphertext, AAD y plaintext esperado antes de reservar memoria. Un ciphertext adversarial no puede dictar asignaciones ilimitadas.

Los errores internos pueden distinguir «key unavailable», «malformed envelope» y «authentication failed» para operar, pero la interfaz externa evita un oracle innecesario. Reintentar Open con otras claves o algoritmos sólo se hace bajo una lista pequeña gobernada; nunca mediante fallback abierto.

Caso trabajado: blob cifrado movido entre tenants

Un servicio almacena nonce || ciphertext || tag para cada documento. Usa AES-GCM con una clave regional compartida. El path de almacenamiento contiene tenant y document-id, pero AAD está vacía. La base impide leer filas de otro tenant desde la API normal.

Un job interno copia blobs durante una migración y asocia uno al tenant equivocado. El tag sigue validando: GCM autenticó el ciphertext, no la fila ni el path. Si el plaintext no contiene y valida tenant, el servicio entrega un documento auténtico bajo la clave regional pero fuera de su contexto autorizado.

La corrección define un envelope versionado:

AAD = domain || version || region || tenant-id || document-id || content-type

P = document bytes

El key-id se usa para encontrar una clave permitida por la policy regional y también queda ligado al header autenticado según el formato. Mover el blob sin reconstruir y volver a cifrar hace fallar Open porque la AAD ya no coincide. La autorización de lectura todavía se evalúa antes y después; AEAD no reemplaza el control de tenant.

La auditoría descubre otro problema: cada worker conserva un contador local que comienza en cero. Todos comparten K_region, así que existen pares (K,N) repetidos. Se cambia a claves por shard y namespaces de emisor asignados de forma única, con contador persistente reservado antes de publicar. Al restaurar una snapshot, el deployment recibe una nueva key epoch antes de procesar.

Finalmente se fijan límites por key epoch, métricas de nonce allocation, número de seals, bytes y fallos de Open. Un límite cercano bloquea nuevas escrituras y activa rotación; no espera a que una prueba de seguridad se vuelva falsa.

Método de revisión

Para evaluar cualquier cifrado simétrico, responde:

  1. Propiedad: ¿qué debe ocultarse y qué debe autenticarse?
  2. Perfil: ¿algoritmo y parámetros exactos, no sólo «AES»?
  3. Clave: ¿propósito, tenant, dirección, lifecycle y poseedores?
  4. Nonce/IV: ¿qué propiedad exige el perfil y quién la garantiza?
  5. Concurrencia: ¿cómo evitan colisiones varios encryptors?
  6. Rollback: ¿qué ocurre con snapshots, clones, restores y retries?
  7. AAD: ¿qué contexto queda visible pero ligado al ciphertext?
  8. Framing: ¿cómo se codifican versión, longitudes y campos?
  9. Open: ¿plaintext completo o FAIL sin efectos parciales?
  10. Bounds: ¿mensajes, bytes, intentos y usuarios se agregan por clave?
  11. Errores: ¿hay oracle por respuesta, timing o fallback?
  12. Migración: ¿cómo coexisten versiones sin downgrade?
  13. Evidencia: ¿test vectors y negativos cubren bit flips, AAD y reuse?

Los tests incluyen mensaje y AAD vacíos, tamaños límite, un bit alterado en nonce/ciphertext/tag/AAD, tags cortos y largos, key-id desconocido, algoritmo no permitido, contexto de otro tenant y buffers truncados. Se verifican concurrencia, crash entre reserva y emisión, restore de snapshot y rotación. Un vector positivo acredita interoperabilidad; no acredita el estado distribuido que preserva nonce uniqueness.

La revisión debe observar el efecto, no sólo el retorno de la función. Ante un tag inválido se comprueba que no apareció archivo, fila, evento, log con plaintext ni fragmento entregado a otro componente. Ante un crash se reconstruye si el nonce quedó reservado o puede volver a asignarse. También se ejecutan dos encryptors realmente concurrentes bajo la misma key epoch: una prueba secuencial no revela la colisión que introduce el despliegue. Finalmente, se prueba una versión futura desconocida y se exige rechazo cerrado; interpretar el envelope con el parser equivocado puede romper AAD y límites aunque la primitive permanezca correcta.

Transferencia al capítulo 66

El cifrado simétrico presupone que las partes autorizadas ya comparten una clave. El capítulo 66 introduce criptografía asimétrica: pares de claves, problemas difíciles, encapsulación y las propiedades que no aparecen por llamar «pública» a una clave.

Síntesis

AES es una primitiva de bloque, no un protocolo completo. ECB filtra igualdad; CBC y CTR pueden ser maleables y sus IV/nonces forman parte del contrato. Estudiarlos explica por qué confidencialidad sin autenticación deja bytes peligrosamente interpretables.

AEAD recibe clave, nonce, plaintext y AAD; produce ciphertext autenticado. AAD permanece visible. Open entrega plaintext sólo después de verificar o devuelve FAIL sin salida utilizable. Un tag válido no concede frescura ni autorización.

La unicidad se diseña por (K,N) bajo múltiples procesos, persistencia, retries y rollback. GCM y ChaCha20-Poly1305 sufren daños graves por reuse; GCM-SIV reduce el daño, pero no legitima repetir. Los límites pertenecen al perfil y al volumen agregado, no al nombre AES-256.

El cifrado profesional no consiste en escoger una primitive fuerte. Consiste en preservar su contrato durante toda la vida del dato, incluso cuando el sistema concurre, falla, migra y se restaura.

Fuentes primarias y documentación técnica