Created
October 25, 2013 06:13
-
-
Save maxisoft/7150122 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <inttypes.h> | |
#include <limits.h> | |
#include <math.h> | |
#define forever for(;;) | |
#define NBR_LETTRE 26 | |
#define INDICE_COINCIDENCE .0746 | |
/** | |
* Permet d'avoir false et true comme boolean. | |
*/ | |
enum { | |
false = 0, true | |
}; | |
typedef char* mstring; // Malloced char* | |
struct vigenere_step { | |
unsigned char* clef; | |
int index; | |
int clefLen; | |
}; | |
typedef struct vigenere_step vigenere_step_t; | |
/** | |
* Structure definissant une operation de chiffrage / dechiffrage tres simple à appliquer a des fichiers. | |
*/ | |
struct operation { | |
/** | |
* Le fichier source. | |
*/ | |
FILE *fichierEntre; | |
/** | |
* Le fichier de sortie. | |
*/ | |
FILE *fichierSortie; | |
vigenere_step_t *etape; | |
/** | |
* boolean mis a true si l'operation a deja été effectuer et ne doit plus être utilisée. | |
*/ | |
unsigned int finie : 1; | |
}; | |
typedef struct operation operation_t; | |
/** | |
* Validation d'une opperation | |
* @param self | |
* @return 1 si operation valide; 0 sinon | |
*/ | |
uint8_t operation_valide(operation_t self) { | |
return !self.finie && self.fichierEntre && self.fichierSortie; | |
} | |
void help() { | |
printf("Exemple d'utilisation : \n\n"); | |
printf("Chiffrage : vigenere -ch FichierEntré cle FichierSortie\n"); | |
printf("Dechiffrage : vigenere -d FichierEntré cle FichierSortie\n"); | |
printf("vigenere -dc FichierEntré FichierSortie [TailleCleMax] [DeltaMax]\n"); | |
} | |
/** | |
* Ferme tous les fichiers d'une operation et la marque comme finie. | |
* @param selfp pointeur sur l'opperation. | |
*/ | |
void operation_clean(operation_t *selfp) { | |
fclose(selfp->fichierEntre); | |
selfp->fichierEntre = NULL; | |
fclose(selfp->fichierSortie); | |
selfp->fichierSortie = NULL; | |
free(selfp->etape); | |
selfp->etape = NULL; | |
selfp->finie = true; | |
} | |
/** | |
* returne le decalage dans [0;25]. (modulo 26) | |
* @param decalage | |
* @return le decalage dans [0;25] | |
*/ | |
inline uint8_t modulo26(int decalage) { | |
int ret = (decalage % 26); | |
if (ret < 0) { // Suivant les normes du compilateur, si "decalage" est negatif alors l'opperation modulo (%) peut retourner un negatif . | |
ret += 26; | |
} | |
return (uint8_t) (ret); | |
} | |
/** | |
* Verifie que le char passé en parametre peut etre chiffré. | |
* Dans le cas present, regarde si le char est une majuscule. | |
* @param c | |
* @return 1 si c peut etre chiffré; 0 sinon. | |
*/ | |
inline int8_t is_ciphable_char(unsigned char c) { | |
return c <= 'Z' && c >= 'A'; | |
} | |
void vigenere_step_incr(vigenere_step_t *st) { | |
st->index += 1; | |
if (st->index >= st->clefLen) { | |
st->index = 0; | |
} | |
} | |
unsigned char vigenere_dechiffre(unsigned char c, vigenere_step_t *st) { | |
if (!is_ciphable_char(c)) { // Non traité | |
return c; | |
} | |
unsigned char decalage = NBR_LETTRE - (st->clef[st->index] - 'A'); | |
decalage = modulo26(decalage); | |
int pad = c + decalage - 'Z'; | |
vigenere_step_incr(st); | |
if (pad > 0) { | |
return pad + 'A' - 1; | |
} | |
return c + decalage; | |
} | |
unsigned char vigenere_chiffre(unsigned char c, vigenere_step_t *st) { | |
if (!is_ciphable_char(c)) { // Non traité | |
return c; | |
} | |
unsigned char decalage = st->clef[st->index] - 'A'; | |
decalage = modulo26(decalage); | |
int pad = c + decalage - 'Z'; | |
vigenere_step_incr(st); | |
if (pad > 0) { | |
return pad + 'A' - 1; | |
} | |
return c + decalage; | |
} | |
/** | |
* Chiffre un fichier et met le resultat du chiffrement dans un autre fichier. | |
* @param op | |
* @return 1 si operation effectuer; 0 sinon | |
*/ | |
uint8_t static chiffre(operation_t op) { | |
if (!operation_valide(op)) { | |
return false; | |
} | |
int i; | |
while ((i = fgetc(op.fichierEntre)) != EOF) { | |
unsigned char c = (unsigned char) i; | |
c = vigenere_chiffre(c, op.etape); | |
fputc(c, op.fichierSortie); | |
} | |
return true; | |
} | |
/** | |
* Chiffre un fichier et met le resultat du chiffrement dans un autre fichier. | |
* @param op | |
* @return 1 si operation effectuer; 0 sinon | |
*/ | |
uint8_t static dechiffre(operation_t op) { | |
if (!operation_valide(op)) { | |
return false; | |
} | |
int i; | |
while ((i = fgetc(op.fichierEntre)) != EOF) { | |
unsigned char c = (unsigned char) i; | |
c = vigenere_dechiffre(c, op.etape); | |
fputc(c, op.fichierSortie); | |
} | |
return true; | |
} | |
/** | |
* Effectue une rotation par la droite sur une chaine de caractere. | |
* Crée un nouveau string. | |
* @param in le string source | |
* @param n le nombre de rotation | |
* @return le nouveau string | |
*/ | |
mstring rotation_texte(mstring in, int n) { | |
size_t len = strlen(in); | |
if (len <= n) { | |
return NULL; | |
} | |
int coupure = len - (n % len); | |
mstring ret = calloc(len + 1, sizeof (char)); | |
memcpy(&(ret[coupure]), in, len - coupure); | |
memcpy(ret, &(in[len - coupure]), coupure); | |
return ret; | |
} | |
/** | |
* Recherche la taille d'une cle. | |
* @param s le string a analyser. | |
* @param maxkeylen la taille maximale de la clef. (tout param inf ou eq a 0 est mis par defaut a 255) | |
* @param deltaok precision acceptable | |
* Represente la precision acceptable du carrée de la differance entre l'indice de coincidence theorique et de celui calculée. | |
* Peut permettre de ne pas effectuer maxkeylen iteration. | |
* mettre a -1 pour precision par defaut (.0001), | |
* mettre a 0 pour faire maxkeylen iteration. | |
* mettre a un réel compris entre 0 et 1 pour definir la precision. | |
* | |
* @return la taille probable de la cle. 0 si erreur | |
*/ | |
int recherche_taille(mstring s, int maxkeylen, float deltaok) { | |
int i, j; | |
int ret = 0; | |
float mindiff = INFINITY; | |
float currdiff; | |
int slen = strlen(s); | |
int coincidences; | |
if (maxkeylen <= 0) { | |
maxkeylen = 255; | |
} | |
if (deltaok < 0. || deltaok >= 1.) { | |
deltaok = 0.0001; | |
} | |
for (i = 1; i <= maxkeylen; ++i) { | |
mstring rs = rotation_texte(s, i); | |
if (rs == NULL) { | |
continue; | |
} | |
coincidences = 0; | |
for (j = 0; j < slen; ++j) { | |
if (s[j] == rs[j]) { | |
coincidences += 1; | |
} | |
} | |
free(rs); | |
currdiff = (((float) coincidences) / slen - INDICE_COINCIDENCE); | |
currdiff = currdiff * currdiff; // la differance au carré | |
//(ex: 0.1 * 0.1 = 0.01 et 0.2 * 0.2 = 0.04) | |
//permet d'etre plus "precis" (pour la comparaison avec deltaok) et supprime le signe. | |
if (currdiff < mindiff) { | |
if (deltaok && currdiff < deltaok) { // si le delta au carré est "convenable". | |
return i; | |
} | |
ret = i; | |
mindiff = currdiff; | |
} | |
} | |
return ret; | |
} | |
/** | |
* Cherche la cle probable d'un texte. | |
* @param s le string a analyser. | |
* @param keylen la taille de la cle (a calculer avec recherche_taille() ) | |
* @return la cle | |
*/ | |
mstring calcul_cle(mstring s, unsigned int keylen) { | |
mstring ret = calloc(keylen + 1, sizeof (char)); | |
if (!keylen) { | |
return ret; //chaine vide. | |
} | |
int i, j; | |
int slen = strlen(s); | |
int** freqanalysetab = malloc(keylen * sizeof (int*)); | |
for (i = 0; i < keylen; ++i) { | |
freqanalysetab[i] = calloc(NBR_LETTRE, sizeof (int)); | |
} | |
//pour chaque groupe de mots de taille keylen. | |
int lim = slen / keylen; | |
for (i = 0; i < lim; ++i) { | |
int tmp = i * keylen; | |
for (j = 0; j < keylen; ++j) { | |
char c = s[tmp + j]; | |
freqanalysetab[j][c - 'A'] += 1; | |
} | |
} | |
//On cherche la plus grande freq | |
for (i = 0; i < keylen; ++i) { | |
int* freqanalyse = freqanalysetab[i]; | |
char kmax; | |
int vmax = 0; | |
for (j = 0; j < NBR_LETTRE; ++j) { | |
int v = freqanalyse[j]; | |
if (v > vmax) { | |
vmax = v; | |
kmax = j; | |
} | |
} | |
// On suppose que le texte est grand et que E est la lettre la plus utilisée. | |
ret[i] = modulo26(kmax + 'A' - 'E') + 'A'; | |
} | |
return ret; | |
} | |
/** | |
* Ouvre un fichier et retourne string contenant toutes les lettres en majuscule du fichier. | |
* @param filename | |
* @return contenu en majuscule du fichier. | |
*/ | |
mstring get_file_caps_content(const char *filename) { | |
mstring fcontent = NULL; | |
int fsize = 0; | |
int i; | |
size_t fcontent_index = 0; | |
FILE *fp; | |
fp = fopen(filename, "r"); | |
if (fp) { | |
//recherche la taille du fichier (en nombre de char) | |
fseek(fp, 0, SEEK_END); | |
fsize = ftell(fp); | |
rewind(fp); | |
fcontent = calloc(fsize + 1, sizeof (char)); | |
while ((i = fgetc(fp)) != EOF) { | |
unsigned char c = (unsigned char) i; | |
if (is_ciphable_char(c)) { | |
fcontent[fcontent_index++] = c; | |
} | |
} | |
fclose(fp); | |
// realloc en fonction du nombre réel de carateres en majuscule. | |
fcontent = realloc(fcontent, fcontent_index == 0 ? 1 : fcontent_index); | |
} | |
return fcontent; | |
} | |
int8_t entre_cle_valide(char* s) { | |
int len = strlen(s); | |
int i; | |
int8_t ret = true; | |
for (i = 0; i < len && ret; ++i) { | |
ret &= is_ciphable_char(s[i]); | |
} | |
return ret; | |
} | |
int main(int argc, char** argv) { | |
if (argc < 3) { | |
help(); | |
return (EXIT_FAILURE); | |
} | |
if (strcmp(argv[1], "-ch") == 0 && argc > 4) { //chiffre | |
vigenere_step_t *st = calloc(1, sizeof (vigenere_step_t)); | |
operation_t op = {fopen(argv[2], "r"), fopen(argv[4], "w"), st, 0}; | |
if (!entre_cle_valide(argv[3])) { | |
printf("La cle doit être en majuscule !\n"); | |
return (EXIT_FAILURE); | |
} | |
st->clef = argv[3]; | |
st->clefLen = strlen(st->clef); | |
chiffre(op); | |
operation_clean(&op); | |
} else if (strcmp(argv[1], "-d") == 0 && argc > 4) { //dechiffre | |
vigenere_step_t *st = calloc(1, sizeof (vigenere_step_t)); | |
operation_t op = {fopen(argv[2], "r"), fopen(argv[4], "w"), st, 0}; | |
if (!entre_cle_valide(argv[3])) { | |
printf("La cle doit être en majuscule !\n"); | |
return (EXIT_FAILURE); | |
} | |
st->clef = argv[3]; | |
st->clefLen = strlen(st->clef); | |
dechiffre(op); | |
operation_clean(&op); | |
} else if (strcmp(argv[1], "-dc") == 0 && argc > 3) { //decrypt | |
vigenere_step_t *st = calloc(1, sizeof (vigenere_step_t)); | |
operation_t op = {fopen(argv[2], "r"), fopen(argv[3], "w"), st, 0}; | |
mstring s = get_file_caps_content(argv[2]); | |
if (s == NULL) { | |
return (EXIT_FAILURE); | |
} | |
int maxlen = 0; | |
int deltamax = -1.; | |
if (argc > 4) { | |
maxlen = atoi(argv[4]); | |
maxlen = maxlen > 0 ? maxlen : 0; | |
} | |
if (argc > 5) { | |
deltamax = atof(argv[5]); | |
} | |
int cleflen = recherche_taille(s, maxlen, deltamax); | |
mstring key = calcul_cle(s, cleflen); | |
printf("La clef doit être : \"%s\"\n", key); | |
free(s); | |
st->clef = key; | |
st->clefLen = strlen(st->clef); | |
dechiffre(op); | |
operation_clean(&op); | |
free(key); | |
} else { | |
help(); | |
return (EXIT_FAILURE); | |
} | |
return (EXIT_SUCCESS); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment