Skip to content

Instantly share code, notes, and snippets.

@maxisoft
Created October 25, 2013 06:13
Show Gist options
  • Save maxisoft/7150122 to your computer and use it in GitHub Desktop.
Save maxisoft/7150122 to your computer and use it in GitHub Desktop.
#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