Hacker 2020 issue numéro 4, par Clad Strife.

Dissection d'un encrypteur (programmation en C)
Bon, le listing que je présente est celui du premier encrypteur que j'ai réalisé dontla sécurité doit bien valoir celle des sauvegardes SimCity ... Bon je vais pas m'attarder , le principe n'est pas compliqué : l'utilisateur entre le fichier à crypter,le fichier sortant, nous vérifions qu'il n'en efface pas un autre , puis nous lui demandons le mot de passe, et après confirmation, nous lançons la procédure d'encryptage ... Celle-ci est simple, basé sur une transformation octet par octet .Bon le listing est disponible soit directement en cliquant ici auquel cas, il s'affichera dans une nouvelle fenêtre, soit à la fin de l'article, compressé avec l'executable .
Afficher le listing .

Commençons à étuider le programme : comme nous l'avons vu dans le premier guide, il commence par une série de #include et puis par la fonction main:

#include "stdio.h"
#include "conio.h"
#include "dos.h"

void main(void)
{

Ceci est aussitôt suivi des déclarations des variables :
FILE *sourc,*dest;int code,verif,car=0,i,j,sur,oct;
char src[60],dst[60];struct date d;
En examinant ces variables, 2 types nous sont inconnus : FILE , ainsi que date . struct n'est pas tout à fait un type de variable, c'est en fait une structure de données : un groupe contenant plusieurs données .Ces 2 types de données sont en fait définis dans le fichier dos.h , FILE est aussi une structure mais contenant des informations sur le fichier (son handle,sa taille,ses droits d'accès ...) alors que date contient 3 données ,une pour le jour,une pour le mois et une pour l'année ;celle-ci sont toujours appellées de la même manière, respectivement  da_day,da_mon et da_year .Mais comme elles sont comprises dans une structure, pour les utiliser il faut utiliser le nom de la structure juste devant avec un point .Ici le nom de la structure est d .

Ensuite , nous avons les premières fonctionsd'initialisation :

getdate(&d);clrscr();
La fonction clrscr() définie dans conio.h sert à effacer l'écran alors que la fonction getdate( struct date) permet d'initialiser une structure date à la date actuelle, c'est à dire mettre dans da_day le jour, dans da_mon le mois et dans da_year l'année .

Ensuite une petite routine permet de vérifier le millénaire actuel afin de n'afficher la date qu'avec l'année sur 2 chiffers ( 17/01/99 au lieu de 17/01/1999 ) :

if(d.da_year<2000)
    {d.da_year-=1900;}
    else
    {d.da_year-=2000;}
Ceci fait,le programme affiche quelques informations :
printf("\t\tEncryptor V 2.0\n");
printf("%d/%d/%d\n",d.da_day,d.da_mon,d.da_year);
On constate que lors de l'affichage de la date, les variables sont référencées par d.da_day,d.da_mon et d.da_year ... Ensuite, une routine nous permet de demander lenom du fichier que l'utilisateur souhaite encrypter :
get_name:
printf("Name of the file to encrypt or decrypt (with full path):\n");
scanf("%s",src);
sourc=fopen(src,"rb");
if(sourc==NULL)
    {
    printf("\aError opening file:(C)hange/(Q)uit\n");
    ask_erase:
    car=getch();
    switch(car)
        {
        case 99:
        goto get_name;
        case 113:
        goto end;
        default:
        goto ask_erase;
        }
    }
A l'aide de la fonction scanf() ,nous récupérons le nom du fichier d'origine, lui attribuons le pointeur de type FILE src via la fonction fopen(), puis vérifions l'état du pointeur src . Si celui-i vaut NULL, cela signifie qu'il s'est produit une erreur lors du chargement du fichier Si c'est le cas, nous dmandons àl'utilisaeur s'il veut resaisir un nom ou quitter le programme. Pour cela nous utilisons la fonction getch() combinées à une structure conditionnelle switch()
et_code:
code=0;verif=0;
printf("Enter your encrypt-key:");
get_key:
car=getch();
switch(car)
    {
    case 13:
    goto confirmation_code;
    case 27:
    clrscr();
    printf("Are you sure?(Y/N)");
    ask_other:
    switch(sur)
        {
        case 121:
        sur=getch();
        goto end;
        case 110:
        clrscr();
        printf("File to encrypt or decrypt:\n%s\n",src);
        goto get_code;
}
goto ask_other;
    default:
    code +=car;
    printf("*");
    goto get_key;
}

confirmation_code:
printf("\nConfirm your encrypt-key:");
reget_key:
car=getch();
switch(car)
    {
    case 13:
    goto test_cod;
    case 27:
    clrscr();
    printf("Are you sure?(Y/N)");
    re_ask:
        sur=getch();
        switch(sur)
            {
            case 121:
            goto end;
            case 110:
            printf("\nFile to encrypt or decrypt:\n%s\n",src);
            goto get_code;
            }
    goto re_ask;
    default:
    verif +=car;
    printf("*");
    goto reget_key;
    }

Cette routine permet donc de stocker dans les variables code et verif la somme des codes ASCII des tocuhes frappées par l'utilisateur en tant que code .C'est une des failles du programme dans la mesure ou les mots de passes "bc" et "ad" seront codés de la même manière ...
test_cod:
if(code==verif)
    {
    printf("\nOK...starting working");
    goto encrypt;
    }
    else
    {
    clrscr();
    printf("Error in confirming your encrypt-key...");
    code=0;verif=0;
    printf("\nFile to encrypt or decrypt:\n%s\n",src);
    goto get_code;
    }
Cette routine permet de vérifier que le code rentré puis confirmé sont bien les mêmes . Si c'est le cas, le programme poursuit l'exécution , sinon il revient à la demande de code après avoir réinitialisé les variables .
encrypt:
printf("\nName of the encrypted or decrypted file to generate (with full path):\n");
scanf("%s",dst);
dest=fopen(dst,"rb");
if(dest!=NULL)
    {
    fclose(dest);
    printf("File already exists:(O)verwrite/(C)hange name?");
    re_ask2:
    sur=getch();
    switch(sur)
        {
        case 99:
        clrscr();
        goto encrypt;
        case 111:
        goto crypt;
        default:
        goto re_ask2;
    }
}
Ce passage demande à l'utilisateur le nom du fichier vers lequel il veut crypter ou décrypter le fichier source .Si celui-ci existe déjà, il lui demande s'il désire l'effacer .Pour celà, nous essayons d'abord d'ouvrir le fichier en mode lecture . Si le pointeur contient NULL, cela veut dire que le fichier n'existe pas . Sinon, le fichier existe déjà . Pour la demande à l'utilisateur,nous utilisons encore une structure conditionnelle switch().
crypt:
for(car=0;code<0;code+=256);
for(car=0;code>255;code-=256);

fclose(dest);
dest=fopen(dst,"wb");

Cette routine permet de préparer la procédure principale d'encryptage en ouvrant le fichier destination et en préparant la clé de cryptage en la remettant sur un octet c'est-à-dire entre 0 et 255 compris .Nous le faisons au moyen de la structure conditionnelle for();
cryptage:
oct=fgetc(sourc);
if(feof(sourc))
    {goto file_end;}

oct +=code;

for(sur=0;oct<0;oct+=256);
for(sur=0;oct>255;oct-=256);
oct=255-oct;
fputc(oct,dest);
goto cryptage;

Voici la routine d'encryptage : celle-ci consiste a lire un octet du fichier, à y ajouter le code de l'utilisateur,à le rétablir sur un octet c'est-à-dire entre 0 et 255 compris et à faire l'inverse bit-à-bit ce qui consiste à soustraire la valeur à 255 . Le résultat de cette soustraction est écrite dans le fichier de destination . Si l'octet lu est le dernier, on quitte la rutine d'encryptage sinon on continue . Les fonctions fgetc() et fputc() permettent de respectivement lire et écrire un octet dans un fichier .
file_end:
clrscr();
fcloseall();
Cette série de 2 instructions permet d'une part d'effacer l'écran mais aussi de fermer tous les fichiers ouverts grace à fcloseall() . Ceci est très important dans la mesure ou les données ne sont écrites sur le disque qu'après fermeture des fichiers .
printf("Delete old file: %s (y/n)?",src);
re_ask3:
i=getch();
switch(i)
    {
    case 121:
    sourc=fopen(src,"rb");
    fputc(0,sourc);
    fclose(sourc);remove(src);
    goto pre_end;
    case 110:
    goto pre_end;
    default:
    goto re_ask3;
    }
Ici, nous demandons à l'utilisateur s'il souhaite effacer le fichier source . Si c'est le cas, nous n'allons pas directement effacer moyen de la command remove() . En effet, celle-ci ne protège pas contre les programmes comme undelete qui permettrait de retrouver le fichier . Nous allons d'abord l'ouvrir en écriture de manière à effacer son contenu puis nous y écrivons juste un octet nul , nous le refermons et l'effaçons ensuite avec remove . Il est toujurs accessible via undelete mais on accède à un fichier vide .
pre_end:

printf("\nEncrypting finished...\nAny other file to encrypt or decrypt (Y/N)?\n");

re_ask4:
car=getch();
switch(car)
    {case 121:
    oct=0;goto get_name;
    case 110:
    goto end;
    default:
    goto re_ask4;
    }
end:
clrscr();
printf("\twww.multimania.com/xcpu:Encryptor V 2.0 coded by Bloodwaves\
\n\tBloodwaves@Hotmail.com January 1999");
fcloseall();
}

Voici les dernières instructions ,ainsi que la demande à l'utilisateur s'il possède d'autres fichiers à transformer .

Bon,j'ai essayé via cette dissection de vous expliquer quelques fonctions et principes du C sous Dos dumoins ... Le programme compilé avec le listing sont téléchargeables juste en dessous.