Strona główna » Algorytmy » Szyfry » Szyfr Kołowy
 

Szyfr Kołowy

Opis szyfru

Szyfr polega na zastępowaniu każdej litery "współrzędnymi" odczytanymi z tabelki. Interesujący jest zapis tabelki - nie jest to kolejna typowa, prostokątna tabelka, a koło:

Chociaż można zapisać podane koło w postaci tabelki w taki sposób wygląda inaczej niż pozostałe tabelki szyfrów. Ponadto w tej formie bardzo łatwo zmienić tabelkę. Wystarczy obrócić wybrane koło w prawo lub lewo.

Metoda szyfrowanie jest bardzo prosta - szukamy szyfrowanej literki na kole. Po znalezieniu odczytujemy współrzędną X, która jest cyfrą zapisaną w tej samej linii zapisanym w pierścieniu oznaczonym kołem. Z kolei współrzędną Y odczytujemy z kolumny oznaczonej kołem, czyli dana litera leży w kole oznaczonym I lub II. Przykładowo jeśli chcemy zaszyfrować literą A to odczytujemy, że leży w I kole i 1 kolumnie, więc szyfrujemy ją jako I1. Innym przykładem jest litera X, którą szyfrujemy jako II11.

Implementacja

Szyfrowanie

Nie istnieję natywne sposoby przechowywania tego typu tabelki w pamięci komputera, ale jesteśmy w stanie odczytać współrzędne na podstawie wartość ASCII wybranego znaku. Zakładamy, że szyfrujemy tylko duże litery alfabetu łacińskiego. Każdy rozpatrywany znak zamienimy na kod ASCII i odejmiemy pozycję litery A. Wtedy w celu uzyskania grupy podzielimy wyliczoną wartość przez 13. Z kolei do uzyskania drugiej współrzędnej wyciągniemy resztę z dzielenie wyliczonej wartości przez 13.

  1. char* cipher(const char* txt){
  2.   int dl = 0;
  3.   for(int i = 0; txt[i]; i++){
  4.     int a = txt[i] - 'A';
  5.     dl += (a/13 + 1);
  6.     dl += ((a+1)%14 + (a/13 == 1) < 10) ? 1 : 2;
  7.   }

(1.) Funkcja szyfrująca cipher() przyjmuje argument txt - tekst do zaszyfrowania. Zwracanym wynikiem jest tablica char zawierając zaszyfrowany tekst. (2.) Na początek ustalamy długość tekstu wynikowego (dl) na 0. (3.) Dla każdego znaku w szyfrowanym tekście: (4.) wyliczamy jego pozycję względem litery A. (5.) Do długości dodajemy długość numeru grupy oraz (6.) długość liczby oznaczającą kolumnę.

  1.   char* wynik = new char[dl + 1];
  2.   for(int i = 0, j = 0; txt[i]; i++){
  3.     int a = txt[i] - 'A';
  4.     for(int k = 0; k <= a/13; k++){
  5.       wynik[j++] = 'I';
  6.     }
  7.     if((a+1)%14 + (a/13 == 1) >= 10) wynik[j++] = '1';
  8.     wynik[j++] = ((a+1)%14 + (a/13 == 1))%10 + '0';
  9.   }
  10.   wynik [dl] = '\0';
  11.   return wynik;
  12. }

(8.) Alokujemy pamięć pod zwracany wynik. (9.) Rozpoczynamy pętle dla każdego numeru w tekście. Ze względu na niestałą długość zaszyfrowanego tekstu dla pojedynczego wyniku użyjemy dwóch liczników: i - będzie przechowywać, który znak tekstu szyfrujemy, a j, który znak wyniku zapisaliśmy. (10.) wyliczamy jego pozycję względem A. (11. - 13.) Dopisujemy numer grupy. (14.) W celu uproszczenia przepisywania liczby do tekstu patrzymy czy liczba jest większa od 10. Jeśli tak to dopisujemy do wyniku 1., a potem (15.) Dopisujemy cyfrę z wyliczonej numeru kolumny. Na koniec (17.) dopisujemy znak końca danych i (18.) zwracamy wynik.

Deszyfrowanie

Deszyfrowanie również podzielimy na dwie części: pierwsza wyliczy długość tekstu rozszyfrowanego, a druga wykona deszyfrowanie.

  1. char* decipher(const char* txt){
  2.   int dl = 1;
  3.   for(int i = 1; txt[i]; i++){
  4.     if(txt[i] == 'I' && txt[i - 1] != 'I')
  5.       dl++;
  6.   }

(2.) Ustalamy długość tekstu dl wynikowego na 1. (3.) Wyliczamy długość badając każdy znak. (4., 5.) Długość zwiększamy tylko wtedy, gdy i-ty znak to I, a znak przed jest inny od I.

  1.   char* wynik = new char[dl];
  2.   for(int i = 0, j = 0; txt[i];){
  3.     int x = 0;
  4.     while(txt[i] == 'I'){
  5.       x++;
  6.       i++;
  7.     }
  8.     int y = 0;
  9.     while(txt[i] >= '0' && txt[i] <= '9'){
  10.       y = y*10 + txt[i] - '0';
  11.       i++;
  12.     }
  13.     wynik[j++] = y + ((x == 2) ? 13 : 0) - 1 + 'A';
  14.   }
  15.   wynik[dl] = '\0';
  16.   return wynik;
  17. }

Deszyfrowanie jest prostsze od szyfrowania. (7.) Alokujemy pamięć pod tekst wynikowy. (8.) Pętle wykonujemy dopóki nie skończą nam się dane. Tutaj również używamy dwóch liczników: i - przechowuje, który znak tekstu zaszyfrowanego rozpatrujemy oraz j - przechowuje, który znak tekstu wynikowego zapisujemy. (9.) Deklarujemy zmienną x, która przechowa do której grupy należy znak. (10.) Pod warunkiem, że i-tym znakiem jest I (11.) zwiększamy x oraz (12.) i. (14.) W zmiennej y przechowamy numer kolumny do której należy znak. (15. - 18.) Wczytujemy numer kolumny. (19.) Wyliczamy jaki znak reprezentuje dana para wczytanych liczb (x, y). Na koniec (21.) dopisujemy znak końca danych i (22.) zwracamy wynik.

Testowanie funkcji

Funkcja main(), która przetestuje działanie programu wygląda następująco:

  1. int main () {
  2.   char* txt = new char[128];
  3.   cin.getline(txt, 128);
  4.   char* txtc = cipher(txt);
  5.   cout << txtc << endl;
  6.   char* txtd = decipher(txtc);
  7.   cout << txtd << endl;
  8.   delete[] txt, txtc, txtd;
  9.   system("pause");
  10.   return 0;
  11. }

Zadania

Zadanie 1

Napisz funkcję szyfrującą i deszyfrującą, która będzie też działać dla małych liter alfabetu łacińskiego. W celu rozróżnienia wielkości liter zakładamy, że w przypadku małej litery numer grupy oznaczamy małą literą i. Zakładamy, że wprowadzony tekst składa się tylko z dużych i małych liter alfabetu łacińskiego.

Przykładowo dla danych:

  1. Informacja

otrzymujemy:

  1. I9ii1i6ii2ii5i13i1i3i10i1