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

Szyfr Grandpre

Szyfr

Szyfr Grandpre to szyfr, który do szyfrowania wykorzystuje klucz, który jest tablicą 8×8. Klucz składa się z dziewięciu, ośmioliterowych wyrazów. Osiem z nich jest zapisanych wierszami jeden pod drugim. Dziewiąty wyraz musi powstać z liter czytanych od góry w pierwszej kolumnie. Znalezienie takiego klucza nie należy do najłatwiejszych zadań i warto do tego celu wykorzystać komputer.

Proces szyfrowania polega na zastępieniu każdej litery przy pomocy współrzędnych odczytanych na podstawie klucza. Warto zauważyć, że np. znaków w alfabecie łacińskim jest 26, a pól 64, więc na pewno istnieje znak, która można zaszyfrować na trzy różne sposoby! Zapisanie kolejnych par współrzędnych wiersz×kolumna jedna po drugiej utworzy szyfrogram.

Proces rozszyfrowywania jest bardzo prosty i polega na odczytaniu każdych kolejnych dwóch cyfr, a następnie znalezieniu litery w tabeli na podstawie odczytanej pary znaków. Odczytane wartości z tabeli utworzą tekst jawny.

Przykład

Do zaszyfrowanie jest tekst "TAJNAINFORMACJA". Podczas szyfrowania zostanie użyty klucz rozpisany niżej. Jak można zauważyć 8 wyrazów jest wpisanych w kolejnych wierszach, a pierwsza kolumna również zawiera prawidłowy wyraz. Polskie znaki zostały specjalnie zastąpione ich łacińskimi odpowiednikami.

12345678
1GALECZKA
2ABECADLO
3RACHOWAC
4NAKLEJKA
5IMPAKTOR
6TAKSOWKA
7UMYWALKA
8REFLEKSY

Pierwsza litera T znajduje się w piątym wierszu i szóstej kolumnie, więc odpowiada jej para cyfr 56. Jednak literę tę można też zaszyfrować jako 61. Kolejna litera to A. Ze względu na jej wysoką częstotliwość występowania w słowniku w tabelce można znaleźć, aż 13 razy. Innymi słowy literę A można zapisać jako jedną z następujących opcji: {12, 18, 21, 25, 32, 37, 42, 48, 54, 62, 68, 75, 78}.

Przykładowy ostateczny szyfrogram to: "563246417851418357817262384654".

Implementacja

Przedstawiony poniżej kod korzysta z pseudolosowości w celu wybrania jednej z wielu dostępnych opcji zaszyfrowania wybranego znaku. Szyfrowany tekst może zawierać tylko znaki umieszczone w kluczu. Ponadto program zakłada poprawność danych wejściowych. Klucz jest przechowywany jako 64 znakowy ciąg znaków. Dzięki temu kod się nieco upraszcza.

Szyfrowanie

Do szyfrowania należy wywołać funkcję szyfruj() i podać dwa argumenty: tekst - tekst jawny do zaszyfrowania oraz klucz - tabelka w formie ciągu znaków. Funkcja zwróci wskaźnik na miejsce w pamięci gdzie znajdują się zaszyfrowane dane.

  1. char* szyfruj(char* tekst, char* klucz) {
  2.   int dl = strlen(tekst);
  3.   char* wynik = new char[2 * dl + 1];
  4.   for (int i = 0; i < dl; i++) {
  5.     int pos = szukajLosowa(klucz, tekst[i]);
  6.     int x = pos % 8;
  7.     wynik[2 * i] = (pos - x) / 8 + '1';
  8.     wynik[2 * i + 1] = x + '1';
  9.   }
  10.   wynik[2 * dl] = '\0';
  11.   return wynik;
  12. }

(2.) Pobierz długość tekstu i (3.) alokuj miejsce pod tablicę wynikową. (4.) Dla każdego znaku tekstu jawnego: (5.) znajdź pozycję znaku w kluczu, (6.) określ numer kolumny, a potem (7. - 8.) dopisz współrzędne do tablicy wyniku. Na koniec (10.) dopisz znak końca danych i (11.) zwróć wskaźnik.

Losowanie znaku

W celu wylosowania pozycji znaku szyfrowanego funkcja szyfruj() korzysta z funkcji szukajLosowa(), która przyjmuje data - ciąg znaków klucza oraz c - znak do wyszukania.

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

Pierwszy etap polega na zliczeniu ile jest wystąpień danego znaku w kluczu. (2.) Inicjalizacja licznika, a następnie (3. - 7.) policzenie wystąpień. Jeśli (8.) zmienna ile wynosi 0 to szukany znak nie występuje w kluczu. W takim przypadku (9.) można zwrócić dowolną wartość.

  1.   int los_indeks = rand() % ile;
  2.   ile = 0;
  3.   for (int i = 0; data[i]; i++) {
  4.     if (data[i] == c) {
  5.       if (ile == los_indeks) {
  6.         return i;
  7.       } else {
  8.         ile++;
  9.       }
  10.     }
  11.   }
  12.   return -1;
  13. }

Drugi etap polega na: (10.) wylosowaniu, która pozycja ma zostać pobrana danego znaku. Następnie (11. - 20.) wyszukiwanie jest takie samo jak w poprzednim przypadku z tą różnicą, że jeśli (14.) zostanie znaleziona wylosowana pozycja to (15.) należy zwrócić pozycję znaku w kluczu. (21.) Linijka ta jest co prawda zbędna, ale bez niej nie można skompilować programu, ponieważ kompilator nie widzi tego, że program zawsze zwróći wartość w linijce (15.).

Rozszyfrowanie

Do rozszyfrowania danych służy funkcja rozszyfruj(), która pryjmuje dwa argumenty: tekst - szyfrogram do rozszyfrownia oraz klucz - klucz, który został użyty do zaszyfrowania danych.

  1. char* rozszyfruj(char* tekst, char* klucz) {
  2.   int dl = strlen(tekst) / 2;
  3.   char* wynik = new char[dl + 1];
  4.   for (int i = 0; i < dl; i++)
  5.     wynik[i] = klucz[((tekst[2*i] - '1') * 8 + (tekst[2 * i + 1] - '1'))];
  6.   wynik[dl] = '\0';
  7.   return wynik;
  8. }

(2.) Wylicz długość tekstu jawnego i (3.) alokuj pamięć. Następnie (4.) dla każdej pary cyfr: (5.) znajdź na podstawie współrzędnych zaszyfrowany znak. (6.) Dopisz znak końca danych i (7.) zwróć wynik.

Testowanie funkcji

Poniżej została przedstawiona przykładowa funkcja main(), która wczytuje od użytkownika klucz oraz tekst jawny, a następnie pokazuje szyfrogram oraz roszyfrowany szyfrogram:

  1. int main () {
  2.   srand(time(NULL));
  3.   cout << "Wprowadz klucz: (8 linijek po 8 znakow)\n";
  4.   char* klucz = kluczWczytaj();
  5.   cout << "Podaj tekst do zaszyfrowania:\n";
  6.   char* tekst = new char[512];
  7.   cin.getline(tekst, 512);
  8.   char* tekstZ = szyfruj(tekst, klucz);
  9.   cout << "Szyfrogram:\n" << tekstZ << endl;
  10.   char* tekstR = rozszyfruj(tekstZ, klucz);
  11.   cout << "Tekst jawny:\n" << tekstR << endl;
  12.   delete klucz, tekst, tekstZ;
  13.   system("pause");
  14.   return 0;
  15. }

W celu wczytania klucza została napisana dodatkowa funkcja kluczWczytaj(), która wczytuje od użytkownika 8 linijek tabeli po 8 znaków.

  1. char* kluczWczytaj() {
  2.   int dl = 64;
  3.   char* klucz = new char[dl + 1];
  4.   char* temp = new char[16];
  5.   for (int i = 0; i < 8; i++) {
  6.     cin.getline(temp, 16);
  7.     cin.clear();
  8.     for (int j = 0; j < 8; j++)
  9.       klucz[8 * i + j] = temp[j];
  10.   }
  11.   klucz[dl] = '\0';
  12.   return klucz;
  13. }