Brevet FR3139214A1 — publié le 20240301

Procédé d'exécution d'un code machine par un calculateur Ce procédé comportant : - la construction (162) d'une signature pour une instruction courante : - à partir de signaux générés par un étage d’une chaîne matérielle de traitement, cet étage étant un décodeur ou un étage suivant le décodeur dans la chaîne matérielle de traitement, et - à partir de la précédente signature construite pour une instruction qui la précède, puis - la vérification (163) de l’intégrité du code machine exécuté en comparant (170) la signature construite pour l’instruction courante à une signature de référence pré-enregistrée, puis - seulement lorsque la vérification de l’intégrité de l’instruction courante est réussie, le déchiffrement (156) d’un cryptogramme de l’instruction suivante à l'aide de la signature construite pour l’instruction courante. Fig. 4 PROCÉDÉ D'EXÉCUTION D'UN CODE MACHINE PAR UN CALCULATEUR L’invention concerne un procédé d'exécution d'un code machine par un calculateur ainsi que le code machine exécuté par ce procédé. L'invention concerne également : - un support d'enregistrement d'informations et un calculateur pour la mise en œuvre de ce procédé d'exécution, et - un compilateur pour générer ce code machine. Pour obtenir des informations sur un code machine ou provoquer un fonctionnement inattendu du code machine, il est connu de le soumettre à des attaques connues sous le terme d'« injection de fautes » ou « fault attack » en anglais. Ces attaques consistent à perturber le fonctionnement du calculateur lors de l'exécution du code machine par divers moyens physiques comme des modifications des tensions d'alimentation, des modifications du signal d'horloge, l'exposition du calculateur à des ondes électromagnétiques et autres. À l'aide de telles perturbations, un attaquant peut altérer l'intégrité des instructions machines ou des données pour, par exemple, retrouver une clé secrète d'un système cryptographique, contourner des mécanismes de sécurité tels que la vérification d'un code PIN lors d'une authentification ou simplement empêcher l'exécution d'une fonction essentielle pour la sécurité d'un système critique. Une attaque par injection de fautes peut provoquer une altération du fonctionnement du calculateur, par exemple, par des modifications des instructions qui sont exécutées par l'unité arithmétique et logique. Pour cela, il est fréquent que les fautes injectées visent à perturber le fonctionnement du décodeur d'instructions du calculateur pour produire des instructions fautées. Lorsque la perturbation du décodeur empêche seulement l'exécution d'une ou plusieurs des instructions du code machine ou lorsque l’altération a un effet sur le processeur équivalent au fait de ne pas exécuter l’instruction fautée, on parle alors de saut d'instructions. Lorsque la perturbation du décodeur conduit à remplacer une ou plusieurs des instructions du code machine par d'autres instructions exécutables par le calculateur, on parle alors de remplacement d'instructions. Lorsque la perturbation du décodeur modifie une instruction de branchement, on observe un effet de détournement du flot de contrôle. Le flot de contrôle correspond au chemin d'exécution suivi lors de l'exécution du code machine. Le flot de contrôle est classiquement représenté sous la forme d'un graphe orienté connu sous le terme de graphe de flot de contrôle ou « control flow graph » en anglais. L'effet de détournement du flot de contrôle peut être observé quand une instruction de branchement est altérée ou quand la condition impliquée dans un branchement conditionnel est modifiée ou quand l'adresse de retour d'une fonction est modifiée. De tels attaques sont rendues plus faciles si, au préalable, le code machine peut être analysé. Ainsi, pour rendre ces attaques plus difficiles, il a été proposé de chiffrer les instructions du code machine afin de rendre son analyse plus compliquée. Un exemple de procédé d’exécution d’un code machine chiffré est décrit dans l’article suivant : M.Werner, T. Unterluggauer, D. Schaenrath, and S. Mangard : « Sponge-Based Control-Flow Protection for IoT Devices », EuroS&P, 2018. Par la suite, cet article est désigné par le terme « Werner2018 ». Le procédé décrit dans Werner2018 est particulièrement intéressant car le cryptogramme de chaque instruction est déchiffré à partir d’un état interne du calculateur qui est mis à jour en fonction du cryptogramme de la précédente instruction déchiffrée. Ainsi, le cryptogramme de l’instruction courante à exécuter ne peut être déchiffré correctement que si les cryptogrammes de l’ensemble des instructions précédentes sont intègres, c’est-à-dire qu’ils n’ont pas été modifiés, par exemple, par une injection de fautes. Ceci est avantageux mais ne permet pas de se prémunir contre une attaque qui provoque seulement une erreur lors du décodage d’une instruction. En effet, dans ce dernier cas, le décodage étant effectué après le déchiffrement de l’instruction, le cryptogramme de l’instruction n’est pas modifié. Pour remédier à cet inconvénient, Werner2018 suggère en plus, sans le décrire en détail, de construire l’état interne du calculateur en fonction des signaux générés par le décodeur d’instructions lors du décodage de la précédente instruction. Cela permet de garantir l’intégrité des signaux générés par le décodeur d’instructions en plus de l’intégrité de son cryptogramme. Plus précisément, dans Werner2018, un cryptogramme fauté d’une instruction courante Ii ou une erreur introduite lors du décodage de l’instruction Ii, entraîne un déchiffrement incorrect du cryptogramme Ii+1* de l’instruction suivante. Ainsi, le déchiffrement du cryptogramme Ii+1* produit une instruction erronée I’i+1 différente de l’instruction attendue Ii+1. Puisque les signaux générés par le décodeur lors de l’exécution de l’instruction I’i+1 sont pris en compte pour mettre à jour l’état du calculateur utilisé pour déchiffrer le cryptogramme de l’instruction Ii+2, à partir de l’instruction Ii, le calculateur génère uniquement des instructions erronées. La première instruction erronée I’i+n produite qui n’appartient pas au jeu d’instructions du calculateur, provoque une faute d’exécution qui arrête l’exécution du code machine. Dans le cas où le jeu d’instructions du calculateur est clairsemé, l’indice n de l’instruction qui provoque la faute d’exécution est petit. Par contre, si le jeu d’instructions du calculateur n’est pas clairsemé, alors l’indice n peut être très grand ce qui retarde, voire rend impossible, la détection du défaut d’intégrité. De plus, si l’instruction I’i+1 appartient au jeu d’instructions du calculateur, cela provoque un comportement inattendu du calculateur puisque que l’instruction exécutée I’i+1 est différente de l’instruction attendue Ii+1. Un tel comportement inattendu peut remettre en cause la sécurité du code machine. L'invention vise à améliorer le procédé décrit dans Werner2018. En particulier, l’invention vise donc à proposer un procédé d'exécution d'un code machine qui permet de signaler une altération d'une instruction, un saut d'instruction et une altération du fonctionnement du décodeur d'instructions du calculateur sans présenter les inconvénients du procédé de Werner2018. Elle a donc pour objet un tel procédé d'exécution d'un code machine par un calculateur comportant une chaîne matérielle de traitement d'instructions, cette chaîne matérielle de traitement comportant une succession d’étages qui traitent les uns après les autres chaque instruction à exécuter du code machine, cette succession d’étages comportant au moins les étages suivants : un chargeur d'instructions, un décodeur et une unité arithmétique et logique, ce procédé comportant l’exécution des étapes suivantes pour chaque cryptogramme d’une instruction d’une suite d’instructions consécutives du code machine : - le chargement, par le chargeur d'instructions, du cryptogramme d’une instruction désignée par un compteur ordinal pour obtenir un cryptogramme chargé, puis - le déchiffrement du cryptogramme chargé pour obtenir une instruction déchiffrée, puis - le décodage de l'instruction déchiffrée, par le décodeur, pour générer des signaux qui configurent le calculateur pour exécuter l'instruction déchiffrée, puis, - l'exécution, par l'unité arithmétique et logique, de l'instruction déchiffrée, dans lequel le procédé comporte également les étapes suivantes pour au moins une instruction courante de la suite d’instructions consécutives : - après l'opération de décodage de l’instruction courante et avant le déchiffrement du cryptogramme de l’instruction suivante dans la suite d’instructions consécutives, la construction d'une signature pour l’instruction courante : - à partir d’un ensemble de signaux générés par un étage de la succession d’étages en réponse au traitement de cette instruction courante par cet étage, cet étage qui génère cet ensemble de signaux étant le décodeur ou un étage suivant le décodeur dans la succession d’étages, et - à partir de la précédente signature construite pour l’instruction qui la précède dans la suite d’instructions consécutives, cette signature pour l’instruction courante variant ainsi en fonction de l'instruction courante et en fonction de toutes les instructions précédant l’instruction courante dans la suite d’instructions consécutives, puis - la vérification de l’intégrité du code machine exécuté en comparant la signature construite pour l’instruction courante à une signature de référence pré-enregistrée, puis - seulement lorsque la vérification de l’intégrité de l’instruction courante est réussie, le déchiffrement du cryptogramme de l’instruction suivante à l'aide de la signature construite pour l’instruction courante. Les modes de réalisation de ce procédé peuvent comporter une ou plusieurs des caractéristiques suivantes : 1) l’étape de vérification de l’intégrité comporte : - le chargement d’un cryptogramme de la signature de référence, puis - le déchiffrement de ce cryptogramme à l’aide d’une des signatures construites pour l’une des instructions de la suite d’instructions. 2) - le cryptogramme de la signature de référence est chargé à partir de l’adresse contenue dans le compteur ordinal après le chargement du cryptogramme de l’instruction courante et avant le chargement du cryptogramme de l’instruction suivante, et - le cryptogramme de la signature de référence est déchiffré à l’aide de la signature construite pour l’instruction courante ou pour l’instruction qui précède cette instruction courante dans la suite d’instructions consécutives. 3) lors de la construction de la signature pour l’instruction courante, cette signature est en plus construite à partir d’une clé secrète pré-enregistrée dans une mémoire du calculateur. 4) l’étage qui génère l’ensemble de signaux utilisé pour construire la signature est le décodeur. 5) lors de la construction d’une signature pour l’instruction courante, cette signature est construite à partir de signaux, générés par le décodeur en réponse au décodage de l'instruction courante, qui varient en fonction de l'opcode de l'instruction courante et en fonction de chaque opérande de l'instruction courante. 6) le déchiffrement du cryptogramme de chaque instruction à l'aide de la signature construite consiste en la réalisation d'un "OU EXCLUSIF" entre les bits du cryptogramme de l'instruction et les bits de la signature construite pour l’instruction qui précède cette instruction dans la suite d’instructions consécutives. 7) lorsque la signature construite pour l’instruction courante est différente de la signature de référence pré-enregistrée à laquelle elle est comparée, l’étape de vérification de l’intégrité de l’instruction courante se poursuit par une étape de signalement d’un défaut d’intégrité. L'invention a également pour objet un code machine apte à être exécuté en mettant en œuvre le procédé d’exécution ci-dessus, ce code machine comprenant un cryptogramme pour chaque instruction d’une suite d’instructions consécutives, dans lequel - chacun de ces cryptogramme est le chiffré d’une instruction correspondante de cette suite d’instructions consécutives à l'aide d'une signature construite : - à partir des signaux générés par un étage de la succession d’étages en réponse au décodage de cette instruction correspondante par cet étage, cet étage qui génère cet ensemble de signaux étant le décodeur ou un étage suivant le décodeur dans la succession d’étages, et - à partir de la précédente signature construite pour l’instruction qui la précède dans la suite d’instructions consécutives, cette signature pour l’instruction correspondante variant ainsi en fonction de l'instruction correspondante et en fonction de toutes les instructions précédant l’instruction correspondante dans la suite d’instructions consécutives, et - le code machine comporte également la signature de référence pré-enregistrée à laquelle la signature construite pour une instruction courante est comparée lors de l’exécution de ce code machine en mettant en œuvre le procédé ci-dessus. L'invention a également pour objet un support d'enregistrement d'informations lisible par un microprocesseur d’un calculateur, ce support d'enregistrement d'informations contenant le code machine ci-dessus. L'invention a également pour objet un calculateur pour la mise en œuvre du procédé d'exécution ci-dessus, ce calculateur comportant une chaîne matérielle de traitement d'instructions, cette chaîne matérielle de traitement comportant une succession d’étages qui traitent les uns après les autres chaque instruction à exécuter du code machine, cette succession d’étages comportant au moins les étages suivants : un chargeur d'instructions, un décodeur et une unité arithmétique et logique, cette chaîne matérielle de traitement étant apte, pour chaque cryptogramme d’une instruction d’une suite d’instructions consécutives d’un code machine, à exécuter les opérations suivantes : - le chargement, par le chargeur d'instructions, du cryptogramme d’une instruction désignée par un compteur ordinal pour obtenir un cryptogramme chargé, puis - le déchiffrement du cryptogramme chargé pour obtenir une instruction déchiffrée, puis - le décodage de l'instruction déchiffrée, par le décodeur, pour générer des signaux qui configurent le calculateur pour exécuter l'instruction déchiffrée, puis, - l'exécution, par l'unité arithmétique et logique, de l'instruction déchiffrée, dans lequel la chaîne matérielle de traitement est également configurée pour exécuter les étapes suivantes pour au moins une instruction courante de la suite d’instructions consécutives : - après l'opération de décodage de l’instruction courante et avant le déchiffrement du cryptogramme de l’instruction suivante dans la suite d’instructions consécutives, la construction d'une signature pour l’instruction courante : - à partir des signaux générés par un étage de la succession d’étages en réponse au décodage de cette instruction courante par cet étage, cet étage qui génère cet ensemble de signaux étant le décodeur ou un étage suivant le décodeur dans la succession d’étages, et - à partir de la précédente signature construite pour l’instruction qui la précède dans la suite d’instructions consécutives, cette signature pour l’instruction courante variant ainsi en fonction de l'instruction courante et en fonction de toutes les instructions précédant l’instruction courante dans la suite d’instructions consécutives, puis - la vérification de l’intégrité de l’instruction courante en comparant la signature construite pour l’instruction courante à une signature de référence pré-enregistrée, puis - seulement lorsque la vérification de l’intégrité de l’instruction courante est réussie, le déchiffrement du cryptogramme de l’instruction suivante à l'aide de la signature construite pour l’instruction courante. Enfin, l'invention a également pour objet un compilateur apte à transformer automatiquement un code source d'un programme d'ordinateur en un code binaire comportant un code machine exécutable par un calculateur comportant une chaîne matérielle de traitement d'instructions, cette chaîne matérielle de traitement comportant les étages suivants : un chargeur d'instructions, un décodeur et une unité arithmétique et logique, ce compilateur étant apte à transformer automatiquement le code source en un code machine conforme au code machine ci-dessus. L'invention sera mieux comprise à la lecture de la description qui va suivre, donnée uniquement à titre d'exemple non limitatif et faite en se référant aux dessins sur lesquels : - la est une illustration schématique de l'architecture d'un calculateur électronique apte à exécuter un code machine; - la est une illustration schématique d'un compilateur apte à générer le code machine exécuté par le calculateur de la ; - la est un organigramme d'un procédé de compilation du code machine à l'aide du compilateur de la ; - la est un organigramme d'un procédé d'exécution du code machine à l'aide du calculateur de la . CHAPITRE I : Notations et définitions Dans ces figures, les mêmes références sont utilisées pour désigner les mêmes éléments. Dans la suite de cette description, les caractéristiques et fonctions bien connues de l’homme du métier ne sont pas décrites en détails. Dans cette description, les définitions suivantes sont adoptées. Un « programme » désigne un ensemble d'une ou de plusieurs fonctions prédéterminées que l'on souhaite faire exécuter par un calculateur. Un « code source » est une représentation du programme dans un langage informatique, n'étant pas directement exécutable par un calculateur et étant destiné à être transformé, par un compilateur, en un code machine directement exécutable par le calculateur. Un programme ou un code est dit être « directement exécutable » lorsqu'il est apte à être exécuté par un calculateur sans que ce calculateur n'ait besoin au préalable que le programme soit compilé au moyen d'un compilateur ou de l'interpréter au moyen d'un interpréteur. Une « instruction » désigne une instruction machine exécutable par un calculateur. Une telle instruction est constituée : - d'un opcode, ou code d'opération, codant la nature de l'opération à exécuter, et - d'un ou plusieurs opérandes définissant la ou les valeurs des paramètres de cette opération. La « valeur d'une instruction » est une valeur numérique obtenue, à l'aide d'une fonction bijective, à partir de la succession de « 0 » et de « 1 » qui code, en langage machine, cette instruction. Cette fonction bijective peut être la fonction identité. Un « code machine » est un ensemble d'instructions machines. Il s'agit typiquement d'un fichier contenant une succession de bits portant la valeur « 0 » ou « 1 », ces bits codant les instructions à exécuter par le microprocesseur. Le code machine est directement exécutable par le calculateur, c'est-à-dire sans nécessiter une compilation ou une interprétation préalable. Le code machine comporte une succession d'instructions classées les unes après les autres et qui forme, dans le code machine, une suite ordonnée d'instructions. Le code machine débute par une instruction initiale et se termine par une instruction finale. Par rapport à une instruction Ii donnée du code machine, l'instruction Ii-1 située du côté de l'instruction initiale est appelée « instruction précédente » et l'instruction Ii+1 situées du côté de l'instruction finale, est appelée « instruction suivante ». L'indice "i" est le numéro d'ordre de l'instruction Ii dans le code machine. Un « code binaire » est un fichier contenant une succession de bits portant la valeur « 0 » ou « 1 ». Ces bits codent des données et des instructions à exécuter par le microprocesseur. Ainsi, le code binaire comprend au moins un code machine et en plus, généralement, des données numériques traitées par ce code machine. Un « flot d'instructions » est une succession d'instructions exécutées les unes après les autres. La notation "Ii*" désigne le cryptogramme de la valeur d’une instruction Ii en clair. Dans ce texte, une « suite d’instructions consécutives » est un groupe d'instructions du code machine qui sont systématiquement exécutées les unes après les autres. Une « instruction de branchement » est une instruction qui, lorsqu'elle est exécutée par le calculateur, est apte à remplacer l’adresse contenue dans le compteur ordinal par une autre adresse. L’instruction de branchement comporte donc au moins comme paramètre cette autre adresse. On rappelle que le compteur ordinal contient l'adresse de la prochaine instruction à exécuter par le calculateur. En absence d'instruction de branchement, à chaque fois qu'une instruction est exécutée, le compteur ordinal est incrémenté de la taille de l'instruction actuellement exécutée. En absence d'instruction de branchement, les instructions sont systématiquement exécutées séquentiellement les unes après les autres dans l'ordre où elles sont enregistrées dans une mémoire principale, c'est-à-dire dans l'ordre de leur indice "i". On parle d'exécution d'une fonction pour désigner l'exécution des instructions réalisant cette fonction. CHAPITRE II : Exemples de mode de réalisation La représente un calculateur électronique 1 comportant un microprocesseur 2, une mémoire principale 4 et un support 6 de stockage de masse. Par exemple, le calculateur 1 est un ordinateur, un smartphone, une tablette électronique, une carte à puce ou similaire. Le microprocesseur 2 comporte ici : - une chaîne matérielle 10 de traitement des instructions à exécuter; - un ensemble 12 de registres ; - un module de commande 14, - une interface 16 d'entrée/sortie de données, et - un bus 17 qui relie les différents composants du microprocesseur 2 entre eux. La mémoire 4 est configurée pour stocker des instructions d'un code binaire 30 d'un programme devant être exécuté par le microprocesseur 2. La mémoire 4 est une mémoire à accès aléatoire. Typiquement, la mémoire 4 est une mémoire volatile. La mémoire 4 peut être une mémoire externe au microprocesseur 2 comme représenté sur la . Dans ce cas, la mémoire 4 est, par exemple, réalisée sur un substrat mécaniquement séparé du substrat sur lequel sont réalisés les différents éléments du microprocesseur 2 comme la chaîne 10. Le support 6 est typiquement une mémoire non volatile. Par exemple, il s'agit d'une mémoire du type EEPROM ou Flash. Il contient ici une copie 40 de sauvegarde du code binaire 30. Typiquement, c'est cette copie 40 qui est automatiquement recopiée dans la mémoire 4 pour restaurer le code 30, par exemple, après une coupure de courant ou similaire ou juste avant que débute l'exécution du code 30. Dans cet exemple de réalisation le code binaire 30 comporte notamment un code machine 32 chiffré. Le code machine 32 contient une succession de mots Wi chacun de même taille que l’instruction qu’il contient. Typiquement, la taille de chaque mot Wi, en nombre de bits, est supérieure à huit ou seize bits. Ici, la taille de chaque mot Wi est égale à trente-deux bits. Par la suite, l’indice i est le numéro d’ordre du mot Wi dans le code machine 32. Ainsi, l’indice i-1 correspond au mot précédent le mot Wi. De même, l’indice i+1 correspond au mot suivant le mot Wi. Comme expliqué plus loin, chaque mot Wi contient soit un cryptogramme Ii* d’une instruction Ii à exécuter soit un cryptogramme Srefi* d’une signature de référence. Ici la taille d’un mot Wi est égale à la taille du cryptogramme qu’il contient. Dans cet exemple de réalisation, les mots Wi contenant un cryptogramme Srefi* représentent moins de 30 % et, typiquement, moins de 20 % ou moins de 10 % du nombre total de mots Wi du code machine 32. Les autres mots Wi du code machine 32 contiennent chacun le cryptogramme Ii* d’une instruction à exécuter. A titre d'illustration, le microprocesseur 2 est conforme à l'architecture ARM (« Advanced Risk Machine ») version 7 et supporte les jeux d'instructions tels que Thumb1 et/ou Thumb2. Un jeu d'instructions définit de façon limitative la syntaxe des instructions que le microprocesseur 2 est capable d'exécuter. Ce jeu d'instructions définit donc notamment l'ensemble des opcodes possibles pour une instruction. La syntaxe d’une instruction est incorrecte si sa syntaxe ne correspond à aucune des syntaxes possibles pour une instruction exécutable par le microprocesseur 2. Par exemple, si la plage de bit d’une instruction Id qui correspond à la plage de bit utilisée pour coder l’Opcode de l’instruction contient une valeur qui est différente de toutes les valeurs possibles pour un Opcode, alors sa syntaxe est incorrecte. Dans cet exemple de réalisation, l'ensemble 12 comporte des registres généraux utilisables pour stocker tout type de données et des registres dédiés. Contrairement aux registres généraux, les registres dédiés sont dédiés au stockage de données particulières généralement automatiquement générées par le microprocesseur 2. Le module 14 est configuré pour déplacer des données entre l'ensemble 12 de registres et l'interface 16. L'interface 16 est notamment apte à acquérir des données et des instructions, par exemple, depuis la mémoire 4 et/ou le support 6 extérieurs au microprocesseur 2. La chaîne 10 est plus connue sous le terme anglais de "pipeline". La chaîne 10 permet de commencer à exécuter une instruction du code machine alors que le traitement, par la chaîne 10, de la précédente instruction de ce code machine n'est pas encore terminé. De telles chaînes de traitement sont bien connues et seuls les éléments de la chaîne 10 nécessaires à la compréhension de l'invention sont décrits plus en détail. La chaîne 10 comporte typiquement les étages suivants : - un chargeur 18 d'instructions, - un module 20 de déchiffrement, - un décodeur 22 d'instructions, et - une unité arithmétique et logique 24 qui exécute les instructions. Le chargeur 18 charge la prochaine instruction à exécuter par l'unité 24 à partir de la mémoire 4. Plus précisément, le chargeur 18 charge le mot Wi du code machine 32 sur lequel pointe un compteur ordinal 26. Sauf si sa valeur est modifiée par l'exécution d'une instruction de branchement, la valeur du compteur ordinal 26 est incrémentée d'un pas régulier à chaque exécution d’une instruction par l’unité arithmétique et logique 24. Le pas régulier est égal à l'écart entre les adresses de deux instructions immédiatement consécutives dans le code machine 32. Ce pas est ici appelé "pas unitaire". Le module 20 de déchiffrement déchiffre le cryptogramme Ii* chargé et transmet l’instruction déchiffrée Ii au décodeur 22. L’instruction déchiffrée Ii est également appelée « instruction en clair ». Pour cela, le module 20 implémente et exécute une fonction pré-programmée g-1(Ii*, Si-1) de déchiffrement, où : - Ii* est le cryptogramme de l'instruction Ii en clair, - Si-1 est une signature construite pour l’instruction précédente Ii-1, et - g-1() est l’inverse de la fonction de chiffrement g(). La construction de la signature Si-1 est décrite plus loin. Dans ce premier mode de réalisation, la fonction g() est une fonction qui limite la dépendance statistique entre la valeur de Ii et la valeur de Ii*. Ici, la fonction g() est la fonction « OU EXCLUSIF » représentée par le symbole XOR. Ainsi, dans ce mode de réalisation, l’instruction Ii en clair est obtenue à l’aide de la relation suivante : Ii = Ii* XOR Si-1. Le décodeur 22 décode l'instruction déchiffrée Ii pour obtenir des signaux de configuration qui configurent le microprocesseur 2 pour qu'il exécute, typiquement lors du prochain cycle d'horloge, l'instruction déchiffrée. Un de ces signaux de configuration code la nature de l'opération à exécuter par l'unité 24. Ce signal de configuration est issu de / est construit à partir de l'opcode de l'instruction déchiffrée. D'autres signaux de configuration indiquent, par exemple, si l'instruction déchiffrée est une instruction de chargement d'une donnée depuis la mémoire 4 ou d'écriture d'une donnée dans la mémoire 4. Ces signaux de configuration sont transmis à l'unité 24. D'autres signaux de configuration comportent les valeurs des opérandes chargées. Selon l'instruction à exécuter, ces signaux sont transmis à l'ensemble 12 de registres ou à l'unité 24. Lorsque le décodeur 22 n'arrive pas à décoder une instruction, il génère un signal d'erreur. Typiquement, cela se produit si la syntaxe de l'instruction déchiffrée est incorrecte. L'unité 24 exécute les unes après les autres les instructions déchiffrées. L'unité 24 est aussi capable d'enregistrer le résultat de l’exécution de ces instructions dans un ou plusieurs des registres de l'ensemble 12. Dans cette description, on utilisera comme synonymes « exécution par le microprocesseur 2 » et « exécution par l'unité 10 ». Une instruction (machine) Ii donnée doit successivement être traitée, dans l'ordre, par le chargeur 18, le module 20 de déchiffrement, le décodeur 22 et l'unité 24. De plus, le chargeur 18, le module 20 de déchiffrement, le décodeur 22 et l'unité 24 sont capables de travailler en parallèle les uns des autres pendant un même cycle d’horloge. Ainsi, au cours d’un même cycle d’horloge, le chargeur 18 peut être en train de charger le cryptogramme Ii+1* de l'instruction suivante Ii+1, le décodeur 22 en train de décoder l'instruction déchiffrée Ii et l'unité 24 en train d'exécuter l’instruction Ii-1. La chaîne 10 permet ainsi de traiter en parallèle plusieurs instructions du code machine 30. Le module 20 déchiffre le cryptogramme Ii+1* après le décodage de l’instruction Ii par le décodeur 22. Pour assurer l’intégrité du code machine 32, la chaîne 10 comporte en plus les modules matériels suivants : - un constructeur 42 de signature, et - un vérificateur 44 d’intégrité. Le constructeur 42 est configuré pour réaliser les opérations suivantes : 1) mémoriser la précédente signature Si-1 construite pour la précédente instruction Ii-1, 2) construire une signature Si pour l’instruction Ii à partir de la précédente signature Si-1 construite et des signaux générés par le décodeur 22 en réponse au décodage de l’instruction Ii. Pour réaliser l'opération 2) ci-dessus, le constructeur 42 implémente et exécute une fonction pré-programmée f(Idi ; Si-1), où : - Idi est un ensemble de signaux générés par le décodeur 22 en réponse au décodage de l’instruction Ii, - Si-1 est la précédente signature construite pour l’instruction Ii-1, et - f() est une fonction de signature prédéterminée. Chaque signal généré par le décodeur se présente sous la forme d’un vecteur de bits composé des valeurs 0 et 1. L’ensemble Idi contient les valeurs actuelles de chacun des signaux de l’ensemble. L’ensemble Idi est calculable statiquement, c'est-à-dire calculable avant que le code machine 32 soit déployé dans la mémoire 4. Autrement dit, l’ensemble Idi est calculable au moment de la compilation du code machine 32. De plus, dans ce mode de réalisation, si un bit utile de l'instruction Ii change, au moins un bit de l’ensemble Idi change également. Les bits utiles de l’instruction Ii sont ceux qui contribuent soit à la définition de l’opcode soit à la définition de l’un des opérandes de l’instruction Ii. Ainsi, l’ensemble Idi varie en fonction de l’opcode et de la valeur de chaque opérande de l’instruction Ii. Par exemple, l’ensemble Idi comporte généralement les signaux de sélection des opérandes et les signaux de commande de l’unité 24. La fonction f() de signature a les propriétés suivantes : i) Résistance aux collisions, ii) Préservation de l'erreur, et iii) Non-associativité. La résistance aux collisions signifie que, connaissant la signature Si d’une instruction Ii, il est pratiquement impossible de trouver une instruction I’i qui est différente de l’instruction Ii et qui présente la même signature Si. En particulier, il est pratiquement impossible en modifiant seulement quelques bits de l’instruction Ii d’obtenir une instruction I’i qui présente la même signature Si. La préservation de l’erreur signifie que si une signature S’i est erronée, c’est-à-dire qu’elle est différente de la signature Srefi attendue, alors toutes les signatures suivantes Si+n sont également erronées, où n est nombre entier supérieur à zéro. Cela est rendu nécessaire par le fait que la fonction f() est une fonction de signature récursive qui construit la signature courante à partir de la signature précédente. Grâce au propriété i) et ii), l’intégrité d’une instruction Ii, peut être confirmée ou infirmée en vérifiant l’intégrité de n’importe quelle instruction suivante Ii+n. La non-associativité signifie que quelle que soit la modification de l’ordre des instructions I1 à Ii-1, la signature S’i construite pour l’instruction Ii est différente de la signature Si construite en absence de modifications de l’ordre des instructions I1 à Ii-1. De plus, ici, pour assurer la confidentialité des instructions du code machine 32, la fonction f() présente les propriétés suivantes : - associer une signature Si différente pour chaque instruction Ii différente, - se comporter comme un générateur de nombre pseudo-aleatoire sûr, c’est-à-dire un CSPRNG (« cryptographically secure pseudorandom number generator »), et - générer une signature de taille égale ou supérieure à la taille des instructions Ii. Par exemple, la fonction f() est une fonction CBC-MAC (« cipher block chaining message authentication code »). Toujours à titre d’illustration, dans cette fonction CBC-MAC, l’algorithme de chiffrement utilisé est un algorithme de chiffrement par bloc, par exemple, l’algorithme de chiffrement connu sous le nom de « Prince » (voir par exemple au sujet de cet algorithme, la page suivante de Wikipedia : https://en.wikipedia.org/wiki/Prince_(cipher)). L’algorithme de chiffrement « Prince » est paramétré par une clé secrète ks qui est seulement connue du calculateur 2 et du compilateur qui a généré le code machine 32. Typiquement, la clé ks est enregistrée dans un mémoire sécurisée du constructeur 42 de signature Ici, la signature Si est codée sur le même nombre de bits que l'instruction Ii. De préférence, il n'existe pas de code machine pour exécuter les fonctions g-1() et f() dans une mémoire située en dehors du microprocesseur 2. Typiquement, elles sont implémentées sous forme matérielle à l'intérieur, respectivement, du module 20 et du constructeur 42. Le vérificateur 44 vérifie l’intégrité du code machine déchiffré et exécuté par le microprocesseur 2. Pour cela, le vérificateur 44 compare une signature Si construite par le constructeur 42 à une signature de référence Srefi pré-enregistrée. Si la signature Si est identique à la signature Srefi pré-enregistrée, alors le code machine est intègre. Dans le cas contraire, le vérificateur 44 déclenche le signalement d’un défaut d’intégrité. Typiquement, la signature Srefi est construite lors de la compilation du code machine 2. Dans ce mode de réalisation, la signature Srefi est enregistrée dans le code machine 32. Plus précisément, immédiatement après le mot Wi du code machine 32 qui contient le cryptogramme Ii*, le code machine comporte un mot Wi+1 qui contient le cryptogramme Srefi* de la signature Srefi. Ici, le cryptogramme Srefi* est obtenu en utilisant la même fonction de chiffrement g() que celle utilisée pour chiffrer les instructions. Par exemple, le cryptogramme Srefi est obtenu à l’aide de la relation suivante : Srefi* = Srefi XOR Srefi-1, où la signature Srefi-1 est celle utilisée lors de la compilation du code machine pour chiffrer l’instruction Ii. Comme expliqué précédemment dans le cas des instructions Ii, une erreur dans l’instruction déchiffrée ou décodée entraîne une erreur sur toutes les signatures Si+n suivantes construites par le constructeur 42. Ainsi, pour détecter un défaut d’intégrité, il n’est pas nécessaire que le vérificateur 44 vérifie l’intégrité du code machine après l’exécution de chaque instruction Ii. Ici, le vérificateur 44 vérifie l’intégrité du code machine à des emplacements choisis comme étant pertinents pour garantir la sécurité du code machine exécuté. Par exemple, dans ce mode de réalisation, le vérificateur 44 vérifie l’intégrité du code machine après l’exécution de chaque instruction de branchement. A cet effet, après chaque instruction de branchement, le code machine 32 comporte un mot Wi+1 contenant le cryptogramme Srefi*. Dans ce mode de réalisation, c’est donc l’exécution d’une instruction de branchement qui déclenche la comparaison de la signature Si construite par le constructeur 42, à la signature de référence Srefi obtenue en déchiffrant le cryptogramme Srefi* contenu dans le mot Wi+1. La représente un compilateur 60 apte à générer automatiquement le code machine 32 à partir d'un code source 62. À cet effet, le compilateur 60 comporte typiquement un microprocesseur 64 programmable et une mémoire 66. La mémoire 66 contient les instructions et les données nécessaires pour, lorsqu'elles sont exécutées par le microprocesseur 64, générer automatiquement le code machine 32 à partir du code source 62. En particulier, la mémoire 66 contient les instructions nécessaires pour exécuter le procédé de la . La représente un procédé de génération du code machine 32 à partir du code source 62 par le compilateur 60. Lors d’une étape 70, le compilateur 60 réalise une compilation initiale du code source 62 pour obtenir un premier code machine en clair dans lequel les instructions Ii ne sont pas chiffrées. Le premier code machine ne comporte pas, à ce stade, d’instructions qui déclenchent la vérification de l’intégrité du code machine. Le premier code machine ne comporte pas non plus de signatures de référence. Lors d’une étape 72, le compilateur 60 transforme automatiquement le premier code machine en un deuxième code machine qui contient en plus les instructions qui déclenchent la vérification d’intégrité. A cet effet, le compilateur 60 repère automatiquement, dans le premier code machine, les emplacements où doivent être insérées les instructions qui déclenchent la vérification d’intégrité. Ici, il repère les emplacements des instructions de branchement dans le premier code. Puis, après chacune de ces instructions repérées, le compilateur 60 insère automatiquement un emplacement permettant l’insertion ultérieure d’une signature de référence. Lors d’une étape 74, le compilateur génère, à partir du deuxième code machine, un troisième code machine 32 dans lequel chaque instruction Ii est remplacée par son cryptogramme Ii* correspondant. Par exemple, lors de l’étape 74, pour chaque suite d’instructions consécutives, le compilateur parcourt cette suite d’instructions dans l'ordre croissant des instructions Ii. Ici, une suite d’instructions consécutives est une suite d’instructions du deuxième code machine qui sont systématiquement exécutées les unes après les autres lors de l’exécution du code machine 32 par le calculateur 2. Pour chaque instruction Ii en clair rencontrée dans cette suite d’instructions, le compilateur 60 construit la signature Srefi à utiliser pour obtenir le cryptogramme I*i+1 correspondant. En absence d’erreur, la signature Srefi construite par le compilateur 60 est la même que celle qui est construite par le constructeur 42 pour déchiffrer le cryptogramme I*i+1 lors de l'exécution du code machine 32 par le microprocesseur 2. Pour cela, le compilateur 60 construit chaque signature Srefi en utilisant la même fonction f() que celle utilisée par le constructeur 42. Ainsi, chaque signature Srefi est obtenue à l’aide de la relation suivante : Srefi = f(Idi ; Srefi-1). Par exemple, pour cela, le compilateur 60 implémente un simulateur qui reproduit le fonctionnement de la chaîne 10 et, en particulier, du décodeur 22 et du constructeur 42. En particulier, l’émulateur parcourt le deuxième code machine et pour chaque instruction Ii du deuxième code machine : - le simulateur produit les mêmes signaux de configuration que ceux générés par le décodeur 22 lorsqu'il a fini de décoder l'instruction Ii, puis - le simulateur construit la signature Srefi à partir de l’ensemble Idi de ces signaux et de la précédente signature Srefi-1 construite en utilisant la fonction f(). Dans ce mode de réalisation, pour chiffrer la première instruction I1 du code machine, le compilateur utilise une signature de référence Sref0 prédéterminée et connue du microprocesseur 2. Typiquement, la signature Sref0 est une signature secrète connue seulement du microprocesseur 2 et du compilateur 60. Par exemple, la signature Sref0 est enregistrée dans une mémoire sécurisée du microprocesseur 2 et utilisée par le constructeur 42 pour déchiffrer le cryptogramme contenu dans le premier mot W1 du code machine 32. Une fois la signature Srefi construite, le compilateur 60 obtient le cryptogramme Ii* à l'aide de la relation Ii* = g(Ii; Srefi-1), où la fonction g() est l'inverse de la fonction g-1(), c'est-à-dire qu'elle vérifie la relation suivante: Ii = g-1(g(Ii)). Dans cet exemple, le cryptogramme Ii* est obtenu à l'aide de la relation suivante : Ii* = Ii XOR Srefi-1. Chaque instruction Ii du deuxième code machine est alors remplacée par son cryptogramme Ii* pour obtenir le troisième code machine. Le deuxième code machine peut comporter des instructions de branchement de sorte que l’instruction précédent une instruction Ii peut être soit l’instruction Ii-1 soit une autre instruction Ij selon le chemin emprunté. Dans ce cas, l’instruction Ii a plusieurs instructions précédentes Ii-1 et Ij. Par contre, il ne peut y avoir qu’un seul cryptogramme Ii*. Ici, le cryptogramme Ii* est soit égal à g(Ii; Srefi-1) soit égal à g(Ii; Srefj). Pour que le cryptogramme Ii* soit le même quel que soit le chemin emprunté, il faut que la signature Srefj soit identique à la signature Srefi-1. A cet effet, un mécanisme de mise à jour de la signature Srefj est implémenté. Par exemple, ici, le mécanisme de mise à jour des signatures connu sous l’acronyme GPSA (« Generalized Path Signature Analysis ») est implémenté. Le mécanisme GPSA est par exemple décrit dans l’article suivant : Mario Werner et Al : « Protecting the Control Flow of Embedded Processors against Fault Attacks », CARDIS 2015: Revised Selected Papers of the 14th International Conference on Smart Card Research and Advanced Applications - Volume 9514November 2015 Pages 161–176. Puisque le mécanisme de mise à jour des signatures est connu, la mise à jour des signatures dans le cas où une instruction a plusieurs instructions précédentes n’est pas décrite dans ce texte. Autrement dit, par la suite, la description est faite dans le cas particulier d’une suite d’instructions immédiatement consécutives, sachant que l’homme du métier sait comment appliquer cet enseignement dans le cas où le flot de contrôle du code machine présente plusieurs bifurcations correspondant, typiquement, à des instructions de branchement conditionnel. Lors d’une étape 76, immédiatement après le cryptogramme Ii* de chaque instruction qui déclenche la vérification d’intégrité, le compilateur insère automatiquement un mot Wi+1 contenant le cryptogramme Srefi* pour obtenir le code machine 32. Dans ce mode de réalisation, le cryptogramme Srefi* est obtenu à l’aide de la relation suivante : Srefi* = g(Srefi ; Srefi-1), où Srefi et Srefi-1 sont les signatures construites, respectivement, pour les instructions Ii et Ii-1 lors de l’étape 74. La représente un procédé d’exécution du code machine 32 par le calculateur 2. Le procédé débute par une étape 150 de fourniture du code binaire 30 dans la mémoire 4. Pour cela, par exemple, le microprocesseur 2 recopie la copie 40 à l'intérieur de la mémoire 4 pour obtenir le code binaire 30 enregistré dans la mémoire 4. Au préalable, ce code binaire 30 a été généré par le compilateur 60 en mettant en œuvre le procédé de la . Ensuite, lors d'une phase 152, le microprocesseur 2 exécute le code binaire 30 et, en particulier, le code machine 32. Pour cela, pour chaque mot Wi pointé par le compteur ordinal 26, la chaîne 10 exécute successivement les étapes suivantes : - une étape 154 de chargement, par le chargeur 18, du mot Wi pointé par la valeur actuelle du compteur ordinal 26, puis - une étape 156 de déchiffrement, par le module 20, du cryptogramme contenu dans le mot Wi chargé pour obtenir une instruction Ii en clair, - une étape 158 de décodage, par le décodeur 22, de l’instruction Ii en clair, puis - une étape 160 d’exécution, par l’unité 24, de l’instruction Ii décodée. De plus, par exemple en parallèle de l’étape 160, lors d’une étape 162, le constructeur 42 construit la signature Si à partir de l’ensemble Idi de signaux générés par le décodeur 22 à l’issue de l’étape 158 et de la précédente signature Si-1 construite. La signature Si ainsi construite est alors transmise au module 20 de déchiffrement qui est alors en mesure de déchiffrer le cryptogramme Ii+1*de la prochaine instruction à exécuter. Si lors de l’étape 160, l’instruction Ii exécutée n’est pas une instruction qui déclenche la vérification d’intégrité, alors le compteur ordinal 26 est incrémenté du pas unitaire pour pointer sur le mot suivant Wi+1 et le procédé retourne directement à l’étape 154 pour exécuter l’instruction suivante Ii+1. Si lors de l’étape 160, l’instruction Ii exécutée est une instruction qui déclenche la vérification d’intégrité, alors la chaîne 10 de traitement exécute une étape 163 de vérification de l’intégrité du code machine exécuté jusqu’à présent. Ici, cette étape 163 comporte les opérations suivantes : - une opération 164 de chargement, par le chargeur 18, du mot Wi+1 qui suit immédiatement le mot Wi qui contient le cryptogramme Ii*, puis - une opération 168 de déchiffrement, par le module 20, du cryptogramme Srefi* contenu dans le mot Wi+1 pour obtenir la signature Srefi en clair, puis - une opération 170 de comparaison, par le vérificateur 44, de la signature Si construite pour l’instruction Ii à la signature Srefi obtenue à l’issue de l’opération 168. L’adresse du mot Wi+1 contenant le cryptogramme Srefi* est déduite de la valeur du compteur ordinal 26. Par exemple, ici, l’adresse du mot Wi+1 est égale à l’adresse contenue dans le compteur ordinal 26 après que l’instruction Ii ait été exécutée. Ensuite, si les signatures comparées Si et Srefi sont identiques, le procédé se poursuit par une étape 172 lors de laquelle le compteur ordinal 26 est incrémenté pour pointer directement sur le mot Wi+2. Après l’étape 172, le procédé retourne à l’étape 154 pour exécuter l’instruction Ii+2. A l’inverse, si les signatures comparées Si et Srefi sont différentes, le procédé se poursuit par une étape 180 lors de laquelle un défaut d’intégrité est signalé. De plus, lors de l’étape 158, si une instruction Ii ne peut pas être décodée car sa syntaxe est incorrecte, le procédé se poursuit aussi par l’étape 180 de signalement d’un défaut d’intégrité. Lors de cette étape 180, le décodeur 22 déclenche le signalement d’un défaut d’intégrité. En réponse à un signalement de défaut d’intégrité, lors d'une étape 182, le microprocesseur 2 met en œuvre une ou plusieurs contre-mesures. De très nombreuses contre-mesures sont possibles. Les contre-mesures mises en œuvre peuvent avoir des degrés de sévérité très différents. Par exemple, les contre-mesures mises en œuvre peuvent de la levée d’une interruption jusqu'à une mise hors service définitive du microprocesseur 2 et la suppression de données sensibles. Le microprocesseur 2 est considéré comme étant hors service lorsqu'il est définitivement placé dans un état où il est incapable d'exécuter un quelconque code machine. Entre ces degrés de sévérité extrêmes, il existe de nombreuses autres contre-mesures possibles telles que : - l'indication par l'intermédiaire d'une interface homme-machine de la détection des fautes, - l'interruption immédiate de l'exécution du code machine 32 et/ou sa réinitialisation, et - la suppression du code machine 32 de la mémoire 4 et/ou la suppression de la copie 40 de sauvegarde et/ou la suppression des données secrètes. Les étapes 154, 156, 158 et 160 sont typiquement exécutées chacune en un cycle d’horloge. De plus, certaines de ces étapes sont, de préférence, exécutées en parallèle pour différentes instructions successives du code machine 32. Par exemple, la chaîne 10 peut exécuter en parallèle : - l’étape 154 pour charger le cryptogramme Ii+1*, - l’étape 158 de décodage de l’instruction Ii, et - l’étape 160 d’exécution de l’instruction Ii-1. Chapitre III : Variantes Variantes du calculateur : La mémoire 4 peut aussi être une mémoire non volatile. Dans ce cas, il n'est pas nécessaire de copier le code binaire 30 à l'intérieur de cette mémoire avant le lancement de son exécution puisqu'il s'y trouve déjà. La mémoire 4 peut aussi être une mémoire interne intégrée à l'intérieur du microprocesseur 2. Dans ce dernier cas, elle est réalisée sur la même puce (« die » en anglais) que les autres éléments du microprocesseur 2. Enfin, dans d'autres configurations, la mémoire 4 se compose de plusieurs mémoires dont certaines sont réalisées sur la puce du microprocesseur et d’autres sont réalisées sur une autre puce mécaniquement indépendante de la puce du microprocesseur. En variante, l’opération de chargement du mot Wi et l’opération de déchiffrement du mot Wi sont réalisées lors du même cycle d’horloge par l’étage de chargement. Autrement dit, dans cette variante, le module 20 de déchiffrement est intégré dans le chargeur 18. Dans une autre variante, l’opération de déchiffrement du cryptogramme Wi et l’opération de décodage de l’instruction Ii sont réalisées lors du même cycle d’horloge. Autrement dit, dans cette variante, le module 20 de déchiffrement est intégré dans le décodeur 22. Il est aussi possible de placer le module 20 de déchiffrement n’importe où entre la mémoire d’instructions et le chargeur 18 d’instructions. Dans ce cas, le chargeur 18 d’instructions charge une instruction Ii qui a déjà été déchiffrée et non pas le mot Wi contenant le cryptogramme Ii*. Toutefois, cette dernière variante peut présenter un niveau de sécurité inférieur aux autres variantes. En variante, la chaîne matérielle de traitement comporte un ensemble de plusieurs unités arithmétiques et logiques et non pas une seule unité arithmétique et logique. Dans ce cas, en général, cet ensemble comporte des unités arithmétiques et logiques spécialisées dans l’exécution de certaines instructions spécifiques. Ainsi, lorsque l’une de ces instructions spécifiques est décodée, les signaux générés par le décodeur active spécifiquement l’unité arithmétique et logique spécialisée dans l’exécution de cette instruction spécifique. Par exemple, l’ensemble de plusieurs unités arithmétiques et logiques peut comporter : - un ou plusieurs co-processeurs, - une ou plusieurs mémoires IMC (« In Memory Computing ») chacune capable d’exécuter des traitements sur les données qu’elles stockent. En variante, la chaîne de traitement n’est pas située dans un microprocesseur mais dans un co-processeur ou dans une mémoire IMC. Dans une autre variante, les différents étages de la chaîne matérielle de traitement sont répartis différemment. En particulier, il n’est pas nécessaire que tous les étages de la chaîne de traitement soient localisés sur la même puce. Par exemple, dans une variante, le chargeur d’instruction et le décodeur sont situés sur la puce du microprocesseur tandis que l’unité arithmétique et logique est située sur une autre puce comme, par exemple, la puce d’une mémoire IMC. Dans une autre variante, c’est le constructeur 42 et le vérificateur 44 qui sont implémentés sur une autre puce. En variante, les instructions Ii n’ont pas toutes la même taille. Dans ce cas, les mots Wi n’ont pas non plus tous la même taille. Variantes de la construction de la signature S i : En variante, la signature Si est construite, en plus, à partir de signaux provenant d’un ou plusieurs étages suivant le décodeur 22 dans la chaîne 10 de traitement. Par exemple, les signaux générés par l’unité 24 sont utilisés pour construire la signature Si. Dans une variante particulière, seuls les signaux générés par un ou plusieurs étages suivants le décodeur 22 sont utilisés pour construire la signature Si. Dans ce cas, les signaux générés par le décodeur 22 ne sont pas utilisés. Par exemple, seuls les signaux générés par l’unité 24 lorsqu’elle exécute l’instruction Ii sont utilisés pour construire la signature Si. Dans cette variante particulière, il faut donc attendre que l’instruction Ii soit exécutée avant que la signature Si construite puisse être comparée à la signature Srefi. Autrement dit, dans cette variante, la vérification de l’intégrité de l’instruction Ii ne peut pas être exécutée immédiatement après son décodage par le décodeur 22. Dans un mode de réalisation simplifié, la signature Si est construite uniquement à partir du signal de configuration qui code l'opcode de l'instruction Ii ou uniquement à partir des signaux de configuration qui varient en fonction de la ou des valeurs des opérandes de l'instruction Ii. D’autres modes de réalisation de la fonction f() sont possibles. Par exemple, la fonction CBC-MAC est remplacée par une autre fonction d’authentification de message comme la fonction connue sous l’acronyme H-MAC (« H ash-based Message Authentication Code ») Dans un mode de réalisation simplifié, la fonction f() n’utilise pas de clé secrète. Dans ce cas, l’authenticité du code machine n’est pas garantie. Par exemple, la fonction f() est une fonction connue sous l’acronyme CRC (« Cyclic Redondancy Check) ou une fonction connue sous l’acronyme MISR (« Multiple-Input Signature Registers »). En variante, la fonction f() ne se comporte pas comme un CSPRNG. Dans ce cas, le procédé décrit permet tout de même la dissimulation du code machine. Il existe d’autres possibilités pour obtenir la signature initiale Sref0. Par exemple, le microprocesseur 2 est configuré pour construire la signature initiale Sref0 à partir du premier mot W1 du code machine 32. A titre d’illustration, la signature Sref0 est prise égale au premier mot W1. Dans ce dernier cas, la signature Sref0 est publique. Variantes du déchiffrement : D'autres fonctions g-1() sont possibles. Par exemple, la fonction g-1() est définie par la relation suivante : ii = (i*i + Si-1) modulo(n), où : - "modulo" est l'opération de l'arithmétique modulaire qui au couple (a, b) d'entiers, associe le reste de la division euclidienne de a par b, - n est le diviseur de l’opération modulaire, et - (i*i + Si-1) est le résultat de l’addition arithmétique de I*i et Si-1. Dans cet exemple, n est un nombre entier prédéterminé supérieur à deux. Par exemple, n est égal à 32. Un autre exemple possible de fonction g-1() est celle définie par la relation suivante : ii = i*i XOR Si-1 XOR ks, où ks est la clé secrète connue seulement du calculateur 2. Si la puissance de calcul le permet, la fonction g-1() peut aussi être une fonction de déchiffrement, par exemple, symétrique. La signature Si-1 peut alors être utilisée comme clé de déchiffrement. Dans un autre exemple, la clé de déchiffrement est la clé secrète ks indépendante des signatures Si. Dans ce dernier exemple, c’est une combinaison des bits du cryptogramme Ii* et de la signature Si-1 qui est déchiffrée à l’aide de la clé ks. A chaque fois que la fonction g-1() est modifiée, la fonction g() de chiffrement doit être adaptée en conséquence. D’autres modes de réalisation sont possibles pour chiffrer les signatures de référence contenues dans le code machine. Par exemple, en variante, le cryptogramme Srefi* contenu dans le mot Wi+1 est obtenu à l’aide de la relation suivante : Srefi* = g(Srefi ; Srefi) et non pas la relation Srefi* = g(Srefi ; Srefi-1). Cette variante présente l’avantage que quel que soit le mot Wi du code machine, la clé utilisée pour déchiffrer le cryptogramme qu’il contient est la signature Srefi-1. Ainsi, il n’est pas nécessaire de savoir si le mot Wi contient le cryptogramme d’une instruction ou d’une signature de référence pour être capable de sélectionner la clé de déchiffrement. Toutefois, dans ce cas, cela impose des contraintes supplémentaires sur le choix de la fonction g() de chiffrement. Par exemple, la fonction g() de chiffrement ne peut plus être un simple « OU EXCLUSIF » comme précédemment décrit car le résultat de Srefi XOR Srefi est systématiquement nul. Un exemple d’une fonction g() qui convient dans ce cas est une fonction de chiffrement symétrique. Une autre fonction g’-1() de déchiffrement peut être utilisée à la place de la fonction g-1() lorsque le cryptogramme à déchiffrer est celui d’une signature de référence. Par exemple, alors que la fonction « OU EXCLUSIF » est utilisée pour déchiffrer les cryptogrammes Ii*, la fonction g’-1() est une fonction de déchiffrement symétrique qui utilise une clé secrète prédéterminée kSref. Variantes de la vérification de l’intégrité : D’autres solutions sont possibles pour identifier que le mot chargé contient une signature de référence et non pas une instruction. Par exemple, dans un mode de réalisation particulier, chaque mot Wi contenant le cryptogramme Ii * d’une instruction est suivi d’un mot Wi+1 contenant tout ou partie du cryptogramme Srefi*. Dans ce cas, chaque mot pair chargé de la suite d’instructions, contient un cryptogramme d’une signature de référence. Il n’est alors pas nécessaire que l’instruction Ii soit une instruction de branchement qui indique que le mot suivant du code machine contient le cryptogramme Srefi*. Dans une variante du précédent mode de réalisation, la taille des mots Wi est augmentée de manière à enregistrer dans chaque mot Wi à la fois le cryptogramme Ii* et le cryptogramme Srefi*. Dans cette dernière variante, le cryptogramme Srefi* n’est pas enregistré dans le mot supplémentaire Wi+1. D’autres instructions que les instructions de branchement peuvent être utilisées pour déclencher la vérification d’intégrité. Par exemple, en variante, le code machine comporte une instruction spécifique qui, lorsqu’elle est exécutée par l’unité 24, indique que le mot suivant contient tout ou partie du cryptogramme Srefi* et déclenche le déchiffrement du cryptogramme Srefi* puis sa comparaison à la signature Si construite. En variante, le cryptogramme Srefi* est contenu dans le mot Wi-1 qui précède le mot Wi contenant le cryptogramme Ii* et non pas dans le mot Wi+1 comme précédemment décrit. Dans ce cas, l’instruction contenu dans le mot Wi-2 provoque le déchiffrement et le chargement de la signature Srefi dans le vérificateur 44 et le vérificateur compare la signature Srefi chargée à la signature Si construite après que le décodeur 22 ait décodé l’instruction Ii. Dans une autre variante, les signatures de référence ne sont pas enregistrées dans la mémoire d’instructions qui contient le code machine 32. Par exemple, les signatures de référence sont enregistrées dans une mémoire sécurisée indépendante de la mémoire d’instructions contenant les cryptogrammes Ii*. Typiquement, la mémoire sécurisée est une mémoire seulement accessible par le vérificateur 44. Dans ce cas, il n’est pas nécessaire que les signatures de référence soient stockées dans cette mémoire sécurisée sous forme de cryptogrammes. Dans cette variante, le code machine comporte des cryptogrammes d’instructions de chargement. Après déchiffrement, cette instruction de chargement est exécutée. Son exécution provoque le chargement de la signature de référence enregistrée dans la mémoire sécurisée. Par exemple, en réponse à l’exécution d’une telle instruction de chargement, la signature de référence est chargée dans le vérificateur 44 puis utilisée pour vérifier la signature construite pour une instruction décodée. En variante, seule une partie du cryptogramme Srefi* est enregistrée dans un mot du code machine. L’autre partie de ce cryptogramme Srefi* est enregistrée ailleurs, par exemple, dans la mémoire sécurisée mentionnée au paragraphe précédent. D’autres mécanismes de mise à jour des signatures, différents du mécanisme GPSA, sont possibles. Par exemple, en variante, à chaque fois qu’une instruction de branchement est exécutée, cela déclenche le chargement, par exemple à partir d’une mémoire sécurisée, d’une signature de référence associée à cette instruction de branchement. Autres variantes : En variante, seules certaines instructions du code machine sont chiffrées. Par exemple, pour cela, une instruction spécifique est ajoutée au jeu d'instructions du microprocesseur 2. Lorsque cette instruction spécifique est exécutée par l'unité 24, elle indique au microprocesseur que les T prochaines instructions ne sont pas des instructions chiffrées et ne doivent donc pas être déchiffrées. Typiquement, le nombre T est un nombre entier supérieur ou égal à 1 ou 10 ou 100. Chaque mot Wi peut contenir des métadonnées en plus du cryptogramme Ii*. Par exemple, ces métadonnées permettent de vérifier l’intégrité ou l’authenticité du cryptogramme Ii* avant que celui-ci ne soit chargé par la chaîne 10 de traitement. Ces métadonnées peuvent aussi être utilisées pour indiquer que le mot Wi contient le cryptogramme d’une signature de référence ou, au contraire, le cryptogramme d’une instruction. Selon une autre variante, c'est un bit spécifique d'un registre de statut ou de contrôle du microprocesseur 2 qui indique si le mot chargé contient ou non le cryptogramme d’une instruction. Plus précisément, lorsque ce bit spécifique prend une valeur prédéterminée, le mot chargé est traité par la chaîne 10 comme une instruction. Si ce bit spécifique prend une valeur différente de cette valeur prédéterminée, alors le mot chargé est traité comme une signature de référence. Lors de la compilation du code machine 30, l’étape 76 peut être réalisée en même temps que l’étape 72. Dans ce cas, lors de l’étape 72, pour chaque instruction de branchement, le compilateur 60 calcule en plus la signature Srefi correspondante et l’insère dans le mot Wi+1 qui suit cette instruction de branchement. Dans ce cas, de préférence, lors de l’étape 74 chaque signature Srefi est chiffrée en utilisant exactement le même algorithme que celui utilisé pour chiffrer les instructions Ii de sorte que, lors de l’étape 74, le compilateur n’a pas à distinguer les mots qui contiennent une instruction en clair des mots qui contiennent une signature en clair. Plusieurs des différents modes de réalisation décrits ici peuvent être combinés entre eux. Chapitre III : Avantages des modes de réalisation décrits Dans les modes de réalisation décrits ici, les instructions du code machine ne sont pas enregistrées en clair dans la mémoire principale ce qui rend plus difficile l’analyse du code machine. La signature Si est construite à partir de la signature Si-1 qui est elle-même fonction de la précédente instruction Ii-1 et de la précédente signature Si-2. Ainsi, par récursivité, la signature Si-1 utilisée pour déchiffrer l’instruction Ii dépend de toutes les instructions précédemment exécutées. Dès lors, une erreur dans le déchiffrement d’une instruction Ii rend impossible le déchiffrement de toutes les instructions suivantes. L’intégrité du code est donc garantie avec un très haut niveau de sécurité. En particulier, les modes de réalisation décrits ici permettent de déclencher le signalement d'un défaut d’intégrité en cas de modification d'une instruction ou de saut d'instructions. De plus, la signature Si dépend de l’ensemble Idi de signaux de configuration. Par conséquent, les modes de réalisation décrits ici permettent aussi de déclencher le signalement d’un défaut d’intégrité en cas de modification de l’instruction après son décodage, c’est-à-dire typiquement en cas d'erreur dans le décodage de l'instruction. Le fait de comparer la signature construite Si à une signature de référence pré-enregistre Srefi permet de détecter un défaut d’intégrité sans avoir pour cela à déchiffrer et à exécuter l’instruction suivante Ii+1. Plus précisément, cela permet de détecter un défaut d’intégrité sans reposer sur le fait que le déchiffrement d’un cryptogrammes Ii+n* d’une instruction suivante produit nécessairement une instruction erronée I’i+n qui n’appartient pas au jeu d’instructions du microprocesseur 2 si l’intégrité de l’instruction Ii a été compromise, où n est un nombre entier supérieur ou égal à un. Ainsi, la comparaison de la signature Si à la signature de référence Srefi, permet de détecter un défaut d’intégrité même lorsque le jeu d’instructions du calculateur n’est pas clairsemé. Cette comparaison permet aussi de limiter le nombre de comportements inattendus du calculateur et donc d’augmenter la sécurité du procédé. Le fait de déchiffrer la signature de référence à l’aide d’une signature construite pour l’une des instructions de la suite d’instructions permet d’augmenter la sécurité du procédé. En effet, la signature de référence est dissimulée et de plus elle peut être correctement déchiffrée uniquement si la suite d’instructions précédemment déchiffrées est intègre. Le fait de déchiffrer le cryptogramme de la signature de référence Srefi à partir de la signature construite Si-1 ou Si permet de simplifier le fonctionnement du calculateur car la même fonction g() est utilisée que le cryptogramme à déchiffrer soit celui d’une instruction ou d’une signature de référence. Le fait d’utiliser une clé secrète pour construire la signature Si permet en plus d’authentifier le code car seul un code machine authentique comporte une suite d’instructions chiffrées à l’aide de cette même clé secrète. Le fait d’utiliser seulement les signaux générés par le décodeur pour construire la signature Si permet d’accélérer l’exécution du code machine. En effet, dans ce cas, il n’est pas nécessaire d’attendre que l’instruction Ii soit traitée par un étage suivant le décodeur 22 pour que la signature Si puisse être construite puis comparée à la signature Srefi. Le fait de construire la signature Si en fonction de l’opcode et des opérandes de l’instruction Ii renforce la garantie d’intégrité du code puisque une modification quelconque de l’instruction Ii entraîne une modification de la signature Si. Procédé d'exécution d'un code machine par un calculateur comportant une chaîne matérielle de traitement d'instructions, cette chaîne matérielle de traitement comportant une succession d’étages qui traitent les uns après les autres chaque instruction à exécuter du code machine, cette succession d’étages comportant au moins les étages suivants : un chargeur d'instructions, un décodeur et une unité arithmétique et logique, ce code machine comprenant un cryptogramme pour chaque instruction d’une suite d’instructions consécutives, ce procédé comportant l’exécution des étapes suivantes pour chaque cryptogramme d’une instruction d’une suite d’instructions consécutives du code machine : - le chargement (154), par le chargeur d'instructions, du cryptogramme d’une instruction désignée par un compteur ordinal pour obtenir un cryptogramme chargé, puis - le déchiffrement (156) du cryptogramme chargé pour obtenir une instruction déchiffrée, puis - le décodage (158) de l'instruction déchiffrée, par le décodeur, pour générer des signaux qui configurent le calculateur pour exécuter l'instruction déchiffrée, puis, - l'exécution (160), par l'unité arithmétique et logique, de l'instruction déchiffrée, caractérisé en ce que le procédé comporte également les étapes suivantes pour au moins une instruction courante de la suite d’instructions consécutives : - après l'opération de décodage de l’instruction courante et avant le déchiffrement du cryptogramme de l’instruction suivante dans la suite d’instructions consécutives, la construction (162) d'une signature pour l’instruction courante : - à partir d’un ensemble de signaux générés par un étage de la succession d’étages en réponse au traitement de cette instruction courante par cet étage, cet étage qui génère cet ensemble de signaux étant le décodeur ou un étage suivant le décodeur dans la succession d’étages, et - à partir de la précédente signature construite pour l’instruction qui la précède dans la suite d’instructions consécutives, cette signature pour l’instruction courante variant ainsi en fonction de l'instruction courante et en fonction de toutes les instructions précédant l’instruction courante dans la suite d’instructions consécutives, puis - la vérification (163) de l’intégrité du code machine exécuté en comparant (170) la signature construite pour l’instruction courante à une signature de référence pré-enregistrée, puis - seulement lorsque la vérification de l’intégrité de l’instruction courante est réussie, le déchiffrement (156) du cryptogramme de l’instruction suivante à l'aide de la signature construite pour l’instruction courante. Procédé selon la revendication 1, dans lequel l’étape de vérification de l’intégrité comporte : - le chargement (164) d’un cryptogramme de la signature de référence, puis - le déchiffrement (168) de ce cryptogramme à l’aide d’une des signatures construites pour l’une des instructions de la suite d’instructions. Procédé selon la revendication 2, dans lequel : - le cryptogramme de la signature de référence est chargé à partir de l’adresse contenue dans le compteur ordinal après le chargement du cryptogramme de l’instruction courante et avant le chargement du cryptogramme de l’instruction suivante, et - le cryptogramme de la signature de référence est déchiffré à l’aide de la signature construite pour l’instruction courante ou pour l’instruction qui précède cette instruction courante dans la suite d’instructions consécutives. Procédé selon la revendication 1, dans lequel lors de la construction (162) de la signature pour l’instruction courante, cette signature est en plus construite à partir d’une clé secrète pré-enregistrée dans une mémoire du calculateur. Procédé selon l'une quelconque des revendications précédentes, dans lequel l’étage qui génère l’ensemble de signaux utilisé pour construire la signature est le décodeur. Procédé selon la revendication 5, dans lequel, lors de la construction (162) d’une signature pour l’instruction courante, cette signature est construite à partir de signaux, générés par le décodeur en réponse au décodage de l'instruction courante, qui varient en fonction de l'opcode de l'instruction courante et en fonction de chaque opérande de l'instruction courante. Procédé selon l'une quelconque des revendications précédentes, dans lequel le déchiffrement du cryptogramme de chaque instruction à l'aide de la signature construite consiste en la réalisation d'un "OU EXCLUSIF" entre les bits du cryptogramme de l'instruction et les bits de la signature construite pour l’instruction qui précède cette instruction dans la suite d’instructions consécutives. Procédé selon l’une quelconque des revendications précédentes, dans lequel, lorsque la signature construite pour l’instruction courante est différente de la signature de référence pré-enregistrée à laquelle elle est comparée, l’étape (163) de vérification de l’intégrité de l’instruction courante se poursuit par une étape (180) de signalement d’un défaut d’intégrité. Code machine (32) apte à être exécuté en mettant en œuvre un procédé conforme à l’une quelconque des revendications précédentes, ce code machine comprenant un cryptogramme pour chaque instruction d’une suite d’instructions consécutives, caractérisé en ce que : - chacun de ces cryptogramme est le chiffré d’une instruction correspondante de cette suite d’instructions consécutives à l'aide d'une signature construite : - à partir des signaux générés par un étage de la succession d’étages en réponse au décodage de cette instruction correspondante par cet étage, cet étage qui génère cet ensemble de signaux étant le décodeur ou un étage suivant le décodeur dans la succession d’étages, et - à partir de la précédente signature construite pour l’instruction qui la précède dans la suite d’instructions consécutives, cette signature pour l’instruction correspondante variant ainsi en fonction de l'instruction correspondante et en fonction de toutes les instructions précédant l’instruction correspondante dans la suite d’instructions consécutives, et - le code machine comporte également la signature de référence pré-enregistrée à laquelle la signature construite pour une instruction courante est comparée lors de l’exécution de ce code machine en mettant en œuvre un procédé conforme à l’une quelconques des revendications précédentes. Support d'enregistrement d'informations lisible par un microprocesseur d’un calculateur, caractérisé en ce qu'il comporte un code machine conforme à la revendications 9. Calculateur pour la mise en œuvre d'un procédé d'exécution conforme à l'une quelconque des revendications 1 à 8, ce calculateur comportant une chaîne matérielle (10) de traitement d'instructions, cette chaîne matérielle de traitement comportant une succession d’étages qui traitent les uns après les autres chaque instruction à exécuter du code machine, cette succession d’étages comportant au moins les étages suivants : un chargeur d'instructions (18), un décodeur (20) et une unité arithmétique et logique (22), cette chaîne matérielle de traitement étant apte, pour chaque cryptogramme d’une instruction d’une suite d’instructions consécutives d’un code machine, à exécuter les opérations suivantes : - le chargement, par le chargeur d'instructions, du cryptogramme d’une instruction désignée par un compteur ordinal pour obtenir un cryptogramme chargé, puis - le déchiffrement du cryptogramme chargé pour obtenir une instruction déchiffrée, puis - le décodage de l'instruction déchiffrée, par le décodeur, pour générer des signaux qui configurent le calculateur pour exécuter l'instruction déchiffrée, puis, - l'exécution, par l'unité arithmétique et logique, de l'instruction déchiffrée, caractérisé en ce que la chaîne matérielle de traitement est également configurée pour exécuter les étapes suivantes pour au moins une instruction courante de la suite d’instructions consécutives : - après l'opération de décodage de l’instruction courante et avant le déchiffrement du cryptogramme de l’instruction suivante dans la suite d’instructions consécutives, la construction d'une signature pour l’instruction courante : - à partir des signaux générés par un étage de la succession d’étages en réponse au décodage de cette instruction courante par cet étage, cet étage qui génère cet ensemble de signaux étant le décodeur ou un étage suivant le décodeur dans la succession d’étages, et - à partir de la précédente signature construite pour l’instruction qui la précède dans la suite d’instructions consécutives, cette signature pour l’instruction courante variant ainsi en fonction de l'instruction courante et en fonction de toutes les instructions précédant l’instruction courante dans la suite d’instructions consécutives, puis - la vérification de l’intégrité de l’instruction courante en comparant la signature construite pour l’instruction courante à une signature de référence pré-enregistrée, puis - seulement lorsque la vérification de l’intégrité de l’instruction courante est réussie, le déchiffrement du cryptogramme de l’instruction suivante à l'aide de la signature construite pour l’instruction courante. Compilateur apte à transformer automatiquement un code source d'un programme d'ordinateur en un code binaire comportant un code machine exécutable par un calculateur comportant une chaîne matérielle de traitement d'instructions, cette chaîne matérielle de traitement comportant les étages suivants : un chargeur d'instructions, un décodeur et une unité arithmétique et logique, ce compilateur comportant un microprocesseur programmable (64) et une mémoire (66), caractérisé en ce que le compilateur est apte à transformer automatiquement le code source en un code machine conforme à la revendication 8.