next up previous contents
suivant: Changement de base monter: Corrigés des programmes précédent: Le plus beau métier   Table des matières

Vigenere

vigenere.c


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

#define CLEAR_BUFFER while(getchar() != '\n')
#define MSG_SIZE 500
#define KEY_SIZE 20
#define NB_LETTRES 26

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

/*
  Ce programme propose a son utilisateur de saisir 
  un message et effectue ensuite son chiffrement 
  par la methode Vigenere. Il est aussi possible de 
  dechiffrer. Nous indicerons les lettres de 0 a 25.
  Le message "abz" sera donc represente par la suite 
  de nombres 0 1 25. On chiffrera en decalant les lettres d'une 
  position dans l'alphabet si la cle est un 'a', deux positions 
  si c'est un 'b', etc. "abz" chiffre avec la cle "ab" nous donne 
  donc "bda". Pour dechiffrer "bda", on inverse la cle "ab", ce qui 
  nous donne "yx", et on applique la cle "yx" au message chiffre
  "bda".
*/

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

/*
  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);
}


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

/*
  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];
  printf("Saisissez le message :\n");
  saisitChaine(msg, MSG_SIZE);
  cleanMessage(msg, msg);
  printf("Saisissez la cle :\n");
  saisitChaine(key, KEY_SIZE);
  encrypt(chiffre, msg, key);
  printf("Le message chiffre est :\n");
  printMessage(chiffre);
}

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

/* 
  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];
  printf("Saisissez le message chiffre :\n");
  saisitChaine(chiffre, MSG_SIZE);
  printf("Saisissez la cle :\n");
  saisitChaine(key, KEY_SIZE);
  decrypt(msg, chiffre, key);
  printf("Le message dechiffre est :\n");
  printMessage(msg);
}

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

/*
  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: Changement de base monter: Corrigés des programmes précédent: Le plus beau métier   Table des matières
klaus 2010-08-05