Advanced Encryption Standard résistant dans un contexte
Transcription
Advanced Encryption Standard résistant dans un contexte
Advanced Encryption Standard résistant dans un contexte Boı̂te Blanche Rémy REY May 13, 2015 1 1 Introduction L’Advanced Encryption Standart (AES) définit une référence pour la cryptographie symétrique moderne depuis 2000. Cependant, si sa conception le rend résistant aux attaques sur un message chiffré, elle ne s’attaque ni au problème de partage de clef qui relève de la cryptographie symétrique, ni au problème de confiance en l’hôte (ou la machine) qui l’exécute. Il va de soi que la cryptographie asymétrique permet déjà d’échanger des clefs, ce ne sera donc pas le problème soulevé ici. En revanche, la sûreté de l’environnement d’exécution est une question épineuse. Laisser une clef secrète en clair sur une machine possiblement infectée, ou entre les mains d’un tiers malveillant, peut être compromettant pour une zone de sécurité (celle dont on donne l’accès avec la clef). Considérer un tel cas de figure peut sembler étrange, c’est pourquoi il est nécessaire de se placer d’un point de vue un peu particulier : celui de l’industrie multimédia. En effet, l’industrie multimédia (maison de disques, studios, jeux vidéos, cinéma) subit des pertes considérables à cause du piratage et du partage de fichier. C’est pourquoi ils ont besoin de se prémunir des attaques sur le contenu distribué en le chiffrant. Comme chaque utilisateur est un pirate potentiel, il faut donc introduire un contrôle de ces données, ce qu’on appelle la Gestion Numérique des Droits ou DRM (Digital Right Managment en anglais). C’est ce contexte particulier qui nécessite un nouveau mode de cryptage. On doit pouvoir décrypter sur la machine du client sans pour autant lui fournir la clef, et en personnalisant l’algorithme pour restreindre l’utilisation à ce seul client. Nous allons ici étudier une méthode, proposée à l’origine par Chow et al.[6] et explicité par Muir[3] qui permet de transformer le standard pour tenter de le rendre plus résistant, c’est-à-dire essayer de le protéger dans un contexte plus général qu’a l’accoutumée. 2 A propos des différents contextes d’attaque Pour comprendre l’enjeu de la construction, nous allons délimiter le contexte des attaques sur le système de chiffrement. En effet, un cryptosystème n’a de sens que lorsqu’il est plongé dans un contexte d’attaque bien défini. Il faut distinguer les limites technologiques et les hypothèses d’attaque. Il est par exemple admis que quelque soit la nature de l’attaquant, une attaque brute nécessitant 2100 opérations élémentaires est aujourd’hui hors de portée. En revanche, on peut émettre certaines hypothèses concernant les connaissances de l’attaquant (sur du hardware par exemple) ou sur son accès à l’exécution du programme cible. Aussi une implantation, ou un système qui peut être considérer comme sûr dans un contexte, ne fonctionnera plus forcément dans un contexte plus général. On va donc définir trois contextes généraux d’attaque hiérarchisés pour expliquer précisément pourquoi l’AES standard n’est plus adapté dans le cas évoqué en introduction. 2.1 Boite Noire La boı̂te noire est le cas le plus favorable pour la défense. On considère que l’attaquant ne voit l’algorithme que comme un oracle qui répond selon les entrées 2 fournies. Les hypothèses sur les pouvoirs de l’attaquant peuvent influencer la complexité des attaques : connaissance du clair, clair choisi, chiffré choisi, etc. Un exemple simple est l’attaquant observant du trafic crypté sur le réseau. Dans cette situation un AES standard en mode CBC est résistant et aucune attaque praticable n’est à ce jour connue. Évidemment, cela nécessite d’avoir des machines parfaitement sécurisées et que le client derrière la machine soit quelqu’un de confiance, et cette hypothèse peut sembler utopiste. On comprend bien qu’au delà d’une simple application aux DRM, le contexte de boı̂te noire est peut être un peu trop restrictif et que le design d’algorithme plus résistant va devenir une nécessité pour augmenter la sécurité. 2.2 Boite Grise Ici, l’attaquant dispose bien évidemment de la boite noire, mais également d’un accès indirect à l’exécution. Il va pouvoir déployer ce que l’on appelle les attaques par canaux auxiliaires (Side-channel Attacks en anglais). On peut collecter des données physiques lors de l’exécution comme le temps d’exécution, la consommation énergétique, le bruit acoustique, les émanations électromagnétiques. On va ensuite les mettre à profit pour en déduire des informations sur la clef ou même l’implantation. On peut également essayer de générer des fautes en espérant que la machine fuite des informations via ses registres ou sa RAM. Un exemple simple de boı̂te grise est une carte bancaire. En effet, on connaı̂t l’algorithme exécuté qui est issu des standards en la matière (donc soit RSA, soit ECC) et on a accès à la carte (moyennant un peu de matériel, on peut la questionner avec différentes entrées et récupérer ses réponses). Cependant, l’architecture reste partiellement inconnue, et l’accès aux registres reste compliqué du fait des protections du hardware. On a donc un système relativement bien protégé du point de vue purement informatique, et pourtant, il était à la base très fragile à cause des informations physique émises. Une des premières attaques développée passait par l’analyse de la consommation énergétique de la carte. En effet, lors de l’exécution on doit porter un nombre m à une puissance d qui se trouve être la clef secrète. La fonction d’exponentiation associée est la suivante : int p u i s s a n c e ( int m, int d ) = { i f ( d == 0 ) return 1 ; int r e s = p u i s s a n c e (m, d >> 1 ) ; res = res ∗ res ; i f ( ! ( d && 1 ) ) { return r e s ∗ m; } else { return r e s ; } } Il s’agit de l’exponentiation rapide récursive. A chaque étape on élève au carré et on divise l’exposant par deux, si l’exposant est impair, il faut une multiplication supplémentaire. Cette multiplication introduit une sur-consommation 3 d’énergie pour chaque bit de clef valant 1. On peut donc aisément lire sur un oscilloscope la valeur de la clef. Cette attaque est relativement simple et une contre-mesure fût apportée rapidement, en uniformisant le calcul : int p u i s s a n c e ( int m, int d ) = { i f ( d == 0 ) return 1 ; int r e s = p u i s s a n c e (m, d >> 1 ) ; res = res ∗ res ; i f ( ! ( d && 1 ) ) { r e s = r e s ∗ m; } else { r e s ∗ m; } return r e s ; } La deuxième opération ne sert pas, mais génère quand même l’énergie nécessaire pour uniformiser l’énergie mesurée. On constate donc que même si un système présente les caractéristiques d’une boı̂te noire, il est souvent difficile d’assurer ce contexte parfaitement. D’une part les capteurs physiques deviennent de plus en plus puissants, d’autre part on ne peut pas envisager tous les moyens d’attaques possibles, ce qui entraı̂ne une course entre attaques et contre-mesures. Cela justifie déjà la volonté de se placer dans le pire des cas qui soit et de supposer un attaquant tout puissant sur la plate-forme d’exécution. 2.3 Boı̂te Blanche On donne maintenant les pleins pouvoirs à l’attaquant. Il dispose d’un accès complet à la machine et au code, peut exécuter le programme via un débogueur, peut choisir autant d’entrées qu’il le souhaite, peut tenter de régénérer le code source. Il faut donc apporter des contre-mesures à chacun des aspects évoqués ci-dessus. Le premier constat que l’on peut faire est que la clef ne doit pas apparaı̂tre en clair dans la mémoire. Il est donc nécessaire de la diffuser dans l’algorithme de manière à pouvoir l’utiliser sans la révéler. Un AES standard échoue déjà à cette tâche puisqu’il faut lui donner la clef en clair en argument pour qu’il fonctionne. En ce qui concerne l’algorithmique et le reverse engineering, la tâche est plus délicate. On peut supposer que l’adversaire connaı̂t l’algorithme utilisé, qu’il a par exemple connaissance de cet article, et que par conséquent, il sait quel type de données et de variables il doit chercher. L’offuscation du code source constitue donc une solution mitigée. Elle ne servira après tout qu’à ralentir ou à augmenter les ressources nécessaires à l’attaque. La question est de quantifier cette apport de difficulté. Là encore le standard ne présente aucune protection 4 : le code source est disponible et l’exécution via un déboguer révèle la totalité des informations. Enfin le choix des entrées du programme est un problème. En effet, pouvoir choisir ses entrées permet de monter une analyse statistique sur l’implantation qui peut lâcher des informations sur une partie de la clef secrète, et donc diminuer la complexité d’une attaque. Il s’agira donc de modifier les entrées pour en supprimer le contrôle. La norme définie pour AES constitue un système résistant dans le cadre d’un usage particulier (exécution dans un environnement de confiance). Nous voulons prendre plus de cas d’attaque en ligne compte et cela souligne forcément les faiblesses du premier modèle plongé dans ce contexte. En contre partie, l’implantation présentée ici n’atteindra pas les mêmes niveaux de résistances dans le contexte boı̂te blanche (la complexité des attaques sera bien inférieure à 2128 si on dispose du code source par exemple). Commençons par analyser la composition de ce fameux algorithme. 3 Advanced Encryption Standart Ce standard a été conçu en 2000 par Joan Daemen et Vincent Rijmen [1]. Il est depuis décrit comme l’algorithme de référence pour la cryptographie symétrique dans le FIPS 197[4]. 3.1 Le corps fini de Rijndael Commençons par définir le corps fini F28 . En effet les octets servent de représentation aux éléments d’un corps spécial, défini lors de la conception du standard et qui induit une opération particulière. D’un point de vue purement mathématique, tous les corps de ce cardinal sont identiques, mais pour l’algorithmique, ils diffèrent. Le choix effectué est donc celui d’une opération. Le corps est défini comme l’ensemble des polynômes à coefficient binaire (i.e. appartenant à F[X]) modulo un polynôme primitif. Un polynôme primitif P est un polynôme irréductible, et de plus, si α était une racine de ce polynôme, alors : F2 (α)X = {αi , i = 1, . . . #F2 [α] − 1} (1) La racine d’un polynôme primitif génère les éléments inversibles du corps. On note que #F2 [α] = deg(P ), il faut choisir le polynôme en relation avec la taille de l’espace que l’on veut représenter. Dans notre cas, nous choisissons le polynôme P (X) = X 8 +X 4 +X 3 +X 2 +1. Chaque octet représente alors un polynôme de degré 7, chaque bit étant la valeur du coefficient devant un monôme X i . L’opération d’additionLest assez naturellement définie comme le ’ou exclusif’ logique (aka xor noté ). L’opération de multiplication est définie comme la multiplication des polynômes modulo le polynôme primitif P. Cela donne en pratique un algorithme particulier sur les octets. 5 3.2 L’algorithme L’algorithme de l’AES est composé de différentes opérations sur les 16 octets de l’état. Ces opérations constituent le cœur de l’algorithme qui est répété dans un certain nombre de rondes (de l’anglais round ). Nous étudions ici la version 128 bits du standard, cependant les versions 192 et 256 bits ne diffèrent que par la génération de la clef complète et dans le nombre d’itérations. Nous détaillons ci-dessous les différentes opérations dans une optique de comprendre leur nécessité dans la conception et de déterminer une manière naturelle et sécurisée d’y intégrer la clef. Subbytes Opération de substitution des octets. Pour rendre plus difficile la cryptanalyse, on choisit une bijection, fortement non linéaire. SubBytes compose une opération d’inversion dans le corps fini de Rijndael F28 avec une transformation affine (explicité par l’équation 2) sur le même corps vu en tant qu’espace vectoriel. f (X) = 1 1 1 1 1 0 0 0 0 1 1 1 1 1 0 0 0 0 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 0 0 0 1 •X + 1 1 0 0 0 1 1 0 (2) Shiftrows Change l’ordre des octets dans l’état. Cette opération est censé apporter la diffusion dans l’algorithme, c’est à dire, mélanger au mieux les octets de l’état entre les différentes opérations. En effet, chaque ronde opère en parallèle sur les quatre colonnes de l’état, composée chacune de 4 octets. Il s’agit donc de mélanger ces colonnes en décalant les lignes. La première ligne reste en place, la deuxième est décalée de une case vers la droite, la troisième de deux cases et la quatrième de trois cases. 0 1 2 3 4 5 6 7 8 9 10 11 12 0 5 13 ⇒ 10 14 15 15 4 9 14 3 8 13 2 7 12 1 6 11 (3) Si on représente l’état en ligne, on obtient une permutation de Z/16Z qui correspond également à la génération de ce groupe muni de l’addition, par l’élément 5. 0 5 10 15 4 9 14 3 8 2 7 12 1 6 11 (4) MixColumns Multiplication de chaque colonne de l’état avec une matrice MC. 02 03 01 01 01 02 03 01 MC = (5) 01 01 02 03 03 01 01 02 6 Figure 1: Schéma de ShiftRows avec deux état de 128 bits Chaque colonne est considérée comme un vecteur de taille 4 à valeur dans F28 . L’état devient les colonnes résultants des quatre multiplications avec M C. Cette opération linéaire sur les octets permet d’ajouter de la diffusion entre les 4 valeurs d’une colonne de l’état. Du fait de sa combinaison avec ShiftRows, à la fin d’une ronde la sortie devient dépendante de tous les bits de l’entrée. AddRoundKey opération binaire xor avec un bloc de 128 bits dérivés de la clef. Cette opération ajoute à chaque ronde une couche de confusion liée à la clef. Cela permet de brouiller l’état à chaque exécution du cœur de l’algorithme. Déroulement L’algorithme consiste en une alternance de ces différentes opérations sur 10 itérations (uniquement en AES 128 bit, le nombre est plus important pour les autres versions). On peut noter la présence d’une ronde 0, où on ajoute seulement la clef primitive (a partir de laquelle on va dériver 10 clefs secondaires de 128 bits chacune). De plus, dans la dernière ronde, on n’effectue pas l’opération MixColumns parce qu’elle n’apporte pas grand chose à la sécurité de l’ensemble et qu’elle constituerait un surcoût inutile. AddRoundKey(0) for i in 1..9 SubBytes Shiftrows MixColumn AddRoundKey(i) SubBytes Shitrows AddRoundKey(10) 3.3 L’implantation de référence Dans l’implantation, on manipule un état de 16 octets d’information (représenté par une matrice de 4x4 octets). L’implantation tabule les opérations au détriment d’un peu de place en mémoire. Tabuler un ensemble d’opération f revient à pré-calculer la sortie associée à chaque entrée possible, et à l’enregistrer dans une table. Ainsi, le programme 7 n’a plus qu’a lire la valeur f (x) à l’indice x de la table. L’idée est bien sûr que l’ensemble des opérations correspondant à une table coûte plus cher qu’un accès. Pour le mode 128 bits, on dispose de 4 tables T ei (i ∈ 0..3), qui contiennent chacune SubBytes et une partie de MixColumns (détails ci-dessous). ShiftRows est effectué avant SubBytes en mappant les octets de l’état dans les bonnes tables. Une dernière opération xor avec un bloc de clef dérivée réalise le AddRoundKey(i). Opération MixColumns Pour cette opération, on décompose la multiplication du vecteur d’entrée (vecteurs de 4 octets [x0 , x1 , x2 , x3 ]) par la matrice MC en quatre multiplication de colonnes par un scalaire, et 3 xor. 01 01 x 03 3 02 (6) Chacune de ces multiplications de colonne par un scalaire x appartenant à F256 est tabulé. On n’a donc qu’à lire la valeur dans la table correspondante à l’indice x. Cette table comporte donc 256 entrées de mots de 32 bits, pour relier chaque octet possible en entrée à un résultat. Bien évidemment, l’opération de substitution des octets est également tabulée et cette table est composée avec les quatre tables découlant de MixColumns ce qui limite les accès lors de l’exécution. En définitive, une ronde d’AES classique ne nécessite que 16 accès à des tableaux ainsi que quelques opérations bits à bits (exactement 12 décalages, 12 and et 16 xor 32 bits). 02 01 01 03 4 03 02 01 01 01 03 02 01 01 x0 x1 01 03 x2 02 x3 02 01 = 01 x0 ⊕ 03 03 02 x ⊕ 01 1 01 01 03 x ⊕ 02 2 01 Implantation boite blanche Nous allons a présent nous intéresser a la transformation de cet algorithme, en une version boı̂te blanche. L’idée principale étant d’embarquer la clef au cœur de l’implantation (et donc, de ne plus l’avoir comme entrée du programme) et de la protéger par des couches d’offuscation aléatoires. La clef ne doit plus apparaı̂tre dans les registres lors de l’exécution, et tous les éléments qui en dépendent doivent être considérés comme autant de secrets à encrypter. Le code que nous allons donc générer sera instancié avec une clef particulière et ne pourra donc calculer les cipher de l’AES que pour cette clef. On peut dès lors gérer la communication avec une personne sans lui confier le secret de la clef. 4.1 Le principe de la protection Pour mener a bien cette tâche, nous allons dans un premier temps tabuler toutes les opérations. Avoir les opérations effectuées par la machine compromettrait 8 Figure 2: Schéma d’une partie de ronde 9 les opérandes, notamment les clefs de rondes dans AddRoundKey, parce qu’ils seraient alors chargés en clair dans la mémoire. On va reprendre le principe de l’implantation de référence (opérations du coeur de ronde tabulées) mais altérer l’algorithme de manière a pouvoir intégrer l’ajout de clef dans la table. Modification de l’algorithme for i in 1..9 Shiftrows AddShiftedRoundKey(i-1) SubBytes MixColumn Shitrows AddShiftedRoundKey(9) SubBytes AddRoundKey(10) ShiftRows opère sur l’ensemble des 128 bits d’état et ne peut pas être tabulée (cela nécessiterait le montant irréalisable de 2128 × 128 bits en mémoire). On va donc séparer cette opération du reste de la ronde. SubBytes opère octet par octet, on peut la commuter avec ShiftRows (modifier les octets avant ou après les avoir mélangés donne le même résultat). Pour éviter d’avoir la clef primitive ajoutée seule, on décale chaque clef dans la ronde suivante. Cette modification nécessite d’appliquer a chaque clef ShiftRows pour conserver l’algorithme initial. La dernière ronde intègre alors l’ajout de la 9ème clef mélangée par ShiftRows en plus de SubBytes et l’ajout de la 10ème clef non modifiée. Tabulation des opérations Le choix des tailles des tables (et donc des représentation utilisée pour les opérations) est motivé par la nécessité d’un bon compromis sécurité/mémoire. En effet, tabuler une fonction ayant n bits en entrée et m bits en sortie, nécessite 2n × m bits en mémoire. En poussant le raisonnement a l’extrême, on pourrait tabuler l’opération complète de l’AES en générant une table de 2128 entrées possibles correspondant aux 2128 sorties qui donnerait immédiatement le résultat de l’opération d’encryptage. Cependant, cela est inimaginable. En effet 2128 vaut environ 3.4 × 1038 , on a donc une taille bien au delà de la capacité de stockage disponible sur la planète. On va donc choisir des implantations occupant une taille raisonnable en mémoire et nous discuterons par la suite du niveau de sécurité atteint. Les opérations de l’AES, prennent chacune en entrée une taille spécifique, ce qui induit plusieurs échelles pour le choix des tables. L’implantation de référence utilise des tables de 256 valeurs (8 bits en entrée) ce qui constitue un bon rapport mémoire/rapidité des opérations. C’est également adapté a la représentation de l’état en octet, et au calcul de l’opération MixColumns. Nous allons reprendre ce modèle comme base de travail. Les rondes sont calculées de la manière suivante : une première série de 16 tables 10 Taille de l’entrée 128 bits 32 bits 16 bits 8 bits Taille de la sortie 128 bits 32 bits 32 bits 32 bits Espace Mémoire nécessaire 2131 Go 17 Go 260 Ko 1 Ko Table 1: Espace mémoire nécessaire a la tabulation d’une opération notées (Ti ) donne pour chaque octet de l’état sk (en position i après ShiftRows), une valeur sur 32 bits ti . ti = MixColumnsi mod 4 ◦ SubBytes ◦ AddRoundKey(nround)i (sk ) Les ti sont alors ajoutés 4 à 4 via 3 séries de tables xor. Pour les raisons de mémoire évoqué plus haut, ces tables prennent en entrée 2 × 4 bits et donnent le résultat du xor bit à bit des deux nibbles. On est obligé de générer une nouvelle table pour chaque opération xor à cause des encodages des tables que l’on va introduire ci-dessous. Au final on obtient l’état avec une itération de plus. s00−3 = t0 ⊕ t1 ⊕ t2 ⊕ t3 s04−7 = t4 ⊕ t5 ⊕ t6 ⊕ t7 s08−11 = t8 ⊕ t9 ⊕ t10 ⊕ t11 s012−15 = t12 ⊕ t13 ⊕ t14 ⊕ t15 Nous avons, pour l’instant, pour chaque ronde, 16 tables 8 à 32 bits (8 bits en entrées, 32 en sortie) pour les opérations de ronde et un total de 96 tables 8 bits à 4 bits pour effectuer les 12 xor de 32 bits. 4.2 L’encodage Nous disposons a présent de tables permettant de calculer une ronde, cependant a partir des entrées et sorties de ces tables il sera aisé pour un attaquant de retrouver les différentes clefs de ronde. En effet, étant donnée l’état après une ronde, il suffit de calculer l’inverse de MixColumns ◦ SubBytes pour obtenir la clef de ronde ajoutée a l’entrée. n SubBytes−1 ◦ MixColumns−1 (s00−3 ) = s0−3 ⊕ k0−3 C’est encore plus facile pour l’attaquant si il a accès à tout le contenu de ces tables. On comprend de ce fait la nécessité de considérer ces tables comme un véritable secret qui ne doit pas être visible en clair sur la machine exécutant le programme. 4.2.1 La composition Pour protéger le contenu d’une table, on va composer notre table représentant une fonction P , avec deux bijections aléatoires F −1 et G. Ainsi le contenu de la table devient aléatoire, et les entrées et sorties de la table ne sont plus compromettantes. P → P 0 = F −1 ◦ P ◦ G 11 Figure 3: Table xor protégée Si l’entrée de cette table P provient d’une table O, on va lier correctement les bijections de manière à conserver le calcul originel à deux bijections près. O → O0 = E −1 ◦ O ◦ F O0 ◦ P 0 = (E −1 ◦ O ◦ F ) ◦ (F −1 ◦ P ◦ G) = E −1 ◦ (O ◦ P ) ◦ G Pour complexifier le décodage, on va utiliser ce principe de composition aux différents niveaux de calcul dans l’algorithme. Par exemple, on peut considérer une ronde comme étant une seule opération et ajouter des fonctions entre les rondes. On va donc générer un grand nombre de bijections de différents types et opérant sur différents espaces pour fondre les clefs dans les boı̂tes. 4.2.2 Les différents niveaux d’encodage Boı̂tes Pour protéger toutes les boı̂tes de l’implémentation, on va disposer des petites bijections 4 × 4 bits qui seront des permutations de l’ensemble des mots de 4 bits. Ce format est imposé par les sorties des tables xor qui sont fixées à 4 bits. Pour les autre boı̂tes (de 8 et 32 bits), on juxtapose simplement plusieurs de ces bijections. Un travail de cartographie précis est nécessaire pour tenir compte des correspondances entre entrées et sorties des différentes tables. Par exemple, une seule table du cœur va alimenter 8 tables xor. D’une ronde a l’autre il est également nécessaire de tenir compte de l’opération ShiftRows qui modifie l’ordre des tables. Ronde On va également intégrer pour chaque ronde un codage linéaire, à l’aide de deux matrices : L et M B. Elles sont appliquées respectivement en entrée et en sortie des tables opérant AES. Pour annuler leur effet, on introduit de nouvelles tables Oi en composant M Br−1 et L−1 r . on détaille leur construction ci-après. 12 Programme Enfin nous intégrons des protections au niveau du programme. C’est-à-dire que nous encodons l’entrée et la sortie du programme. Il s’agit d’encodages 8 × 8 bits qui sont composés avant les premières tables et après les dernières tables. Cet encodage externe est nécessaire pour deux raisons. D’abord il transforme la boı̂te qui à l’origine décrypte le contenu en une boı̂te qui décode, puis décrypte, puis encode le contenu. Si cet encodage n’était pas présent, la recherche de la clef ne serait plus forcément nécessaire puisqu’on dispose de l’outil permettant de décrypter. D’autre part, cet encodage offre une protection pour les premières et dernières tables qui jusque là n’étaient encodées que d’un seul côté (qu’en sortie pour les premières boı̂tes et qu’en entrée pour les dernières boı̂tes). Laisser ces boites sans un double encodage laisserait le champ libre à l’exploitation d’une attaque relativement accessible sur un ordinateur commun. Comme pour les encodages de boı̂tes, on choisit des bijections aléatoires uniformément choisies parmi les permutations de l’ensemble des mots de 8 bits. 4.3 La diffusion Les encodages aléatoires sont mis en place pour assurer la confusion. Maintenant pour protéger le secret de la clef dans les tables, il est nécessaire d’ajouter de la diffusion. Pour ce faire, nous intégrons les transformations linéaires (encodages de rondes) aux tables de base. La première (notée L) appliquée en entrée est diagonale par bloc. Chaque bloc de 8 bits s’applique à une partie de la ronde (un octet de l’état) et son inverse est appliquée à la ronde suivante sur le bloc correspondant (la rotation par ShiftRows mélangeant les blocs). La deuxième matrice MB doit assurer un maximum de diffusion pour chaque colonne de l’état, c’est-à-dire pour 32 bits sur les 128. Pour maximiser son efficacité, on recommande qu’elle soit composé de sous blocs 4 × 4 inversibles. Ce choix est lié à la taille des bijections encodant toutes les boı̂tes. L’idée est de faire dépendre au maximum chaque nibble de sortie de tous les autres nibbles. Elle est donc appliquée à la sortie des opérations de l’AES et inversée lors de la ronde suivante. Pour chaque ronde, on construit 4 matrices MB composées de sous-blocs 4 × 4 inversibles et 4 matrices Li de 32 bits qui sont composées de 4 sous-blocs de 8 bits (sur la diagonale). Sur chaque colonne i..i + 3, on applique d’abord la matrice −1 M Bi..i+3 , puis on construit une autre table contenant l’opération M Bi..i+3 ◦ Li . L0−3 L0 (0) (0) (0) (0) L1 (0) (0) = (0) (0) L2 (0) (0) (0) (0) L3 M B 0−3 B1,1 = ... B8,1 13 ... ¨ ... B1,8 .. . B8,8 Figure 4: Table du coeur protégée Figure 5: Table introduite pour supprimer les effets de MB 14 Construction Pour construire une telle matrice M B, nous employons la méthode inductive développée par Xiao et Zhou[7] . Cette méthode commence avec des sous-blocs de taille k et produit une matrice de taille n multiple de k dont tous les sousblocs de taille k sont de rang maximal. On va donc expliciter la méthode pour n = 32 et k = 4. Résultats Préliminaires On va utiliser plusieurs résultats sur les matrices pour parvenir à construire l’induction. Tout d’abord, on utilise une décomposition matricielle relativement simple : M = P × Ir × Q−1 où la matrice Ir est définie avec le rang r de la matrice M tel que : Idr (0) Ir = (0) (0) Une telle décomposition est accessible avec un pivot de Gauss. On stocke les opérations sur les lignes dans une matrice, et les opérations sur les colonnes dans l’autre matrice. Le pivot est exécuté sur les lignes jusqu’à atteindre le rang de la matrice, on remonte ensuite en simplifiant les colonnes. A la fin, on se retrouve avec la matrice Ir et dans les autres, les deux matrices de la décomposition. On note que les opérations sur les lignes de la matrice M doivent être exécutées sur les colonnes de la matrice P et celles sur les colonnes de M sur les lignes de Q−1 . Du fait des opérations utilisées, les matrices P et Q−1 sont inversibles. Une fois que nous disposons de cette décomposition, on construit des matrices Ar , telles que Ar + Ir soit inversible. Comme la taille des matrices que nous cherchons est 4, on peut les énumérer pour les 4 valeurs de r. 1 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 r = 1 A1 = 0 0 1 0 A1 + I1 = 0 0 1 0 0 0 0 1 0 0 0 1 0 1 0 0 1 1 0 0 1 1 0 0 1 0 0 0 r = 2 A2 = 0 0 1 0 A2 + I2 = 0 0 1 0 0 0 0 1 0 0 0 1 1 1 1 0 0 1 1 0 1 1 0 0 1 0 0 0 r = 3 A3 = 1 0 0 0 A3 + I3 = 1 0 1 0 0 0 0 1 0 0 0 1 0 1 0 0 1 1 0 0 1 1 0 0 1 0 0 0 r = 4 A4 = 0 0 0 1 A4 + I4 = 0 0 1 1 0 0 1 1 0 0 1 0 15 L’induction Par la suite on s’intéresse à l’équation qui va permettre l’induction : M 0 I M −1 Y M Y • = X W 0 I X XM −1 Y + W M est une matrice carrée inversible de taille n = 4k. X et Y sont respectivement des matrices de taille 4 × n et de taille n × 4. Si W est un bloc 4 × 4 inversible, le membre de gauche est produit de deux matrices inversibles donc la matrice de droite est une matrice carrée de taille n + 4 inversible. On cherche donc à trouver une matrice W tel que la matrice XM −1 Y + W soit un bloc inversible. Alors si M est constituée de blocs inversibles, en construisant X et Y au hasard à partir de blocs inversibles, on réussit à générer une matrice un peu plus grande, dont tous les sous-blocs de taille 4 sont inversibles. En choisissant W = P Ar Q−1 avec r le rang de XM −1 Y et en utilisant les résultats préliminaires, on obtient le résultat voulu. Cette induction nous permet donc de générer une matrice M B de taille 32 × 32 dont tous les sous-blocs de taille 4 × 4 sont inversibles, tel que Chow et al.[6] le recommandent. L’induction présentée à la base par Xiao et Zhou généralise le concept à toutes les tailles de matrices et hors du corps Z/2Z. 5 5.1 Les choix de conception Taille et performance de l’implantation Espace mémoire Cette implantation totalise un nombre important de tables de tailles diverses. Toutes les tables ont 256 entrées (8 bits), mais la valeur qu’elles rendent varie en taille. On va distinguer les tables opérant les xor qui contiennent des nibbles, les tables d’opérations qui du fait des matrices contiennent des mots de 32 bits, et les tables de la dernière ronde qui contiennent des octets. Les tailles en octets sont explicitées ci-dessous. Type xor Opérations Ronde 10 Taille sortie 4 bits 32 bits 8 bits Nombre 1920 320 16 Espace total 245 Ko 327 Ko 4 Ko On compte de plus les instructions intermédiaires pour effectuer les accès et repositionner les variables (pour effectuer les xor 32 bits avec les 8 tables par exemple). En tout, le fichier binaire arrive à une taille de 2,3 Mo sur le disque. C’est donc une taille qui reste raisonnable pour un transfert régulier via le réseau internet par exemple. On reste donc dans le domaine du possible pour les applications envisagées (principalement les DRM) et on peut même changer les clefs assez souvent. Cela reste cependant démesuré comparé au standard dont l’implémentation tient en un peu moins de 5 ko. 16 17 Figure 6: Partie de ronde avec encodage complet Temps d’exécution L’ajout des protections a considérablement ralenti l’AES par rapport au standard (qui est optimisé rappelons-le). Lors d’une exécution, on va accéder à chaque table exactement une fois soit 2256 fois. De plus, pour gérer les xor, on doit effectuer pour chaque table, deux et logiques, deux ou logiques et deux décalages. soit un total de presque 12000 opérations binaires. Par comparaison, l’implantation de base compte environ 500 opérations binaires et 160 accès aux tables. Le rapport semble être de base de plus de 20 fois plus lent. Dans la pratique on obtient un coefficient de l’ordre de 50 fois plus lent. Ci-dessous, une expérience réalisée sur un ordinateur personnel (Macbook Pro 2011, MacOS X Yosemite, Intel Core i7 2.7 GHz). Classique Boite Blanche Temps 162 ms 7.64 s Débit 790 Mb/s 17 Mb/s Nous avons seulement testé une boı̂te blanche nue. L’offuscation de cette implantation nécessaire pour augmenter la protection va la ralentir. 6 Réflexions a posteriori Nous avons produit une implantation primitive de boı̂te blanche pour AES. Elle offre une couche de protection qui introduit déjà une certaine complexité pour l’attaquant, cependant elle ne se suffit pas à elle-même. Par exemple, on peut constater que la matrice M B peut simplement être ignorée. On ne prend donc plus en compte seulement les entrées et les sorties au niveau de la ronde (entrées des boı̂tes Lri ◦ Ti ◦ M B et la deuxième série de boites M B −1 ◦ Lr+1 ). Le résultat possède l’apparence d’une boı̂te Lri ◦ Ti ◦ Lr+1 i i qui est plus facilement analysable. C’est d’ailleurs le point d’entrée de l’attaque développée par Billet, Gilbert et Eisen[5]. Cette attaque peut s’effectuer en moins de 230 opérations, ce qui en fait une attaque praticable causée par cette faiblesse. On ne comprend donc l’intérêt de tous les éléments présentés ici que dans un contexte plus général. Il est nécessaire d’appliquer d’autres couches de protection, comme les encodages duaux proposés par Karroumi[2] et des techniques plus génériques d’offuscation. Dans l’état actuel, la cryptographie boı̂te blanche reste très empirique, et la recherche se fait par tâtonnement (essais et contre-mesures associées se succèdent). Il est nécessaire d’étendre le domaine en apportant différents exemples d’implantation (variation des paramètres de taille des entrées, des clefs ou changement de représentation, d’encodages). Nous pourrons alors espérer dégager des principes qui permettront de construire des modèles génériques ou de valider les modèles existants. 7 Remerciements Mes remerciements vont d’abord à Mme Cani, notre professeur responsable du module Introduction à la Recherche en Laboratoire, grâce à qui j’ai pu effectuer 18 ce travail de recherche. Je remercie également mon professeur référent M. ElbazVincent qui m’a proposé ce sujet d’étude, a suivi mes efforts tout au long du semestre et m’a apporté de nombreuses références et connaissances. Je voudrais encore remercier l’Ensimag et l’UJF pour permettre ce genre d’initiatives qui sont intéressantes dans notre parcours. Ma dernière pensée va pour tous les étudiants de l’Ensimag avec qui j’ai pu échanger sur ce sujet et sur les problèmes que j’ai rencontré. References [1] Joan Daemen and Vincent Rijmen. The design of rijndael: Aes - the advanced encryption standard. Springer, 2002. [2] Mohamed Karroumi. Protecting white-box aes with dual ciphers. [3] James A. Muir. A tutorial on white-box. Advances in Network Analysis and its Applications, (18):209–229, 2013. [4] N.I.S.T. Announcing the advanced encryption standard. Federal Information Processing Standards Publication, (197), 2001. [5] C. Ech-Chatbi O. Billet, H. Gilbert. cryptanalysis of a white box aes implementation. SAC, (3357):227–240, 2005. [6] S. Chow P. Heisen H. Johnson P.C. van Oorschot. White box cryptography and an aes implementation. 2002. [7] James Xiao and Yongxin Zhou. Generating large non-singular matrices over an arbitrary field with blocks of full rank. 2002. 19