AEAD de streaming AES-GCM-HKDF

Ce document définit formellement la fonction mathématique représentée par les clés de streaming AES-GCM-HKDF, encodées au format proto sous la forme type.googleapis.com/google.crypto.tink.AesGcmHkdfStreamingKey.

Ce chiffrement est basé sur HRRV151. Pour l'analyse de la sécurité, nous nous référons à la norme HS202.

Clé et paramètres

Les clés sont décrites par les parties suivantes (toutes les tailles de ce document sont exprimées en octets):

  • \(\mathrm{KeyValue}\), une chaîne d'octets.
  • \(\mathrm{CiphertextSegmentSize} \in \{1, 2, \ldots, 2^{31}-1\}\).
  • \(\mathrm{DerivedKeySize} \in \{16, 32\}\)
  • \(\mathrm{HkdfHashType} \in \{\mathrm{SHA1}, \mathrm{SHA256}, \mathrm{SHA512}\}\).

Les clés valides répondent également aux propriétés suivantes:

  • \(\mathrm{len}(\mathrm{KeyValue}) \geq \mathrm{DerivedKeySize}\).
  • \(\mathrm{CiphertextSegmentSize} > \mathrm{DerivedKeySize} + 24\) (ce qui équivaut à \(\mathrm{len}(\mathrm{Header}) + 16\) , comme expliqué plus loin).

Les clés qui ne répondent à aucune de ces propriétés sont rejetées par Tink, soit lors de l'analyse de la clé, soit lors de la création de la primitive correspondante.

Fonction de chiffrement

Pour chiffrer un message \(\mathrm{Msg}\) avec des données associées\(\mathrm{AssociatedData}\), nous créons un en-tête, divisons le message en segments, chiffrons chaque segment et concaténons les segments chiffrés.

Créer l'en-tête

Nous choisissons une chaîne aléatoire uniforme \(\mathrm{Salt}\) de longueur\(\mathrm{DerivedKeySize}\) et une chaîne aléatoire uniforme \(\mathrm{NoncePrefix}\)de longueur 7.

Nous définissons ensuite \(\mathrm{Header} := \mathrm{len}(\mathrm{Header}) \| \mathrm{Salt} \| \mathrm{NoncePrefix}\), où la longueur de l'en-tête est encodée en un seul octet. Notez que \(\mathrm{len}(\mathrm{Header}) \in \{24, 40\}\).

Ensuite, nous utilisons HKDF3 avec la fonction de hachage donnée par \(\mathrm{HkdfHashType}\)et les entrées \(\mathrm{ikm} := \mathrm{KeyValue}\), \(\mathrm{salt} := \mathrm{Salt}\)et \(\mathrm{info} := \mathrm{AssociatedData}\), avec une longueur de sortie \(\mathrm{DerivedKeySize}\). Nous appelons ce résultat \(\mathrm{DerivedKey}\).

Diviser le message

Le message \(\mathrm{Msg}\) est ensuite divisé en parties: \(\mathrm{Msg} = M_0 \| M_1 \| \cdots \| M_{n-1}\).

Leur longueur est choisie pour répondre aux critères suivants:

  • \(\mathrm{len}(M_0) \in \{0,\ldots, \mathrm{CiphertextSegmentSize} - \mathrm{len}(\mathrm{Header}) - \mathrm{16}\}\).
  • Si \(n>1\), alors \(\mathrm{len}(M_1), \ldots, \mathrm{len}(M_{n-1}) \in \{1,\ldots, \mathrm{CiphertextSegmentSize} - \mathrm{16}\}\).
  • Si \(n>1\), alors \(\mathrm{len}(M_{0}), \ldots, \mathrm{len}(M_{n-2})\) doit avoir une longueur maximale conformément aux contraintes ci-dessus.

\(n\) ne doit pas dépasser \(2^{32}\). Sinon, le chiffrement échoue.

Chiffrer les blocs

Pour chiffrer le segment \(M_i\), nous calculons \(\mathrm{IV}_i := \mathrm{NoncePrefix} \| \mathrm{i} \| b\), où \(\mathrm{i}\) correspond à 4 octets en codage big-endian et où l'octet $b$ est 0x00 si $i < n-1$ et 0x01 dans le cas contraire.

Nous chiffrons ensuite \(M_i\) à l'aide d'AES-GCM4, où la clé est\(\mathrm{DerivedKey}\), le vecteur d'initialisation est \(\mathrm{IV}_i\)et les données associées sont la chaîne vide. \(C_i\) est le résultat de ce chiffrement (c'est-à-dire la concaténation de \(C\) et \(T\) dans la section 5.2.1.2 de la référence AES-GCM associée).

Concatenate les segments chiffrés

Enfin, tous les segments sont concatenatés en tant que \(\mathrm{Header} \| C_0 \| \cdots \| C_{n-1}\), qui est le texte chiffré final.

Déchiffrement

Le déchiffrement inverse le chiffrement. Nous utilisons l'en-tête pour obtenir\(\mathrm{NoncePrefix}\)et déchiffrer chaque segment de texte chiffré individuellement.

Les API peuvent (et le font généralement) autoriser un accès aléatoire ou un accès au début d'un fichier sans inspecter la fin du fichier. Il s'agit d'une intention délibérée, car il est possible de déchiffrer \(M_i\) à partir de \(C_i\), sans déchiffrer tous les blocs de texte chiffré précédents et restants.

Toutefois, les API doivent veiller à ne pas permettre aux utilisateurs de confondre les erreurs de fin de fichier et de déchiffrement: dans les deux cas, l'API doit probablement renvoyer une erreur, et ignorer la différence peut permettre à un pirate informatique de tronquer efficacement des fichiers.

Sérialisation et analyse des clés

Pour sérialiser une clé au format "Tink Proto", nous mappons d'abord les paramètres de manière évidente dans le proto donné dans aes_gcm_hkdf_streaming.proto. Le champ version doit être défini sur 0. Nous sérialisons ensuite cette valeur à l'aide de la sérialisation de proto normale, puis intégrons la chaîne obtenue dans la valeur du champ d'un proto KeyData. Nous définissons le champ type_url sur type.googleapis.com/google.crypto.tink.AesGcmHkdfStreamingKey. Nous définissons ensuite key_material_type sur SYMMETRIC et l'intégrons dans un ensemble de clés. Nous définissons généralement output_prefix_type sur RAW. L'exception est que si la clé a été analysée avec une valeur différente définie pour output_prefix_type, Tink peut écrire RAW ou la valeur précédente.

Pour analyser une clé, nous inversons le processus ci-dessus (comme d'habitude lors de l'analyse des protocoles). Le champ key_material_type est ignoré. La valeur de output_prefix_type peut être ignorée, ou les clés dont output_prefix_type est différent de RAW peuvent être rejetées. Les clés dont l'version est différent de 0 doivent être rejetées.

Problèmes connus

Les implémentations de la fonction de chiffrement ci-dessus ne sont pas censées être compatibles avec la création de forks. Consultez la section Sécurité des forks.

Références


  1. Hoang, Reyhanitabar, Rogaway, Vizar, 2015. Chiffrement authentifié en ligne et sa résistance à l'utilisation abusive du nonce CRYPTO 2015. https://eprint.iacr.org/2015/189 

  2. Hoang, Shen, 2020. Sécurité de l'algorithme de chiffrement en streaming dans la bibliothèque Tink de Google. https://eprint.iacr.org/2020/1019 

  3. RFC 5869 Fonction de dérivation de clé (HKDF) basée sur l'extraction et l'expansion HMAC. https://www.rfc-editor.org/rfc/rfc5869 

  4. NIST SP 800-38D Recommandation pour les modes de fonctionnement des algorithmes de chiffrement par bloc : mode Galois/Counter (GCM) et GMAC. https://csrc.nist.gov/pubs/sp/800/38/d/final