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

Szyfr Phillips

Wstęp

Szyfr Phillips został opracowany przez Brytyjczyków podczas I wojny światowej. Cały proces szyfrowania opiera się na tablicy Polibiusza. Jego podstawowa wersja przewiduje szyfrowanie 25 znaków alfabetu bez litery J, ale istnieje również wersja rozszerzona, która pozwala na zaszyfrowanie wszystkich znaków alfabetu oraz wszystkie cyfry.

Zasada szyfrowania

Klucz i alfabet

W celu utworzenia tablic szyfrujących należy wpierw ustalić słowo klucz, które składa się tylko ze znaków przewidzianych do szyfrowania. W celu utworzenia alfabetu należy przepisać z klucza tylko pierwsze wystąpienia każdego znaku, a potem alfabet uzupełnić pozostałymi literami alfabetu.

Przykładowo przyjmuj za klucz wyrażenie "PHILLIPS" utworzony alfabet to będzie "PHILSABCDEFGKMNOQRTUVWXYZ". Jak widać drugie występienie liter P, I oraz L zostały usunięte.

Tablice

Następnie na podstawie alfabetu utworzonego przy użyciu klucza należy rozrysować 8 tablic 5×5 (lub 6×6 w zależności od wybranej wersji). Pierwsza tablica powstaje poprzez wpisanie klucza do kolejnch wierszy tabeli. Następnie tablica 2 powstaje przez przesunięcie pierwszego wiersza o 1 wiersz niżej. Tablica 3 powstaje przez ponowne przesunięcie przesuniętego wiersza. Analogicznie powstaje tablica 4 i 5. Dla tablic 6, 7 i 8 należy oznaczyć jako wybrany i przesuwać go w kolejnych przekształceniach.

Utworzony alfabet "PHILSABCDEFGKMNOQRTUVWXYZ" generuje następujące tablice:

Tablica [1]
PHILS
ABCDE
FGKMN
OQRTU
VWXYZ
Tablica [2]
ABCDE
PHILS
FGKMN
OQRTU
VWXYZ
Tablica [3]
ABCDE
FGKMN
PHILS
OQRTU
VWXYZ
Tablica [4]
ABCDE
FGKMN
OQRTU
PHILS
VWXYZ
Tablica [5]
ABCDE
FGKMN
OQRTU
VWXYZ
PHILS
Tablica [6]
FGKMN
ABCDE
OQRTU
VWXYZ
PHILS
Tablica [7]
FGKMN
OQRTU
ABCDE
VWXYZ
PHILS
Tablica [8]
FGKMN
OQRTU
VWXYZ
ABCDE
PHILS

Szyfrowanie danych

Szyfrowanie danych polega na pogrupowaniu znaków w pięcioznakowe grupy. Do każdej grupy należy cyklicznie przyporządkowąć kolejną tablicę szyfrującą począwszy od pierwszej. Każdy znak w grupie jest szyfrowany oddzielnie zgodnie z przyporządkowaną tablicą. W celu zaszyfrowania znaku należy znaleźć go w tablicy, a następnie pobrać znak znajdujący się o 1 pozycję w prawo i 1 pozycję w dół. W przypadku, gdy przekroczy się szerokość tablicy to należy wziąć znak z nowego wiersza, ale pierwszej kolumny. Podobnie jeśli przekroczy się dół tablicy to należy pobrać znak z nowej kolumny w pierwszym wierszu.

Na podstawie przygotowanych danych zaszyfrujmy wyrażenie "DANEDOZASZYFROWANIA". Poniższa tabelka obrazuje proces szyfrowania:

Grupa znakówTablica szyfrującaSzyfrogram
{D, A, N, E, D}Tablica [1]{N, G, O, F, N}
{O, Z, A, S, Z}Tablica [2]{W, A, H, F, A}
{Y, F, R, O, W}Tablica [3]{E, H, Y, W, C}
{A, N, I, A}Tablica [4]{G, O, Y, G}

Na podstawie tabelki można odczytać, że szyfrogramem będzie "NGOFNWAHFAEHYWCGOYG".

Odszyfrowanie danych

W celu do odszyfrowania danych należy powtórz proces tworzenia alfabetu na podstawie klucza, a następnie proces szyfrowania, ale tablicy obrócić o 180 stopni.

Implementacja

Założenia

Przedstawiona dalej implementacja zakłada poprawność danych wejściowych. Tekst wejściowy oraz klucz mogą składać się tylko z duzych liter alfabetu łacińskiego z wyłączeniem litery "J".

Utworzenie alfabetu

Do tworzenia klucza służy funkcja utworzKlucz(), która na podstawie podanego wyrażenia wKlucz tworzy alfabet i zwraca go w postaci jednowymiarowej tablicy znaków.

  1. char* utworzKlucz(char* wKlucz) {
  2.   char* klucz = new char[25];
  3.   int poz = 0;
  4.   for (int i = 0; wKlucz[i]; i++)
  5.     if (szukaj(klucz, poz, wKlucz[i]) == -1)
  6.       klucz[poz++] = wKlucz[i];
  7.   for (char i = 'A'; i <= 'Z'; i++)
  8.     if (i != 'J' && szukaj(klucz, poz, i) == -1)
  9.       klucz[poz++] = i;
  10.   return klucz;
  11. }

Proces tworzenia alfabetu składa się z (2.) zadeklarowania tablicy wynikowej i (3.) rozpoczęcia przepisywania od pierwszej pozycji. Najpierw (4. - 6.) przepisywane są unikalne znaki z przekazanego wyrażenia, a potem (7. - 9.) dopisywane pozostałe znaki alfabetu.

Tworzenie tablic

Tablice są generowane poprzez odpowiednio przesuwanie wierszy tablic co odpowiada przesuwaniu określonych grup pięcioznakowych w utworzonym alfabecie. Na tej podstawie można napisać funkcję przepisz(), która będzie przyjmowała dwa argumenty: tab - w tym przypadkowy zawsze to jest alfabet, a klucz - określa kolejność wierszy w tablicy. Składa się z cyfr od 1 - 5.

  1. char* przepisz(char* tab, char* klucz) {
  2.   char* wynik = new char[25];
  3.   for (int i = 0; i < 5; i++) {
  4.     int czesc = klucz[i] - '1';
  5.     for (int j = 0; j < 5; j++) {
  6.       wynik[5 * i + j] = tab[czesc * 5 + j];
  7.     }
  8.   }
  9.   return wynik;
  10. }

(3.) Dla każdego wiersza: (4.) określane jest, który wiersz ma być przepisany i (5. - 7.) jest to wykonane.

Pozostaje teraz tylko utworzyć wszystkie 8 tablic. Tablice będą przechowywane w tablicy tablic, aby ułatwić odczytywanie danych w pozostałych funkcjach.

  1. char** utworzTabele(char* klucz) {
  2.   char** tablice = new char*[8];
  3.   tablice[0] = przepisz(klucz, "12345");
  4.   tablice[1] = przepisz(klucz, "21345");
  5.   tablice[2] = przepisz(klucz, "23145");
  6.   tablice[3] = przepisz(klucz, "23415");
  7.   tablice[4] = przepisz(klucz, "23451");
  8.   tablice[5] = przepisz(klucz, "32451");
  9.   tablice[6] = przepisz(klucz, "34251");
  10.   tablice[7] = przepisz(klucz, "34521");
  11.   return tablice;
  12. }

Szyfrowanie danych

W celu zaszyfrowania danych należy wywołać funkcję szyfruj() i podać txt - tekst do zaszyfrowania oraz tablice - utworzone tablice szyfrujące.

  1. char* szyfruj(char* txt, char** tablice) {
  2.   int dl = strlen(txt);
  3.   char* szyfr = new char[dl + 1];
  4.   for (int i = 0; txt[i]; i++)
  5.     szyfr[i] = szyfrujZnak(txt[i], tablice[(i / 5) % 8]);
  6.   szyfr[dl] = '\0';
  7.   return szyfr;
  8. }

Funkcja pomocnicza szyfrujZnak() odszukuje znak w przyporządkowanej tabeli, a następnie dokonuje przesunięcia pozycji na której znajduje się szukany znak uwzględniając, aby nie wyjść poza zakres tablicy.

  1. char szyfrujZnak(char znak, char* tab) {
  2.   int poz = szukaj(tab, 25, znak);
  3.   int x = poz % 5;
  4.   int y = (poz - x) / 5;
  5.   x++; y++;
  6.   if (x >= 5) x = 0;
  7.   if (y >= 5) y = 0;
  8.   return tab[y * 5 + x];
  9. }

Rozszyfrowanie danych

Do odszyfrowania danych należy skorzystać z funkcji odszyfruj(). Struktura i działanie funkcji odszyfrowywujących jest analogiczne do funkcji szyfrujących.

Testowanie funkcji

Działanie napisanych funkcji można przetestować przy pomocy poniższej funkcji main(), która wczytuje od użytkownika dane, a następnie wypisuje je na ekran.

  1. int main() {
  2.   cout << "Podaj klucz: " << endl;
  3.   char* klucz = new char[128];
  4.   cin.getline(klucz, 128);
  5.   cout << "Podaj tekst: " << endl;
  6.   char* tekst = new char[512];
  7.   cin.getline(tekst, 512);
  8.   char* kluczW = utworzKlucz(klucz);
  9.   char** tablice = utworzTabele(kluczW);
  10.   char* tekstZ = szyfruj(tekst, tablice);
  11.   cout << "Szyfrogram to: " << tekstZ << endl;
  12.   char* tekstR = odszyfruj(tekstZ, tablice);
  13.   cout << "Odszyfrowane dane: " << tekstR << endl;
  14.   delete kluczW, tablice, klucz, tekstZ, tekstR;
  15.   system("pause");
  16.   return 0;
  17. }

Zadania

Zadanie 1

Przepisz przedstawiony w artykule kod w taki sposób, aby można było szyfrować pełen alfabet oraz cyfry.

Przykładowo szyfrując wyrażenie "TAJNAINFORMACJA123" przy pomocy klucza "1SILNYKLUCZ" program wypisze:

  1. VJMBJZJQX3WYG1JO94