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
-
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 ↩
-
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 ↩
-
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 ↩
-
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 ↩