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

Szyfr Zmiennik

O szyfrze

Szyfr Zmiennik nie posiada typowego klucza do szyfrowania. Rolę klucza odgrywa tutaj tabelka wypełniona znakami. Jej wielkość i zawartość są dowolne. Kiedy chcemy zaszyfrować tekst sprawdzamy czy dany znak znajduje się w tabelce. Jeśli tak to bierzemy znak stojący kolumnę wcześniej. Jeśli znak znajduje się w pierwszej kolumnie to żądany znak bierzemy z ostatniej kolumny.

Szyfrowanie

Przykładowo stwórzmy taką tabelkę:

  1. A « E « I « M « R « W
  2. B « F « J « N « S « X
  3. C « G « K « O « T « Y
  4. D « H « L « P « U « Z

Teraz chcąc zaszyfrować słowo "INFORMACJA" szyfrujemy kolejno: I na E, N na J, F na B, O na K, R na M, M na I, A na W (A jest w pierwszej kolumnie, więc znak po lewej bierzemy z ostatniej kolumny), C na Y, J na F, A na W i otrzymujemy zaszyfrowany tekst: EJBKMIWYFW.

Deszyfrowanie

W przypadku deszyfrowania znajdujemy literkę z tekstu zaszyfrowanego w tabelce i odczytujemy znak po prawej stronie. Analogicznie przy szyfrowaniu jeśli znak jest w ostatniej kolumnie to znak pobieramy z pierwszej.

Implementacja

Założenia

Program otrzyma na wejściu dwie wartości w, h całkowitoliczbowe, które określą wielkość tablicy szyfrującej. Potem w h linijkach będzie w znaków porozdzielanych spacjami. W następnej linijce po tablicy będzie wprowadzony tekst do zaszyfrowania. Na wyjściu ma zostać wypisany zaszyfrowany tekst zgodnie z szyfrem zmiennik. Przykładowo dla wejścia:

  1. 6 4
  2. A E I M R W
  3. B F J N S X
  4. C G K O T Y
  5. D H L P U Z
  6. INFORMACJA

otrzymamy:

  1. EJBKMIWYFW

Szyfrowanie

Funkcja szyfrująca przyjmie cztery argumenty: tekst do zaszyfrowania, tablicę, która będzie dwuwymiarową tablicą typu char oraz szerokość i wysokość tabelki. Wynikiem działania funkcji będzie zaszyfrowany tekst.

  1. char* cipher(char* txt, char** tablica, int width, int height){
  2.   char* wynik = new char[strlen(txt)];
  3.   for(int i = 0; wynik[i]; i++)
  4.     wynik[i] = getLeftCharFromTable(txt[i], tablica, width, height);
  5.   wynik[strlen(txt)] = '\0';
  6.   return wynik;
  7. }

(2.) Alokujemy pamięć pod wynik. (3.) Dla każdego znaku w tekście (4.) wywołamy funkcję getLeftCharFromTable(), która zwróci odpowiedni znak z tablicy. (5.) Dopisujemy na koniec znak końca napisu \0 i (6.) zwracamy wynik.

Funkcja getLeftCharFromTable() przyjmuje cztery argumenty: szukany znak, tablicę znaków oraz szerokość i wysokość tablicy. Wynikiem będzie znak. Jeśli szukany znak zostanie znaleziony to zwracamy nowy znak. Jeśli szukany znak nie występuje w tablicy to zwracamy znak, którego szukaliśmy.

  1. char getLeftCharFromTable(char lookfor, char** tablica, int width, int height){
  2.   for(int x = 0; x < height; x++)
  3.     for(int y = 0; y < width; y++)
  4.       if(tablica[x][y] == lookfor)
  5.         return tablica[x][(y == 0) ? width - 1 : y - 1];
  6.   return lookfor;
  7. }

(2.) W każdej linijce i (3.) dla każdego znaku w przeszukiwanym wierszu (4.) sprawdzamy czy na pozycji x, y występuje szukany znak: jeśli tak to (5.) zwracamy odpowiedni znak z tablicy. Należy tu pamiętać o przypadku, gdy szukany znak jest w pierwszej kolumnie, ponieważ wtedy potrzebujemy zwrócić z ostatniej kolumny, ponieważ kolumna "0" nie istnieje. Jeśli po wszystkie pętle zostaną ukończone to znaczy, że dany znak nie występuje w tablicy, więc zwracamy szukany znak.

Deszyfrowanie

Deszyfrowanie opiera się na tej samej zasadzie co szyfrowanie. Różnica tkwi tutaj, który znak z tablicy jest zwracany. Kod pozostawiam do własnego przemyślenia:

  1. char getRightCharFromTable(char lookfor, char** tablica, int width, int height){
  2.   for(int x = 0; x < height; x++)
  3.     for(int y = 0; y < width; y++)
  4.       if(tablica[x][y] == lookfor)
  5.         return tablica[x][(y == width - 1) ? 0 : y + 1];
  6.   return lookfor;
  7. }
  8. char* decipher(char* txt, char** tablica, int width, int height){
  9.   char* wynik = new char[strlen(txt)];
  10.   for(int i = 0; wynik[i]; i++)
  11.     wynik[i] = getRightCharFromTable(txt[i], tablica, width, height);
  12.   wynik[strlen(txt)] = '\0';
  13.   return wynik;
  14. }

Testowanie funkcji

Poniższa funkcja main() pozwala na wczytanie danych zgodnie z założeniami. Wczytany tekst najpierw szyfruje, a potem rozszyfruje na podstawie klucza i szyfrogramuu.

  1. int main () {
  2.   int w, h;
  3.   cin >> w >> h;
  4.   char** tablica = new char*[h];
  5.   for(int i = 0; i < h; i++){
  6.     tablica[i] = new char[w];
  7.     for(int j = 0; j < w; j++)
  8.       cin >> tablica[i][j];
  9.   }
  10.   char* txt = new char[128];
  11.   cin.sync();
  12.   cin.getline(txt, 128);
  13.   char* txtc = cipher(txt, tablica, w, h);
  14.   cout << txtc << endl;
  15.   char* txtd = decipher(txtc, tablica, w, h);
  16.   cout << txtd << endl;
  17.   for(int i = 0; i < h; i++)
  18.     delete[] tablica[i];
  19.   delete[] tablica, txtc, txtd;
  20.   system("pause");
  21.   return 0;
  22. }

Poprawa kodu

Funkcję szyfrowania i deszyfrowania można napisać jako nie cztery, a tylko dwie funkcje jeśli będziemy przekazywać argument o ile przesuwamy indeks znaku w każdym wierszu.

Funkcja cipher() i decipher() były identyczne, dlatego możemy z nich zrobić jedną. Jednak potrzebny jest kolejny argument przes, który określi czy dane mają być zaszyfrowane czy rozszyfrowane.

  1. char* change(char* txt, char** tablica, int width, int height, int przes){
  2.   char* wynik = new char[strlen(txt)];
  3.   for(int i = 0; wynik[i]; i++)
  4.     wynik[i] = getCharFromTable(txt[i], tablica, width, height, przes);
  5.   wynik[strlen(txt)] = '\0';
  6.   return wynik;
  7. }

Funkcja getLeftCharFromTable() oraz getRightCharFromTable() też mają identyczną strukturę prócz linijki (5.). Mając teraz dodatkowy argument przes będziemy przyjmować odpowiednie wartości, które wystarczy zastąpić -1 i +1 w dotychczasowych funkcjach:

  1. char getCharFromTable(char lookfor, char** tablica, int width, int height, int przes){
  2.   for(int x = 0; x < height; x++)
  3.     for(int y = 0; y < width; y++)
  4.       if(tablica[x][y] == lookfor)
  5.         return tablica[x][(y + width - przes) % width];
  6.   return lookfor;
  7. }

Od teraz szyfrować będziemy przy pomocy:

  1.   char* txtc = change(txt, tablica, w, h, 1);

a jeśli będziemy chcieli odszyfrować to wystarczy wpisać:

  1.   char* txtd = change(txtc, tablica, w, h, -1);

Zadania

Zadanie 1

Zmodyfikuj funkcję, aby na wejściu przed wszystkimi innymi danymi wejściowymi program powinien wczytać rozmiar jednego bloku - innymi słowy każdy blok nie będzie się składał z 10 znaków, a dowolnej ilości.

Przykładowo dla danych:

  1. 6 4
  2. A E I M R W
  3. B F J N S X
  4. C G K O T Y
  5. D H L P U Z
  6. Informacja
otrzymujemy:
  1. Ejbkmiwyfw