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 respectent pas l'une de ces propriétés sont rejetées par Tink, soit lorsque la clé est analysée, soit lorsque la primitive correspondante est créée.
Fonction de chiffrement
Pour chiffrer un message \(\mathrm{Msg}\) avec les données associées\(\mathrm{AssociatedData}\), nous créons un en-tête, scindons le message en segments, puis nous 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 fournie 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\) en utilisant 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 lié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
-
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 ↩
-
Hoang, Shen, 2020. Security of Streaming Encryption in Google's Tink Library (Sécurité du chiffrement en continu dans la bibliothèque Tink de Google). https://eprint.iacr.org/2020/1019 ↩
-
RFC 5869. Fonction de dérivation de clé d'extraction et de développement (HKDF) basée sur le protocole HMAC. https://www.rfc-editor.org/rfc/rfc5869
-
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 ↩