Strona główna » Algorytmy » Szyfry » Szyfr Dziesiątkowy
 

Szyfr Dziesiątkowy

Szyfr

Szyfr dziesiątkowy polega na ukryciu znaków tekstu jawnego wśród losowych znaków. Ustalamy, że w każdych dziesięciu znakach ukryjemy n liczb. Ustalamy również pozycję znaków w każdej dziesiątce.

Szyfrowanie

Działanie szyfrowania łatwiej wyjaśnić na konkretnym przykładzie: ustalmy, że szyfrujemy tekst "INFORMACJA". Decydujemy się ukryć po dwa znaki w każdej dziesiątce tekstu zaszyfrowanego na pozycjach 1 i 4. Tworzenie pierwszej dziesiątki wygląda tak:

Chociaż w wolne pola można wstawić dowolne znaki to nie warto dostawiać : " [ ) &, ponieważ pozwala to łatwiej określić, które znaki należy wybierać. Jeśli nasza wiadomość składa się tylko z dużych liter alfabetu łacińskiego to tylko je warto wykorzystywać do uzupełniania luk.

Deszyfrowanie

Proces deszyfrowania polega na wybraniu z każdej dziesiątki odpowiednie znaki i zapisaniu ich w kolejności w jakiej były wybierane z tekstu rozszyfrowywanego.

Implementacja

Losowość

W celu uzyskania losowych znaków posłużymy się funkcja rand(), która jest dostępna po dodaniu bibliotek:

  1. #include <ctime>
  2. #include <cstdlib>

zainicjowania funkcji losującej przed użyciem, np.:

  1.   srand(time(NULL));

Założenia

Zakładamy, że tekst do zaszyfrowania będzie złożony wyłącznie z dużych liter alfabetu łacińskiego. Na wejściu będzie podana liczba n, która będzie oznaczać ile znaków będzie w dziesiątce, a potem n liczb oznaczających na których pozycjach w każdej dziesiątce. W trzeciej linijce wejścia będzie podany tekst, którego długość nie będzie przekraczać 128 znaków. Na wyjście zostanie wypisany szyfrogram.

Szyfrowanie

Funkcja szyfrująca przyjmuje trzy argumenty: ile znaków znajdzie się w każdej dziesiątce, tablice liczb całkowitych z pozycjami na których umieścimy znaki w każdej dziesiątce oraz tekst do zaszyfrowania.

  1. char* cipher(int n, int* index, char* txt){
  2.   int dl = 10*((int)((strlen(txt) + n - 1)/n)) + 1;
  3.   char* wynik = new char[dl];
  4.   for(int i = 0; i < dl; i++)
  5.     wynik[i] = rand()%('Z' - 'A' + 1) + 'A';

(1.) Deklaracja funkcji i (2.) obliczenie długość tekstu wynikowego w celu zoptymalizowania wykorzystania pamięci. (3.) Alokujemy pamięć pod zaszyfrowany tekst. (4.) Dla każdego znaku w tekście wynikowym (5.) losujemy duży literę alfabetu łacińskiego.

  1.   for(int i = 0; txt[i]; i++)
  2.     wynik[(i / n) * 10 + index[i % n] - 1] = txt[i];
  3.   wynik[dl - 1]='\0';
  4.   return wynik;
  5. }

(6.) Dla każdego znaku w tekście do zaszyfrowania (7.) wyliczamy miejsce dla i-tego znaku w tekście wynikowym i tam go umieszczamy. (8.) Na końcu tekstu umieszczamy znak specjalny \0 i (9.) zwracamy zaszyfrowany tekst.

Deszyfrowanie

Funkcja deszyfrująca przyjmie ile znaków jest w każdej dziesiątce i listę na jakich pozycjach oraz tekst do rozszyfrowania.

  1. char* decipher(int n, int* index, char* txt){
  2.   int dl = (strlen(txt) / 10) * n + 1;
  3.   char* wynik = new char[dl];
  4.   wynik[dl]='\0';
  5.   for(int i = 0; i < dl; i++)
  6.     wynik[i] = txt[(i / n) * 10 + index[i % n] - 1];
  7.   return wynik;
  8. }

(1.) Deklarujemy funkcję i (2.) obliczamy długość tekstu wynikowego. (3.) Alokujemy pamięć pod tekst wynikowy. (4.) Dopisujemy na ostatniej pozycji znak końca linii \0. (5.) Dla każdego znaku w tekście wynikowym wyliczamy gdzie znajduje się w tekście do rozszyfrowania. Na koniec (7.) zwracamy wynik.

Testowanie funkcji

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

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

Przykład

Przykładowo dla poniższych danych:

  1. 2
  2. 1 4
  3. INFORMACJA
program może wypisać:
  1. IDFNGQWWCAFWKODDACFDRZEMBBJYCZATGCLOEARQJCMAEXZLFN

Zadania

W podanych przykładach pogrubione znaki nie są losowane, a powstają wskutek faktycznego szyfrowania. Zostały wyróżnione jedynie w celu prezentacji ich pozycji.

Zadanie 1

Dostosuj kod źródłowy artykułu, aby:

Przykładowo dla danych:

  1. 2
  2. 1 4
  3. 10
otrzymujemy:
  1. 1870934729

Zadanie 2

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 wskazanej przez użytkownika.

Przykładowo dla danych:

  1. 2
  2. 1
  3. 1
  4. INFORMACJA
otrzymujemy:
  1. IANKFYODRFMBATCYJZAE