=====================================================================
4 . PROGRAMMATION : ENCRYPTEUR EN C
=====================================================================

Date : 10/06/2003
Auteur : Nocte
Sujet :
ENCRYPTEUR EN C .

La programmation en C style BTS est soûlante, vous en conviendrez...
Alors, en considérant que vous connaissiez déjà les bases élémentaires
de programmation en C, on va s'intéresser à la pratique. Ainsi, voici un
programme que nous allons réaliser : un encrypteur en C que nous allons
décortiquer dans les moindres détails afin d'apprendre par la pratique
d'une part la méthode de programmation d'un logiciels (architecture de
celui-ci) et, d'autre part, des bases indispensables.


I. LE PROGRAMME
----------------

Commençons à étudier le programme : 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;

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. 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 : jour,
mois, année ; celles-ci sont toujours appelé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 fonctions d'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 chiffres :

if(d.da_year<2000)
{d.da_year-=1900;}
else
{d.da_year-=2000;}
Ceci fait, le programme affiche quelques informations :
printf("\t\tEncrypteur\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 le nom 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-ci vaut NULL, cela signifie
qu'il s'est produit une erreur lors du chargement du fichier Si c'est le
cas, nous demandons à l'utilisateur s'il veut ressaisir 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("Entrez votre clé de cryptage:");
get_key:
car=getch();
switch(car)
{
case 13:
goto confirmation_code;
case 27:
clrscr();
printf("Etes-vou sûr ?(Y/N)");
ask_other:
switch(sur)
{
case 121:
sur=getch();
goto end;
case 110:
clrscr();
printf("Fichier à encrypter / décrypter:\n%s\n",src);

goto get_code;
}
goto ask_other;
default:
code +=car;
printf("*");
goto get_key;
}
confirmation_code:
printf("\nConfirmez votre clé de cryptage:");
reget_key:
car=getch();
switch(car)
{
case 13:
goto test_cod;
case 27:
clrscr();
printf("Etes-vous sûr ?(Y/N)");
re_ask:
sur=getch();
switch(sur)
{
case 121:
goto end;
case 110:
printf("\nFIchier à encrypter / décrypter:\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 vérification
la somme des codes ASCII des touches 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("Erreur de confirmation de la clé de cryptage...");

code=0;verif=0;
printf("\nFichier à encrypter ou décrypter:\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("\nNOm du fichier encrypté / décrypté à générer (full path)
:\n");
scanf("%s",dst);
dest=fopen(dst,"rb");
if(dest!=NULL)
{
fclose(dest);
printf("Ce fichier existe déjà : (O)verwrite / (C)hanger son nom?");

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 cela, 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 grâce à 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 toujours accessible via undelete mais on accède à un fichier vide.

pre_end:
printf("\nFin du cryptage...\nAutre fichier à encrypter / décrypter
(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("\t coded by Nocte\
\n\tAll rights reserved Juin 2003");
fcloseall();
}


Alors, ça vous a plu ? Voilà ce programme fini. Ne vous inquiétez pas,
nous irons plus loin la prochaine fois et développerons les points qui
vous auront parus obscurs : pour cela, n'hésitez pas, balancez vos soucis
sur le forum. J'espère que cet article vous aura appris des choses intéressantes.