Strona główna » Algorytmy » Szyfry » Szyfr Cezara
 

Szyfr Cezara

· Szyfrowanie · Łamanie szyfru ·

O szyfrze

W szyfrze Cezara wykorzystuje się alfabet łaciński. Do szyfrowania lub deszyfrowania potrzebny jest klucz a, który jest liczbą całkowitą. Szyfrując znak szukamy jego pozycji w alfabecie i pobranie znaku a pozycji dalej. W przypadku, gdy wyjdziemy poza zakres alfabetu to wyciągamy z wyliczonej modulo długość alfabetu. Podczas deszyfrowania szyfrujemy ponownie podstawiając za klucz -a.

Przykładowo szyfrujemy wyraz INFORMACJA z kluczem 3. Możemy stworzyć tabelkę, która pozwoli szybciej wykonać szyfrowanie:

Tekst jawnyABCDEFGHIJKLMNOPQRSTUVWXYZ
SzyfrogramDEFGHIJKLMNOPQRSTUVWXYZABC

Dzięki tabelce bardzo łatwo odczytać jaka litera z tekstu jawnego na jaką przechodzi: I na L, N na Q, ... i w ten sposób odczytujemy, że INFORMACJA przechodzi na LQIRUPDFMD.

Zadanie 1

Napiszemy funkcję, która będzie przyjmowała dwa argumenty: tekst do zaszyfrowania typu char* oraz klucz typu int. Wynikiem funkcji będzie zaszyfrowany tekst. Zakładamy, że w podanym tekście występują tylko duże litery alfabetu łacińskiego, znaki interpunkcyjne oraz spacje. Przykładowo dla danych:

  1. 2
  2. SZYFR CEZARA

otrzymamy:

  1. VCBIU FHCDUD

Szyfrowanie

Funkcja przyjmuje dwa argumenty txt - tekst do zaszyfrowania oraz przes - klucz według którego szyfrujemy. Wynikiem funkcji jest tablica znaków typu char*, która będzie zawierać zaszyfrowany tekst.

  1. char* cipher(char* txt, int przes){
  2.   while(przes < 0) przes += ('Z' - 'A' + 1);
  3.   char* wynik = new char[strlen(txt) + 1];
  4.   for(int i = 0; txt[i]; i++){
  5.     if(txt[i] >= 'A' && txt[i] <= 'Z'){
  6.       wynik[i] = (((txt[i] - 'A') + przes) % ('Z' - 'A' + 1)) + 'A';
  7.     } else {
  8.       wynik[i] = txt[i];
  9.     }
  10.   }
  11.   wynik[strlen(txt)] = '\0';
  12.   return wynik;
  13. }

(2.) Jeśli przesunięcie jest ujemne to dodajemy do niego długość alfabetu. Dzięki temu unikamy rozpatrywania przypadku kiedy wyjdziemy poza alfabet z lewej strony. (3.) Alokujemy pamięć pod tekst wynikowy. (4.) Rozpoczynamy szyfrowanie każde znaku po kolei: jeśli nasz znak jest dużą literą to (5.) wyliczamy jego nową pozycje i pobieramy odpowiedni znak. Korzystamy tutaj z tablicy ASCII. Gdybyśmy w (2.) nie usunęli ujemności przes to trzeba by rozpatrzeć dwa przypadki, albo przesunięcie poprawić podczas wyliczania nowej litery. (7.) Jeśli jednak i-ty znak nie jest literą to (8.) przepisujemy znak bez żadnych dodatkowych zmian. (11.) Na koniec dostawiamy znak \0 i (12.) zwracamy wynik.

Deszyfrowanie

Deszyfrowanie polega na zaszyfrowaniu kluczem przeciwnym - czyli jeśli zaszyfrowaliśmy tekst przy pomocy a to deszyfrujemy go szyfrując przy pomocy -a, dlatego deszyfrowanie możemy wywołać przy pomocy funkcji cipher():

  1. cipher(txt, -3);

Jednak bardziej eleganckim rozwiązaniem jest dopisanie funkcji decipher(), której będziemy podawać ten sam klucz do szyfrowania:

  1. char* decipher(char* txt, int przes){
  2.   return cipher(txt, -przes);
  3. }

Testowanie funkcji

Zamieszczona poniżej funkcja main() pozwala przetestować działanie funkcji poprzez wczytanie tekstu, a następnie wypisaniu szyfrogramu z przesunięciem 3, a potem wypisaniu próby deszyfrowania danych.

  1. int main () {
  2.   char* txt = new char[128];
  3.   cin.getline(txt, 128);
  4.   char* txtc = cipher(txt, 3);
  5.   cout << txtc << endl;
  6.   char* txtd = decipher(txtc, 3);
  7.   cout << txtd << endl;
  8.   system("pause");
  9.   return 0;
  10. }

Zadanie 2

Tym razem będziemy chcieli ustalić własny alfabet według, którego będziemy szyfrowali dane: w ten sposób prócz klucz będzie potrzeba ustalenia alfabetu.

  1. ZYXWVUTSRQPONMLKJIHGFEDCBA
  2. INFORMACJA
  3. 2

otrzymamy:

  1. GLDMPKYAHY

Funkcja pomocnicza

Dotychczasowy kod potrzebuje drobnej modyfikacji. Podczas szyfrowania nie możemy wyliczać grupy i pozycji na podstawie odległości od litery A. Wyliczymy je na podstawie pozycji znaku w podanym alfabecie. Żeby to osiągnąć dopiszemy funkcję, która dla podanego ciągu i znaku znajdzie jego pozycję i ją zwróci.

  1. int findChar(const char* data, const char c){
  2.   for(int i = 0; data[i]; i++)
  3.     if(data[i] == c)
  4.       return i;
  5.   return -1;
  6. }

Szyfrowanie

Spójrzmy teraz na funkcję szyfrującą:

  1. char* cipher(char* alphabet, char* txt, int przes){
  2.   while(przes < 0) przes += (strlen(alphabet));
  3.   char* wynik = new char[strlen(txt) + 1];
  4.   for(int i = 0; txt[i]; i++){
  5.     int t = -1;
  6.     if((t = findChar(alphabet, txt[i])) != -1){
  7.       wynik[i] = alphabet[(t + przes) % strlen(alphabet)];
  8.     } else {
  9.       wynik[i] = txt[i];
  10.     }
  11.   }
  12.   wynik[strlen(txt)] = '\0';
  13.   return wynik;
  14. }

(1.) Modyfikujemy nagłówek funkcji, który od tej pory będzie przyjmował także alphabet - ciąg znaków alfabetu według którego szyfrujemy. (2.) Długością alfabetu nie jest już 'Z' - 'A' + 1 tylko długość alphabet co też ma wpływ na (3.). (4.) Dla każdego znaku: (5.) deklarujemy zmienną pomocniczą t dla której (5.) sprawdzamy czy występuje w alfabecie. Jeśli tak to (6.) szyfrujemy go. (8.) Jeśli nie występuje w alfabecie to (9.) tylko przepisujemy. (12.) Kończymy wynik znakiem \0 i (13.) zwracamy wynik.

Deszyfrowanie

Deszyfrowanie wymaga tylko dodania nowego argumentu, który przekażemy dalej do cipher().

  1. char* decipher(char* alphabet, char* txt, int przes){
  2.   return cipher(alphabet, txt, -przes);
  3. }

Testowanie funkcji

Poniżej znajduje się zaktualizowana funkcja main(), która przetestuje działanie napisanych funkcji.

  1. int main () {
  2.   char* alphabet = new char[128];
  3.   cin.getline(alphabet, 128);
  4.   char* txt = new char[128];
  5.   cin.getline(txt, 128);
  6.   int przes;
  7.   cin.sync();
  8.   cin >> przes;
  9.   char* txtc = cipher(alphabet, txt, przes);
  10.   cout << txtc << endl;
  11.   char* txtd = decipher(alphabet, txtc, przes);
  12.   cout << txtd << endl;
  13.   system("pause");
  14.   return 0;
  15. }

Zadania

Zadanie 1

Na podstawie kodu źródłowego do zadania 1:

  1. Zmodyfikuj funkcję cipher(), aby szyfrowała tak samo małe jak i duże litery alfabetu łacińskiego.

Przykładowo dla danych:

  1. Szyfr Cezara
  2. 3
otrzymujemy:
  1. Vcbiu Fhcdud