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 forma vaga en HRRV151. Para el análisis de seguridad, consulta HS202.

Clave y parámetros

Las claves se describen con las siguientes partes (todos los tamaños en este documento se indican en bytes):

  • \(\mathrm{KeyValue}\), una cadena 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 cumplen con las siguientes propiedades:

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

Tink rechaza las claves que no cumplen con 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\(\mathrm{AssociatedData}\), creamos un encabezado, dividimos el mensaje en segmentos, encriptamos cada segmento y concatenamos los segmentos encriptados.

Crea el encabezado

Elegimos una cadena aleatoria uniforme \(\mathrm{Salt}\) de longitud\(\mathrm{DerivedKeySize}\) y una cadena aleatoria uniforme \(\mathrm{NoncePrefix}\)de longitud 7.

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

A continuación, usamos HKDF3 con la función hash que proporciona \(\mathrm{HkdfHashType}\)y las entradas \(\mathrm{ikm} := \mathrm{KeyValue}\), \(\mathrm{salt} := \mathrm{Salt}\)y \(\mathrm{info} := \mathrm{AssociatedData}\), con una longitud de salida \(\mathrm{DerivedKeySize}\). Llamamos al resultado \(\mathrm{DerivedKey}\).

Cómo dividir el mensaje

A continuación, el mensaje \(\mathrm{Msg}\) se divide en partes: \(\mathrm{Msg} = M_0 \| M_1 \| \cdots \| M_{n-1}\).

Sus longitudes se eligen para satisfacer los siguientes requisitos:

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

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

Encripta los bloques

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

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 son la cadena vacía. \(C_i\) es el resultado de esta encriptación (es decir, la concatenación de \(C\) y \(T\) en la sección 5.2.1.2 de la referencia de AES-GCM vinculada).

Concatena los segmentos encriptados

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 invierte la encriptación. Usamos el encabezado para obtener\(\mathrm{NoncePrefix}\)y desencriptar cada segmento de texto cifrado de forma individual.

Las APIs pueden permitir (y suelen 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\) desde \(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 tenga que mostrar un error, y si se ignora la diferencia, un adversario puede truncar archivos de manera eficaz.

Serialización y análisis de claves

Para serializar una clave en el formato "Tink Proto", primero asignamos los parámetros de la manera más obvia al proto que se proporciona en aes_gcm_hkdf_streaming.proto. El campo version debe establecerse en 0. Luego, lo serializamos con la serialización de proto normal y, luego, incorporamos la cadena resultante en el valor del campo de un proto KeyData. Configuramos el campo type_url como type.googleapis.com/google.crypto.tink.AesGcmHkdfStreamingKey. Luego, configuramos key_material_type en SYMMETRIC y lo incorporamos 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 establecido para output_prefix_type, Tink puede escribir RAW o el valor anterior.

Para analizar una clave, invertimos el proceso anterior (de la manera habitual cuando se analizan protos). 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 diferente de 0.

Problemas conocidos

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

Referencias


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

  2. Hoang, Shen, 2020. Seguridad de la encriptación de transmisión en la biblioteca de tink de Google. https://eprint.iacr.org/2020/1019 

  3. RFC 5869. Función de derivación de claves (HKDF) de extracción y expansión basada en HMAC. https://www.rfc-editor.org/rfc/rfc5869 

  4. NIST SP 800-38D. Recomendación para los modos de operación de los algoritmos de cifrado por bloques: Galois/Counter Mode (GCM) y GMAC. https://csrc.nist.gov/pubs/sp/800/38/d/final