CryptAfinity

  1. Description
    1. Auteurs
  2. Pré-requis
    1. Sur un système Debian GNU/Linux
    2. Sur un système Apple MacOSX (≥10.3)
    3. Sur un système Microsoft Windows
  3. Se procurer CryptAfinity
  4. Utiliser CryptAfinity
    1. Compilation
    2. Utilisation
  5. Documentation
    1. Code
    2. Décodeur "Afine"
    3. Décodeur "Vigenère"

1. Description

CryptAfinity est un logiciel libre permettant de déchiffrer des texte obfusqués par des systèmes Afines ou l'algorithme de Vigenère. Il possède les caractéristiques suivantes :

1.1. Auteurs

CryptAfinity a été entièrement réalisé par Glenn ROLLAND <glenux@fr.st> et Roland LAURÈS <shamox@mac.com> à l'occasion de travaux pratiques du cours de système du Master 2 Ingénierie Informatique - Systèmes, Réseaux et Internet.

2. Pré-requis

CryptAfinity nécessite les bibliothèques de fonctions suivantes (dans leur version de développement si compilez le programme vous-même):

2.1. Sur un système Debian GNU/Linux

Il vous suffit de taper (en tant qu'administrateur) les commandes suivantes pour installer le nécessaire: 

# apt-get install libglib-2.0-dev

2.2. Sur un système Apple MacOS X (>= 10.3)

Il est nécessaire d'avoir installé les autotools (automake, autoconf...) dans leur dernière version. À partir de là, il suffit de taper les commandes suivantes dans un terminal :

# sudo fink install glib2-dev

2.3. Sur un système Microsoft Windows

Cela ne fut pas (encore) testé, mais il est très probable que cela fonctionne sous Cygwin.

3. Se procurer CryptAfinity

Vous pouvez télécharger la dernière archive des sources, ou bien directement la version la plus récente du projet sur le dépôt Subversion du projet.

3.1. L'archive des sources

Elle est disponible à l'adresse :

http://glenux2.free.fr/pub/projets/CryptAfinity/archives/

3.2. Le dépôt Subversion

Afin d'obtenir les sources les plus à jour, vous pouvez utiliser le logiciel de contrôle de sources Subversion

$ svn checkout http://repository.glenux.ath.cx/svn/CryptAfinity/

Il n'y a pas de mot de passe, il suffit donc de presser la touche "Entrée" pour l'utilisateur "anonymous", si ce dernier vous est demandé.

4. Utiliser CryptAfinity

4.1. Compilation

Commencez par décompressez l'archive.

$ tar -xzvf CryptAfinity-0.1.tar.gz

Rendez vous ensuite dans le dossier qui vient d'être créé lors de la décompression.

$ cd CryptAfinity-0.2

Puis lancez l'auto-configuration du logiciel, puis la compilation.

$ ./autogen
$ ./configure
$ make

Le programme sous forme binaire se trouvera alors dans le sous-dossier src/tools/, sous le nom break_afinity

4.2. Utilisation

CryptAfinity nécessite de nombreux paramètres, avec la syntaxe suivante:

Usage: break_afinity -a <fichier> -e <float> -f <float> -p <fichier> -t <fichier> -m

Où les paramètres sont les suivants:      

-a, --alphabet <file>  Fichier contenant les lettres de l'alphabet, dans l'ordre.

-e, --epsilon <float>
Tolerance pour le test des clefs.
-f, --frequencies <float> Proportion moyenne que représentent les 9 lettres "prioritaires" dans le texte clair.
-k, --keylength <int>       Taille de la clef maximul (obsolète)
-p, --priorities <file> Lettres ordonnées par fréquence décroissante d'apparition dans le texte clair.
-t, --text <file> Fichier contenant le texte chiffré.
-m, --mode <a|v> Selection du mode "Afine" ou "Vigenère"

5. Documentation

5.1. Code

Vous pouvez trouver la documentation du code de CryptAfinity dans le dossier doc/html de l'application, ou en suivant ce lien.

5.2. Principe du "décodeur Afine"

On génère l'espace des clefs possibles pour l'alphabet donné en entrée:

int alpha_size; //taille de l'alphabet
std::list<int> orb; // nombre premiers avec alpha_size
MathTools mt; // bibliotheque d'outils mathématiques
std::list<KeyAfine> keyList;
std::list<int>::iterator orbIt;

for (i=1; i<alpha_size; i++){
    if (mt.pgcd(i, alpha_size) == 1) {
        orb.push_back(i);
    }
}
// 1 - générer l'espace des 312 clefs
for (orbIt = orb.begin(); orbIt != orb.end(); orbIt++){
    KeyAfine key;
    key.setCoefA((*orbIt));
    for (i=0; i<alpha_size; i++){
        key.setCoefB(i);
        keyList.push_back(key);
    }
}

Puis on fait une attaque par analyse de fréquence sur les textes obtenus par "décodage" du texte chiffré avec les clefs essayées.

float frequencies; // fréquence cumulée des 9 lettres les plus présentes
float epsilon; // marge d'erreur

std::list<KeyAfine>::iterator kLIt;
for (kLIt = keyList.begin(); kLIt != keyList.end(); kLIt++){
    float score = 0;
    printf("Trying key %s\n", (*kLIt).toString().c_str());

    plainText = codec.decode(cypherText, *kLIt);   
    plainText.setAlphabet(this->_config.getAlphabet());
    for (int i=0; i<9; i++){
        score += plainText.getCountOf(prio_conf[i]);
    }
    score = score / plainText.size();
    if (fabs(score - frequencies) < epsilon){
      printf("KEY = %s\n",(*kLIt).toString().c_str());
      printf("PLAIN TEXT(%f) = %s\n", fabs(score-frequencies),
        plainText.toAlphabet().c_str());
    }

}

5.3. Principe du "décodeur Vigenère"

On commence par faire récupérer les groupes de caratères qui se répètent dans le texte.

Une fois les groupes répétés de lettres de plus grande longueur obtenus (dans l'ordre décroissant en fonction de la longueur), on calcule la distance séparant les deux premiers groupes (note d1) puis la distance entre les deux suivant (d2).
On pose K = PGCD(d1, d2). Il est fortement probable que K soit un multiple de la longueur de la clef. L'hypothèse sous-jacente est que ces groupes de lettres sont issue du chiffrement des mêmes bouts de mots avec les mêmes bouts de la clef. Si le K = 1 on peut raisonnablement supposer que ce n'est pas le cas, et qu'il n'y a pas de répétitions.

L'étape suivante consiste à faire une analyse de fréquence en découpant le texte en K colonnes. On classe ensuite les lettres apparaissant dans les colonnes en fonction de leur nombre d'apparitions.
Dans un monde utopique, il suffirait de calculer la distance entre la lettre apparaissant le plus souvent dans la colonne, et celle apparaissant le plus souvent dans le langage attendu pour le texte clair (l'anglais en l'occurrence).
Cependant il arrive fréquemment que l'ordre de lettre soit légèrement changé par rapport au résultat attendu. Dans le programme, on calcule donc pour chaque colonne les distances entre les X lettres les plus fréquentes dans la colonne et la lettre la plus fréquente dans le langage.
On génère ensuite un espace de X ^ K clefs a partir des combinaisons de ces différents décalages obtenus sur chaque colonne.

Enfin, on décode ensuite le texte avec chacune des clef générées, et en fonction de données statistiques relative à notre connaissance préalable du texte et d'une petite marge d'erreur, on filtre les texte déchiffrés.
(Exemple: les 9 lettres les plus fréquentes représentent 70% du texte, et on une marge de +/- 4%).
En jouant sur la marge d'erreur, on laisse passer plus ou moins de textes déchiffrés, parmi lesquels devrait se trouver le texte clair attendu.