Obligement - L'Amiga au maximum

Lundi 24 juillet 2017 - 18:43  

Translate

En De Nl Nl
Es Pt It Nl


Rubriques

 · Accueil
 · A Propos
 · Articles
 · Galeries
 · Glossaire
 · Hit Parade
 · Liens
 · Liste jeux Amiga
 · Quizz
 · Téléchargements
 · Trucs et astuces


Articles

 · Actualité (récente)
 · Actualité (archive)
 · Comparatifs
 · Dossiers
 · Entrevues
 · Matériel (tests)
 · Matériel (bidouilles)
 · Points de vue
 · En pratique
 · Programmation
 · Reportages
 · Tests de jeux
 · Tests de logiciels
 · Tests de compilations
 · Articles divers

 · Articles in english
 · Articles in other languages


Twitter

Suivez-nous sur Twitter




Liens

 · Sites de téléchargements
 · Associations
 · Pages Personnelles
 · Moteurs de recherche
 · Pages de liens
 · Constructeurs matériels
 · Matériel
 · Autres sites de matériel
 · Réparateurs
 · Revendeurs
 · Presse et médias
 · Programmation
 · Développeurs logiciels
 · Logiciels
 · Développeurs de jeux
 · Jeux
 · Autres sites de jeux
 · Scène démo
 · Divers
 · Informatique générale


Jeux Amiga

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Trucs et astuces

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Glossaire

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Partenaires

Annuaire Amiga

Amedia Computer

Relec

Hit Parade


Contact

David Brunet

Courriel

 


Programmation : Assembleur - protégez vos données
(Article écrit par Frédéric Delacroix et extrait d'Amiga News - juillet 1995)


Il est souvent utile de protéger ses données des regards indiscrets par un système de mots de passe. Sous Unix, c'est chose courante dans la mesure où la plupart du temps plusieurs personnes utilisent une machine. Sur Amiga, le système n'offre pas de telles protections par lui-même : il faut l'y aider. Le but de cet article n'est pas de vous offrir une protection absolue. D'ailleurs, les éditeurs de jeux le savent bien, il n'y a pas de sécurité totale. Un sorcier pourra toujours se débrouiller pour aller fouiner dans vos fichiers. Il s'agit juste de vous proposer un petit programme gérant des mots de passe pour plusieurs utilisateurs et pouvant être utilisé dans un script. J'en profiterai pour vous présenter la bibliothèque liable amiga.lib et la reqtools.library, que Nico François a placé en freeware.

Je précise tout de suite qu'un tel système de mots de passe ne vaut que si ceux-ci sont sauvegardés sous forme codée avec les données à protéger et que l'utilitaire chargé de leur gestion vérifie le mot de passe à chaque fois. Il peut également être utile de coder les données à l'aide de ce mot de passe, un peu comme le fait l'algorithme de cryptage de la powerpacker.library.

Le lien (linkage)

Le coeur du programme est la fonction ACrypt(). Ne cherchez pas dans la dos.library ou intuition.library, elle ne s'y trouve pas. Il s'agit de l'une des nouvelles fonctions de l'amiga.lib, qui est une bibliothèque liable. A la différence des bibliothèques partagées (run-time comme disent les grands bretons), les routines que contiennent les bibliothèques liables sont explicitement incluses dans le code exécutable. Ce sont surtout des "stubs" pour la programmation en C, mais amiga.lib contient quelques routines intéressantes en assembleur. La plupart (pas toutes) exigent que le passage de paramètres se fasse sur la pile (au lieu des registres), à la manière du C : on empile les paramètres (uniquement des mots longs, il ne s'agit pas de provoquer une "adress error" quand le système décide de commuter la tâche !) par ordre inverse de leur énumération, on saute à la routine par un JSR et surtout on n'oublie pas de corriger le pointeur de pile : on lui ajoute 4 par paramètre.

Lors de l'assemblage, il ne faut pas produire un code exécutable comme on en a l'habitude mais un code liable (avec le suffixe .o). Pour Devpac, on réclame ce mode soit dans la fenêtre de configuration de l'assembleur, soit avec l'option ALINK sur la première ligne du source. Les symboles à exporter (ceux que vous voulez accessibles à d'autres modules) sont à déclarer avec la directive XDEF (eXternal DEFinition) et ceux à importer (c'est-à-dire ceux qui sont définis dans d'autres modules) par XREF (eXternal REFerence). L'éditeur de lien (BLink pour Devpac) fait le reste en rassemblant les différents modules objets dans un exécutable et en résolvant tous ces liens. C'est ici qu'interviennent les bibliothèques liables : ce sont des gros fichiers qui contiennent une multitude de fonctions, dont seules celles qui sont utilisées sont réellement incluses dans l'exécutable.

Ici, la seule référence externe est le nom de la fonction : _ACrypt. Comme vous le montrera un message d'erreur de BLink si vous l'oubliez, elle a besoin d'une définition qui est _SysBase : adresse d'une variable contenant l'adresse de la structure ExecBase. Vous pouvez la mettre à 4. Remarquez le nom de la fonction qui commence par un underscore : c'est le cas de tous les symboles accessibles par un compilateur C. Là où un compilateur C lit ACrypt, l'assembleur lit _ACrypt. Ce stratagème permet par exemple de définir deux symboles pour une même fonction : un point d'entrée (sans underscore) avec passage des paramètres dans les registres pour l'assembleur et un autre (avec underscore) avec passage des paramètres sur la pile pour le C (et les autres langages), qui met les paramètres dans les registres et saute au premier point. On retrouve un peu le même genre de système dans le Hooks avec les champs h_Entry et h_SubEntry.

Le cryptage

On utilise donc la fonction ACrypt(). Pour cela, on commence par demander le nom de l'utilisateur. J'ai utilisé, par souci de concision, la fonction rtGetStringA() de la reqtools.library. Il s'agit d'une bibliothèque partagée très performante écrite par Nico François qui rend l'affichage de fenêtres de requêtes de toutes sortes un jeu d'enfant. On la trouve absolument partout dans les collections de domaine public.

Une fois ce nom entré, on le place dans une variable d'environnement locale (je ne m'étendrai pas sur ce sujet aujourd'hui car la place m'est comptée) et on le crypte par ACrypt(). Cette fonction s'attend à trouver à la fois un mot de passe à crypter et le nom de l'utilisateur (qui est utilisé pour le codage). Ici, on utilise deux fois le nom de l'utilisateur. Le résultat de cette fonction est toujours un mot d'exactement 11 lettres et constitué de caractères imprimables, ce qui permet de l'utiliser comme nom de fichier.

On examine ensuite le répertoire L:Passwords/ à la recherche d'un fichier portant ce nom. S'il n'existe pas, ou si le répertoire n'existe pas, il s'agit d'un nouvel utilisateur. On lui demande alors d'entrer un nouveau mot de passe (avec confirmation et entrée invisible, merci la reqtools.library), qu'on code et qu'on enregistre dans un nouveau fichier portant le nom de l'utilisateur codé, et en créant le répertoire s'il n'existe pas. Si le fichier en question existe déjà, on le lit et on demande le mot de passe à l'utilisateur. On les compare et on retourne le code correspondant (voir code source), ce qui permet un test facile par la commande IF dans un script.

Il est à noter que la fonction ACrypt() n'est disponible qu'à partir de la version 39 de l'amiga.lib, mais fonctionne sous la version 37 du Kickstart. Si la dépendance à la reqtools.library vous insupporte pour une raison qui ne peux imaginer, vous pouvez toujours réécrire une routine n'utilisant qu'Intuition, mais pourquoi réinventer la roue ?

Pour le programme, vous obtenez après assemblage un fichier avec le suffixe .o (mettons Pass.o). Vous devez alors lier avec la bibliothèque amiga.lib (on la trouve avec Devpac et dans le kit développeur 3.1) avec une ligne de commande du style :

Blink FROM Pass.o TO Pass LIB LIB:amiga.lib

J'oubliais : le programme est réentrant, c'est-à-dire qu'il ne gère aucune variable globale (on réserve juste une zone mémoire qui est toujours pointée par A5 et qui contient toutes les variables et tous les tampons nécessaires. De cette façon, vous pouvez rendre ce programme résident par la commande Resident.

Ce qu'il vous reste à écrire maintenant est un programme qui permet à un utilisateur de changer son mot de passe. Il y a bien sûr la possibilité d'effacer son fichier du répertoire L:Passwords, mais ce n'est pas facile de savoir lequel s'il y en a cinquante. Il faudrait de plus prévoir un système de stockage plus sûr qu'un simple fichier, comme un nouveau système de fichiers codant ses données (un peu comme XDisk), mais c'est assez difficile. Je laisse ce problème à votre sagacité. Passez de bonnes vacances et, rendez-vous à la rentrée pour de nouvelles aventures.

    opt ALINK

; codes de retour:
;   0: OK, pas de problème
;  10: Mauvais mot de passe
;  20: Erreur
; 100: Erreur d'initialisation

    include exec/exec.i
    include exec/exec_lib.i
    include dos/dos.i
    include dos/var.i
    include dos/dos_lib.i
    include libraries/reqtools.i
    include libraries/reqtools_lib.i

    STRUCTURE   MyData,0
     APTR   md_ExecBase
     APTR   md_DOSBase
     APTR   md_ReqToolsBase
     BPTR   md_PasswordHandle
     STRUCT md_UserName,40
     STRUCT md_CryptedName,12
     STRUCT md_Password1,20
     STRUCT md_Password2,20
     STRUCT md_CryptedPass1,12
     STRUCT md_CryptedPass2,12
    LABEL   md_SIZEOF

_SysBase    EQU 4

    XREF    _ACrypt
    XDEF    _SysBase

    moveq   #100,d7 ; code de retour
    move.l  4.w,a6
    move.l  #md_SIZEOF,d0
    move.l  #MEMF_PUBLIC!MEMF_CLEAR,d1
    jsr     _LVOAllocMem(a6)
    move.l  d0,a5
    move.l  a5,d0
    beq     exit
    move.l  a6,md_ExecBase(a5)
    lea     DOS.Name(pc),a1
    moveq   #37,d0
    jsr     _LVOOpenLibrary(a6)
    move.l  d0,md_DOSBase(a5)
    beq     freemem
    lea     ReqTools.Name(pc),a1
    moveq   #38,d0
    jsr     _LVOOpenLibrary(a6)
    move.l  d0,md_ReqToolsBase(a5)
    beq     closedos

; demande le nom de l'utilisateur
    lea     md_UserName(a5),a1
    move.l  #39,d0
    lea     Requester.Title(pc),a2
    suba.l  a3,a3
    lea     UserName.Tags(pc),a0
    move.l  md_ReqToolsBase(a5),a6
    jsr     _LVOrtGetStringA(a6)
    move.l  #User.VarName,d1
    lea     md_UserName(a5),a0
    move.l  a0,d2
    move.l  #-1,d3
    move.l  #GVF_LOCAL_ONLY,d4
    move.l  md_DOSBase(a5),a6
    jsr     _LVOSetVar(a6)
    tst.w   d0
    beq     closereqtools

    pea     md_UserName(a5)
    pea     md_UserName(a5)
    pea     md_CryptedName(a5)
    jsr     _ACrypt
    add.l   #12,sp
    tst.l   d0
    beq     closereqtools

    bsr     LockPassDir
    move.l  d0,d6   ; d6=lock du dir
    beq.s   NewPass
    move.l  d6,d1
    jsr     _LVOCurrentDir(a6)
    move.l  d0,d5   ; d5=ancien dir

    lea     md_CryptedName(a5),a0
    move.l  a0,d1
    move.l  #MODE_OLDFILE,d2
    jsr     _LVOOpen(a6)
    move.l  d0,md_PasswordHandle(a5)
    bne     ComparePass

    move.l  d5,d1
    jsr     _LVOCurrentDir(a6)
    move.l  d6,d1
    jsr     _LVOUnLock(a6)

; nouveau mot de passe à créer
NewPass moveq   #20,d7
    lea         GetNewPass.MSG(pc),a0
    lea         md_Password1(a5),a1
    bsr         GetPassword
    beq         closereqtools
    lea         ConfirmPass.MSG(pc),a0
    lea         md_Password2(a5),a1
    bsr         GetPassword
    beq         closereqtools

; comparer les deux mots de passe:
    lea         md_Password1(a5),a0
    lea         md_Password2(a5),a1
.CompLoop
    cmp.b       (a0)+,(a1)+
    bne         closereqtools
    tst.b       -1(a0)
    bne.s       .CompLoop
    bsr         CryptPass
    beq         closereqtools

; enregistrer dans le fichier
    bsr         LockPassDir
    move.l      d0,d6
    bne.s       .PassDirGot
    move.l      #Pass.DirName,d1
    jsr         _LVOCreateDir(a6)
    move.l      d0,d6
    beq         closereqtools
    move.l      #Pass.DirName,d1
    move.l      #FIBF_EXECUTE!FIBF_DELETE,d2
    jsr         _LVOSetProtection(a6)
.PassDirGot
    move.l      d6,d1
    jsr         _LVOCurrentDir(a6)
    move.l      d0,d5
    lea         md_CryptedName(a5),a0
    move.l      a0,d1
    move.l      #MODE_NEWFILE,d2
    jsr         _LVOOpen(a6)
    move.l      d0,md_PasswordHandle(a5)
    beq.s       .Unlockdir
    move.l      d0,d1
    lea         md_CryptedPass1(a5),a0
    move.l      a0,d2
    move.l      #12,d3
    jsr         _LVOWrite(a6)
    cmp.l       d3,d0
    bne.s       .NotOK
    moveq       #0,d7   ; retour: OK
.NotOK  move.l  md_PasswordHandle(a5),d1
    jsr         _LVOClose(a6)
    lea         md_CryptedName(a5),a0
    move.l      a0,d1
    move.l      #FIBF_WRITE!FIBF_DELETE!FIBF_EXECUTE,d2
    jsr         _LVOSetProtection(a6)
.Unlockdir
    move.l      d5,d1
    jsr         _LVOCurrentDir(a6)
    move.l      d6,d1
    jsr         _LVOUnLock(a6)
    bra.s       closereqtools

ComparePass
    moveq       #20,d7
    move.l      md_PasswordHandle(a5),d1
    lea         md_CryptedPass2(a5),a0
    move.l      a0,d2
    move.l      #12,d3
    jsr         _LVORead(a6)
    cmp.l       d3,d0
    bne.s       .CloseIt
    lea         EnterPass.MSG(pc),a0
    lea         md_Password1(a5),a1
    bsr.s       GetPassword
    beq.s       .CloseIt
    bsr         CryptPass
    lea         md_CryptedPass1(a5),a0
    lea         md_CryptedPass2(a5),a1
    move.l      #2,d0   ; 3 mots longs=12 chars
.Loop   cmp.l   (a0)+,(a1)+
    bne.s      .BadPass
    dbra        d0,.Loop
    moveq       #0,d7
    bra.s       .CloseIt
.BadPass
    moveq       #10,d7
    lea         BadPass.MSG(pc),a1
    lea         BadPass.GAD(pc),a2
    suba.l      a3,a3
    move.l      a3,a0
    move.l      md_ReqToolsBase(a5),a6
    jsr         _LVOrtEZRequestA(a6)
.CloseIt
    move.l      md_DOSBase(a5),a6
    move.l      md_PasswordHandle(a5),d1
    jsr         _LVOClose(a6)
    move.l      d5,d1
    jsr         _LVOCurrentDir(a6)
    move.l      d6,d1
    jsr         _LVOUnLock(a6)

closereqtools
    move.l      md_ExecBase(a5),a6
    move.l      md_ReqToolsBase(a5),a1
    jsr         _LVOCloseLibrary(a6)
closedos
    move.l      md_DOSBase(a5),a1
    jsr         _LVOCloseLibrary(a6)
freemem move.l  a5,a1
    move.l      #md_SIZEOF,d0
    jsr         _LVOFreeMem(a6)
exit    move.l  d7,d0
    rts

GetPassword ; (MSG,Buffer)(A0,A1)
    move.l      md_ReqToolsBase(a5),a6
    clr.l       -(sp)
    pea         GSREQF_CENTERTEXT
    pea         RTGS_Flags
    move.l      a0,-(sp)
    pea         RTGS_TextFmt
    pea         -1
    pea         RTGS_Invisible
    move.l      sp,a0
    move.l      #19,d0
    lea         Requester.Title(pc),a2
    suba.l      a3,a3
    jsr         _LVOrtGetStringA(a6)
    add.l       #7*4,sp
    tst.l       d0
    rts

LockPassDir
    move.l      md_DOSBase(a5),a6
    move.l      #Pass.DirName,d1
    jsr         _LVOLock(a6)
    tst.l       d0
    rts

CryptPass
    pea         md_UserName(a5)
    pea         md_Password1(a5)
    pea         md_CryptedPass1(a5)
    jsr         _ACrypt
    add.l       #12,sp
    rts

UserName.Tags
    dc.l        RTGS_Flags,GSREQF_CENTERTEXT
    dc.l        RTGS_TextFmt,UserName.MSG
    dc.l        TAG_DONE

DOS.Name        dc.b    'dos.library',0
ReqTools.Name   dc.b    'reqtools.library',0
Requester.Title dc.b    'Password',0
UserName.MSG    dc.b    'Enter your name:',0
User.VarName    dc.b    'User',0
Pass.DirName    dc.b    'L:Passwords',0
GetNewPass.MSG  dc.b    'Enter a new password:',0
ConfirmPass.MSG dc.b    'Please confirm:',0
EnterPass.MSG   dc.b    'Enter password:',0
BadPass.MSG     dc.b    'Wrong password !',10
                dc.b    'See your system supervisor.',0
BadPass.GAD     dc.b    'Will do.',0



[Retour en haut] / [Retour aux articles] [Article précédent] / [Article suivant]