Partager via


En-têtes de contexte dans ASP.NET Core

Arrière-plan et théorie

Dans le système de protection des données, une « clé » désigne un objet qui peut fournir des services de chiffrement authentifiés. Chaque clé est identifiée par un ID unique (un GUID) et elle contient des informations algorithmiques et du matériel entropique. Il est prévu que chaque clé comporte une entropie unique, mais le système ne peut pas l’appliquer, et nous devons également prendre en compte les développeurs qui peuvent modifier manuellement l’anneau de clés en modifiant les informations algorithmiques d’une clé existante dans l’anneau de clés. Pour répondre à nos exigences de sécurité dans ces cas, le système de protection des données a un concept d’agilité de chiffrement, qui permet d’utiliser en toute sécurité une seule valeur entropique sur plusieurs algorithmes de chiffrement.

La plupart des systèmes qui prennent en charge l’agilité de chiffrement le font en incluant des informations d’identification sur l’algorithme à l’intérieur de la charge utile. L’OID de l’algorithme est généralement un bon candidat pour cela. Toutefois, un problème que nous avons rencontré est qu’il existe plusieurs façons de spécifier le même algorithme : « AES » (CNG) et les classes Aes, AesManaged, AesCryptoServiceProvider, AesCng et RijndaelManaged (paramètres spécifiques donnés) sont en fait toutes la même chose, et nous devons maintenir un mappage de toutes ces classes vers l’OID correct. Si un développeur voulait fournir un algorithme personnalisé (ou même une autre implémentation d’AES!), il doit nous indiquer son OID. Cette étape d’inscription supplémentaire rend la configuration système particulièrement pénible.

En réfléchissant, nous avons décidé que nous abordions le problème de la mauvaise direction. Un OID vous indique ce qu’est l’algorithme, mais nous ne nous en soucions pas vraiment. Si nous devons utiliser une seule valeur entropique en toute sécurité dans deux algorithmes différents, il n’est pas nécessaire pour nous de savoir ce que sont réellement les algorithmes. Ce qui nous importe en fait, c’est la façon dont ils se comportent. Tout algorithme de chiffrement de blocs symétriques décent est également une permutation pseudo-aléatoire forte (PRP) : corriger les entrées (clé, mode de chaînage, IV, texte clair) et la sortie de texte de chiffrement sera avec une probabilité écrasante distincte de tout autre algorithme de chiffrement de blocs symétriques en fonction des mêmes entrées. De même, toute fonction de hachage à clé décente est également une fonction pseudo-aléatoire (PRF) forte et, pour un ensemble d'entrées fixe, sa sortie sera très majoritairement distincte de toute autre fonction de hachage à clé.

Nous utilisons ce concept de PRP et de PRFs forts pour créer un en-tête de contexte. Cet en-tête de contexte agit essentiellement comme une empreinte numérique stable sur les algorithmes utilisés pour une opération donnée, et il fournit l’agilité de chiffrement requise par le système de protection des données. Cet en-tête est reproductible et est utilisé ultérieurement dans le cadre du processus de dérivation de sous-clé. Il existe deux façons différentes de générer l’en-tête de contexte en fonction des modes de fonctionnement des algorithmes sous-jacents.

Chiffrement en mode CBC + authentification HMAC

L'en-tête de contexte se compose des éléments suivants :

  • [16 bits] Valeur 00 00, qui est un marqueur qui signifie « chiffrement CBC + authentification HMAC ».

  • [32 bits] Longueur de clé (en octets, big-endian) de l’algorithme de chiffrement de blocs symétriques.

  • [32 bits] Taille de clé (en octets, big-endian) de l’algorithme de chiffrement de blocs symétriques.

  • [32 bits] Longueur de clé (en octets, big-endian) de l’algorithme HMAC. (Actuellement, la taille de la clé correspond toujours à la taille de synthèse.)

  • [32 bits] Taille de synthèse (en octets, big-endian) de l’algorithme HMAC.

  • EncCBC(K_E, IV, ""), qui est la sortie de l’algorithme de chiffrement de blocs symétriques en fonction d’une entrée de chaîne vide et où IV est un vecteur tout zéro. La construction de K_E est décrite ci-dessous.

  • MAC(K_H, ""), qui est la sortie de l’algorithme HMAC avec une entrée de chaîne vide. La construction de K_H est décrite ci-dessous.

Dans l’idéal, nous pourrions passer des vecteurs tout zéro pour K_E et K_H. Toutefois, nous voulons éviter la situation où l’algorithme sous-jacent vérifie l’existence de clés faibles avant d’effectuer des opérations (notamment DES et 3DES), ce qui empêche l’utilisation d’un modèle simple ou reproductible comme un vecteur tout zéro.

Au lieu de cela, nous utilisons le NIST SP800-108 KDF en mode compteur (voir NIST SP800-108, sec. 5.1) avec une clé de longueur nulle, une étiquette et un contexte et HMACSHA512 comme PRF sous-jacent. Nous dérivons | K_E | + | K_H | des octets de sortie, puis nous décomposons le résultat en K_E et K_H eux-mêmes. Mathématiquement, cela est représenté comme suit.

( K_E || K_H ) = SP800_108_CTR(prf = HMACSHA512, key = "", label = "", context = "")

Exemple : AES-192-CBC + HMACSHA256

Par exemple, considérez le cas où l’algorithme de chiffrement de blocs symétriques est AES-192-CBC et où l’algorithme de validation est HMACSHA256. Le système génère l’en-tête de contexte en procédant comme suit.

Tout d’abord, laissez ( K_E || K_H ) = SP800_108_CTR(prf = HMACSHA512, key = "", label = "", context = ""), où | K_E | = 192 bits et | K_H | = 256 bits selon les algorithmes spécifiés. Cela conduit à K_E = 5BB6..21DD et K_H = A04A..00A9 dans l’exemple ci-dessous :

5B B6 C9 83 13 78 22 1D 8E 10 73 CA CF 65 8E B0
61 62 42 71 CB 83 21 DD A0 4A 05 00 5B AB C0 A2
49 6F A5 61 E3 E2 49 87 AA 63 55 CD 74 0A DA C4
B7 92 3D BF 59 90 00 A9

Ensuite, calcul Enc_CBC (K_E, IV, "") pour AES-192-CBC donné IV = 0* et K_E comme ci-dessus.

result := F474B1872B3B53E4721DE19C0841DB6F

Ensuite, calcul MAC(K_H, "") pour HMACSHA256 donné K_H comme ci-dessus.

result := D4791184B996092EE1202F36E8608FA8FBD98ABDFF5402F264B1D7211536220C

Cela génère l’en-tête de contexte complet ci-dessous :

00 00 00 00 00 18 00 00 00 10 00 00 00 20 00 00
00 20 F4 74 B1 87 2B 3B 53 E4 72 1D E1 9C 08 41
DB 6F D4 79 11 84 B9 96 09 2E E1 20 2F 36 E8 60
8F A8 FB D9 8A BD FF 54 02 F2 64 B1 D7 21 15 36
22 0C

Cet en-tête de contexte est l’empreinte numérique de la paire d’algorithmes de chiffrement authentifié (chiffrement AES-192-CBC + validation HMACSHA256). Les composants, comme décrit ci-dessus sont les suivants :

  • le marqueur (00 00)

  • longueur de clé de chiffrement de bloc (00 00 00 18)

  • taille du bloc de chiffrement de blocs (00 00 00 10)

  • longueur de clé HMAC (00 00 00 20)

  • taille de synthèse HMAC (00 00 00 20)

  • la sortie PRP de chiffrement de bloc (F4 74 - DB 6F) et

  • la sortie HMAC PRF (D4 79 - end).

Notes

L’en-tête de contexte d’authentification en mode CBC + HMAC est généré de la même façon, que les implémentations d’algorithmes soient fournies par Windows CNG ou par les types SymmetricAlgorithm et KeyedHashAlgorithm managés. Cela permet aux applications s’exécutant sur différents systèmes d’exploitation de produire de manière fiable le même en-tête de contexte, même si les implémentations des algorithmes diffèrent d’un système d’exploitation à l’autre. (En pratique, le KeyedHashAlgorithm n’a pas besoin d’être un HMAC approprié. Il peut s’agir de n’importe quel type d’algorithme de hachage à clé.)

Exemple : 3DES-192-CBC + HMACSHA1

Tout d’abord, laissez ( K_E || K_H ) = SP800_108_CTR(prf = HMACSHA512, key = "", label = "", context = ""), où | K_E | = 192 bits et | K_H | = 160 bits selon les algorithmes spécifiés. Cela conduit à K_E = A219..E2BB et K_H = DC4A..B464 dans l’exemple ci-dessous :

A2 19 60 2F 83 A9 13 EA B0 61 3A 39 B8 A6 7E 22
61 D9 F8 6C 10 51 E2 BB DC 4A 00 D7 03 A2 48 3E
D1 F7 5A 34 EB 28 3E D7 D4 67 B4 64

Ensuite, calcul Enc_CBC (K_E, IV, "") pour 3DES-192-CBC donné IV = 0* et K_E comme ci-dessus.

result := ABB100F81E53E10E

Ensuite, calcul MAC(K_H, "") pour HMACSHA1 donné K_H comme ci-dessus.

result := 76EB189B35CF03461DDF877CD9F4B1B4D63A7555

Cela produit l’en-tête de contexte complet qui est une empreinte de la paire d’algorithmes de chiffrement authentifié (chiffrement 3DES-192-CBC + validation HMACSHA1), illustrée ci-dessous :

00 00 00 00 00 18 00 00 00 08 00 00 00 14 00 00
00 14 AB B1 00 F8 1E 53 E1 0E 76 EB 18 9B 35 CF
03 46 1D DF 87 7C D9 F4 B1 B4 D6 3A 75 55

Les composants se décomposent comme suit :

  • le marqueur (00 00)

  • longueur de clé de chiffrement de bloc (00 00 00 18)

  • taille du bloc de chiffrement de blocs (00 00 00 08)

  • longueur de clé HMAC (00 00 00 14)

  • taille de synthèse HMAC (00 00 00 14)

  • la sortie PRP de chiffrement de bloc (AB B1 - E1 0E) et

  • la sortie HMAC PRF (76 EB - end).

Chiffrement Galois/Counter Mode + authentification

L'en-tête de contexte se compose des éléments suivants :

  • [16 bits] Valeur 00 01, qui est un marqueur qui signifie « chiffrement GCM + authentification ».

  • [32 bits] Longueur de clé (en octets, big-endian) de l’algorithme de chiffrement de blocs symétriques.

  • [32 bits] Taille de nonce (en octets, big-endian) utilisée lors des opérations de chiffrement authentifiées. (Pour notre système, cela est résolu à la taille nonce = 96 bits.)

  • [32 bits] Taille de clé (en octets, big-endian) de l’algorithme de chiffrement de blocs symétriques. (Pour GCM, cela est résolu à la taille de bloc = 128 bits.)

  • [32 bits] Taille de la balise d’authentification (en octets, big-endian) produite par la fonction de chiffrement authentifiée. (Pour notre système, cela est résolu à la taille de balise = 128 bits.)

  • [128 bits] La balise deEnc_GCM (K_E, nonce, ""), qui est la sortie de l’algorithme de chiffrement de blocs symétriques en fonction d’une entrée de chaîne vide et où nonce est un vecteur tout zéro 96-bit.

K_E est dérivé à l’aide du même mécanisme que dans le scénario d’authentification de chiffrement CBC + HMAC. Toutefois, comme il n’y a pas K_H de jeu ici, nous avons essentiellement | K_H | = 0, et l’algorithme se réduit à la forme ci-dessous.

K_E = SP800_108_CTR(prf = HMACSHA512, key = "", label = "", context = "")

Exemple : AES-256-GCM

Tout d’abord, laissez K_E = SP800_108_CTR(prf = HMACSHA512, key = "", label = "", context = ""), où | K_E | = 256 bits.

K_E := 22BC6F1B171C08C4AE2F27444AF8FC8B3087A90006CAEA91FDCFB47C1B8733B8

Ensuite, calculez la balise d’authentification de Enc_GCM (K_E, nonce, "") pour AES-256-GCM donnée nonce = 096 et K_E comme ci-dessus.

result := E7DCCE66DF855A323A6BB7BD7A59BE45

Cela génère l’en-tête de contexte complet ci-dessous :

00 01 00 00 00 20 00 00 00 0C 00 00 00 10 00 00
00 10 E7 DC CE 66 DF 85 5A 32 3A 6B B7 BD 7A 59
BE 45

Les composants se décomposent comme suit :

  • le marqueur (00 01)

  • longueur de clé de chiffrement de bloc (00 00 00 20)

  • la taille nonce (00 00 00 0C)

  • taille du bloc de chiffrement de blocs (00 00 00 10)

  • la taille (00 00 00 10) de la balise d’authentification et

  • la balise d’authentification à partir de l’exécution du chiffrement de bloc (E7 DC - end).