FR 2765363 A1 19981231 FR 9708210 A 19970630 PROCEDE ET SYSTEME DE CONTROLE DE L'UTILISATION D'UN LOGICIEL La présente invention concerne un procédé de contrôle de l'utilisation d'un logiciel fonctionnant sous une plate-forme déterminée, associé à un dispositif muni d'un circuit électronique à mémoire rémanente à lecture/écriture, connecté aux bornes d'un port parallèle entre un ordinateur et un appareil périphérique, dans lequel on traite dans le dispositif et/ou on renvoie à partir dudit dispositif des signaux à l'ordinateur en réponse à des signaux émis à partir de ce dernier. Par plate-forme on entend un environnement correspondant à un système d'exploitation déterminé, TM tel que l'environnement Windows>, l'environnement TM TM Unix, ou d'autres environnements (Apple, par exemple), faisant notamment appel à des bibliothèques de liens dynamiques (DLL, initiales de Dynamic Lien Librairy en langage anglo-saxon). On sait que les bibliothèques de liens dynamiques (DLL) constituent un utilitaire important au sein des systèmes d'exploitation. Les DLL offrent la possibilité de connecter des modules préécrits dans le système d'exploitation. Cela permet aux applications de partager le codage commun, de modulariser les fonctions couramment utilisées et d'assurer une certaine extensibilité. La présente invention concerne également un système de contrôle interactif de l'utilisation de logiciels. Elle trouve une application particulièrement importante bien que non exclusive dans le domaine de la protection contre la copie de logiciels utilisée sur des micro-ordinateurs sous plate-forme WindowsTM 16 et 32 bits. On connait déjà des méthodes de protection de logiciels stockées par exemple sur disquettes permettant d'éviter la copie de ces dernières. La première méthode de protection consiste à court-circuiter la partie de programme du micro- ordinateur qui lit les disquettes. S15 Une deuxième méthode consiste à marquer la disquette de manière irréversible en détruisant un endroit particulier du support magnétique avec un rayon laser. Les deux méthodes mentionnées ci-dessus présentent des inconvénients notamment parce qu'elles empêchent l'utilisateur de faire une copie de sauvegarde de ses programmes. Une troisième méthode consiste à marquer l'ordinateur au moyen d'un dispositif électronique, parfois appelé clé. Le programme, au cours de son exécution, va alors vérifier la présence de cette clé constituée par un circuit électronique qui renvoie des codes lorsqu'il est sollicité. Ce circuit peut se loger directement dans l'un des connecteurs d'extension de l'ordinateur, ou plus simplement se brancher sur l'une des prises ou ports externes, par exemple celle de l'imprimante sans pour autant perturber le fonctionnement de cette dernière. On peut ainsi copier le logiciel à volonté. Ce système qui a été encore amélioré en rendant les clés directement programmables grâce à une mémoire rémanente à lecture/écriture est de loin le plus efficace. Il présente cependant un certain nombre d'inconvénients. En effet, dans les logiciels qui fonctionnent actuellement sur une plate-forme déterminée, et plus particulièrement ceux qui fonctionnent sur plate- forme WindowsTM (16 et 32 bits), se posent des problèmes de compatibilité des systèmes utilisés lors de la programmation par le programmeur de la clé en fonction des langages et/ou générations de logiciels qu'il utilise. La présente invention vise à fournir un procédé et un système de contrôle du fonctionnement d'un logiciel répondant mieux que ceux antérieurement connus aux exigences de la pratique, notamment en ce qu'elle permet de palier les inconvénients ci-dessus mentionnés, et en ce qu'elle permet par des procédures d'installation simplifiées de ne plus se préoccuper de la plate-forme finale sur laquelle fonctionnera l'application. Avec ladite invention, le programmeur va donc autoriser ou non le fonctionnement du logiciel protégé de façon optimisée, ce qui présente un résultat technique particulièrement avantageux,à une époque o le piratage de logiciels est malheureusement en recrudescence. Dans ce but, l'invention propose notamment un procédé de contrôle de l'utilisation d'un logiciel développé sous une plate-forme déterminée, associé à un dispositif muni d'un circuit électronique à mémoire rémanente à lecture/écriture, connecté aux bornes d'un port parallèle entre un ordinateur et un appareil périphérique, dans lequel on traite dans le dispositif et/ou on renvoie à partir dudit dispositif des signaux à l'ordinateur en réponse à des signaux émis à partir de ce dernier, caractérisé en ce que on écrit et on lit dans le circuit du dispositif en faisant appel à une fonction intégrée dans un fichier objet (.OBJ) ou un fichier de Librairie Dynamique (.DLL) préalablement inséré dans ledit logiciel, ladite fonction ayant la forme suivante: Résultat = cnrm(varl, var2,... varn) avec n > 3 dans laquelle varl à varn correspondent à des valeurs particulières selon ce que l'on souhaite exécuter avec le dispositif et à au moins une valeur spécifique correspondant à un utilisateur déterminé, ladite fonction étant agencée pour permettre de détecter automatiquement le type de plate-forme déterminée, et calculer le contexte d'exécution du logiciel en fonction de ladite plate-forme. Après appel, varl à varn contiennent des valeurs résultats dépendant de l'action exécutée donc des valeurs données lors de l'appel. Résultat contiendra la valeur de varl après appel. Plus précisément l'interface logicielle permettant de lire et d'écrire dans la clé se présente sous les formes suivantes: - un fichier objet (.OBJ) à utiliser pour les programmes écrits dans les langages compilés comme le C ou le Pascal, pour lequel l'appel est conforme à ce qui est décrit ci-dessus, ou - une librairie dynamique (.DLL) à utiliser par les programmes écrits dans les langages interprétés ou semi- compilés (VISUAL BASIC, WINDEV), mais aussi dans certains cas avec des langages compilés. Avantageusement, lors de la mise en oeuvre de la fonction de liaison (Login) entre le logiciel et le dispositif, on identifie la clé et/ou sa position par l'intermédiaire d'une valeur spécifique (cfgFun et/ou cfgKey), par exemple donnée par le logiciel, ou obtenue ou explorant les clés successives, et on mémorise cette valeur spécifique qu'on utilise ensuite comme constante lors du fonctionnement dudit logiciel. Dans un mode de réalisation avantageux la fonction cnrm est agencée (fonction cnrmcb) pour rappeler au moins une fois le logiciel en cours de fonctionnement de façon à vérifier que c'est bien la fonction cnrm d'origine qui a été appelée. Par fonction cnrm d'origine on entend celle qui a été conçue et prévue pour fonctionner d'origine avec le dispositif, par le constructeur du dispositif. Dans un mode de réalisation avantageux, la plate- forme déterminée est une plate-forme WindowsTM, ladite fonction cnrm étant agencée pour permettre de reconnaître automatiquement le type de passage de paramètres par référence ou par valeur mis en oeuvre dans le logiciel. Rappelons que dans ce cas, en raison de la nature de certains langages de programmation, la librairie dynamique est en réalité construite sous la forme de deux librairies dynamiques: - une librairie dynamique avec passage des paramètres par référence pour lequel l'appel est conforme à ce qui est décrit ci-dessus, c'est-à-dire pour lequel Résultat contient la valeur varl après appel (soit un premier fichier DLL pour application 16 bits, et un deuxième fichier DLL pour application 32 bits), - une librairie dynamique avec passage des paramètres par valeur pour laquelle un paramètre supplémentaire permet de définir quelle valeur de varl à varn est à mettre dans Résultat après appel. (soit un troisième fichier DLL pour les applications 16 bits et un quatrième fichier DLL pour les applications 32 bits). Antérieurement à l'invention, lors d'un fonctionnement sous le système d'exploitation WINDOWS NT d'une application 16 bits (écrite pour WINDOWS 3.xx), des mécanismes supplémentaires étaient nécessaires. Le programmeur était en effet obligé d'utiliser une librairie dynamique même pour un langage compilé, ceci afin de pouvoir remplacer le premier fichier DLL par un cinquième fichier DLL spécifique à l'environnement WINDOWS NT. Ce cinquième fichier DLL spécifique appelait alors lui-même un sixième fichier DLL 32 bits spécifique à WINDOWS NT qui à son tour appelait le module d'interface périphéricue/unité centrale(driver en langage anglo-saxon) chargé des entrées/sorties vers la clé. Il fallait utiliser le même type de mécanisme pour le troisième fichier DLL en cas de passage des paramètres par référence. Pour résumer les cas de figures suivants existaient sous plate-forme WindowsTM avant l'invention: Avec une application 16 bits avec programmes compilés, lors de l'utilisation de la librairie.OBJ le fonctionnement s'effectuait exclusivement sous WINDOWS 16 bits. Lors de l'utilisation du premier fichier DLL (version WINDOWS 16 bits) il fallait par contre remplacer ce premier fichier DLL par une version spéciale NT, prévoir un sixième fichier DLL spécial pour WINDOWS NT et installer le driver NT. Avec une application 16 bits avec programmes semi- compilés ou interprétés, si l'application permettait le passage de paramètres par références, lors de l'utilisation du premier fichier DLL (version WINDOWS 16 bits) pour fonctionner sous WINDOWS NT il fallait remplacer ce premier fichier DLL par une version spéciale NT, prévoir un cinquième fichier spécial pour WINDOWS NT et installer le driver NT. Mais si l'application ne permettait pas le passage de paramètres par références lors de l'utilisation du troisième fichier DLL (version WINDOWS 16 bits) pour fonctionner sous WINDOWS NT il fallait remplacer ce troisième fichier DLL par une version spéciale NT, prévoir une autre DLL spéciale pour WINDOWS NT et installer le driver NT. Avec une application 32 bits avec programmes compilés, lors de l'utilisation de la librairie.OBJ, le fonctionnement s'effectuait par contre exclusivement sous WINDOWS 32 bits (WINDOWS 95 ou WIN32S). Le fonctionnement ne s'effectuait pas sous NT, cas dans lequel il faut un.OBJ spécifique donc deux programmes différents pour le 32 bits. Lors de l'utilisation du deuxième fichier DLL (version WINDOWS 32 bits) pour fonctionner sous WINDOWS NT il fallait par contre remplacer ce deuxième fichier DLL par une version spéciale NT et installer le driver NT. Enfin avec une application 32 bits avec programmes semi-compilés ou interprétés, si l'application permettait le passage de paramètres par références, lors de l'utilisation du deuxième fichier DLL (version WINDOWS 32 bits) pour fonctionner sous WINDOWS NT il fallait remplacer ici encore ce deuxième fichier DLL par une version spéciale NT et installer le driver NT. Par contre si l'application ne permettait pas le passage de paramètres par références, lors de l'utilisation du quatrième fichier DLL (version WINDOWS 32 bits) pour fonctionner sous WINDOWS NT il fallait remplacer ce quatrième fichier DLL par une version spéciale NT et installer obligatoirement, le driver NT. De tels procédés présentent donc des inconvénients. En effet le nombre de DLL et la différenciation des DLL selon la plate- forme d'exécution obligent les utilisateurs à prendre en compte tous les cas de figures et à avoir une procédure d'installation complexe. Les programmes compilés sont amenés à utiliser obligatoirement une DLL pour être portables sur NT sans compilation. La compréhension des différents cas possibles n'est donc pas évidente et conduisait les programmeurs à faire des erreurs, ce qui augmentait les coûts d'intervention lors de l'installation et l'utilisation des logiciels et entraînait de ce fait des effets techniques non satisfaisants. La plate-forme déterminée étant une plate-forme Windows, et/ou ladite fonction cnrm étant agencée pour permettre de reconnaître automatiquement le type de passage de paramètres par référence ou par valeur mis en oeuvre dans le logiciel, ces divers inconvénients sont palliés. De façon classique, avant toute manipulation de clé, on sait qu'on effectue une opération dite ci- après Login. Le login est en effet une action nécessaire afin d'être sûr de lire et d'écrire dans la bonne clé. Selon un mode de réalisation de l'invention, à chaque appel de cnrm, on va ainsi et par exemple passer les codes éditeurs dans les variables var2, var3 pour valider la bonne clé. Lors du login clé, on alloue alors une zone mémoire (pile) associée au login, dans laquelle seront stockées les valeurs de retour de varl à varn et aussi les éléments du contexte d'exécution spécifique à la plate-forme. Pour permettre la reconnaissance et le passage automatique de paramètres par référence et par valeur, l'appel de la fonction cnrm est complété par une fonction cnrmvar dont l'objectif est de récupérer le contenu après appel de varl à varn. Sa forme est la suivante: Résultat = cnrmvar(handle de login, numéro de variable(l à n)) Son utilisation se fera en lieu et place de la variable correspondante. Par exemple, dans un mode avantageux de l'invention ou la valeur n est égale à 8, au lieu d'utiliser une méthode du type: varl = 12; {lecture de registre} var2 = codeO; {code éditeur} var3 = codel; {code éditeur} var4 = cleO; {mot de passe éditeur} var5 = 0; var6 = O; var7 = 5; {numéro de registre à lire} var8 = O; res = cnrm (varl, var2, var3, var4, var5, var6, var7, var8); if (varl == Vrai { } On prévoit une affectation comme suit: varl = 12; {lecture de registre} var2 = codeO; {code éditeur} var3 = codel; {code éditeur} var4 = cleO; {mot de passe éditeur} var5 = 0; var6 = O; var7 = 5; {numéro de registre à lire} var8 = O; res = cnrm (varl, var2, var3, var4, var5, var6, var7, var8); if (cnrmvar(cfgLog, 1) == Vrai { } Au moment de l'appel, la fonction cnrm va analyser le contenu de la pile. Si elle trouve les codes éditeurs dans la pile alors elle saura que c'est un passage par valeur, sinon c'est un passage par référence. A noter que ce mécanisme nécessite que les interfaces logiciels soient personnalisés par éditeur, que chaque interface par éditeur soit capable de reconnaître les codes éditeurs dans la pile, et que chaque éditeur possède des codes différents, ce qui est prévu et mis en oeuvre par le fabricant des clés. De cette manière, le programmeur n'a plus du tout à se soucier du mode de passage des paramètres, et peut choisir le mode qu'il souhaite quand il le souhaite. Lors de l'utilisation de programmes semi- compilés mettant en oeuvre uniquement des passages de paramètres par valeur, il aura un fonctionnement et un principe d'écriture identique à celui d'un programme compilé avec passage de paramètres par référence. L'appel à la fonction cnrm s'en trouve uniformisé et les appels peuvent se faire de la même manière quel que soit le langage. Dans un mode de réalisation avantageux on ne met en place le contexte d'exécution qu'une seule fois, lors de la première mise en oeuvre de la fonction de liaison entre le logiciel et le dispositif (login d'entrée). Ceci procure ainsi le maximum de performance pour les autres appels de la fonction cnrm. Avantageusement le procédé comprend de plus la mise en oeuvre d'une méthode de protection dans laquelle on choisit quelques fonctions sensibles du logiciel à protéger, on masque le point d'entrée de ces fonctions par un appel indirect, et on crypte la structure qui contient le point d'entrée desdites fonctions. Ainsi, on garantit que la clé a bien été lue sinon le décryptage ne se fait pas, les points d'entrée des fonctions n'étant pas trouvés. En d'autres termes, si un utilisateur normal ayant une licence ne met pas sa clé, il aura le message " clé absente ". Si un pirate tente de remplacer la clé ou de supprimer le test de présence de la clé, le décryptage ne se fait pas, et dans ce cas les points d'entrée des fonctions ne sont pas trouvés. Le cryptage est avantageusement assuré par un programme externe après compilation et édition de liens. Il peut par exemple utiliser une chaîne dite REPERE1 qui doit être unique pour trouver la zone à crypter et la longueur de ladite zone. De façon plus générale, l'outil de cryptage sera adapté par le programmeur en fonction de ses besoins spécifiques. L'invention concerne aussi un système mettant en oeuvre le procédé décrit ci-dessus. Elle concerne également un système de contrôle de l'utilisation d'un logiciel développé sous une plate- forme déterminée, comprenant un dispositif muni d'un circuit électronique à mémoire rémanente à lecture/écriture, connectable aux bornes d'un port parallèle entre un ordinateur et un appareil périphérique, agencé pour traiter et/ou renvoyer des signaux à l'ordinateur en réponse à des signaux émis à partir de ce dernier, caractérisé en ce que le système comprend des moyens d'écriture et de lecture dans le circuit du dispositif en faisant appel à une fonction intégrée dans un fichier objet (.OBJ) ou un fichier de Librairie Dynamique (.DLL) préalablement inséré dans ledit logiciel, ladite fonction ayant la forme suivante: résultat = cnrm(varl, var2,... varS) dans laquelle varl à var8 correspondent à des valeurs particulières selon ce que l'on souhaite exécuter avec le dispositif et à au moins une valeur spécifique correspondant à un utilisateur déterminé, ladite fonction étant agencée pour permettre de détecter automatiquement le type de plate-forme déterminée, et de calculer le contexte d'exécution du logiciel en fonction de ladite plate-forme. Avantageusement le système comprend de plus des moyens propres à reconnaître automatiquement le type de passage de paramètres par référence ou par valeur mis en oeuvre dans le logiciel. L'invention sera mieux comprise à la lecture de la description des modes de réalisation donnés ci-après à titre d'exemple non limitatifs, en faisant notamment référence à différents tableaux. La description se réfère également aux dessins qui l'accompagnent, dans lesquels: - La figure 1 est une vue en perspective, schématique, d'un micro-ordinateur équipé d'un dispositif selon l'invention branché sur le port parallèle de connexion avec l'imprimante. - La figure 2 est un schéma bloc général d'un dispositif électronique appartenant au système selon l'invention. - Les figures 3 et 4 montrent un organigramme donnant les étapes de fonctionnement du système et du procédé de contrôle selon le mode de réalisation de l'invention plus particulièrement décrit ici. - La figure 5 est un organigramme d'un procédé de cryptage utilisé dans un mode de réalisation de l'invention. La figure 1 montre un micro-ordinateur 1 comportant un boîtier 2 et un écran 3. Le boîtier est muni d'une prise 4 à port parallèle de connexion via un câble 5 avec un appareil périphérique qui en l'espèce est une imprimante 6. Le micro-ordinateur 1 qui est programmé avec un logiciel protégé est muni sur son port parallèle d'un dispositif 7 correspondant audit logiciel protégé, en forme de connecteur double, branchables sur le port parallèle de l'ordinateur d'un côté et sur un autre boîtier de dispositif ou le câble de l'imprimante 5 de l'autre côté. Plus précisément, en référence à la figure 2, le dispositif selon le mode de réalisation de l'invention plus particulièrement décrit ici 7 comprend un boîtier 8 muni de deux prises 9 et 10 de branchement pour port parallèle connues en elles- mêmes, de type normalisé à 25 branches ("pins" en langage anglo-saxon) du côté du micro-ordinateur et d'un type femelle correspondant du côté imprimante. Le dispositif 7 selon l'invention comporte connecté à la prise mâle 9 reliée au micro-ordinateur 2 un circuit 11, lui-même raccordé d'une part à la prise femelle 10 et d'autre part au circuit automate de gestion 12. Le dispositif 7 est par exemple du type décrit dans le document 2.740.236 incorporé ici par référence, et qui ne sera donc pas détaillé plus avant. Dans le cadre des modes de réalisation de l'invention plus particulièrement décrits ici, on a TM envisagé ci-après le cas des plates-formes WindowsTM (16 et 32 bits). Le passage par valeur et par référence ayant dors et déjà été décrit ciavant, on va maintenant préciser la mise en place du contexte d'exécution selon la plate-forme WindowsTM en faisant notamment référence aux figures 3 et 4. Dans la suite, les bibliothèques et programmes utilisés font donc en particulier référence à ceux de la Société américaine Microsoft. Ils peuvent être consultés plus avant dans des guides du type et par exemple la " Bible des API " ou " Windows 95, Win32 programmation des API Secrets d'experts " publiés par Simon & Schuster Macmillan. Ainsi des API tel que getVersion, ou des DLL tels que GetProcAdress32W, vont pouvoir être mis en oeuvre sans explication complémentaire. Un mode de réalisation de l'algorithme de calcul et gestion du contexte selon le mode de réalisation de l'invention plus particulièrement décrit ici va maintenant être détaillé, la zone mémoire lors du login contenant les informations du contexte. Rappelons que lors du login de la clé, cnrm va automatiquement faire une reconnaissance de la plate- forme et mettre en place le contexte d'exécution adéquat. Ce contexte n'est avantageusement calculé qu'une seule fois. Pour ce faire, après mise en route de l'ordinateur (étape 16) et chargement du logiciel protégé avec mise en place de la clé (étape 18), cnrm va identifier (étape 20) si l'environnement est 16 ou 32 bits). Pour ce faire, la zone mémoire allouée lors du Login contient les informations du contexte. On va maintenant détailler le fonctionnement 32 bits. Si l'environnement est 32 bits Lors du login (test 22): - Recherche de plate-forme par l'API getVersion (étape 24) - Mémorisation du fait d'être sous NT ou non (étape 26) - Selon la plate-forme (test 28) on appelle les routines internes de cnrm pour le dialogue avec la clé (étape 30), ou on appelle le driver cnrm pour WINDOWS NT (étape 32) Lors des autres appels (étape 34): - Selon la plate-forme (test 28), on appelle les routines internes de cnrm pour le dialogue avec la clé (étape30), ou on appelle le driver cnrm pour WINDOWS NT (étape32) Si l'environnement est 16 bits Lors du login (test 36): Recherche de plate-forme par l'API getVersion (étape 38) - Si la version est ≤3.10 (test 40) on est sûr de ne pas être sous WINDOWS NT donc le fonctionnement en 16 bits peut continuer normalement (étape 48), c'est- à-dire appeler les routines internes de la fonction cnrm (voir ci-après étape 69) - Si la version est >3.10 alors on est sous une version 16 ou 32 bits On va alors retrouver la version en se plaçant en mode 32 bits (étape 42) - Chargement de la librairie dynamique KRNL386.DLL (16 bits) (étape 44) - Si le chargement échoue (test 46), on est sûr d'être sur une plate-forme 16 bits (étape 48) - Si le chargement n'échoue pas on va charger dynamiquement (étape 50) les fonctions - GetProcAddress32W LoadLibraryEX32W - CallProc32W - FreeLibrary32W Si l'une de ces fonctions n'existe pas (Echec du Chargement) (test 52) on est sûr d'être sur une plate-forme 16 bits seulement (48). Sinon, on est sur une plate-forme 32 bits, on va charger dynamiquement (étape 54) la DLL KERNEL32.DLL grâce à LoadLibrary32W chargé précédemment. On va charger dynamiquement (étape 56) la fonction GetVersion (32 bits) du module KERNEL32.DLL grâce à la fonction getProcAddress32W chargée précédemment. GetVersion (32 bits) est appelée (étape 58) par l'intermédiaire de callProc32W chargée précédemment, on obtient ainsi (étape 60) le numéro de version de la plate-forme 32 BITS sur laquelle on se trouve. Ce numéro de version nous permet de savoir si on est sur NT ou non. - Mémorisation du fait d'être sous NT ou non (étape 62) - Selon la plate-forme (test 66), on appelle les routines internes de cnrm (étape 69) pour le dialogue avec la clé, ou on appelle le driver CNRM (étape 68) pour WINDOWS NT de la manière suivante: On va charger dynamiquement (étape 70) les fonctions (on est sûr qu'elles sont là dans KRNL386.DLL car on les a déjà chargées lors du Login): GetProcAddress32W LoadLibraryEX32W CallProc32W FreeLibrary32W GetVDMPointer32W (fonction permettant de convertir des adresses du monde 16 bits vers le monde 32 bits) On va charger alors les fonctions de KERNEL32.DLL suivantes (étape 72) (par l'intermédiaire de LoadLibraryEX32W et GetProcAddress32W): CreateFileW DeviceIoControl CloseHandle afin de pouvoir appeler directement (étape 74) le driver NT en mode 32 bits. Lors des autres appels (test 36, étape 76) Selon la plate-forme (test 78), on appelle (étape ) les routines internes de cnrm pour le dialogue avec la clé (étape 69), ou on appelle le driver CNRM (étape 82) pour WINDOWS NT de la manière suivante: On va charger dynamiquement (étape 70) les fonctions (on est sûr qu'elles sont là dans le KNRL386. DLL car on les a déjà chargées): GetProcAddress32W LoadLibraryEX32W CallProc32W FreeLibrary32W GetVDMPointer32W (fonction permettant de convertir une adresse du monde 16 bits vers le monde 32 bits) On va charger alors dynamiquement (étape 72) les fonctions de KERNEL32.DLL suivantes (par l'intermédiaire de LoadLibraryEX32W et GetprocAddress32W): CreateFileW DeviceIoControl CloseHandle afin de pouvoir appeler directement (étape 74) le driver NT en mode 32 bits. On convertit alors, comme lors du Login, ce qui n'avait pas été décrit jusqu'alors, tous les pointers 16 bits en 32 bits par GetVDMPointer32 (étape 84). On appelle le driver (étape 86) par appel des fonctions CreateFileW, DeviceIoControl et CloseHandle par l'intermédiaire de la fonction CallProc32W. On va maintenant décrire plus précisément la fonction cnrm. Cnrm permet de réaliser de nombreuses actions vis à vis de la clé. Toutes ces actions (nommées aussi fonctions par la suite) sont accessibles à travers une fonction unique appelée " cnrm " de la forme générale: entier cnrm (référence varl, référence var2, référence var3, référence var4, référence var5, référence var6, référence var7, référence var8) En cas d'utilisation du langage C, on aura par exemple: Déclaration en C: Int cnrm (int *varl, int *var2 int *var3, int *var4, int *var5, int *var6, int *var7, int *var8); En cas d'utilisation du Pascal, il vient: Déclaration en Pascal: Fonction cnrm(var varl, var2, var3, var4, var5, var6, var7, var8: integer): integer; On notera selon les langages, qu'il peut être nécessaire de qualifier plus précisément ces prototypes, par exemples sous Windows on utilisera WINAPI. Ces éléments sont à la portée de l'homme du métier. Les actions sont par ailleurs regroupées en différentes catégories selon le mode de réalisation ci-après donné à titre d'exemple: Les actions locales pures Fonction 00: Test de présence clé sur la machine localeFonction 01: Initialisation du mot de passe de la clé s'il n'est pas initialisé Les actions de Login et Logout: Fonction 02: Login sur une clé particulière ou sur la première trouvée Fonction 03: Logout sur une clé pour laquelle un login a été fait Toutes les autres actions ne peuvent être exécutées que si un Login a été réussi et jusqu'au Logout correspondant. Les actions de verrouillage de registres de la clé: Fonction 04: Ecriture du registre de protection (défini des registres protégés en écriture) Fonction 05: Lecture du registre de protection (Lecture du nombre de registres protégés) Les actions de lecture et d'écriture dans des registres de la clé: Fonction 06: Ecriture d'un Buffer Far dans la clé Fonction 07: Lecture dans un Buffer Far du contenu de la clé Fonction 08: Ecriture d'un Buffer near dans la clé Fonction 09: Lecture dans un Buffer near du contenu de la clé Fonction 10: Ecriture de deux entiers dans deux registres consécutifs Fonction 11: Lecture de deux entiers dans deux registres consécutifs Fonction 12: Ecriture d'un entier dans un registre Fonction 13: Lecture d'un entier dans un registre Fonction 14: Ecriture d'un octet dans un registre Fonction 15: Lecture d'un octet dans un registre de 8 bits Fonction 16: Ecriture d'un bit dans un registre Fonction 17: Lecture d'un bit dans un registre Fonction 18: Ecriture d'une valeur à partir du registre X au registre Y Fonction 19: Incrémentation (+) ou décrémentation (-) Fonction 20: Rotation droite (+) ou gauche(-) Fonction 21: Décalage droite (+) ou gauche (-) Fonction 22: Ecriture d'une date Fonction 23: Lecture d'une date Les actions de gestion de la clé de cryptage et cryptage/décryptage Fonction 25: Ecriture d'une clé de cryptage far Fonction 26: Lecture d'une clé de cryptage far Fonction 27: Ecriture d'une clé de cryptage near Fonction 28: Lecture d'une clé de cryptage near Fonction 29: Cryptage texte far selon clé de cryptage Fonction 30: Décryptage texte far selon clé de cryptage Fonction 31: Cryptage texte near selon clé de cryptage Fonction 32: Décryptage texte near selon clé de cryptage Les actions de lecture et écriture d'informations système dans la clé Fonction 24: Lecture de la date de fabrication Fonction 34: Ecriture code utilisateur final Fonction 35: Lecture du code utilisateur final Fonction 36: Ecriture du code SSII Fonction 37: Lecture du code SSII Fonction 38: Réservation des registres destinés à une SSII Fonction 39: Lecture du nombre de registres destinés à une SSII Fonction 40: Ecriture du code multiprotection Fonction 41: Lecture du code multiprotection Fonction 42: Lecture du code distributeur national Fonction 43: Lecture du cheksum Fonction 44: Lecture du numéro de série Les actions spécifiques aux clés sur un réseau Fonction 46: Réseau: Ecriture du nombre maximum d'utilisateurs Fonction 47: Réseau: Lecture du nombre d'utilisateurs réseau Les actions spécifiques aux clés à horloge Fonction 50: Initialisation de la date et de l'heure dans l'horloge Fonction 51: Lecture de la date et de l'heure clé avec horloge Fonction 52: Clé avec horloge avec écriture alarme Fonction 53: Clé avec horloge avec lecture alarme Fonction 54: Clé avec horloge avec lecture statut Fonction 55: Clé avec horloge-Ecriture RAM/HORLOGE Fonction 56: Clé avec horloge-Lecture RAM/HORLOGE Les actions spécifiques aux clés à microprocesseur Fonction 48: Sauvegarde EEPROM vers microprocesseur Fonction 49: Initialisation EEPROM depuis le microprocesseur Les fonctions 33 et 45 sont réservées dans l'exemple plus particulièrement décrit ici. La fonction cnrm renvoie un entier (16 ou 32 bits selon que l'on est en environnement 16 ou 32 bits) Elle reçoit toujours 8 paramètres varl à var8 passés par référence (pointeurs) dont la valeur doit être initialisée avant appel, et dont la valeur après appel dépend de l'action demandée. Avant appel, le contenu des variables varl à var8 suit une convention qui est toujours la même. Apres appel, le contenu des variables dépend de l'action demandée, et suit toujours un modèle déterminé. La valeur renvoyée permet de savoir si l'action a réussi ou non, et en cas de succès varl prend une valeur appelée Vrai (la valeur de vrai est spécifique à chaque éditeur au même titre que les codes éditeurs) Pour certaines actions (Fonction 0, Fonction 1 et Fonction 2 uniquement), on peut combiner, par addition, au contenu de varl une valeur appelée CfgFun qui définie une position particulière de la clé. On a ainsi un format général et contenu des variables du type suivant: Avant appel: cfgLog = cnrm (référence varl, {Paramètre numéro d'action (fonction) [+ cfgFun]} référence var2, {Code client O = code0} référence var3, {Code client 1 = codel) référence var4, {Mot de passe (cléO) ou var4 reçu de l'action " LOGIN "} référence var5, {paramètre spécifique à l'action souhaitée} référence var6, {paramètre spécifique à l'action souhaitée} référence var7, {paramètre spécifique à l'action souhaitée} référence var8, {paramètre spécifique à l'action souhaitée}) Pour les fonctions 0, 1 et 2, var4 doit contenir le mot de passe cleO lors de l'appel de cnrm. Pour toutes les autres fonctions, var4 doit contenir la valeur reçue dans var4 lors du login (Fonction 2). Après appel: Pour les fonctions O et 1: cfgLog: toujours O varl: Vrai si l'action a réussie Une autre valeur en cas d'échec Pour toutes les autres fonctions: cfgLog peut-être égal à 0. Dans ce cas varl vaut O et var8 contient un code d'erreur cfgLog peut être différent de 0. Dans ce cas varl contient une valeur qui peut-être 0: Un code d'erreur se trouve dans var8 Vrai: L'action a réussie Autre valeur: Clé pas trouvée Dans tous les cas: var2: Une valeur spécifique à l'action demandée (cfgKey pour fonctions 0, 1 et 2) var3: Une valeur spécifique à l'action demandée (cfgFun pour fonctions 0, 1 et 2) var4: Une valeur unique qui ne plus être modifiée par la suite (Identique à cfgLog) var5: Une valeur spécifique à l'action demandée var6: Une valeur spécifique à l'action demandée var7: Une valeur spécifique à l'action demandée var8: Adresse du port parallèle sur lequel la clé à été trouvée ou code d'erreur La fonction de cfgKey est définie plus précisément ci-après, avec des valeurs prises en exemple de façon nullement limitative. CfgKey est une valeur sur 16 bits qui permet de connaître la position de la clé dans le cas d'utilisation de plusieurs clés. Les bits forment alors des groupes avec les significations suivantes: bits 0 à 3: Nombre de registres éditeur dans la clé 000: Pas de clé 001: 32 registres 010: 96 registres 011: 224 registres : 480 registres 101: 992 registres : 2016 registres 111: 4064 registres bit 4: 0 la clé est une clé multiprotection (Voie fonctions 40 et 41) 1 la clé est une clé multiprotection bit 5: 0 la clé ne contient pas de registre de protection (voir fonctions 4 et 5) 1 la clé contient un registre de protection bit 6: 0 la clé n'est pas une clé à horloge 1 la clé est une clé à horloge bit 7: Indicateur de sortie des données (Ack ou PE) bits 8 et 9: Adresse du port parallèle ou numéro de serveur Pour une clé en local les valeurs sont: 00: Pas de clé 01: 03bch : 0378h 11: 0278h Pour une clé en réseau 00: Serveur numéro 0 01: Serveur numéro 1 : Serveur numéro 2 11: Serveur numéro 3 bits 10 à 12: Numéro de la clé pour des clés empilées 000: Pas de clé 001: Clé numéro 1 010: Clé numéro 2 011: Clé numéro 3 : Clé numéro 4 101: Clé numéro 5 : Clé numéro 6 111: Clé numéro 7 bits 13 à 14: Emplacement de la clé 00: Pas de clé 01: Clé sur le poste local 10: Clé sur un serveur Novell 11: Clé sur un serveur compatible Netbios bit 15: Réservé La fonction de cfgFun est décrite quant à elle ci- après: CfgFun est une valeur sur 16 bits qui permet de connaître la position de la clé, ou de demander un login sur une clé particulière. La signification des bits est la suivante: bits 0 à 7: réservés bit 7: Indicateur de sortie des données (Ack ou PE) bits 8 et 9: Adresse du port parallèle ou numéro de serveur Pour une clé en local les valeurs sont: 00: Pas de clé 01: 03bch : 0378h 11: 0278h Pour une clé en réseau 00: Serveur numéro 0 01: Serveur numéro 1 : Serveur numéro 2 11: Serveur numéro 3 bits 10 à 12: Numéro de la clé pour des clés empilées 000: Pas de clé 001: Clé numéro 1 010: Clé numéro 2 011: Clé numéro 3 : Clé numéro 4 101: Clé numéro 5 : Clé numéro 6 111: Clé numéro 7 bits 13 à 14: Emplacement de la clé 00: Pas de clé 01: Clé sur le poste local : Clé sur un serveur Novell 11: Clé sur un serveur compatible Netbios bit 15: Réservé CfgFun peut-être utilisé pour faire un Login sur une clé particulière. Il faut pour cela positionner les bits en fonction de la recherche. On peut faire une recherche en précisant indépendamment chaque groupe de bits. On sélectionne alors l'emplacement de la clé (Bits 13 et 14) en spécifiant le type de serveur recherché ou si c'est une clé en local qui est recherchée Puis on sélectionne le numéro du serveur ou le port parallèle par les bits 8 et 9. Enfin on sélectionne le numéro de la clé par les bits 10 à 12. Par exemple pour faire un login uniquement sur la clé numéro 3 du serveur 2 de type Novell, la valeur de cfgFun sera: O 10 011 10 0000 0000, soit 04E00h. Lors du login il faudra mettre dans varl CfgFun + 2 pour que le login ne se fasse que sur la clé désirée. Si le cfgFun n'est pas utilisé lors du Login, cnrm recherche la première clé valide dont le nombre de connections n'est pas épuisé, sur l'ensemble du réseau dans l'ordre: Local Novell serveur 0 à serveur 3 Netbios serveur 0 à serveur 3 L'ordre de recherche sur les serveur peut ne pas être respecté pour augmenter l'efficacité de la recherche, cependant cnrm commence toujours par une recherche en local. On va maintenant décrire plus avant, à titre d'exemple les trois premières fonctionnalités de la fonction cnrm. Fonction 00: Test de présence de la clé en local Public: Non Système: Non Lecture: Non Ecriture: Non Ecriture une fois: Non Mot de passe: Oui, si déjà initialisé Accès SSII: Fonction 64 Protection: Non La fonction O permet de savoir si une clé du développeur est présente. Toutes les clés ont un code attribué par le fabricant de clés à chaque développeur. Elles seront reconnues quelque soit le contenu des différents registres. Contenu des variables Avantappel Après-appel Varl O + CfgFun Vrai Var2 CodeO cfgKey Var3 Codel cfgFun Var4 CléO ou O si CléO O pas initialisé Var5 0 Durée d'exécution de la fonction Var6 0 ou unité de temps Temps de début d'exécution de ou Vrai la fonction Var7 0 Version du logiciel ou Date du logiciel Var8 0 Adresse du port parallèle Avant appel: Initialisation des variables Les valeurs entre [] sont optionnelles. Varl: O [+ cfgFun] - Numéro de fonction. Ajouter cfgFun pour une clé locale afin que le test soit plus rapide. Var2: CodeO - Poids forts du code éditeur fourni par le vendeur clé Var3: Codel - Poids faibles du code éditeur fourni par le vendeur clé Var4: O ou mot de passe - Si le mot de passe n'est pas initialisé il faut utiliser 0, sinon il faut utiliser le mot de passe. Var5: O Var6: 1 ou 2 ou 3 ou 4 ou Vrai: Avec la valeur Vrai on demande de renvoyer la date dans var7. 1 permet de demander une valeur de durée d'exécution en microsecondes, 2 permet d'avoir la durée en millisecondes, 3 permet d'avoir la durée en ticks d'horloge (55 ms), et 4 permet d'avoir une durée en secondes. Pour toute autre valeur la fonction renvoie un temps en microsecondes dans Var6 et la version du logiciel dans Var7. Var7: O - Réservée Var8: O - Réservée Après appel: Contenu des variables si la clé est présente Varl: Vrai si la clé est présente, sinon valeur aléatoire. Var2: cfgKey - Cette valeur donne des informations sur l'emplacement et le type de clé. Var3: cfgFun - Cette valeur donne des informations sur l'emplacement et le type de clé. Var4: Toujours 0 Var5: Durée d'exécution de l'appel de la fonction. Ce temps dépend de l'unité précisée dans var4, et ne constitue qu'une valeur approchée. Il est possible d'obtenir les valeurs exactes de la manière suivante: Si le temps est exprimé en micro secondes, diviser cette valeur par 1,193180 Si le temps est exprimé en millisecondes, diviser cette valeur par 1,193180 Si le temps est exprimé en Ticks horloges, diviser la valeur par 18,20648193 pour obtenir le temps en secondes. Le temps en seconde est celui de l'horloge interne. Mais il convient ici de noter qu'en mode protégé 32 bits (WINDOWS 32 bits, DOS EXTENDERS 32 bits), le temps n'est pas retourné. Var6: Temps de début d'exécution de la fonction. Le temps est exprimé dans l'unité spécifiée par Var4 Ici encore, en mode protégé 32 bits (WINDOWS 32 bits, DOS EXTENDERS 32 bits), le temps n'est pas retourné Var7: Version du logiciel ou date compactée. Si avant appel var6 contenait Vrai, alors Var7 contient la date au format compacté: bits 15 14 13 8 7 6 5 4 3 2 1 0 12 10 9 valeur Année + 1980 Mois Jour Dans les autres cas var7 contient la version du logiciel avec deux décimales. Exemple: 100 correspond à la version 1.00 Var8: Adresse du port parallèle sur lequel se trouve la clé. Fonction 01: Initialisation du mot de passe (local uniquement) Public: Non Système: Oui Lecture: Non Ecriture: Non Ecriture une fois: Oui Mot de passe: Oui, pour l'initialiser Accès SSII: Fonction 65 Protection: Non A la première commande d'un développeur, le fabricant de clés attribue par exemple deux codes: Code 0 et Code 1. Un troisième code est disponible pour une initialisation par le développeur. Cependant, pour une meilleure gestion des clés du développeur, le fabricant peut éventuellement aussi l'initialiser. Dans le mode décrit ici le mot de passe ne sera écrit qu'une seule fois et il ne pourra être ni lu, ni modifié. Si le développeur tente de le réinitialiser, Varl contiendra une valeur différente de Vrai lors de l'appel. En l'espèce il est alors conseillé d'utiliser toujours le même mot de passe après l'initialisation. Si le mot de passe est présent, il sera obligatoire pour accéder à toutes les fonctions. Contenu des variables Avantappel Après appel Varl 01 + CfaFu Vrai Var2 CodeO cfgKey Var3 Codel cfgFun Var4 ClO, mot de pass O à initialiser Var5 0 Réservée Var6 0 Réservée Var7 0 Valeur du mot de passe écrit dans la clé Var8 0 Adresse du port parallèle Avant appel: Initialisation des variables Les valeurs entre [] sont optionnelles. Varl: 01 [+ cfgFun] - Numéro de fonction. Ajouter cfgFun pour sélectionner une clé locale particulière. Var2: Code0 - Poids forts du code éditeur fourni par le fabricant Var3: Codel - Poids faibles du code éditeur fourni par le fabricant Var4: CléO = mot de passe à initialiser toujours différent de O Var5: O Var6: O - Réservée Var7: O - Réservée Var8: Réservée Apres appel: Contenu des variables si la clé est présente et cléO non initialisée Varl: Vrai si la clé est présente et a pu être initialisée. Var2: cfgKey - Cette valeur donne des informations sur l'emplacement et le type de clé. Var3: cfgFun - Cette valeur donne des informations sur l'emplacement et le type de clé. Var4: 0 Var5: Réservée Var6: Réservée Var7: Contient la valeur du mot de passe écrit dans la clé à condition que ce soit la première initialisation de celle-ci. Si la clé est absente ou déjà initialisée, une valeur quelconque s'affichera. Var8: Adresse du port parallèle sur lequel se trouve la clé. Fonction 02: Login clé Public: Non Système: Oui Lecture: Oui Ecriture: Non Ecriture une fois: Non Mot de passe: Oui Accès SSII: Fonction 66 Protection: Oui Cette fonction permet à une application de s'attacher à une clé avec comme objectif la garantie que celle- ci soit liée à la bonne clé lorsqu'il y en a plusieurs. Le login permet aussi d'établir le canal avec le serveur de clé en environnement réseau. Habituellement, une application qui utilise le login est prévue pour fonctionner dans tous les cas possibles: - une ou plusieurs clés en local - une ou plusieurs clés en réseau - une clé pour plusieurs applicatifs plusieurs applications sur des clés identiques ( même éditeur) Le login est un point de passage obligatoire pour pouvoir exécuter les fonctions de numéro supérieur à 2. Il est possible de faire soit un login général (var6 = var7 = var8 = O à l'appel), soit un login sur un registre (var6 = Vrai, Var7 = Numéro du registre et var7 = valeur que doit contenir le registre). Le nombre de connexion au serveur de clé sera toujours compté par machine, donc une machine peut faire autant de login quelle le souhaite, en ne consommant qu'une seule connexion. * Par la suite, le login général est considéré comme un login sur le registre numéro -1, pour une valeur indifférente: Il s'agit donc aussi d'un login registre. Contenu des variables Avant appel Après appel Varl 02 + CfgFun Vrai Var2 CodeO cfgKey Var3 Codel cfgFun Var4 CléO cfgLog ou O en cas d'erreur mémoire Var5 0 Nombre de connexions encore disponible (pour la clé logguée) Var6 Vrai Nombre de connexions déjà installées (pour la clé logguée) Var7 Valeur du Nombre de connexions maximum registre (code autorisées (pour la clé application) logguée) Var8 Adresse du Adresse du port parallèle registre Avant appel: Initialisation des variables Les valeurs entre [] sont optionnelles. Varl: 02 [+ cfgFun] - Numéro de fonction. Ajouter cfgFun pour sélectionner une clé particulière. Var2: CodeO - Poids forts du code éditeur fourni par ACTIKEY Var3: Codel - Poids faibles du code éditeur fourni par ACTIKEY Var4: CléO mot de passe Var5: O Var6: O ou Vrai pour un login sur un registre Var7: Valeur du registre (code application) si Var6 = Vrai Var8: Adresse du registre si Var6 = Vrai Apres appel: Contenu des variables si la clé est présente et le login s'est bien passé Varl: Vrai si la clé est présente, sinon valeur aléatoire. Une valeur de zero indique une erreur de login dont le code d'erreur se trouve dans var8. Ce code d'erreur correspond à celui renvoyé par le dernier serveur rencontré. 0: Erreur d'allocation mémoire 1: Echec de l'initialisation des API réseau : Pas de driver réseau 2: Echec de connexion avec les API réseau: Erreur de fonctionnement du réseau 3: Aucun serveur de clé n'a été trouvé 4: Erreur de dialogue avec le serveur de clé : Accès refusé car utilisateur non loggué 6: Accès refusé car nombre maximum de connexion atteint : IPX non installé 11: Impossible d'ouvrir un socket 254: clé absente 255: Erreur inattendue Var2: cfgKey - Cette valeur donne des informations sur l'emplacement et le type de clé. Var3: cfgFun - Cette valeur donne des informations sur l'emplacement et le type de clé. Var4: cfgLog: Handle de login à utiliser dans tous les appels suivants Var5: Nombre de connexions encore disponibles si le réseau est connecté Var6: Nombre de connexions déjà installées si le réseau est connecté Var7: Nombre de connexions maximum autorisées Var8: Adresse du port parallèle sur lequel se trouve la clé. Comment se protéger avec la fonction 02 Cette fonction permet et garantit l'association unique entre une application et une clé, y compris dans le cadre des réseaux (pour les clés réseaux) En règle générale, un registre est défini par application, avec à l'intérieur, un code application qui sera le numéro de version de l'application. Le logiciel fait alors un login qui trouvera la clé qui correspond à l'application et à sa version, et ce, en monoposte ou en réseau, quelque soit le nombre de clés présentes. Ainsi, une même clé peut être programmée pour fonctionner sur plusieurs applicatifs. En réseau, il est possible de protéger jusqu'à 1024 utilisateurs avec une seule clé, en l'installant sur le serveur pour NOVELL ou sur une station pour NOVELL ou NETBIOS. Varl: Sa valeur doit toujours être égale à Vrai. Si vous avez une autre valeur, soit la clé est absente, soit le login a échoué Var2: Ne pas utiliser pour se protéger. Var3: Ne pas utiliser pour se protéger. Var4: cfgLog: Handle de login. Il faut conserver cette valeur de var4 pour les appels aux autres fonction de numéro supérieur à 2. Chaque login renvoie un cfgLog différent, et il faut faire autant de logout que de login pour libérer la connection des clés en réseau. Si var4 contient un 0 après appel, c'est que le login a échoué, et aucune fonction suivante ne pourra aboutir. Var5: Nombre d'utilisateurs disponibles pour la connexion Var6: Nombre d'utilisateurs connectés au moment de l'appel Var7: Nombre d'utilisateurs maximum autorisés Var8: Adresse du port parallèle. Les constructeurs implémentent les ports parallèles aux adresses 0378h, 0278h et 3BCh. Si vous obtenez une valeur différente, c'est sans doute qu'une routine de remplacement est installée, auquel cas il vaut mieux quitter le programme. Il est aussi possible que la machine ne possède pas un port parallèle non compatible. Dans ce dernier cas la clé n'est pas utilisable. Voir la fonction 47 pour connaitre le nombre de login sur un registre par machine, et le nombre de login sur un registre pour l'ensemble du réseau. Les autres fonctions 03, 04, etc. sont définies de façon à obtenir les résultats recherchés. Leur programmation s'effectue de façon connue en elle-même par l'homme du métier, de façon similaire aux trois fonctions précisées ci-dessus. Dans des modes de réalisation avantageux, et afin de répondre à des cas de figure plus nombreux, la fonction cnrm est par ailleurs complétée par d'autres fonctions. Rappelons que dans toutes les déclaration ci- dessous, et pour une plate-forme Windows (16 ou 32 bits) il faut qualifier les fonctions de WINAPI. Il est ainsi prévu les modes suivants: a - Fonction cnrm avec passage des paramètres par valeur Modèle entier cnrm(valeur varl, valeur var2, valeur var3, valeur var4, valeur var5, valeur var6, valeur var7, valeur var8) Déclaration en C int cnrm(int varl, int var2, int var3, int var4, int var5, int var6, int var7, int var8); Déclaration en Pascal Function cnrm(varl, var2, var3, var4, var5, var6, var7, var8: integer): integer; On remarque que le nom de la fonction est le même que pour un passage par référence. La seule différence provient du fait que dans le premier cas, ce sont des références qui sont transmises à la fonction, tandis que dans le second cas ce sont des valeurs qui sont transmises à la fonction. La définition des arguments est quant à elle similaire à celle déjà décrite. Par contre, pour obtenir le contenu des variables après appel, on utilisera la fonction cnrmvar décrite ci-dessous. Il est par ailleurs tout à fait possible de mélanger les types d'appel dans un même programme, par exemple le login peut se faire par valeur, et la lecture d'un registre peut se faire par référence. b - Fonction cnrmvar Cnrmvar est une fonction qui permet de retrouver les paramètres après appel du cnrm pour le dernier appel si le login a été réussi. Il est principalement utilisé conjointement avec l'appel de cnrm par valeur, mais peut aussi être appelé dans le cas d'appels par référence: dans ce cas cela permet de mémoriser l'état des valeur en retour jusqu'au prochain appel de cnrm. Modèle entier cnrmvar(int cfgLog, int numVar) Déclaration en C int cnrmvar(int cfgLog, int numVar) Déclaration en Pascal Function cnrmvar(cfgLog, numVar: integer): integer; cfgLog: Valeur retournée lors du login numVar: 1 à 8: demande de renvoyer varl à var8 respectivement 9: Demande de renvoyer le code d'erreur du dernier appel au cnrm à 13: Demande de renvoyer le code d'erreur reçu des serveurs de clé de type NOVELL respectivement de numéro de serveur 0 à 3 20 à 23: Demande de renvoyer le code d'erreur reçu des serveurs de clé de type NETBIOS respectivement de numéro de serveur 0 à 3 Pour toutes les autres valeur de numVar, cnrmvar renvoie cfgLog Un exemple de fonctionnement est donné ci-après: exemple: // on suppose le login correct cfgLog = cnrm(13, 12127, 2221, 1654, cfgLog, 0, 0, 0); // lecture du registre 0 passage par valeur if (cnrmvar(cfgLog, 1) == Vrai) { // test si varl = Vrai ≤=> action réussie v = cnrmvar(cfgLog, 7); // v contient la valeur du registre 0 } c Fonction cnrmcb: définition d'un appel en retour L'appel en retour (callBack) est une fonction qui sera appelée par cnrm lors des appels suivants le placement par cnrmcb. Son intérêt réside dans la possibilité de savoir quelle opération effectue cnrm, d'arrêter l'exécution de cnrm prématurément, mais aussi d'améliorer la protection en permettant d'appeler indirectement des fonctions importantes du logiciel application protégé pendant l'exécution de cnrm. Cette fonction augmente considérablement la protection des programmes utilisant cnrm sous forme de librairie dynamique (DLL), si elle définit un appel en retour d'une fonction critique de l'application, comme par exemple l'initialisation de données sensibles dont une des composantes est stockée dans la clé. L'appel en retour ne sera fait que pour les actions de numéro > 2, et seulement si le login est réussi. On a: Modèle entier cnrmcb(int cfgLog, référence cb, entier long non signé Objet) Déclaration en C int cnrmcb(int cfgLog, callBack *cb, unsigned long Objet); Déclaration en Pascal Function cnrmcb(cfgLog: Integer; cb: _callBack; Objet: longInt): integer; far; external; cfgLog: valeur reçue lors du login cb: Adresse de la fonction en retour Objet: Une valeur qui sera toujours transmise à la fonction appelée en retour cnrmcb renvoie toujours cfgLog, donc si cfgLog est invalide c'est la valeur 0 La forme générale de la fonction appelée en retour est par ailleurs la suivante: Modèle int callBack(unsigned long Objet, int E, int SE, int cfgLog); Déclaration en C typedef int _callBack(unsigned long Object, int E, int SE, int cfgLog); Déclaration en Pascal type _callBack = Function(Objet: longInt; E: integer; SE: integer; cfgLog: integer): integer; Si callBack renvoie la valeur 0 alors l'exécution de cnrm est arrêtée dans l'état courant, sinon l'exécution de cnrm continue. "Objet" est un entier non signé qui est laissé à disposition: en général on y met un pointeur this d'un objet C++. Objet à été donné lors du placement du callBack E est la valeur de l'état interne de cnrm au moment de l'appel de callback E = 0 = DEMARRAGE: début de cnrm E = 1 = LOCAL: Avant appel de cnrm en local (test local) E = 2 = NOVELL: Avant appel de cnrm sur NOVELL E = 3 = NETBIOS: Avant appel de cnrm sur NETBIOS E = 255 = FIN: Avant de quitter cnrm L'ordre des appels n'est garanti que pour E = 0 et E = 255. Les autres états peuvent être donnés plusieurs fois dans un ordre quelconque. SE donne des informations de sous état qui dépendent de E. si E = 0 ou E = 255, SE vaut toujours 0 si E = 1, SE peut prendre les valeurs de 1 à 99 si E = 2, SE peut prendre les valeurs de 1 à 99 si E = 3, SE peut prendre les valeurs de 1 à 99 CfgLog permet de retrouver l'état des variables passés en paramètre lors de l'appel au cnrm pour toutes les valeurs de E appel pour toutes les valeurs de E ≥ 255. La fonction callBack ne doit pas appeler cnrm sauf si E = 255, mais elle peut appeler cnrmcb pour placer une nouvelle fonction en retour qui sera appelée pour l'état suivant, ou appeler cnrmccb pour effacer l'appel en retour. Si la fonction callBack appelle cnrm pour E <> 255, il ne se passera rien. Par contre si E = 255, cnrm est appelé normalement, mais sans appel de la fonction en retour. Il n'y a donc aucune précaution à prendre dans les callBack pour éviter la récursion, car elle ne peut pas se produire. d - Fonction cnrmccb: effacement d'un appel en retour L'appel en retour (callBack) est une fonction qui sera appelée par cnrm lors des appel suivants le placement par cnrmcb. Il est possible de supprimer cet appel en retour à n'importe quel moment, y compris dans une fonction callBack, à l'aide de cnrmccb Modèle entier cnrmccb(int cfgLog) Déclaration en C int cnrmccb(int cfgLog); Déclaration en Pascal Function cnrmccb(cfgLog: Integer): integer; far; external; cfgLog: Valeur reçue lors du login cnrmccb renvoie toujours cfgLog, donc si cfgLog est invalide c'est 0 e Fonction cnrmseg - renvoie le segment d'une variable (Environnement 16 bits uniquement) La fonction cnrmseg renvoie le segment d'une variable de type far. Elle s'utilise en général avec les langages ne permettant pas de retrouver les segments et offset (exemple: VISUAL BASIC). Modèle int cnrmseg(void far *s); // avec s la variable dont il faut extraire le segment Déclaration en C int cnrmseg(char far *s); Déclaration en Pascal Function cnrmseg(p: pointer): integer; far; external; f Fonction cnrmoff: renvoie l'offset d'une variable (Environnement 16 bits uniquement) La fonction cnrmoff renvoie le segment d'une variable de type far. Elle s'utilise en général avec les langages ne permettant pas de retrouver les segments et offsets (exemple: VISUAL BASIC). Modèle int cnrmoff(void far *s); // avec s la variable dont il faut extraire le segment Déclaration en C int cnrmoff(char far *s); Déclaration en Pascal Function cnrmoff(p: pointer): integer; far; external; Que ce soit sous forme de librairie statique (.LIB ou.OBJ) ou sous forme de librairies dynamiques, les fonctions décrites ci-dessus sont toutes accessibles, (cnrmseg et cnrmoff n'ont cependant de sens que pour les environnements 16 bits). On va maintenant décrire deux exemples de protections selon les modes de réalisation de l'invention plus particulièrement décrits ici. Ces exemples sont donnés à titre indicatif, l'objectif des protections données ici étant d'être fiable en garantissant une dépendance de l'application au contenu de la clé, et une réelle exécution des interfaces logicielles d'accès à la clé. Ce type de protection est particulièrement recommandé en cas d'utilisation de DLL. Dans les modes décrits plus particulièrement ci- après, il est de plus fait appel à un outil de cryptage externe à appliquer sur le programme exécutable final. Cet outil est le même pour les deux applications et est donné à titre d'exemple non limitatif. Dans tous les cas, le développeur devra l'adapter en fonction de son cas d'espèce. Les deux exemples reprennent une application de calcul de diamètre d'un cercle, de sa circonférence, du volume d'un cylindre basé sur le cercle et de poids dudit cylindre. A chaque fois on affiche le résultat. Le premier exemple est en langage C, le source prévu ici étant en environnement 16 bits. Le principe de la protection est ici de choisir quelques fonctions sensibles du logiciel à protéger, de masquer le point d'entrée de ces fonctions par un appel indirect, et de crypter la structure qui contient le point d'entrée desdites fonctions. Ainsi, on garantit que la clé a bien été lue sinon le décryptage ne se fait pas, et dans ce cas les points d'entrée des fonctions ne sont pas valides. Si un utilisateur normal ayant une licence ne met pas sa clé, il aura le message " clé absente ". Si un pirate tente de remplacer la clé ou de supprimer le test de présence de la clé, le décryptage ne se fait pas, et dans ce cas les points d'entrée des fonctions ne sont pas valides. Le cryptage est assuré par un programme externe après compilation et édition de liens. Il utilise la chaîne REPERE1 qui doit être unique pour trouver la zone à crypter et la longueur de ladite zone. La chaîne REPERE1 a pour seul objet l'identification d'une section de données vue par le programme externe, celui-ci ne pouvant pas lire les sources du programme à protéger. Un exemple de fonctionnement de ce programme de cryptage est précisé en référence à la figure 5. Plus précisément le programme R1 comporte une première étape 90 dans laquelle le fichier exécutable à protéger est ouvert, puis un test 91 sur la fin du fichier. Si le fichier n'est pas terminé la routine s'arrête (étape 97). Si la fin du fichier est observée, une étape 92 de lecture du caractère suivant est entreprise, suivie par un test 93 de comparaison du caractère lu avec un caractère de référence R, qui est le caractère du début de la chaîne dite REPERE1. Si ce n'est pas le bon caractère la lecture du caractère suivant est alors effectuée (retour à l'étape 92), sinon on lit (étape 94) les n caractères suivants, par exemple six. Une étape test 95 est alors effectuée pour vérifier s'il s'agit de la chaîne dite REPERE1. Si cela n'est pas le cas, on revient à l'étape 92, si cela est le cas, l'étape 96 de cryptage de la structure de données est alors initiée juste après la chaîne REPERE1. Une fois le cryptage effectué la routine concernée est arrêtée (étape 97). #include #include #include #include "ACTIKEY.H" //#define _DEBUG_ i /* permet de mettre au point le programme sans protection */ // codes de la clé #define NoCli 4000 // Référence du client #define code0 12127 // code éditeur No 0 #define codel 2221 // code éditeur No 1 #define cleO 1654 // mot de passe éditeur #define vrai 12345 // si clé présente // variables de travail pour clé int cfgLog, varl, var2, var3, var4, var5, var6, var7, var8; const double pi = 3.1415; 'Comme son nom l'indique // valeur initiales double R = 10.0; // rayon de 10 Cm double H = 10.0; // Hauteur en Cm double D = 1.0; // Densité en G/Cm3 // déclaration des fonctions void calcul(HWND hwnd); // déclaration des fonctions a protéger // elle doivent obligatoirement être déclarée near pour que cela marche // si elles sont appellées par un module externe il faut le faire par un appel // par une fonction far dans ce module qui appelle la fonction near // exemple: double farDiametre(double rayon) {return diametre(rayon);} double near diametre(double rayon); double near circonference(double rayon); double near volume(double rayon, double hauteur); double near poids(double rayon, double hauteur, double densite); void near afficheResultat(HANDLE hwnd, int ctrl, double valeur); // fonction d'affichage // déclarations spéciales pour la protection typedef void near fV_V(void); // fonction avec un parametre void qui renvoie un void typedef double near fDD(double pl); // fonction de parametre Double qui renvoie un double typedef double near fDD D(double pl, double p2); // fonction avec deux parametres double qui renvoie double typedef double near fDDDD(double pl, double p2, double p3); // fonction avec troie parametres double qui renvoie double typedef void near fHID_V(HANDLE hwnd, int ctrl, double p2); //fonction qui a un parametre HANDLE, Int et Double qui renvoie Void // ATTENTION CELA SUPPOSE QUE TOUTES LES FONCTIONS CI-DESSUS SONT DANS LE // MEME SEGMENT DE CODE // DONC IL FAUT LES METTRE DANS LE MEME FICHIER SOURCE QUE _ref void near ref(void) {;} // Fonction vide de référence typedef struct { char repere[l0]; // sert a crypter int nbFonction; // nombre de fonctions dans la structure fV V near *ref; // sert à avoir une référence fD D near *diametre; fD D near *circonference; fDDD near *volume; fDDD D near *poids; fHIDV near *afficheResultat; } _fct; _fct fct = { "*REPEREl*", // repère 6, // 6 fonctions ref, // point d'entrée: Entree numéro 0 diametre, // fonction 1 circonference, // fonction 2 volume, // fonction 3 poids, // fonction 4 afficheResultat // fonction 5 }; // la structure en variable globale fct fct; #define CODELOGICIEL 6754; // un code pour être sur que c'est la bonne clé #define REGLOGICIEL 0 // dans le registre 0 // fin de déclarations pour protection // protos de cnrm int WINAPI cnrm(int far *varl, int far *var2, int far *var3, int far *var4, int far *varS, int far *var6, int far *var7, int far *var8); int WINAPI cnrmseg(void far *s); int WINAPI cnrmoff(void far *s); // Programme // déclaration de la procédure de la fenêtre de dialogue BOOL CALLBACK FenetreProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); // prgramme principal #pragma argsused int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) f DLGPROC dlgProc; int delta; // login clé varl=2; var2=codeO; var3=codel; var4=cleO; var5=0; var6=vrai; var7=CODELOGICIEL var8=REGLOGICIEL; cfgLog=cnrm(&varl,&var2, &var3,&var4,&var5,&var6,&var7,&va r8); if (cfgLog && varl == vrai) { // la clé est présente #ifndef _DEBUG_ // mise en place de la protection et calculs pour bonne exécution // demande de décryptage de la structure varl=30; var2=codeO; var3=codel; var4=cfgLog; var5=cnrmseg(&fct.ref); var6=cnrmoff(&fct.ref); var7=fct. nbFonction * 2; // 2 octets par pointeur car fonctions NEAR var8=0; cfgLog=cnrm(&varl,&var2,&var3,&var4,&varS,&var6,&var7,&va r8); // fin de la mise en place de la protection #endif // on ouvre la fenêtre de dialogue qui se charge de faire le travail dlgProc = MakeProcInstance((FARPROC)FenetreProc, hInstance); DialogBox(hInstance, "ACTIKEY", NULL, dlgProc); FreeProcInstance((FARPROC) dlgProc); } else { MessageBox(NULL, "Erreur: Clé absente!n, "ACTIKEY", MB OK); } // logout clé varl=3; var2 =codeO; var3=codel; var4=cfgLog; var5=0; var6=0; var7=0; var8=0; cfgLog=cnrm(&varl,&var2, &var3,&var4,&var5,&var6,&var7,&va r8); return 0; } // Procédure callback associée à la fenêtre de dialogue #pragma argsused BOOL CALLBACK FenetreProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM COMMAND: if (LOWORD(wParam) == IDOK) { // bouton de fin: on quitte PostMessage(hwndDlg, WMCLOSE, 0, 0); return 1; } if (LOWORD(wParam) == IDC_CALCUL) { // on recalcul les résultats en fonction des données calcul(hwndDlg); return 1; } break; case WM CLOSE: EndDialog(hwndDlg, 0); return 1; case WMINITDIALOG: // on remplit les contrôles avec les valeurs par défaut #ifdef DEBUG afficheResultat(hwndDlg, IDCRAYON, R); // appel irect non protégé afficheResultat(hwndDlg, IDCHAUTEUR, H); // appel direct non protégé afficheResultat(hwndDlg, IDCDENSITE, D); // appel direct non protégé #else fct.afficheResultat(hwndDlg, IDCRAYON, R); // appel indirect protégé fct.afficheResultat(hwndDlg, IDC_HAUTEUR, H); // appel indirect protégé fct.afficheResultat(hwndDlg, IDC DENSITE, D); // appel indirect protégé #endif // et on calcul les résultats calcul(hwndDlg); return 1; } // end switch return 0; } void calcul(HWND hwnd) { char bufl37]; #ifdef DEBUG // méthode classique d'appel des fonction sans protection GetDlgItemText(hwnd, IDCRAYON, buf, 37); R = strtod(buf, NULL); afficheResultat(hwnd, IDCRAYON, R); GetDlgItemText(hwnd, IDCHAUTEUR, buf, 37); H = strtod(buf, NULL); afficheResultat(hwnd, IDC HAUTEUR, H); GetDlgItemText(hwnd, IDCDENSITE, buf, 37); D = strtod(buf, NULL); afficheResultat(hwnd, IDCDENSITE, D); afficheResultat(hwnd, IDCDIAMETRE, diametre(R)); afficheResultat(hwnd, IDC CIRCONFERENCE, circonference(R)); afficheResultat(hwnd, IDC VOLUME, volume(R, H)); afficheResultat(hwnd, IDCPOIDS, poids(R, H, D)); #else // methode d'appel de fonctions protégées // la diférence tient dans le préfixe fct. devant le nom des fonction d'après les déclarations // il s'agit d'un appel indirect pour lequel il n'y a pas de point d'entrée connu // car il est calculé lors la mise en place de la protection // on récupère les valeurs dans les champs d'entrée GetDlgItemText(hwnd, IDCRAYON, buf, 37); R = strtod(buf, NULL); // et on les réécrit pour mettre la valeur utilisée réellement fct.afficheResultat(hwnd, IDCRAYON, R); // appel protégé GetDlgItemText(hwnd, IDC_HAUTEUR, buf, 37); H = strtod(buf, NULL); // et on les réécrit pour mettre la valeur utilisée réellement fct.afficheResultat(hwnd, IDCHAUTEUR, H); // appel protégé GetDlgItemText(hwnd, IDC DENSITE, buf, 37); D = strtod(buf, NULL); // et on les réécrit pour mettre la valeur utilisée réellemnt fct.afficheResultat(hwnd, IDC_DENSITE, D); // appel protégé fct. afficheResultat(hwnd, IDCDIAMETRE, fct.diametre(R)); fct. afficheResultat(hwnd, IDC_CIRCONFERENCE, fct.circonference(R)); fct. afficheResultat(hwnd, IDC_VOLUME, fct.volume(R, H)); fct. afficheResultat(hwnd, IDC POIDS, fct.poids(R, H, D)); // cet appel fait un appel protégé à // son tour I11I #endif } double near diametre(double rayon) { return rayon * 2; } double near circonference(double rayon) { return 2 * pi * rayon; } double near volume(double rayon, double hauteur) { return pi * rayon * rayon * hauteur; } double near poids(double rayon, double hauteur, double densite) { #ifdef DEBUG /7 appel normal return volume(rayon, hauteur) * densite; #else // appel protégé return fet.volume(rayon, hauteur) * densite; #endif } void near afficheResultat(HANDLE hwnd, int ctrl, double v) { char buf[37]; // pour stockage temporaire sprintf(buf, "%f", v); SetDlgItemText(hwnd, ctrl, buf); } Le deuxième exemple est celui d'une application avec niveau de protection très élevé en Visual Basic. Cette application fait appel à une DLL et ne permet pas l'utilisation des techniques possibles avec le C. Begin VB.Form Forml description des objets visuels et contrôles ' ils comprennent les contrôles d'affichage de résultats nommés Diamètre, Circonférence, Volume, Poids End Attribute VBName = "Forml" Attribute VBCreatable = False Attribute VB_Exposed = False Programme de démonstration de protection Le principe ici consiste à masquer les nom des contrôles et les constantes importantes du code Il sont cryptés par un programme externe vbCrypte.exe ' Pour cela ils sont stockés dans une constante qui ne doit apparaître qu'une seule fois dans toute l'application La structure de cette chaîne est la suivante: REPERE: Une chaîne unique (*REPEREi* pour cet exemple) ' La taille des éléments à crypter dans la chaîne sur 3 caractères Les éléments a crypter précédes par un espace un espace de fin exemple pour 2 nom de contrôles à crypter ' "*REPEREl*020 controlel controle2 n On compte donc tous les caractères espaces compris après la longueur Du fait de la nature de Visual Basic on ne peut pas se contenter de stocker la constante quelque part dans le code, sinon elle ne serait pas retrouvé par l'outils de cryptage. L'astuce consiste donc à la stocker dans un contrôle invisible #Const DEBUG = 1 ' Mettre à 1 pour déburg 0 pour version définitive Pour la protection Déclaration des API de cnrm Private Declare Function cnrm Lib "CNRMA000.DLL" (ByRef V1 As Integer, ByRef v2 As Integer, ByRef v3 As Integer, ByRef v4 As Integer, ByRef v5 As Integer, ByRef v6 As Integer, ByRef v7 As Integer, ByRef v8 As Integer) As Integer Private Declare Function cnrmseg Lib "CNRMAOOO.DLL" (ByVal s As String) As Integer Private Declare Function cnrmoff Lib "CNRMAOO0.DLL" (ByVal s As String) As Integer Code de la clé Const NoCli = 4000 ' No du client Const code0 = 12127 ' code client 0 poids fort Const codel = 2221 ' code client 1 poids faible Const cleO = 1654 ' mot de passe du client Const vrai = 12345 ' vrai si clé présente variables de travail Dim cfgLog As Integer Dim varl As Integer Dim var2 As Integer Dim var3 As Integer Dim var4 As Integer Dim var5 As Integer Dim var6 As Integer Dim var7 As Integer Dim var8 As Integer ' Déclaration des constantes de l'application Dim Pi As Double ' = 3.1415: sera crypté aussi Valeurs Initiales Const Rini = 10# Const Hini = 10# Const Dini = 10# Variables de travail Dim R As Double Dim H As Double Dim D As Double les noms des contrôles après décryptage Dim cD As String 'Diamètre Dim cC As String 'Circonférence Dim cV As String 'Volume Dim cP As String 'Poids Sub AfficheResultat() Affiche le résultat #If DEBUG Then Diametre.Text = Format(CalculDiametre(R), "0.0000") Circonference.Text = Format(CalculCirconference(R), n 0.0000") Volume. Text = Format(CalculVolume(R, H), "0.0000") Poids.Text = Format(CalculPoids(R, H, D), "0.0000") #Else Controls("Diamètre").Text = "toto" -- SpToF aumloA eDueSg8UODaTD alqeuTia siTI' ú E 0+TZEadaKu*, qxe' I;o = qD 55 apoa eT inoq Inod enbTun sa alle: eaedTD e ouTqz eI ep uoTqua.dnDeH, stoTxzuoD uoq sel aesseapv =nod Gutytz QI ziedXADep Duop, emueaiboad np 0 quaureuuoTiDuo; ap queur9Tl sol aDvTd ue aqrau i.op uo TDT ()pmeor UO. qns 9AT.d qns puR UxoOA. gADU'ueeaDs pVOTUn ()XoDT ID iTa4Fnq qns ae.F1Td qns pus InDigD (3) XD. ID InDIeDq qns al.tad O uoTi Duni pus H H d H Fd =funloAInDlTD eTqnoa sy (eIqnoa se H 'elqnoa sy H)>enrloAInDTD uoTqDun/ uo.iDun. pua a (H 'H)sumIoAInDTvD = SPTOdlnDIeD SPTod np InDplD, OTqnoa eV (Clqnoa sE a a'Glqnoa 8 H 'sIlqnoa 8sV) sPTOdlnDITD uoTDun 0E uoTqDunI pua z q = 9ueTaInDTeD eaq1DeTp np InID, glqnoa sV (Tqnxoa sV H) I1aueTaInDITeD UoITDun SZ uoTj Dun. pua UOTQDUfl. PU'K X Td E = 0Duea. 8uODzTDTnDTuD BDUGZGUOD.TFD VI ap InOTID, elqnOa 8V (gTqnoa 8V H) aDUe. zeuoD2TDIInDTD UOT3DUnj 0 qns pua (a0000'0M 'a) w-=od = xeln'salTFsu}a (uOOOO'Ou 'H)veu'"o0 = xu.'anOsn;Ha oooo.OOOOOa 'H>neLsoa = ZX9aL9snaneH 5 (0000'Ou 'E)lunoa. = lxJ.'uoArm juemeadozd sanivA. sel i9er, (Ixeae-0 a.sua) IqaD = a ( xeJ.,xne4nwH)IqaD = H (3xeauo{eW) IqaD = 01 iuvy=eA sy A m.a () InDIeD q(ns qns pua 3I puE# q (0OOOO0u '(a 'H 'H)sPpTodnDID)lvm=og = (dD)SIOaqUOD (".0000 0. '(H 'u)emnloAlnoDlD)m=zoL = (AD)SlOI4UOD (.0000' On '(H)eDue; uODTD!nDInlD)3moA = (DD) sIOauoD (uOOOOo0. '(H)ealueuTaInplD)3l=oZ = xel. (aD)sloaquoD ú9 099999ZE les -- de fin ne servent & rien sinon à vérifier par un dump que le cryptage est correct Dim s As String Login clé varl = 2 'Fonction 2 Login var2 = codeO 'code editeur O var3 = codel 'code editeur 1 var4 = cleO 'Mot de passe var5= 0 var6= O0 var7= 0 var8 = O appel a la fonction CNRM cfgLog = cnrm(varl, var2, var3, var4, var5, var6, var7, var8) If (varl <> vrai) Then MsgBox "Erreur clé absente!", MB OK, "ACTIKEY" End End If mise en place de la protection s = Mid$(fct, InStr(fct, "")) ' le seul morceau à décrypter varl = 30 'Fonction de décryptage var2 = code0 'code editeur O var3 = codel 'code editeur 1 var4 = cfgLog 'cfgLog var5 = cnrmseg(s) var6 = cnrmoff(s) var7= Len(Mid$(fct, InStr(fct, " "), Len(fct))) ' la longueur var8 = O ' appel a la fonction CNRM cfgLog = cnrm(varl, var2, var3, var4, var5, var6, var7, var8) normalement c'est décrypté ' extrait le premier élément (Pi) s = Mid$(s, 2, Len(s)) ' saute l'espace de tête Pi = Val(Mid$(s, 1, InStr(s, " ") - 1)) extrait le second élément (cD) s = Mid$(s, InStr(s, " ") + 1, Len(fct)) cD = Mid$(s, 1, InStr(s, ") - 1) extrait l'élément suivant (cC) s = Mid$(s, InStr(s, " ") + 1, Len(fet)) cC = Mid$(s, 1, InStr(s, n) - 1) extrait le suivant (cV) s = Mid$(s, InStr(s, " ") + 1, Len(fct)) cV = Mid$(s, 1, InStr(s, ") 1) extrait le dernier (cP) s = Mid$(s, InStr(s, "") + 1, Len(fct)) cP = Mid$(s, 1, InStr(s, ") - 1) ' Fin de mise en place de la protection Etats initiaux Rayon.Text = Format(Rini, "0n.0000") Hauteur. Text = Format(Hini, "0n.0000") Densite.Text = Format(Dini, "0.0000") calcul End Sub Private Sub FormUnload(Cancel As Integer) ' on fait un logout de clé varl = 3 'fonction 3 Logout var2 = code0 'code editeur O var3 = codel 'code editeur 1 var4 = cfgLog 'Login var5 = O var6 = O var7 = O var8 = O appel a la fonction CNRM contenue dans le fichier CNRMCxxx.DLL cfgLog = cnrm(varl, var2, var3, var4, var5, var6, var7, var8) End Sub Comme il va de soi et comme il résulte d'ailleurs de ce qui précède, la présente invention ne se limite pas aux modes de réalisation plus particulièrement décrits, mais en embrasse au contraire toutes les variantes et notamment celles o d'autres méthodes de cryptage sont utilisées. REVENDICATIONS 1. Procédé de contrôle de l'utilisation d'un logiciel développé sous une plate-forme déterminée, associé à un dispositif muni d'un circuit électronique à mémoire rémanente à lecture/écriture, connecté aux bornes d'un port parallèle entre un ordinateur et un appareil périphérique, dans lequel on traite dans le dispositif et/ou on renvoie à partir dudit dispositif des signaux à l'ordinateur en réponse à des signaux émis à partir de ce dernier, caractérisé en ce que on écrit et on lit dans le circuit du dispositif en faisant appel à une fonction intégrée dans un fichier objet (.OBJ) ou un fichier de Librairie Dynamique (.DLL) préalablement inséré dans ledit logiciel, ladite fonction ayant la forme suivante: résultat = cnmr(varl, var2,... varn) avec n > 3 dans laquelle varl à varn correspondent à des valeurs particulières selon ce que l'on souhaite exécuter avec le dispositif et à au moins une valeur spécifique correspondant à un utilisateur déterminé, ladite fonction étant agencée pour détecter automatiquement le type de plate-forme déterminée, et calculer le contexte d'exécution du logiciel en fonction de ladite plate-forme. 2. Procédé selon la revendication 1, caractérisé en ce que lors de la mise en oeuvre de la fonction de liaison (Login) entre le logiciel et le dispositif on identifie la clé et/ou sa position par l'intermédiaire d'une valeur spécifique (cfgFun ou cfgKey) donnée ou non par le logiciel et on mémorise cette valeur spécifique qu'on utilise ensuite comme constante lors du fonctionnement dudit logiciel. 3. Procédé selon l'une quelconque des revendications précédentes, caractérisé en ce que la fonction cnrm est agencée (fonction cnrmcb) pour rappeler au moins une fois le logiciel en cours de fonctionnement, pour vérifier que c'est bien le cnrm d'origine qui a été appelé. 4. Procédé selon l'une quelconque des revendications précédentes, caractérisé en ce que la plate-forme déterminée est une plate-forme Windows, ladite fonction cnrm étant agencée pour permettre de reconnaître automatiquement le type de passage de paramètres par référence ou par valeur mis en oeuvre dans le logiciel. 5. Procédé selon la revendication 4, caractérisé en ce que on ne met en place le contexte d'exécution qu'une seule fois, lors de la première mise en oeuvre de la fonction de liaison entre le logiciel et le dispositif (login d'entrée). 6. Procédé selon l'une quelconque des revendications précédentes, caractérisé en ce que n est égal à 8. 7. Procédé selon l'une quelconque des revendications précédentes, caractérisé en ce que le procédé comprend une méthode de protection dans laquelle on choisit au moins une fonction sensible du logiciel à protéger, on masque le point d'entrée de cette fonction par un appel indirect, et on crypte la structure qui contient le point d'entrée de ladite fonction. 8. Procédé selon l'une quelconque des revendications précédentes, caractérisé en ce que il comprend une méthode de protection dans laquelle on choisit au moins une fonction de contrôle ou une constante importante, et on crypte cette fonction ou cette constante. 9. Procédé selon l'une quelconque des revendications 7 et 8, caractérisé en ce que le cryptage est assuré par un programme externe après compilation et édition de liens. 10. Système de contrôle interactif de l'utilisation de logiciels caractérisé en ce qu'il comprend au moins un dispositif mettant en oeuvre le procédé selon l'une quelconque des revendications précédentes.