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

Szyfr Gronsfeld

Wstęp

Szyfr Gronsfeld jest to szyfr powstały na podstawie szyfru Vigenère. Ogranicza on liczbę używanych alfabetów podczas szyfrowania co przyśpiesza proces szyfrowania, ale nakłada ograniczenia na wybór hasła do szyfrowania.

Algorytm szyfrowania

Szyfro Gronsfeld ogranicza się jedynie do dziesięciu alfabetów szyfrujących w przeciwieństwo do szyfru Vigenère. Generalnie tabelkę szyfrującą możnaby przepisać zostawiając jedynie pierwsze dziesięć wierszy tak jak poniżej:

ABCDEFGHIJKLMNOPQRSTUVWXYZ
AABCDEFGHIJKLMNOPQRSTUVWXYZ
BBCDEFGHIJKLMNOPQRSTUVWXYZA
CCDEFGHIJKLMNOPQRSTUVWXYZAB
DDEFGHIJKLMNOPQRSTUVWXYZABC
EEFGHIJKLMNOPQRSTUVWXYZABCD
FFGHIJKLMNOPQRSTUVWXYZABCDE
GGHIJKLMNOPQRSTUVWXYZABCDEF
HHIJKLMNOPQRSTUVWXYZABCDEFG
IIJKLMNOPQRSTUVWXYZABCDEFGH
JJKLMNOPQRSTUVWXYZABCDEFGHI

Szyfrowanie pojedynczego znaku polega na znalezieniu kolumny, której nagłówek jest szyfrowanym znakiem. Następnie cyklicznie należy wybrać odpowiedni znak szyfrujący z klucza, a następnie znaleźć wiersz o nagłówku takim jak znak szyfrujący. Przecięcie się wybranej kolumny oraz wiersza wskaże szukany znak. Znaki, które nie zostały wyszczególnione w tabeli należy przepisać do szyfrogramu bez zmian.

Przykładowo szyfrowana litera A przy pomocy znaku F da F. Z kolei szyfrowanie znaku C znakiem E da G.

Hasło szyfrujące

Ze względu na to, że została zmniejszona pula alfabetów szyfrujących należy zauważyć, że hasło może składać się jedynie ze znaków od A do J.

Implementacja

Poniżej została przedstawiona implementacja kodu szyfrującego szyfrem Gronsfelda, która wczytuje od użytkownika klucz oraz tekst jawny. Program zakłada poprawność danych wejściowych tj. wszystkie wpisane znaki są wielkimi literami oraz hasło składa się jedynie ze znaków od A do J.

Szyfrowanie

Ze względu na to, że szyfr Gronsfeld ogranicza jedynie tabelkę to algorytm szyfrowania jest identyczny jak w przypadku szyfru Vigenère. Nie ma potrzeby przechowywania tabelki. Należy pamiętać, że znak szyfrowany pewnym znakiem jest przesunięciem cyklicznym w prawo o pozycję danego znaku w alfabecie pomniejszoną o jeden.

Przykładowa funkcja szyfrująca szyfruj() będzie przyjmować dwa argumenty: klucz - klucz użyty podczas szyfrowania oraz tekst - tekst do zaszyfrowania.

  1. char* szyfruj(char* klucz, char* tekst) {
  2.   int dl = strlen(tekst);
  3.   int KLUCZ_DL = strlen(klucz);
  4.   char* tekstNowy = new char[dl + 1];
  5.   for (int i = 0; tekst[i]; i++) {
  6.     if (tekst[i] >= 'A' && tekst[i] <= 'Z') {
  7.       int znak = (tekst[i]-'A')+(klucz[i % KLUCZ_DL]-'A');
  8.       tekstNowy[i] = (znak % ALFABET_DL) + 'A';
  9.     } else {
  10.       tekstNowy[i] = tekst[i];
  11.     }
  12.   }
  13.   tekstNowy[dl] = '\0';
  14.   return tekstNowy;
  15. }

Najpierw (2.) ustalana jest długość tekstu, (3.) długość klucza i jest (4.) alokowane miejsce w pamięci pod nową tablicę znaków. (5. - 12.) Dla każdego znaku: (6.) sprawdź czy jest znakiem alfabetu łacińskiego. Jeśli tak to (7.) przesuń numer znaku i (8.) wstaw do tekstu wynikowego. W przypadku, gdy znak nie jest wielką literą alfabetu łacińskiego to (9.) wystarczy przepisać. Na koniec należy pamiętać o (13.) dopisaniu znaku końca danych oraz o (14.) zwróceniu wskaźnika na utworzoną wcześniej tablicę znaków.

Deszyfrowanie

W celu rozszyfrowania danych należy wykonać dokładnie te same operacje co w szyfrowaniu z tą różnicą, że należy (7.) odjąć wartość klucza, a nie dodać. W tym miejscu jednak pojawia się jednak jeszcze jeden problem: (8.) wyliczona wartość może być ujemna, więc do wartości należy dodać długość alfabetu.

  1. char* rozszyfruj(char* klucz, char* tekst) {
  2.   int dl = strlen(tekst);
  3.   int KLUCZ_DL = strlen(klucz);
  4.   char* tekstNowy = new char[dl + 1];
  5.   for (int i = 0; tekst[i]; i++) {
  6.     if (tekst[i] >= 'A' && tekst[i] <= 'Z') {
  7.       int znak = (tekst[i]-'A')-(klucz[i % KLUCZ_DL]-'A');
  8.       tekstNowy[i] = ((znak+ALFABET_DL) % ALFABET_DL)+'A';
  9.     } else {
  10.       tekstNowy[i] = tekst[i];
  11.     }
  12.   }
  13.   tekstNowy[dl] = '\0';
  14.   return tekstNowy;
  15. }

Testowanie funkcji

W celu przetestowania napisanych funkcji można skorzystać z poniższej funkcji main(), która pyta użytkownika o dane wejściowe, a potem wypisuje tekst zaszyfrowany oraz rozszyfrowany.

  1. int main () {
  2.   char* klucz = new char[64];
  3.   char* tekst = new char[512];
  4.   cout << "Podaj klucz: ";
  5.   cin.getline(klucz, 64);
  6.   cout << "Podaj tekst jawny:\n";
  7.   cin.getline(tekst, 512);
  8.   cout << "\nTekst zaszyfrowany:\n";
  9.   char* tekstZ = szyfruj(klucz, tekst);
  10.   cout << tekstZ;
  11.   cout << "\nTekst rozszyfrowany:\n";
  12.   char* tekstR = rozszyfruj(klucz, tekstZ);
  13.   cout << tekstR;
  14.   delete klucz, tekst, tekstZ, tekstR;
  15.   system("pause");
  16.   return 0;
  17. }

Zadania

Zadanie 1

Napisz program, który pozwala na zapis klucza szyfrującego nie tylko jako znaki alfabetu łacińskiego, ale również cyfr. Wtedy cyfra 0 odpowiada wartości przesunięcia przez A, a 9 odpowiada przesunięciu przez J. W przygotowanym programie napisz funkcję, która będzie dodatkowało sprawdzała wprowadzony klucz szyfrujący. Jeśli klucz szyfrujący będzie niepoprawny wypisz tylko na ekran "Niepoprawny klucz". Przetestuj napisany kod.

Przykładowo dla klucza "AB123" i tekstu jawnego "INFORMACJA" otrzymamy "IOGQUMBDLD". Ten sam wynik powinien został uzyskany dla klucza "ABBCD".