AES-GCM-HKDF de transmisión de AEAD

En este documento, se define formalmente la función matemática representada por las claves de transmisión AES-GCM-HKDF (codificadas en formato proto como type.googleapis.com/google.crypto.tink.AesGcmHkdfStreamingKey).

Esta encriptación se basa de manera flexible en [HRRV15].1 Para ver un análisis de la seguridad, nos referimos a [HS20]2.

Clave y parámetros

Las claves se describen en las siguientes partes (todos los tamaños de este documento están en bytes):

  • \(\mathrm{KeyValue}\), una string de bytes.
  • \(\mathrm{CiphertextSegmentSize} \in \{1, 2, \ldots, 2^{31}-1\}\).
  • \(\mathrm{DerivedKeySize} \in \{16, 32\}\).
  • \(\mathrm{HkdfHashType} \in \{\mathrm{SHA1}, \mathrm{SHA256}, \mathrm{SHA512}\}\).

Además, las claves válidas satisfacen las siguientes propiedades:

  • \(\mathrm{len}(\mathrm{KeyValue}) \geq \mathrm{DerivedKeySize}\).
  • \(\mathrm{CiphertextSegmentSize} > \mathrm{DerivedKeySize} + 24\) (Esto equivale a\(\mathrm{len}(\mathrm{Header}) + 16\) , como se explica más adelante).

Tink rechaza las claves que no satisfacen ninguna de estas propiedades (ya sea cuando se analiza la clave o cuando se crea la primitiva correspondiente).

Función de encriptación

Para encriptar un mensaje \(\mathrm{Msg}\) con datos asociados a\(\mathrm{AssociatedData}\), creamos un encabezado, dividimos el mensaje en segmentos, encriptamos cada segmento y concatenamos los segmentos. A continuación, se explican estos pasos.

Crea el encabezado

Para crear el encabezado, primero elegiremos una string aleatoria uniforme \(\mathrm{Salt}\)de longitud \(\mathrm{DerivedKeySize}\). A continuación, elegimos una string aleatoria uniforme\(\mathrm{NoncePrefix}\) de 7 longitudes.

Luego, configuramos\(\mathrm{Header} := \mathrm{len}(\mathrm{Header}) \| \mathrm{Salt} \| \mathrm{NoncePrefix}\), en el que la longitud del encabezado se codifica como un solo byte. Ten en cuenta que\(\mathrm{len}(\mathrm{Header}) \in \{24, 40\}\).

Luego, usamos HKDF3 con la función hash proporcionada por \(\mathrm{HkdfHashType}\)y las entradas \(\mathrm{ikm} := \mathrm{KeyValue}\),\(\mathrm{salt} := \mathrm{Salt}\)y\(\mathrm{info} := \mathrm{AssociatedData}\), con longitud de salida \(\mathrm{DerivedKeySize}\). Llamamos al resultado \(k\).

Dividiendo el mensaje

El mensaje \(\mathrm{Msg}\) se divide en partes:\(\mathrm{Msg} = M_0 \| M_1 \| \cdots \| M_{n-1}\).

Sus longitudes se eligen para que satisfagan lo siguiente:

  • \(\mathrm{len}(M_0) \in \{0,\ldots, \mathrm{CiphertextSegmentSize} - \mathrm{len}(\mathrm{Header}) - \mathrm{16}\}\).
  • Si es \(n>1\), entonces \(\mathrm{len}(M_1), \ldots, \mathrm{len}(M_{n-1}) \in \{1,\ldots, \mathrm{CiphertextSegmentSize} - \mathrm{16}\}\).
  • Si es \(n>1\), entonces \(\mathrm{len}(M_{0}), \ldots, \mathrm{len}(M_{n-2})\) debe tener la longitud máxima según las restricciones anteriores.

En esta división, \(n\) puede ser \(2^{32}\)como máximo. De lo contrario, la encriptación fallará.

Encripta los bloques

Para encriptar el segmento \(M_i\), primero calculamos\(\mathrm{IV}_i := \mathrm{NoncePrefix} \| \mathrm{i} \| b\), en el que codificamos\(\mathrm{i}\) en 4 bytes con codificación big-endian, y configuramos el byte $b$ como 0x00 si $i < n-1$ y, de lo contrario, 0x01.

Luego, encriptamos \(M_i\) con AES GCM4, donde la clave es\(\mathrm{DerivedKey}\), el vector de inicialización es \(\mathrm{IV}_i\)y los datos asociados \(A\) es la string vacía. Configuramos \(C_i\) como el resultado de esta encriptación (es decir, la concatenación de \(C\) y \(T\) en la referencia anterior).

Concatena los segmentos

Por último, todos los segmentos se concatenan como\(\mathrm{Header} \| C_0 \| \cdots \| C_{n-1}\), que es el texto cifrado final.

Desencriptación

La desencriptación simplemente invierte la encriptación. Usamos el encabezado para obtener el nonce y desencriptar cada segmento del texto cifrado de forma individual.

Por lo general, las APIs pueden permitir el acceso aleatorio o el acceso al comienzo de un archivo sin inspeccionar el final. Esto es intencional, ya que es posible desencriptar \(M_i\) de \(C_i\)sin desencriptar todos los bloques de texto cifrado anteriores y restantes.

Sin embargo, las APIs deben tener cuidado de no permitir que los usuarios confundan los errores de fin de archivo y de desencriptación: en ambos casos, es probable que la API deban mostrar un error, y si se ignora la diferencia, es posible que un adversario pueda truncar los archivos de manera efectiva.

Serialización y análisis de claves

Para serializar una clave en el formato “Tink Proto”, primero asignamos los parámetros de la manera obvia al proto dado en aes_gcm_hkdf_streaming.proto. El campo version debe establecerse en 0. Luego, serializamos esto con la serialización de proto normal y, luego, incorporamos la string resultante en el valor de campo de un proto KeyData. Configuramos el campo type_url en type.googleapis.com/google.crypto.tink.AesGcmHkdfStreamingKey. Luego, configuramos key_material_type como SYMMETRIC y, luego, incorporamos esto en un conjunto de claves. Por lo general, configuramos output_prefix_type como RAW. La excepción es que, si la clave se analizó con un valor diferente configurado para output_prefix_type, Tink puede escribir RAW o el valor anterior.

Para analizar una clave, revertimos el proceso anterior (de la manera habitual cuando se analizan los protocolos). Se ignora el campo key_material_type. Se puede ignorar el valor de output_prefix_type o se pueden rechazar las claves que tengan un output_prefix_type diferente de RAW. Se deben rechazar las claves que tengan un version distinto de 0.

Errores conocidos

No se espera que las implementaciones de la función de encriptación anterior sean seguras para la bifurcación. Consulta Seguridad de la bifurcación.

Referencias


  1. [HRRV15] Hoang, Reyhanitabar, Rogaway, Vizar. Encriptación autenticada en línea y resistencia al uso inadecuado del nonce. CRYPTO, 2015. https://eprint.iacr.org/2015/189 

  2. [HS20] Seguridad de la encriptación de transmisiones en la biblioteca Tink de Google. Hoang, Shen, 2020. https://eprint.iacr.org/2020/1019 

  3. [HKDF] Función de derivación de claves para extraer y expandir basada en HMAC (HKDF), RFC 5869. https://www.rfc-editor.org/rfc/rfc5869 

  4. NIST SP 800-38D, Recomendación para modos de operación de algoritmo de cifrado de bloque: modo Galois/contador (GCM) y GMAC.