1 puntos por GN⁺ 2024-06-30 | 1 comentarios | Compartir por WhatsApp
  • XAES-256-GCM es una nueva especificación de AEAD que usa una clave de 256 bits y un nonce de 192 bits para hacer menos riesgosa la gestión de nonces en APIs criptográficas de alto nivel
  • Un nonce grande permite un enfoque en el que se genera automáticamente un valor nuevo para cada mensaje desde el CSPRNG del sistema operativo, con el objetivo de un riesgo de colisión de alrededor de 2⁻³² en 2⁸⁰ mensajes
  • Internamente, es una construcción de nonce extendido que deriva una clave y un nonce de 96 bits a partir de la clave de entrada y del nonce grande, y luego usa AES-256-GCM estándar sin cambios
  • La implementación de referencia en Go cabe en menos de 100 líneas usando solo crypto/cipher y crypto/aes, y de las 3 llamadas a AES-256 por mensaje, algunas pueden precalcularse
  • Con énfasis en el cumplimiento de FIPS 140 y la compatibilidad con bibliotecas, puede usarse junto con XChaCha20Poly1305 y AES-GCM-SIV como candidata para una API AEAD sin nonce

AEAD de nonce grande para APIs de alto nivel

  • XAES-256-GCM es un algoritmo de cifrado autenticado con datos asociados (AEAD) que usa una clave de 256 bits y un nonce de 192 bits
  • El objetivo de diseño se resume en tres puntos
    • soporte para nonces grandes cuyo uso aleatorio sea seguro incluso con una cantidad de mensajes prácticamente ilimitada
    • cumplimiento total y directo de FIPS 140
    • implementación sencilla sobre bibliotecas criptográficas comunes
  • Gracias al nonce grande, se puede crear una API que lea un nonce nuevo del CSPRNG del sistema operativo para cada mensaje sin que el usuario tenga que calcular por su cuenta el birthday bound
  • Al priorizar cumplimiento y compatibilidad, puede aplicarse donde se necesite AEAD incluso en entornos donde sea difícil usar otros AEAD de nonce grande

Una construcción de nonce extendido que reutiliza AES-256-GCM tal cual

  • XAES-256-GCM es una construcción de nonce extendido montada sobre un AEAD existente, como XChaCha20Poly1305
  • A partir de la clave de entrada y del nonce de 192 bits, calcula una clave derivada y un nonce derivado para el AES-256-GCM interno
    • la clave y el nonce de entrada son K, N
    • la clave y el nonce derivados para AES-256-GCM son Kₓ, Nₓ
  • Kₓ se forma con llamadas a AES-256ₖ y la parte inicial del nonce, y Nₓ usa los 96 bits finales del nonce de entrada
  • Se requieren 3 llamadas a AES-256ₖ por mensaje
    • una de ellas puede precalcularse para una clave dada
    • las otras dos pueden reutilizar el mismo key schedule

La implementación es corta y puede describirse con componentes estándar

  • La implementación de referencia en Go tiene menos de 100 líneas incluso incluyendo la optimización de precálculo y la mayor parte del boilerplate
  • La implementación en Go usa solo crypto/cipher y crypto/aes de la biblioteca estándar
  • XAES-256-GCM también puede describirse con el KDF estándar NIST SP 800-108r1 y el AEAD estándar NIST AES-256-GCM
    • el KDF es un counter-based KDF
    • el PRF es CMAC-AES256
    • la clave de entrada es Kin
    • la etiqueta es el carácter ASCII X, es decir 0x58
    • el contexto son los primeros 96 bits del nonce de entrada
    • el tamaño del contador es de 16 bits
    • el campo opcional L se omite
    • la salida es una clave derivada de 256 bits
  • La clave derivada y los últimos 96 bits del nonce de entrada se pasan a AES-256-GCM
  • Gracias a la elección de parámetros, al eliminar las abstracciones de KDF y CMAC, es solo un poco más lento y complejo que simplemente llamar a AES-256 sobre un contador
  • Los mismos parámetros también están soportados en la API de alto nivel de OpenSSL

Implementaciones de terceros y vectores de prueba

El abandono de /11 y las alternativas

  • Una idea anterior llevaba el nombre XAES-256-GCM/11, pero en la especificación final se descartó /11
  • /11 era una optimización de rendimiento y, como una de las razones para usar AES-GCM es el cumplimiento de FIPS 140, cambiar el número de rondas eliminaría ese cumplimiento
  • Si el cumplimiento de FIPS 140 no es el objetivo, hay varias alternativas
    • AES-GCM-SIV
    • construcciones AEAD modernas basadas en el núcleo de AES
  • La sección Alternatives de la especificación compara cada alternativa con XAES-256-GCM

Su lugar en Go y en una API AEAD sin nonce

  • XAES-256-GCM apunta a ser un AEAD seguro, sobrio, compatible con cumplimiento normativo e interoperable
  • Su principal caso de uso es el tipo de API de alto nivel que se quisiera añadir a Go
  • XAES-256-GCM complementa a XChaCha20Poly1305 y AES-GCM-SIV, y fue diseñado como candidato de implementación para una hipotética API AEAD sin nonce
  • Como no se prefiere añadir a la biblioteca estándar de Go una construcción específica de Go, se necesita la opinión de otros mantenedores de bibliotecas criptográficas

1 comentarios

 
GN⁺ 2024-06-30
Opiniones de Hacker News
  • El diseño es muy ingenioso: como está basado en CMAC, puede derivar claves con AES-CBC incluso sin primitivas de bajo nivel
    Desde la perspectiva de AES-CBC, puede verse como empezar con L = AES-CBC-256ₖ(iv = 0¹²⁸, plaintext = 0¹²⁸)[:16] para crear K1, cifrar M1 y M2 para obtener Kₓ, y luego usar Nₓ = N[12:]
    Se puede considerar que AES-CBC-256 devuelve solo el primer bloque de 128 bits del texto cifrado y descarta el bloque de padding; incluso si no se puede desactivar el padding, no está mal, porque frente a una implementación de bajo nivel solo cuesta 3 llamadas AES adicionales con la misma clave
    Una implementación en JS basada en la WebCrypto API que aprovecha esta característica está en https://github.com/dchest/xaes, y también soporta características de CryptoKey, como aceptar directamente un CryptoKey para AES-CBC y almacenarlo en IndexedDB con extractable=false

    • En este campo parece notación estándar, pero, sinceramente, no me gusta la notación criptográfica
      En ese pseudocódigo, la mitad de los números parecen contar bytes y la otra mitad bits, y si no conoces ya el algoritmo casi no hay forma de saber cuál es cuál
      Por ejemplo, N[:12] parece 12 bytes, pero 0¹²⁸ son 16 bytes, y X es el carácter real 'X', es decir, la cadena de bits 01011000, mientras que L es una variable, no la cadena de bits 01001100
      Está claro que a los matemáticos no les gusta la notación no ambigua tanto como a la gente de ciencias de la computación
    • Una constante de aspecto inquietante como 0¹²⁰10000111 es la cadena de bits que representa los coeficientes del primer polinomio en orden lexicográfico, entre los polinomios irreducibles de grado b para el tamaño de bloque b del cifrado de bloque subyacente que usa CMAC, con la mínima cantidad de términos distintos de cero
      No hay ninguna intención oculta
    • No soy especialista en criptografía, pero entiendo que, en resumen, el AES-GCM AEAD estándar se rompe de forma catastrófica si se usa dos veces el mismo nonce en mensajes distintos[1], y que el tamaño del nonce también suele ser demasiado pequeño para usar nonces aleatorios con seguridad
      Este trabajo permite evitar fácilmente ese problema cambiando no solo el nonce, sino también la clave en cada llamada a AES-GCM
      Además, si se tiene AES-GCM, usa solo AES “normal”, que suele estar disponible, y evita una construcción nueva y compleja que quizá todavía tenga debilidades
      El overhead por mensaje es de dos buffers pequeños que hay que cifrar/descifrar con AES “normal” y un nonce más largo de 192 bits
      [1]: https://frereit.de/aes_gcm/
  • Parece eliminar la trampa del AES-GCM puro, en la que al usar nonces aleatorios hay que rotar la clave cada unos 2^32 mensajes
    En AES-GCM, una colisión de nonce es catastrófica y, como mínimo, permite que un atacante firme mensajes arbitrarios
    No es obligatorio usar nonces aleatorios, pero normalmente se recomienda, y es bastante ingenioso que lo hagan compatible con FIPS usando dos primitivas: una función de derivación de claves basada en contador y GCM puro

    • Más exactamente, este método hace que los nonces aleatorios sean seguros desde el principio
      En AES-GCM estándar, 96 bits no son suficientes para evitar colisiones aleatorias, así que hay que usar generación determinista de nonces
      Además, sin importar cómo hayas creado el nonce, después de 2^32 bloques hay que cambiar el nonce o la clave, porque el contador hace rollover y el siguiente bloque usará el mismo nonce+contador que el primer bloque
  • Es realmente fantástico. Ojalá hubiera existido hace unos años, la última vez que construí un sistema de archivos cifrado
    En despliegues de sistemas de archivos a gran escala, las colisiones de nonce son una gran preocupación
    2^32 parece mucho, pero si estás escribiendo a 100k IOPS por segundo en un arreglo de varios PB y dependes de la aleatoriedad de un generador seudoaleatorio, la probabilidad de colisión es prácticamente garantizada

    • La competencia CAESAR[1] terminó en 2019 y de ella salieron varios AEAD con espacio de nonce suficiente
      [1] https://en.m.wikipedia.org/wiki/CAESAR_Competition
    • Pero me pregunto por qué una colisión de nonce es un problema
      ¿No significa simplemente que dos bloques comparten la misma clave de cifrado?
      Si no conozco el texto plano de ninguno de los bloques, no veo cómo eso debilita la seguridad del sistema
  • Me gustaría que esto se usara en una variante de age compatible con FIPS para cifrado de archivos de archivo/almacenamiento
    En una auditoría bancaria rechazaron age para este uso porque usa ChaCha, y consideraron aceptable la parte de clave pública X25519 de age. Tenía entendido que X25519 había sido aprobado por NIST hace relativamente poco
    No tengo experiencia con Go, pero viendo la especificación de age parece que se podría encajar directamente, y quizá lo intente si tengo tiempo
    El nombre podría ser “cage”, por “compliant actually good encryption”
    1: https://github.com/FiloSottile/age

    • “compliant actually good encryption” quizá sea un oxímoron
    • Revisé y parece que Ed25519 sí fue aprobado (FIPS 186-5), pero X25519 parece que todavía no
    • Como referencia, la biblioteca estándar de Go todavía no tiene una implementación de XAES; solo existe la implementación de referencia de C2SP
    • bge, bureaucratic good encryption
  • Como no criptógrafo, me pregunto por qué se usa un nonce de 192 bits y no uno de 256 bits
    No parece que esos bits adicionales vayan a considerarse un costo en aplicaciones prácticas

    • No hay espacio para poner 256 bits. Los 192 bits se componen de 96 bits que vienen del espacio de nonce inferior, y 96 bits que, junto con el prefijo necesario, entran en un bloque CMAC de 128 bits
      También se podría hacer más larga la entrada de CMAC, pero eso requeriría ejecutar más veces la función de bloque AES-256 y además se toparía con problemas molestos de control de claves en la función de derivación de claves CMAC
      Es similar a la razón por la que XChaCha20Poly1305 usa nonces de 192 bits, y también es una pequeña ventaja que sea consistente con otros AEAD importantes de nonce extendido
  • Se dice “riesgo de colisión de 2⁻³² con 2⁸⁰ mensajes”, pero ¿no aparecen problemas antes debido a que el tamaño de bloque de AES es de solo 128 bits?

    • Si te refieres al límite de cumpleaños sobre bloques (https://sweet32.info), ese es un límite sobre la cantidad de bloques cifrados con una sola clave
      XAES deriva una clave grande por cada mensaje, así que logra lo que suele llamarse una garantía mejor que el límite de cumpleaños
    • No
      Sin más contexto sobre por qué crees que sería un problema, es difícil responder con más detalle
  • “Seguro, aburrido, apto para cumplimiento e interoperable”
    Mi tipo de tecnología favorita

  • Bien. Me alegra que exista una construcción basada en NIST en la práctica
    Aun así, es una lástima que se renuncie a varias ventajas de la función de derivación de claves de NIST, como etiquetas y contexto
    Entiendo que se haya sacrificado eso para minimizar la cantidad de llamadas AES, pero especialmente para mensajes de más de unos cientos de bytes, yo habría priorizado una separación criptográfica más fuerte antes que ahorrar unas pocas llamadas AES
    Por último, los nonces GCM aleatorios de más de 96 bits sin duda se malinterpretan mucho y ofrecen mejores garantías que los nonces de 96 bits[1]
    Por supuesto, si se puede derivar una clave nueva para cada mensaje, eso es claramente mejor
    [1] https://neilmadden.blog/2024/05/23/galois-counter-mode-and-r...