Article Index

5°) implémentation

/**********************************************************************
 * teste un vecteur d'initialisation :                                *
 *   - "o_rc4" est le premier octet généré par RC4 avec "IV"          *
 *   - "n" est l'octet de la clé que l'on recherche                   *
 *   - "cle" contient les morceaux de la clé que l'on a déjà calculée *
 *                                                                    *
 * La fonction renvoie 1 si la clé était faible, et dans ce cas,      *
 * la prédiction correspondante se trouve dans le dernier paramètre   *
 * "prediction".                                                      *
 * Si la clé n'était pas faible, cette fonction renvoie 1 et le       *
 * paramètre n'est pas modifié.                                       *
 **********************************************************************/
 
int predit_octet_simple(octet o_rc4, int n, octet *cle, octet *prediction)
{
    unsigned char P[256];
    unsigned char s_1;
    unsigned char tmp_key[8];
    int i, j;
    
    memcpy(tmp_key, cle, 8);
    j = s_1 = 0;
    
    for(i=0; i<256; i++)
        P[i] = i;
      
    for(i=0; i<n+3; i++)
    {
        j = (unsigned char)(j+P[i]+tmp_key[i%8]);
        echange(&P[i], &P[j]);
    }
    
    for (i=0; i<256; i++)
    {
        if(P[i] == *prediction)
            s_1 = i;
    }
    
    if(P[0] != n+3 || P[1] != 0)
        return -1;
      
    *prediction = (s_1-j-P[n+3]);
    
    return 1;
}



/**********************************************************************
 * 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 positionne le n-ème octet de "cle_WEP_partielle" en    *
 * utilisant la prédiction faite.                                     *
 **********************************************************************/
void predit_octet_multiple(int n, octet *cle_WEP_partielle, int nb_IV_faibles_total, int nb_IV_total)
{
  int i;
  int faible;

  /* la prédiction finale */
  octet prediction = 0;
  int resultat = -1;

  /* le vecteur d'initialisation courant */
  octet IV[taille_IV];

  /* la clé RC4 que l'on essaie de compléter :
   * les premiers octets sont variables et contiennent le vecteur
   * d'initialisation,
   * les derniers octets contiennent le morceau de la clé WEP que l'on a déjà
   * craquée*/
  octet cle_partielle[taille_cle_RC4];


  for (i = 0; i < taille_cle_RC4 - taille_IV; i++)
    cle_partielle[i + taille_IV] = cle_WEP_partielle[i];  /* cette partie de la clé est constante : c'est le morceau de la clé WEP déjà craqué */

  if (verbose > 2)
    printf("Pour l'octet n=%d :  ", n); fflush(NULL);

  /* nb de vecteurs et de vecteurs faibles rencontrés */
  int nb_IV = 0;
  int nb_IV_faibles = 0;


  while (1) { // on boucle jusqu'à avoir tester suffisamment de vecteurs d'initialisation

    /* si nb_IV_total et nb_IV_faibles_total sont négatifs, on choisit un
     * nouveau vecteur d'initialisation dans la famille (n+3, 255, ...) */
    if (nb_IV_total < 1 && nb_IV_faibles_total < 1) {
      if (nb_IV > 255) break;  //on a testé tous les vecteurs de la forme (n+3, 255, ...)
      IV[0] = n + taille_IV;
      IV[1] = 255;
      IV[2] = nb_IV;
    } else {
    /* sinon, on tire un vecteur d'initialisation aléatoirement */
      if ((nb_IV_total > 0) && (nb_IV > nb_IV_total)) break;  // on a testé suffisamment de vecteurs
      if ((nb_IV_faibles_total > 0) && (nb_IV_faibles > nb_IV_faibles_total)) break; // idem
      for (i=0; i < taille_IV; i++) IV[i] = rand() % 256;
    }

    nb_IV++;

    /* on initialise RC4 avec le vecteur d'initialisation courant,
     * puis on demande le premier octet */
    init_WEP_RC4(IV);
    octet o_rc4 = RC4_PRGA();

    /* On initialize la clé partielle */
    /* on recopie le vecteur d'initialisation dans la clé (le reste de la clé
     * est constant : c'est ce qu'on cherche) */
    for (int k = 0; k < taille_IV; k++)
        cle_partielle[k] = IV[k];

    /***
     * on appelle la fonction "predit_octet_simple" pour vérifier si "IV" est
     * un vecteur d'initialisation faible (et calculer la prédiction)
     ***/
    faible = predit_octet_simple(o_rc4, n, cle_partielle, &prediction);

    /* si le vecteur IV était faible, on prend en compte la prediction */
    if (1 == faible) {
        nb_IV_faibles++;
        resultat = prediction;
    }
  }

  cle_WEP_partielle[n] = resultat;
}