next up previous contents
suivant: Algorithme d'Euclide étendu sous monter: Corrigés des programmes précédent: Prise en main de   Table des matières

Vigenere

vigenereGmp.c


#include<stdio.h>
#include<gmp.h>

#define CLEAR_BUFFER while(getchar() != '\n')
#define MSG_SIZE 500
#define KEY_SIZE 20
#define BASE 27
#define NB_LETTRES (BASE - 1)

/********************************************************/

/*
  Nous numeroterons les lettres de 1 a 27. Cela permettra 
  d'eviter qu'il y  ait des zeros dans la representation 
  en base 27.

  Nous transformerons ces messages en nombres 
  en les convertissant de la base 27 vers la base 10, 
  
  Par exemple,

  a b z = a + 27 (b + 27 (z)) = 1 + 27 * (2 + 27 * (26)).

  Il devra aussi etre possible de saisir les messages 
  et les cles directement en base 10.
*/

/********************************************************/

/*
  Saisit proprement une chaine de caractere. Supprime
  le caractere de retour a la ligne.
*/

void saisitChaine(char* message, int maxSize)
{
  int i;
  fgets(message, maxSize, stdin); 
  i = 0; 
  while(message[i] != 0) 
    i++; 
  if (i > 0 && message[i-1] != '\n') 
    CLEAR_BUFFER; 
  else  
    message[i-1] = 0; 
}

/********************************************************/

/*
  Retourne vrai ssi a est une lettre minuscule ou 
  majuscule de l'alphabet.
*/

int validChar(char a)
{
  return (a >= 'A' && a <= 'z');
}

/********************************************************/

/*
  Convertit a en minuscule s'il n'est pas deja 
  sous ce format.
*/

char formatChar(char a)
{
  if (a >= 'A' && a <= 'Z')
    return a - 'A' + 'a';
  return a;
}

/********************************************************/

/*
  Supprime tous les caracteres non alphabetiques de message.
  place le resultat dans cleaned. Il doit etre possible
  d'utiliser la meme adresse pour cleaned et message.
*/

void cleanMessage(char* cleaned, char* message)
{
  if (*message ==0 )
    *cleaned = 0;
  else
    {
      if (validChar(*message))
	{
	  *cleaned = formatChar(*message);
	  cleanMessage(cleaned + 1, message + 1);
	}
      else
	cleanMessage(cleaned, message + 1);
    }
}

/********************************************************/

/*
  Affiche la chaine message, puis un retour a la ligne.
*/

void printMessage(char* message)
{
  printf("%s\n", message);
}

/********************************************************/

/*
  Retourne le rang de letter dans l'alphabet. On 
  indice a partir de 0.
*/

char rankOfLetter(char letter)
{
  return (letter - 'a');
}

/********************************************************/

/*
  Retourne la lettre de rang rank. 'a' est de rang 0.
*/

char letterOfRank(char rank)
{
  return (rank + 'a');
}

/********************************************************/

/*
  Retourne le nombre de nombre de decalage dans l'alphabet 
  a effectuer pour chiffrer avec la cle key. 1 pour 'a', 
  2 pour 'b', etc. Vous prendrez en compte le cas ou il 
  y a 26 decalages a effectuer...
  
*/

char nbDecalagesOfKey(char key)
{
  char nbDecalages = rankOfLetter(key) + 1;
  return (nbDecalages == NB_LETTRES) ? 
    0 
    : nbDecalages ;
}

/********************************************************/

/*
  Retourne la lettre de la cle correspondant a un decalage 
  de rank lettres.
*/

char keyOfNbDecalages(char nbDecalages)
{
  return (nbDecalages == 0) ? 
    letterOfRank(NB_LETTRES)
    : letterOfRank(nbDecalages - 1);  
}

/********************************************************/

/*
  Chiffre le caractere a avec la cle key, representee par une lettre 
  de l'alphabet.
*/

char encryptChar(char a, char key)
{
  return letterOfRank(
		      (rankOfLetter(a) + nbDecalagesOfKey(key)
		       )%(NB_LETTRES)
		      );
}

/********************************************************/

/*
  Inverse la cle de chiffrement key de sorte qu'on puisse l'utiliser
  pour le dechiffrement. Par exemple, l'inverse de 'a' est 'y', 
  l'inverse de 'b' est 'x', l'inverse de 'c' est 'w', etc. 
*/

char reverseKey(char key)
{
  char nbDecalages = nbDecalagesOfKey(key);
  return (nbDecalages == NB_LETTRES) ?
    NB_LETTRES
    : keyOfNbDecalages(NB_LETTRES - nbDecalages);
}

/********************************************************/

/*
  Inverse toutes les lettres de keys.
*/

void reverseKeys(char* keys)
{
  if (*keys != 0)
    {
      *keys = reverseKey(*keys);
      reverseKeys(keys + 1);
    }
}

/********************************************************/

/*
  Chiffre message avec key, place le resultat dans 
  ciphered. message est suppose ne contenir que des 
  caracteres alphabetiques au format minuscule.
*/

void encrypt(char* ciphered, char* message, char* key) 
{
  int i;
  for(i = 0 ; *message != 0 && *(key + i) != 0 ; 
      i++, message++, ciphered++)
    {
      *ciphered = encryptChar(*message,  *(key + i));
    }
  if(*(key + i) == 0)
    {
      encrypt(ciphered, message, key);
    }
  else
    *ciphered = 0;
}

/********************************************************/

/*
  Dechiffre ciphered, place le resultat dans message. 
  key est la cle qui a servi pour le chiffrement.
*/

void decrypt(char* message, char* ciphered, char* key) 
{
  reverseKeys(key);
  encrypt(message, ciphered, key);
}


/********************************************************/

/*
  Exprime message en base 10. Par exemple, si message = "abzc", 
  result = 1 + BASE (2 + BASE(26 + BASE(3)))
*/

void toBase10(mpz_t result, char* message) 
{
  if (*message == 0)
    mpz_set_ui(result, 0);
  else
    {
      toBase10(result, message+1) ;
      mpz_mul_ui(result, result, BASE);
      mpz_add_ui(result, result, rankOfLetter(*message) + 1);
    }
}

/********************************************************/

/*
  Effectue la transformation inverse de toBase10.
*/

void fromBase10(char* message, mpz_t value) 
{
  if (mpz_cmp_ui(value, 0))
    {
      *message = letterOfRank(mpz_fdiv_q_ui(value, value, BASE)) - 1;
      fromBase10(message + 1, value);
    }
  else
    *message = 0;
}


/********************************************************/

/*
  Saisit soit une chaine, soit un nombre en base 10 
  converti par la suite en chaine.
*/

void saisitValeurs(char* valeurs, int maxSize) 
{
  mpz_t base10;  
  char choix[2];
  mpz_init(base10);
  do
    {
      printf("(c)haine, (b)ase 10 (c/b) ?"); 
      saisitChaine(choix, 2);
      switch(*choix)
	{
	case 'c': 
	  saisitChaine(valeurs, maxSize);
	  toBase10(base10, valeurs);	  
	  printf("(");
	  toBase10(base10, valeurs);
	  mpz_out_str(NULL, 10, base10);
	  printf(" en base 10)\n");	  
	  break;
	case 'b': 
	  saisitChaine(valeurs, maxSize);
	  mpz_set_str(base10, valeurs, 10);
	  fromBase10(valeurs, base10);	  
	  break;
	}
    }
  while(*choix != 'c' && *choix!='b');
  mpz_clear(base10);
}


/********************************************************/

/*
  Saisit un message, une cle, nettoie le message et affiche 
  le message chiffre.
*/

void VigenereEncrypt() 
{
  char msg[MSG_SIZE];
  char key[KEY_SIZE];
  char chiffre[MSG_SIZE];
  mpz_t base10;
  printf("Saisissez le message :\n");
  saisitValeurs(msg, MSG_SIZE);
  cleanMessage(msg, msg);
  printf("Saisissez la cle :\n");
  saisitValeurs(key, KEY_SIZE);
  encrypt(chiffre, msg, key);
  printf("Le message chiffre est :\n");
  printMessage(chiffre);
  printf("(");
  mpz_init(base10);
  toBase10(base10, chiffre);
  mpz_out_str(NULL, 10, base10);
  printf(" en base 10)\n");
  mpz_clear(base10);
}

/********************************************************/

/*
  Saisit un message chiffre, la cle de chiffrement, 
  et affiche le message dechiffre. 
*/

void VigenereDecrypt() 
{
  char msg[MSG_SIZE];
  char key[KEY_SIZE];
  char chiffre[MSG_SIZE];
  mpz_t base10;
  printf("Saisissez le message chiffre :\n");
  saisitValeurs(chiffre, MSG_SIZE);
  printf("Saisissez la cle :\n");
  saisitValeurs(key, KEY_SIZE);
  decrypt(msg, chiffre, key);
  printf("Le message dechiffre est :\n");
  printMessage(msg);
  printf("(");
  mpz_init(base10);
  toBase10(base10, msg);
  mpz_out_str(NULL, 10, base10);
  printf(" en base 10)\n");
  mpz_clear(base10);
}

/********************************************************/

/*
  Donne a l'utilisateur la possibilite de chiffrer un message, 
  dechiffrer un message, ou de quitter. 
*/

void vigenere()
{
  char choix[2];
  do
    {
      printf("\n(c)hiffrer, (d)echiffrer, (q)uitter (c/d/q) ?"); 
      saisitChaine(choix, 2);
      switch(*choix)
	{
	case 'c': VigenereEncrypt();
	  break;
	case 'd': VigenereDecrypt();
	  break;
	case 'q': printf("Au revoir !\n");	  
	}
    }
  while(*choix != 'q');
}

/********************************************************/

/*
  Pour tester les fonctions...
*/

int main()
{
  vigenere();
  return 0;
}


next up previous contents
suivant: Algorithme d'Euclide étendu sous monter: Corrigés des programmes précédent: Prise en main de   Table des matières
klaus 2010-08-05