AEAD de streaming AES-GCM-HKDF

Ce document définit formellement la fonction mathématique représentée par des 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 globalement basé sur la norme HRRV151. Pour l'analyse de la sécurité, nous faisons référence à HS202.

Clé et paramètres

Les clés sont décrites dans 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\) (É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 les données associées\(\mathrm{AssociatedData}\), nous créons un en-tête, nous scindons le message en segments, nous chiffrons chaque segment et nous 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 la longueur de la sortie \(\mathrm{DerivedKeySize}\). Nous appelons ce résultat \(\mathrm{DerivedKey}\).

Diviser le message

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

Leur durée est choisie en fonction des 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 la valeur est \(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 échouera.

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 avec un encodage big-endian et 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 (autrement dit, la concaténation de \(C\) et \(T\) à la section 5.2.1.2 de la documentation de référence AES-GCM associée).

Concaténer les segments chiffrés

Enfin, tous les segments sont concaténés sous la forme \(\mathrm{Header} \| C_0 \| \cdots \| C_{n-1}\), qui correspond au 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 du texte chiffré individuellement.

Les API peuvent (et c'est généralement le cas) autoriser un accès aléatoire ou l'accès au début d'un fichier sans inspecter la fin du fichier. C'est intentionnel, 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. Ignorer la différence peut permettre à un adversaire de tronquer efficacement les fichiers.

Sérialisation et analyse des clés

Pour sérialiser une clé au format "Tink Proto", nous devons d'abord mapper les paramètres de manière évidente dans le proto indiqué dans aes_gcm_hkdf_streaming.proto. Le champ version doit être défini sur 0. Nous sérialisons ensuite cela à l'aide d'une sérialisation proto normale et 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 à une collection 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 un ensemble de valeurs différent pour output_prefix_type, Tink peut écrire RAW ou la valeur précédente.

Pour analyser une clé, nous inverserons le processus ci-dessus (de la manière habituelle lors de l'analyse des protos). Le champ key_material_type est ignoré. La valeur de output_prefix_type peut être ignorée, ou les clés dont l'attribut output_prefix_type est différent de RAW peuvent être refusées. Les clés dont l'version est différente de 0 doivent être refusées.

Problèmes connus

Les implémentations de la fonction de chiffrement ci-dessus ne sont pas censées être sécurisées. Consultez la section Sécurité de la fourche.

Références


  1. Hoang, Reyhanitabar, Rogaway, Vizar, 2015. le chiffrement authentifié en ligne et sa résistance à la mauvaise utilisation de la nonce-réutilisation. CRYPTO 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. Fonction de dérivation de clé d'extraction et de développement (HKDF) basée sur le HMAC. https://www.rfc-editor.org/rfc/rfc5869 

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