Le TP est à rendre, par email, avant le 24 décembre à 23h59...
Pour ce TP, la seule chose à m'envoyer sera un fichier prenom-nom.c
contenant votre programme. Ce fichier sera utilisable directement avec les autres fichiers fournis pour le TP.
Le non-respect de cette consigne risque de me mettre de mauvaise humeur...
Attention, le seul fait que votre programme fonctionne ne suffit pas pour avoir une bonne note. Les points suivants seront pris en compte :
Attention : les points suivants ne rapportent rien, mais ne pas les respecter pourra retrancher jusqu'à 10 points sur la note finale :
-Wall -Werror -Wextra -pedantic -std=c99
,
info528
, ou info-528
ou info 528
,
./FMS
) ne devra pas provoquer d'erreur.
« RC4 » peut-être vu comme un générateur pseudo-aléatoire pour crypter un flot de données sur le modèle du « bloc-notes à usage unique » : chaque octet du flot de données est combiné (avec un XOR
) avec l'octet correspondant de RC4. Il n'existe, à ce jours, pas d'attaque pour RC4 général.
RC4 comporte deux phases :
t
, entre 1 et 256 octets,
En pseudo C, si on note "cle
" la clé, et "t
" sa taille :
KSA: (* Key Scheduling Algorithm *) for(i = 0; i < 256; i++) etat.S[i] = i j = 0 for(i = 0; i < 256; i++) j = (j + etat.S[i] + cle[i % t]) % 256 etat.S[i] <-> etat.S[j] (* échange *) etat.i = 0 etat.j = 0
et
PRGA: (* Pseudo Random Generator Algorithm *) etat.i = (etat.i + 1) % 256 etat.j = (etat.j + etat.S[etat.i]) % 256 etat.S[etat.i] <-> etat.S[etat.j]; (* échange *) return etat.S[ (etat.S[etat.i] + etat.S[etat.j]) % 256]
Programmez une fonction
void code_RC4_drop(char *K, char *M, int n)
qui affiche les octets, en hexadécimal (format "%02X
" pour printf
), du codage de la chaîne M
avec la clé K
.
L'argument "n
" sera le nombre d'octets initiaux qu'on jette lors de la génération. (Autrement dit, on attend "n
" octets générés avant de commencer à coder.) On appelle parfois ce codage "RC4-drop[n]".
Estimation du temps : moins 30 minutes !
strlen
,
typedef unsigned char octet;
" pour définir un type octet
,
char
" en "octet
", il faut faire un "cast" : "(octet) c
" (ce n'est probablement pas nécessaire),
n
" prend la valeur 0 dans ce cas)
.c
" correspondant...
Le WEP ("Wired Equivalent Privacy") crypte chaque paquet en utilisant deux clés :
Chaque paquet est codé avec RC4 en utilisant la clé "vecteur d'initialisation + clé WEP" (sur 8 ou 16 octets donc) et est envoyé avec son vecteur d'initialisation.
Pour décoder, on récupère le vecteur d'initialisation, concatène la clé WEP derrière et décode avec RC4.
De cette manière, on ne peut décoder que si on possède la clé WEP, et on utilise quand même des clés différentes pour chaque paquet. (C'est important, car sinon, il suffirait d'un message décodé pour retrouver le début de la suite pseudo-aléatoire, et donc de pouvoir décoder tous les messages de taille inférieure.
En 2001, Fluhrer, Mantin et Shamir ont montré que l'utilisation de RC4 pour WEP rendait la clé facilement craquable. Il suffit de récupérer un nombre relativement faible de paquets cryptés dont on connaît le premier octet. (On garde également leurs vecteurs d'initialisation...)
Nous avons vu l'attaque de Fluhrer, Mantin et Shamir en cours. Pour ce TP, vous devrez l'implanter pour vérifier qu'on peut effectivement récupérer une clé à partir de suffisamment de paquets codés.
Rappel : si on connaît les "n
" premiers octets de la clé WEP,
IV
,
3+n
premières étapes)
P[1] < n+3
"
P[1] + P[P[1]] == n+3
"
prediction = P'[o] - j - P[n+3]
", où "P'[o]
" est la position de o
(premier octet généré par le PRGA) dans la permutation P
.
On garde la prediction qui apparaît le plus souvent.
Pour récupérer l'archive contenant les fichiers pour la suite du TP, remplacez tp3.html
dans l'url du TP par TP3/tp3-XXXXXXXXXXXXXX.tar
, où XXXXXXXXXXXXXX
est le codage RC4 de "info528
" en utilisant la clé "TP3
" et en jetant les 1024 premiers octets du générateur pseudo-aléatoire. (Argument "n
" à 1024 donc.) Attention, les chiffres hexadécimaux sont en majuscules (printf("%02X",o)
).
L'archive du TP contient un répertoire info528-TP3
qui contient les fichiers :
Makefile
: n'oubliez pas de changer la variable NOM
tp3.h
: le fichier d'entêtes
rc4.c
: les fonctions pour utiliser RC4
FMS.c
: le fichier qui contient une fonction principale pour tester vos fonctions
lucien-tartempion.c
un fichier squelette que vous devrez remplir.
Écrivez la fonction
/********************************************************************** * devine le "n"-ième octet de la clé (en supposant qu'on connaît les * * n-1 octets précédents) en essayant tous les vecteurs * * d'initialisations faibles. * * L'argument "cle_wep_partielle" contient le début de la clé (octets * * 0 à "n"-1, non compris). * * La fonction ne modifie pas les "n"-1 premières valeurs de * * "cle_wep_partielle". * * * * L'argument "nb_IV_faibles" est le nombre de vecteurs faibles à * * considérer. * * L'argument "nb_IV_total" est le nombre total de vecteurs à tester. * * * * La fonction s'arrête quand l'une des deux bornes est atteinte. * * * * Si les 2 bornes sont nulles, on utilise alors uniquement la * * famille de vecteurs (n+3, 255, ...). ATTENTION, ça n'est possible * * que si "taille_IV = 3". * * * * La fonction renvoie "n" si l'opération c'est bien passée. Dans ce * * cas, l'octet "n"-1 de "cle_wep_partielle" est positionné à sa * * valeur. * * * * La fonction renvoie "-1" en cas de problème. La "n"-ième valeur de * * "cle_wep_partielle" est alors quelconque. * **********************************************************************/ int predit_octet(int n, octet *cle_wep_partielle, int nb_IV_faibles, int nb_IV_total) { ...
Je vous conseille d'écrire au moins une fonction auxiliaire du style :
/********************************************************************** * teste un vecteur d'initialisation : * * - "IV" est le vecteur en question * * - "n" est l'octet de la clé que l'on recherche * * - "cle_partielle" est la clé partielle que l'on a déjà calculée * * * * La fonction renvoie 1 si le vecteur était faible, et dans ce cas, * * la prédiction correspondante se trouve dans le dernier paramètre * * "prediction". * **********************************************************************/ int teste_IV(octet *IV, int n, octet *cle_partielle, octet *prediction) { ...
La fonction principale fournie (fichier test.c
et exécutable test
produit par le fichier Makefile
permet de tester facilement votre fonction predit_octet
:
$ ./test
tire une clé WEP au hasard sur 13 octets et essaie de la craquer.
$ ./test -h
vous affichera un message d'aide. Lisez-le !
Si on donne des valeurs négatives à nb_IV_faibles
et nb_IV_total
, votre fonction utilisera uniquement les vecteurs d'initialisation de la forme { n+3, 255, X }
, pour X
= 0, 1, ... 255 qui sont presque tous faibles.
Commencez par faire uniquement cette partie car elle est beaucoup plus rapide. (Seul une toute petite partie des vecteurs d'initialisations est faible au sens vu en cours.)
Le fichier tp3-nom-prenom.c
fournit contient une variable globale verbose
qui est mise à jours lorsqu'on utilise le drapeau -v
sur la ligne de commande. Servez-vous en pour contrôler les affichages de vos fonctions.
{ n+3, 255, X }
?
Vous pouvez récupérer ici et là deux fichiers objets contenant le code compilé de rc4.c
avec une clé secrète. Les seules différences avec rc4.c
sont :
cle_wep
est statique (donc inaccessible à partir d'un autre fichier)
nouvelle_cle_wep_aleatoire()
produit toujours la même clé
Écrivez une petite fonction principale dans un fichier craque.c
qui essaie de récupérer les deux clés secrètes. Mettez-les en commentaire en haut de votre fichier nom-prenom.c
. (Pas besoin de m'envoyer votre fichier "craque.c
".)
Pour ceux qui sont sur une architecture 64 bits, voir plutôt ici et là.