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

Szyfr Trifid

Wstęp

Szyfr Trifid został opracowany przez francuza Felixa Delastelle. Na tle innych szyfrów wyróżnia się faktem, że klucz użyty do szyfrowania można przedstawić jako sześcian podzielony na 27 małych sześcianów. Technika szyfrowania korzysta również z grupowania znaków i ich transpozycji. Z tego powodu szyfr ten jest odporny na większość standardowych sposobów łamania szyfrów.

Algorytm

Klucz

Podczas szyfrowania na początku należy ustalić klucz, który będzie znany zarówno nadawcy i odbiorcy. Większość metod szyfrowania korzysta z dwuwymiarowej tablicy 5x5. Jednak taki zabieg powodował zamianę jednego znaku alfabetu na jeden z możliwych do zaszyfrowania (zwykle j na i). Klucz w szyfrze Trifid to sześcian 3x3x3, więc mieści się tam cały alfabet oraz np. dodatkowy znak przestankowy. Oryginalnie jest to kropka, ale lepszym pomysłem wydaje się znak przerwy.

Ze względu na fakt, że ciężko byłoby odczytywać dane z sześcianu to klucz można przechować jako ciąg znaków, który później można zamienić na trzy tablice reprezentujące kolejne warstwy sześcianu. Na potrzeby przykładu za klucz zostanie przyjęte RNXBJSGLUAQ.MTPYCEKVFOZHDWI. Na podstawie zapisu klucza można utworzyć odpowiednie tablice:

Warstwa 1
123
1RNX
2BJS
3GLU
Warstwa 2
123
1AQ.
2MTP
3YCE
Warstwa 3
123
1KVF
2OZH
3DWI

Ze względu na fakt, że można interpretować ciąg znaków dowolnie zdecydowanie lepszym pomysłem jest wymiana wypełnionych tabelek.

Okresowość

W celu wykorzystania kilku metod szyfrowania w jednej wymusza podania prócz klucz liczby, która będzie oznaczać okresowość. Może być to dowolna liczba. Oznacza ona po ile znaków będzie w każdej szyfrowanej grupie. W przykładzie okresowość zostanie ustalona na 4.

Szyfrowanie

Podczas szyfrowania każdy z znaków ma swój kod na który składa się numer warstwy, numer wiersza, a na końcu numer kolumny. Przykładowo dla podanego wyżej klucza symbol Y ma kod 231. Pierwszy krok podczas szyfrowania tekstu polega na zapisaniu pod każdą literą ich kodów w pionowych słupkach. Wypisywane kolumny najlepiej grupować po tyle elementów jaką wartość ma okresowość. W tym przypadku zgodnie z założeniem kolumny będą grupowane po 4. Szyfrując tekst TRIFID otrzymamy taką tabelkę:

ZnakINFORMACJA
Warstwa3233122212
Wiersz3212121321
Kolumna3131111221

Kolejny krok polega na tym, aby dla każdej z grup zapisać wszystkie numerki kodów jako ciąg znaków odczytując kolejne wiersze. Przykładowo dla grupy znaków INFO będzie to 323332123131. Następnie taki kod rozdziela się na grupy znaków po 3: 323 332 123 131, a potem każda z grup jest zamieniana na znak, który dany kod reprezentuje. Dla grupy, która ma mniej znaków niż wynosi okresowość zasada pozostaje taka sama. W celu lepszego zrozumienia zamianę przedstawia poniższa tabelka:

Warstwa3311121111
Wiersz2323213122
Kolumna3231221221
ZnakFDSYJQGNJB

Ostatecznie szyfrogram to FDSYJQGNJB.

Deszyfrowanie

W procesie deszyfrowania wykonuje się dokładnie te same kroki co podczas szyfrowania. Różnica tkwi podczas tworzenia "transpozycji", ponieważ należy wtedy odczytany ciąg cyfr zamienić na grupy mające po tyle cyfr ile wynosi okresowość, aby odczytać pionowo kody liter tekstu jawnego.

Implementacja

Założenia

Poniższa implementacja jest przykładowa, dlatego pozwala ona na wprowadzenie dowolnej tablicy, okresowości i tekstu do zaszyfrowania. Należy jednak pamiętać, że tekst musi mieć długość, która jest wielokrotnością okresowości. W innym przypadku nie zostanie zaszyfrowany cały tekst. Ponadto istnieje założenie, że wprowadzony tekst składa się jedynie ze znaków występujących w wprowadzonym kluczu.

Funkcje pomocnicze

Wielkość tablicy zostanie wykorzystana w kodzie niejeden raz, dlatego została utworzona stała keyN, której zostanie przypisana wartość 3. Taki zabieg pozwoli na dalszy rozwój implementacji.

  1. const int keyN = 3;

Ze względu na fakt, że wprowadzony klucz będzie przechowywany jako tekst to będzie potrzebna funkcja, która wyszuka w nim konkretną wartość i zwróci odpowiednią pozycję. Zadanie to realizuje funkcja findChar(), która dla danego ciągu key i znaku c zwraca pozycję znaku c w key.

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

Dokładniejsze przyjrzenie się kodom znaków wskazuje, że jeśli kod potraktować jako liczbę w systemie trójkowym to k-ty znak kodu można wyodrębnić z pozycji znaku na liście. Funkcja getPosition() zwraca dla danej liczby a cyfrę, która stoi na pozycji st + 1 od prawej strony w zapisie trójkowym liczby a.

  1. int getPosition(int a, int st) {
  2.   return (a % int(pow(keyN, st + 1)))/(int(pow(keyN, st)));
  3. }

Szyfrowanie

Funkcja szyfrująca cipher() przyjmuje trzy argumenty: txt - tekst do zaszyfrowania, key - klucz szyfrujący tekst oraz period - okresowość grupowania.

  1. char* cipher(char* txt, char* key, int period) {
  2.   int dl = strlen(txt);
  3.   int groups = dl / period;
  4.   char* wynik = new char[dl + 1];
  5.   for (int g = 0; g < groups; g++) {
  6.     for (int i = 0; i < period; i++) {
  7.       int pos = 0;
  8.       for (int j = 0; j < keyN; j++)
  9.         pos += pow(keyN, keyN - 1 - j) * getPosition(findChar(key, txt[period * g + (keyN * i + j) % period]), keyN - ((keyN * i + j) / period) - 1);
  10.       wynik[g * period + i] = key[pos];
  11.     }
  12.   }
  13.   wynik[dl] = '\0';
  14.   return wynik;
  15. }

(2.) Pobierz długość tekstu i (3.) wylicz ile będzie grup do zaszyfrowania. (4.) Zaalokuj pamięć pod wynik. (5.) Dla każdej grupy i (6.) każdego znaku w grupie (7.) ustal pozycję znaku wynikowego na 0. (8.) Dla każdej cyfry kodującej zaszyfrowany znak pobierz odpowiednie cyfry z znaków tekstu jawnego. (9.) Dopisz znak na listę wynikową. (12.) Dopisz znak końca danych i (13.) zwróć wynik.

Deszyfrowanie

Funkcja deszyfrująca decipher() różni się od funkcji szyfrującej tylko sposobem (9.) wyboru jaki znak ma zostać dopisany do wyniku.

  1. char* decipher(char* txt, char* key, int period) {
  2.   int dl = strlen(txt);
  3.   int groups = dl / period;
  4.   char* wynik = new char[dl + 1];
  5.   for (int g = 0; g < groups; g++) {
  6.     for (int i = 0; i < period; i++) {
  7.       int pos = 0;
  8.       for (int j = 0; j < keyN; j++)
  9.         pos += pow(keyN, keyN - 1 - j) * getPosition(findChar(key, txt[period * g + (period * j + i) / keyN]), keyN - ((period * j + i) % keyN + 1));
  10.       wynik[g * period + i] = key[pos];
  11.     }
  12.   }
  13.   wynik[dl] = '\0';
  14.   return wynik;
  15. }

Testowanie funkcji

Powyższe funkcje można przetestować przy pomocy poniższej funkcji main(), która poprosi o podanie danych, a następnie wypisze szyfrogram oraz rozkodowany szyfrogram na ekran:

  1. int main () {
  2.   char* key = new char[28];
  3.   char* txt = new char[512];
  4.   int period;
  5.   cout << "Podaj klucz:\n";
  6.   cin.getline(key, 28);
  7.   cout << "Podaj okres:\n";
  8.   cin >> period;
  9.   cin.ignore();
  10.   cout << "Podaj tekst do zaszyfrowania:\n";
  11.   cin.getline(txt, 512);
  12.   char* txtc = cipher(txt, key, period);
  13.   cout << "Szyfrogram:\n" << txtc << endl;
  14.   char* txtd = decipher(txtc, key, period);
  15.   cout << "Tekst jawny:\n" << txtd << endl;
  16.   delete key, txt, txtc, txtd;
  17.   system("pause");
  18.   return 0;
  19. }