Strona główna » Algorytmy » Szyfry » Szyfr Nihilistów
 

Szyfr Nihilistów

Szyfr Nihilistów

W celu zaszyfrowania tym szyfrem należy ustalić dwa słowa klucze. Na podstawie pierwszego z nich należy utworzyć szachownicę Polibiusza. Drugi klucz z kolei służy do właściwego szyfrowania tekstu jawnego. Ze względu na wybraną metodę szyfrowania, szachownice Polibiusza, literę J zastępuje się poprzez literę I.

Tworzenie szachownicy Polibiusza

Załóżmy, że tajnym kluczem na podstawie, którego zostanie utworzona szachownica to POLIBIUSZ. Pierwszy krok polega na zastąpieniu ewentualnej litery J poprzez I. Jeśli jest litera, która się powtarza to należy usunąć wszystkie jej wystąpienie prócz pierwszego. W tym przypadku klucz POLIBIUSZ zostanie zmienione na POLIBUSZ. Kolejny krok polega na utworzeniu tabelki 5x5 takiej jak poniżej i wpisaniu pierwszego, już wstępnie zmodyfikowanego, klucza:

12345
1POLIB
2USZ
3
4
5

Pozostałe miejsca w tabelce należy wypełnić wierszami od prawe do lewej przy pomocy kolejnych liter alfabetu, ale bez litery J. Jeśli dana litera już w szachownicy występuje to zostaje pominięta. Po zakończeniu tego etapu szachownica Polibiusza jest gotowa:

12345
1POLIB
2USZAC
3DEFGH
4KMNQR
5TVWXY

Wykorzystanie szachownicy

Na podstawie tabelki każdy znak uzyskuje unikalny kod. Kod jest to liczba, która powstaje poprzez zlepienie cyfry kolumny i wiersza położenia wybranej litery w tabelce. Przykładowo w celu zaszyfrowania litery G należy odczytać jej położenie: trzeci wiersz i czarna kolumna. Kod litery G to 34. Załóżmy, że drugi klucz to HASLO, wtedy kolejne litery mają takie kody:

Jawny klucz 2HASLO
Zakodowany klucz 23524221312

Szyfrowanie

Załóżmy, że do zaszyfrowania jest wyrażenie TAJNA INFORMACJA. Należy z niego usunąć wszystkie nieszyfrowane znaki, a następnie zamienić każdą literę na odpowiadający jej kod. Następnie do kodu i-tej litery dodaje się kod i mod n znaku klucza 2, gdzie n to długość klucza 2. Wyznaczona suma to zaszyfrowana wartość i-tej litery. Przykładowo szyfrowania przebiega następująco:

Tekst zakodowany512414432414433312454224251424
Klucz 2352422131235242213123524221312
Szyfrogram864836563686675525577748472736

Na koniec uzyskane wartości liczbowe szyfrogramu należy zapisać jedna koło drugiej rozdzielając przecinkiem. W tym przypadku szyfrogram to: 86, 48, 36, 56, 36, 86, 67, 55, 25, 57, 77, 48, 47, 27, 36.

Deszyfrowanie

W celu rozszyfrowania danych należy znać obydwa klucza i na podstawie pierwszego utworzyć szachownicę. Następnie przy pomocy drugiego klucza uzyskać kody dwucyfrowe kody liter poprzez odjęcie od kolejnych liczb szyfrogramu kod kolejnej litery klucza 2. Ten etap może wyglądać następująco:

Szyfrogram864836563686675525577748472736
Klucz 2352422131235242213123524221312
Tekst zakodowany512414432414433312454224251424

Kolejny krok polega na odszukaniu każdego kolejnego wyliczonego kodu i na tej podstawie zapisanie rozszyfrowanego tekstu jawnego. W tym

Tekst zakodowany512414432414433312454224251424
Tekst jawnyTAINAINFORMACIA

Jak widać pomimo, że szyfrowaną wiadomością było TAJNA INFORMACJA to po rozszyfrowaniu jest ona zapisana jako TAINA INFORMACIA. Jest to spowodowane brakiem litery J w szachownicy Polibiusza. Jednym z rozwiązań jest usunięcie innej litery niż J. Przykładowo w języku polskim praktycznie nieużywanymi znakami są V i X.

Implementacja

Tworzenie szachownicy

W celu przyśpieszenia szyfrowania danych tablica nie będzie przechowywana jako tablica. Utworzona zostanie lista 25 liczb. Każda z nich będzie odpowiadać kolejnej literze alfabetu, z pominięciem litery J. Przykładowo, aby uzyskać kod litery C wystarczy wybrać element o indeksie 2 z listy (indeksowanie od 0).

  1. int* tworzKlucz(char* klucz1) {
  2.   int* alfabet = new int[25];
  3.   for (int i = 0; i < 25; i++)
  4.     alfabet[i] = 0;
  5.   int wiersz = 1, kolumna = 1;
  6.   for (int i = 0; klucz1[i]; i++)
  7.     dopiszZnak(alfabet, klucz1[i], wiersz, kolumna);
  8.   for (int i = 'a'; i <= 'z'; i++)
  9.     dopiszZnak(alfabet, i, wiersz, kolumna);
  10.   return alfabet;
  11. }

(1.) Zwróć listę liczb jako klucz kodujący na podstawie podanego argumentu klucz1, którym jest klucz 1. (2.) Utwórz listę i (3. - 4.) wypełnij ją zerami. Zero oznacza, że dana litera nie ma jeszcze przypisanego kodu. (5.) Zadeklaruj zmienne wiersz, kolumna, które będą przechowywały na której pozycji znak jest aktualnie przechowywany. (6.) Dla każdego znaku w klucz1: (7.) spróbuj dopisać każdy jego znak na listę, a następnie (8. - 9.) spróbuj dopisać każdą literę alfabetu. (10.) Na koniec zwróć utworzoną listę alfabet.

Tworzenie klucza jest wspomagane przez funkcję dopiszZnak(), która sprawdza czy dany znak ma już kod i jeśli nie ma to go przypisuje. Ponadto sprawdza czy dopisywany znak jest prawidłowy. Oto kod:

  1. void dopiszZnak(int* alfabet, char znak, int& wiersz, int& kolumna) {
  2.   if (znak >= 'j') znak--;
  3.   if (alfabet[znak - 'a'] == 0) {
  4.     alfabet[znak - 'a'] = wiersz * 10 + kolumna;
  5.     kolumna++;
  6.     if (kolumna == 6) {
  7.       kolumna = 1;
  8.       wiersz++;
  9.     }
  10.   }
  11. }

(1.) Funkcja przyjmuje cztery argumenty: alfabet - aktualną szachownicę, znak - znak do dopisania, wiersz i kolumna - aktualne miejsce zapisu danych. (2.) Jeśli znak w alfabecie występuje po lub jest literą J to zmniejsz wartość znaku. Następnie (3.) sprawdź czy znak ma już kod. Jeśli nie to (4.) oblicz kod na podstawie pozycji i (5. - 9.) przejdź do następnego wolnego pola w szachownicy.

Szyfrowanie danych

Do szyfrowania wprowadzonych danych służy funkcja szyfruj(), która przyjmuje trzy argumenty: klucz1, klucz2 oraz szyfrogram:

  1. int* szyfruj(char* klucz1, char* klucz2, char* txt) {
  2.   int* alfabet = tworzKlucz(klucz1);
  3.   int dl = strlen(txt);
  4.   int* szyfrogram = new int[dl + 1];
  5.   szyfrogram[dl] = 0;
  6.   for (int i = 0; i < dl; i++)
  7.     szyfrogram[i] = kodujZnak(alfabet, txt[i], klucz2[i % strlen(klucz2)]);
  8.   delete[] alfabet;
  9.   return szyfrogram;
  10. }

(2.) Utwórz szachownice. (3.) Pobierz długość tekstu wynikowego i (4.) utwórz listę wynikową. (5.) Zakładamy, że ostatni znak na liście wynikowej będzie miał wartość 0. Będzie to zawsze ostatnia liczba na liście (tj. wartownik). (6.) Kolejne znaki tekstu jawnego: (7.) zaszyfruj na podstawie szachownicy i klucza 2. Przed (9.) zwróceniem wyniku (8.) usuń utworzoną szachownicę.

Funkcja szyfruj() korzysta z funkcji pomocniczej kodujZnak(), która na podstawie danej szachownicy, znaku tekstu jawnego oraz klucza 2 zwraca wartość wynikową do szyfrogramu.

  1. int kodujZnak(int* alfabet, char znak_tekstjawny, char znak_klucz2) {
  2.   if (znak_tekstjawny >= 'j') znak_tekstjawny--;
  3.   if (znak_klucz2 >= 'j') znak_klucz2--;
  4.   return alfabet[znak_tekstjawny - 'a'] + alfabet[znak_klucz2 - 'a'];
  5. }

(2. - 3.) Uwzględnij pominięcie znaku J. (4.) Zwróć sumę kodów znaku tekstu jawnego oraz znaku z klucza 2.

Deszyfrowanie danych

Dane można rozszyfrować przy pomocy funkcji deszyfruj(). Przyjmuje trzy argumenty: klucz1, klucz2 - klucze szyfrujące podane przez użytkownika oraz szyfrogram - wiadomość do rozszyfrowania.

  1. char* deszyfruj(char* klucz1, char* klucz2, int* szyfrogram) {
  2.   int* alfabet = tworzKlucz(klucz1);
  3.   int dl = 0;
  4.   for (int i = 0; szyfrogram[i] != 0; i++)
  5.     dl++;
  6.   char* wynik = new char[dl + 1];
  7.   wynik[dl] = '\0';
  8.   for (int i = 0; i < dl; i++)
  9.     wynik[i] = rozkodujZnak(alfabet, szyfrogram[i], klucz2[i % strlen(klucz2)]);
  10.   delete[] alfabet;
  11.   return wynik;
  12. }

(2.) Wyznacz szachownicę Polibiusza. (3. - 5.) Oblicz długość tekstu wynikowego korzystają z faktu, że na końcu tablicy znajduje się wartość 0. (6. - 7.) Utwórz tablicę wynikową i dopisz znak końca danych. (8.) Każdy znak szyfrogramu: (9.) rozkoduj i dopisz na tablicę wynikową. (10.) Usuń szachownicę i (11.) zwróć wynik.

Do rozkodowywania znaków funkcja deszyfruj() korzysta z funkcji rozkodujZnak()

  1. char rozkodujZnak(int* alfabet, int znak_szyfrogram, char znak_klucz2) {
  2.   if (znak_klucz2 >= 'j') znak_klucz2--;
  3.   znak_szyfrogram -= alfabet[znak_klucz2 - 'a'];
  4.   char znak_tj = 0;
  5.   while (alfabet[znak_tj] != znak_szyfrogram) {
  6.     znak_tj++;
  7.   }
  8.   znak_tj += 'a';
  9.   if (znak_tj >= 'j') znak_tj++;
  10.   return znak_tj;
  11. }

(2.) Uwzględnij brak litery J w alfabecie. (3.) Odejmij od wartości z szyfrogramu wartość znaku z klucza 2. (4. - 7.) znajdź zaszyfrowany znak w szachownicy, a potem (8.) konwertuj na literę. (9.) Uwzględnij brak litery J i (10.) zwróć wyliczony znak.

Testowanie funkcji

W celu przetestowania działania powyższych funkcji można skorzystać z poniższej funkcji main(). Po uruchomieniu program zapyta się o klucze oraz tekst do zaszyfrowania.

  1. int main () {
  2.   char* klucz1 = new char[32];
  3.   char* klucz2 = new char[32];
  4.   char* txt = new char[1024];
  5.   cout << "Podaj klucz 1:\n";
  6.   cin.getline(klucz1, 32);
  7.   cout << "Podaj klucz 2:\n";
  8.   cin.getline(klucz2, 32);
  9.   cout << "Podaj tekst do zaszyfrowania:\n";
  10.   cin.getline(txt, 1024);
  11.   int* szyfrogram = szyfruj(klucz1, klucz2, txt);
  12.   wypiszListe(szyfrogram);
  13.   char* tekstjawny = deszyfruj(klucz1, klucz2, szyfrogram);
  14.   cout << tekstjawny << endl;
  15.   delete[] klucz1, klucz2, txt, szyfrogram, tekstjawny;
  16.   system("pause");
  17.   return 0;
  18. }

Wypisywanie danych

W celu wypisania zaszyfrowanych danych z zwróconej listy liczb przez funkcję szyfruj() program korzysta z funkcji wypiszListe(). Korzysta ona z faktu, że na końcu listy stoi 0.

  1. void wypiszListe(int* szyfrogram) {
  2.   for (int i = 0; szyfrogram[i] != 0; i++) {
  3.     cout << szyfrogram[i] << ", ";
  4.   }
  5.   cout << "koniec\n";
  6. }

Zadania

Zadanie 1

Napisz wersję programu, która wczyta kolejno klucz 1, klucz 2, pojedynczy znak, a na koniec tekst do zaszyfrowania. Wczytany pojedynczy znak program ma wykluczyć podczas pisania wyznaczania szachownicy w procesie szyfrowania / deszyfrowania. W ten sposób użytkownik będzie mógł wykluczyć inny znak niż J.

Przykładowo dla danych:

  1. polibiusz
  2. haslo
  3. x
  4. tajnainformacja

Program wypisze na ekran zaszyfrowaną wersję i rozszyfrowaną:

  1. 87, 48, 63, 57, 26, 79, 57, 34, 64, 55, 59, 49, 63, 37, koniec
  2. tajnainformacja