Derivación de subclave y cifrado autenticado en ASP.NET Core
La mayoría de las claves del anillo de claves contendrán alguna forma de entropía y tendrán información algorítmica que indica "Cifrado en modo CBC + validación HMAC" o "Cifrado GCM + validación". En estos casos, nos referimos a la entropía incrustada como material de clave maestra (o CM) para esta clave, y realizamos una función de derivación de claves para derivar las que se usarán en las operaciones criptográficas reales.
Nota:
Las claves son abstractas y es posible que una implementación personalizada no se comporte como se indica a continuación. Si la clave proporciona su propia implementación de IAuthenticatedEncryptor
en lugar de usar uno de nuestros generadores integrados, el mecanismo descrito en esta sección ya no se aplica.
Derivación de subclaves y datos autenticados adicionales
La interfaz IAuthenticatedEncryptor
actúa como interfaz principal para todas las operaciones de cifrado autenticadas. El método Encrypt
toma dos búferes: texto no cifrado y additionalAuthenticatedData (AAD). Los contenidos de texto no cifrado conducen la llamada sin cambios a IDataProtector.Protect
, pero la AAD es generada por el sistema y consta de tres componentes:
El encabezado magic de 32 bits 09 F0 C9 F0 que identifica esta versión del sistema de protección de datos.
Identificador de clave de 128 bits.
Cadena de longitud variable formada a partir de la cadena de propósito que creó el objeto
IDataProtector
que realiza esta operación.
Dado que AAD es único para la tupla de los tres componentes, podemos usarlo para derivar nuevas claves de CM en lugar de usarla en todas nuestras operaciones criptográficas. Para cada llamada a IAuthenticatedEncryptor.Encrypt
, se realiza el siguiente proceso de derivación de claves:
( K_E, K_H ) = SP800_108_CTR_HMACSHA512(K_M, AAD, contextHeader || keyModifier)
En este caso, llamamos a NIST SP800-108 KDF en modo counter (consulte NIST SP800-108, Sec. 5.1) con los parámetros siguientes:
Clave de derivación de claves (CDC) =
K_M
PRF = HMACSHA512
etiqueta = additionalAuthenticatedData
contexto = contextHeader || keyModifier
El encabezado de contexto es de longitud variable y básicamente actúa como huella digital de los algoritmos para los que derivamos K_E
y K_H
. El modificador de clave es una cadena de 128 bits generada aleatoriamente para cada llamada a Encrypt
y sirve para garantizar con una probabilidad abrumadora de que KE y KH sean únicas para esta operación de cifrado de autenticación específica, incluso si todas las demás entradas para la KDF son constantes.
En el caso del cifrado en modo CBC + operaciones de validación de HMAC, | K_E |
es la longitud de la clave de cifrado de bloque simétrico y | K_H |
es el tamaño de síntesis de la rutina HMAC. Para las operaciones de cifrado GCM + validación, | K_H | = 0
.
Cifrado en modo CBC + validación HMAC
Una vez que K_E
se genera a través del mecanismo anterior, generamos un vector de inicialización aleatorio y ejecutamos el algoritmo de cifrado de bloques simétricos para cifrar el texto no cifrado. A continuación, el vector de inicialización y el texto cifrado se ejecutan a través de la rutina HMAC inicializada con la clave K_H
para generar el MAC. Este proceso y el valor devuelto se representan gráficamente a continuación.
output:= keyModifier || iv || E_cbc (K_E,iv,data) || HMAC(K_H, iv || E_cbc (K_E,iv,data))
Nota:
La implementación IDataProtector.Protect
antepondrá el encabezado magic y el identificador de clave para generarlos antes de devolverlo al autor de la llamada. Debido a que el encabezado magic y el identificador de clave forman parte implícita de AAD y el modificador de clave se alimenta como entrada para la KDF, significa que el MAC autentica cada byte de la carga final devuelta.
Cifrado del modo galois/counter + validación
Una vez que K_E
se genera a través del mecanismo anterior, generamos un nonce de 96 bits aleatorio y ejecutamos el algoritmo de cifrado de bloque simétrico para cifrar el texto no cifrado y generar la etiqueta de autenticación de 128 bits.
output := keyModifier || nonce || E_gcm (K_E,nonce,data) || authTag
Nota:
Aunque GCM admite de forma nativa el concepto de AAD, todavía estamos alimentando AAD solo al KDF original, optando por pasar una cadena vacía a GCM para el parámetro de AAD. El motivo para esto es doble. En primer lugar, para dar apoyo a la agilidad nunca queremos usar K_M
directamente como clave de cifrado. Además, GCM impone requisitos de unicidad muy estrictos en sus entradas. La probabilidad de que la rutina de cifrado de GCM se invoque en dos o más conjuntos distintos de datos de entrada con el mismo par (clave, nonce) no debe superar los 2^-32. Si corregimos K_E
no podemos realizar más de 2^32 operaciones de cifrado antes de llegar al límite de 2^-32. Esto puede parecer un gran número de operaciones, pero un servidor web de alto tráfico puede pasar por 4 mil millones de solicitudes en tan solo días, dentro de la duración normal de estas claves. Para mantener la conformidad con el límite de probabilidad de 2^-32, seguimos usando un modificador de clave de 128 bits y nonce de 96 bits, que amplía radicalmente el recuento de operaciones utilizables para cualquier K_M
dado. Para simplificar el diseño, compartimos la ruta de acceso del código KDF entre las operaciones de CBC y GCM, y dado que AAD ya se considera en la KDF, no es necesario reenviarlo a la rutina de GCM.