AES-GCM-HKDF de transmisión de AEAD

En este documento, se define de manera formal 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 general en HRRV151. Para el análisis de seguridad, consultamos HS202.

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 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\) (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 los 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 el 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 proporcionada por \(\mathrm{HkdfHashType}\)y entradas \(\mathrm{ikm} := \mathrm{KeyValue}\), \(\mathrm{salt} := \mathrm{Salt}\)y \(\mathrm{info} := \mathrm{AssociatedData}\), con longitud de salida \(\mathrm{DerivedKeySize}\). Llamamos al resultado \(\mathrm{DerivedKey}\).

Divide el mensaje

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

Sus duraciones se eligen para satisfacer 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 una longitud máxima de acuerdo con lo anterior para las restricciones.

\(n\) puede ser como máximo \(2^{32}\). 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\), en el que \(\mathrm{i}\) es 4 bytes en la codificación big-endian y el byte $b$ es 0x00 si $i < n-1$ y 0x01 en caso contrario.

Luego, encriptamos \(M_i\) con AES-GCM4, en el que la clave es\(\mathrm{DerivedKey}\), el vector de inicialización es \(\mathrm{IV}_i\)y los datos asociados son la string 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 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 del texto cifrado de forma individual.

Las APIs pueden (y suelen permitir) el acceso aleatorio o el acceso al principio de un archivo sin inspeccionar el final de este. 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 final de archivo con de desencriptación: en ambos casos, es probable que la API tenga que mostrar un error. Ignorar la diferencia puede llevar a 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 proporcionado en aes_gcm_hkdf_streaming.proto. El campo version debe establecerse en 0. Luego, serializamos esto con la serialización proto normal y, luego, incorporamos la cadena resultante en el valor de campo de un proto KeyData. Establecemos 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, establecemos output_prefix_type en RAW. La excepción es que, si la clave se analizó con un valor diferente establecido para output_prefix_type, Tink podría escribir RAW o el valor anterior.

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

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. Hoang, Reyhanitabar, Rogaway, Vizar, 2015 La encriptación autenticada en línea y su resistencia al uso inadecuado de la reutilización del nonce CRIPTO, 2015. https://eprint.iacr.org/2015/189 

  2. Hoang, Shen, 2020. Security of Streaming Encryption in Google's Tink Library. https://eprint.iacr.org/2020/1019 

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

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