Strona główna » Algorytmy » Szyfry » Chaoszyfr
 

Chaoszyfr

Wstęp

Chaoszyfr został wymyślony w 1918 roku przez John Francis Byrne. Swój szyfr uważał za prosty, ale bardzo trudny do złamania. Nawet oferował nagrodę temu kto odkryłby jak działa jego metoda szyfrowania. Do szyfrowania tekstu jawnego stosowane są dwa alfabety złożone z tych samych znaków, ale mogą posiadać znaki w dowolnej kolejności, niekoniecznie tej samej. To pozwala na szyfrowanie wiadomości sprawia, że utrudnione są ataki poprzez analizę tekstu.

Szyfrowanie

Przygotowanie

Do zaszyfrowania tekstu należy przygotować tekst jawny do zaszyfrowania oraz dwa alfabety: tekstu jawnego oraz szyfrowanego. Alfabety mogą być złożone z dowolnych znaków, ale obydwa muszą zawierać znaki drugiego. Przypuśćmy, że będziemy szyfrować tekst "SZYFR" alfabetem łacińskim "ABCDEFGHIJKLMNOPQRSTUVWXYZ" dla jawnego oraz "ZYXWVUTSRQPONMLKJIHGFEDCBA" dla szyfrowanego.

Kręcenie alfabetami

Dla każdego znaku tekstu znajdujemy jego pozycję w alfabecie tekstu jawnego, a potem odczytujemy znak z tej samej pozycji w alfabecie szyfrowanym. Przykładowo dla pierwszego znaku wiadomości "S" odpowiada litera "H".

Alfabet jawnyABCDEFGHIJKLMNOPQRSTUVWXYZ
Alfabet szyfruZYXWVUTSRQPONMLKJIHGFEDCBA

Teraz należy przesunąć alfabet jawny o znalezioną pozycję + 1, a szyfrowany tylko o pozychę. Znaki, które wyjdą poza lewą stronę cyklicznie przenosimy na koniec alfabetu. Końcowy efekt powinien być taki, że szyfrowany znak jest na końcu swojego alfabetu i jej odpowiednik znajdzie się na początku.

Alfabet jawnyTUVWXYZABCDEFGHIJKLMNOPQRS
Alfabet szyfruHGFEDCBAZYXWVUTSRQPONMLKJI

Dla tekstu jawnego i szyfrowanego należy przenieść 2 znak w alfabecie na środek alfabetu.

Alfabet jawnyTUWXYZABCDEFGVHIJKLMNOPQRS
Alfabet szyfruHFEDCBAZYXWVUGTSRQPONMLKJI

Zmodyfikowana postać alfabetów zostaną teraz użyte do zaszyfrowania kolejnego znaku alfabetu. Końcowy szyfrogram to HBDXM.

Deszyfrowanie

Deszyfrowanie tekstu ma dokładnie takie same kroki jak szyfrowanie, ale zamiast zamieniać tekst alfabetu jawnego na szyfrowany to wybieramy znaki odwrotnie. Przykładowo w pierwszym kroku szukamy litery "H" a alfabecie szyfrowanym, a następnie zapisujemy jej odpowiednik czyli "S". Kręcenie alfabetami pozostaje bez zmian.

Dodatkowe uwagi

W celu przekonania się do czego prowadzi kręcenie kółkami warto przeanalizować szyfrowanie tekstu "ABC" dwoma, identycznymi alfabetami "ABCDEFGHIJKLMNOPQRSTUVWXYZ". Okazuje się, że szyfrogram takiego tekstu to "AAA", mimo że tekst wejściowy zawiera trzy różne znaki!

Implementacja

Kręcenie kołami

Przyjmujemy, że alfabet będziemy przechowywać w postaci łańcuchów znaków. W ten sposób wystarczą operację wybierania odpowiednich fragmentów tekstów oraz ich łączenia. Oto przykładowa funkcja KrecKola, która przyjmuje trzy argumenty: obydwa alfabety oraz pozycję na której znajduje się szyfrowany znak.

  1. void KrecKola(string& kolo_tekst, string& kolo_szyfr, int poz) {
  2.   int nadir = kolo_tekst.length() / 2;
  3.   kolo_szyfr = kolo_szyfr.substr(poz) + kolo_szyfr.substr(0, poz);
  4.   kolo_szyfr = kolo_szyfr[0] + kolo_szyfr.substr(2, nadir - 1) + kolo_szyfr[1] + kolo_szyfr.substr(nadir+1, nadir-1);
  5.   kolo_tekst = kolo_tekst.substr(poz) + kolo_tekst.substr(0, poz);
  6.   kolo_tekst = kolo_tekst.substr(1, 2) + kolo_tekst.substr(4, nadir - 2) + kolo_tekst[3] + kolo_tekst.substr(nadir + 2, nadir - 2) + kolo_tekst[0];
  7. }

Szyfrowanie i deszyfrowanie

Szyfrowanie polega na przygotowaniu pustego łańcucha tekstu i przeprowadzenia szyfrowania każdego znaku po kolei. Jak wiadomo w tekście mogą wystąpić znaki spoza alfabetu. W takim przypadku funkcja po prostu je dopisze do szyfrogramu bez zmian. Na koniec zwracany jest szyfrogram.

  1. string Szyfruj(string tekst, string kolo_tekst, string kolo_szyfr) {
  2.   string szyfrogram = "";
  3.   for (char znak : tekst) {
  4.     int poz = kolo_tekst.find(znak);
  5.     if (poz == string::npos) {
  6.       szyfrogram += znak;
  7.       continue;
  8.     }
  9.     char szyfr_znak = kolo_szyfr[poz];
  10.     szyfrogram += szyfr_znak;
  11.     KrecKola(kolo_tekst, kolo_szyfr, poz);
  12.   }
  13.   return szyfrogram;
  14. }

Kod napisany do rozszyfrowania szyfrogramu ma identyczną strukturą, ale różni się w którym alfabecie jest wyszukiwany deszyfrowany znak. Reszta kodu pozostaje bez zmian.

  1. string Rozszyfruj(string szyfrogram, string kolo_tekst, string kolo_szyfr) {
  2.   string tekst_jawny = "";
  3.   for (char znak : szyfrogram) {
  4.     int poz = kolo_szyfr.find(znak);
  5.     if (poz == string::npos) {
  6.       tekst_jawny += znak;
  7.       continue;
  8.     }
  9.     char szyfr_znak = kolo_tekst[poz];
  10.     tekst_jawny += szyfr_znak;
  11.     KrecKola(kolo_tekst, kolo_szyfr, poz);
  12.   }
  13.   return tekst_jawny;
  14. }

Testowanie funkcji

Kod zawiera funkcję do uruchomienia. Użytkownik zostanie poproszony o wprowadzenie tekstu jawnego oraz dwóch alfabetów. Wypisany zostanie szyfrogram, a następnie rozszyfrowany znak.

  1. int main() {
  2.   string tekst = "";
  3.   string kolo_tekst = "";
  4.   string kolo_szyfr = "";
  5.   cout << "Podaj tekst do zaszyfrowania:\n";
  6.   getline(cin, tekst);
  7.   cout << "Podaj kolejne litery alfabetu tekstu jawnego:\n";
  8.   getline(cin, kolo_tekst);
  9.   cout << "Podaj kolejne litery alfabetu tekstu szyfrujacego:\n";
  10.   getline(cin, kolo_szyfr);
  11.   string szyfrogram = Szyfruj(tekst, kolo_tekst, kolo_szyfr);
  12.   cout << " Szyfrogram: " << szyfrogram << endl;
  13.   string tekst_jawny = Rozszyfruj(szyfrogram, kolo_tekst, kolo_szyfr);
  14.   cout << "Tekst jawny: " << tekst_jawny << endl;
  15.   return 0;
  16. }