Strona główna » Algorytmy » Szyfry » Szyfr Klucz na przemian
 

Szyfr Klucz na przemian

Szyfr

Szyfr klucz na przemian jest szyfrem podstawieniowym. Kluczem szyfrującym jest pewna permutacja alfabetu użytego do zapisu wiadomości. Taki szyfr jest zwykle ładny do złamania, ponieważ można policzyć wystąpienia liter i na tej podstawie określić, która litera to która. Jednak w tym szyfrze problem ten został rozwiązany. k-ta litera z szyfrogramu o i-tej pozycji w alfabecie w przypadku, gdy k jest parzyste zostanie zastąpiona przez i-tą literę z klucza. Jednak jeśli k jest nieparzyste to litera zostanie zastąpienia przez i-ty znak od końca klucza.

Przykład

Przypuśćmy, że mamy do zaszyfrowania tekst TAJNA INFORMACJA. Przyjmujemy, że w tym przypadku używamy standardowego alfabetu łacińskiego tj. ABCDEFGHIKJLMNOPQRSTUVWXYZ. Następnie ustalamy klucz, który jest dowolną permutacją alfabetu. Załóżmy, że kluczem jest RXCZPMOQKHJNABFWUYEVDTIGSL. Na podstawie tych danych można stworzyć poniższą tabelkę:

szyfrowana literaABCDEFGHIKJLMNOPQRSTUVWXYZ
poz. parzystaRXCZPMOQKHJNABFWUYEVDTIGSL
poz. nieparzystaLSGITDVEYUWFBANJHKQOMPZCXR

Szyfrując tekst TAJNA INFORMACJA pierwszą literę zamieniamy zgodnie z trzecim wierszem czyli T to O. Kolejną drugą literę zamieniamy na klucz z wiersza drugiego tj. A to R. Kontynuując w ten sposób otrzymamy zaszyfrowany tekst postaci: ORUBL YBDFKALCUR. Warto zauważyć, że litera, a jest zaszyfrowana na dwa różne sposoby co znacznie utrudnia łamanie szyfru.

Implementacja

Szyfrowanie

Program z założenia będzie przyjmował tylko klucz. Za domyślny alfabet zostanie przyjęty alafabet łaciński. Podczas szyfrowania należy sprawdzić, która pozycja jest parzysta. Należy zwrócić uwagę, że znaki wprowadzonego tekstu są indeksowane nie od jeden, a od 0. Może to powodować brak kompatybilności pomiędzy zaszyfrowaną wersją przez człowieka, a napisanym programie. Funkcja szyfrująca wygląda następująco:

  1. char* cipher(char* key, char* txt){
  2.   char* wynik = new char[strlen(txt) + 1];
  3.   for(int i = 0; txt[i]; i++){
  4.     if(txt[i] >= 'A' && txt[i] <= 'Z'){
  5.       if(i % 2 == 1){
  6.         wynik[i] = key[txt[i] - 'A'];
  7.       } else {
  8.         wynik[i] = key['Z' - txt[i]];
  9.       }
  10.     } else {
  11.       wynik[i] = txt[i];
  12.     }
  13.   }
  14.   wynik[strlen(txt)] = '\0';
  15.   return wynik;
  16. }

(1.) Funkcja szyfrująca przyjmuje key - klucz, którym będziemy szyfrować znaki oraz txt - tekst do zaszyfrowania. Pomijamy podanie klucza, który zgodnie za założeniami jest alfabetem łacińskim. (2.) Alokujemy pamięć pod tekst wynikowy. (3.) Dla każdego znaku w tekście: (4.) będącym literą: (5.) w zależności od pozycji i rozpatrywanej litery wybieramy metodę w jaką pobieramy znak z klucza. Dla pozycji parzystej (6.) wystarczy pobrać tak jak w przypadku normalnych szyfrów podstawieniowych, a dla pozycji nieparzystej (8.) znak wybieramy od końca klucza. W przypadku kiedy znak nie jest literą to (11.) przepisujemy znak bez zmian. (15.) Przed zwróceniem wartości (14.) dopisujemy na koniec listy znak \0.

Deszyfrowanie

Podczas deszyfrowanie będzie potrzeba znalezienia rozszyfrowywanej litery w kluczu. Do tego celu przyda się dodatkowa funkcja pomocnicza findChar(). Funkcja przyjmuje dwa argumenty: key - klucz według którego szyfrujemy oraz c - znak, który chcemy znaleźć w kluczu. W przypadku, gdy znak nie zostanie znaleziony zostanie zwrócona wartość -1. Należy pamiętać, że na brak wystąpienia chociaż jednego znaku program nie jest przygotowany, dlatego należy pamiętać, aby klucz był prawidłowy. Funkcja wygląda następująco:

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

Funkcja deszyfrująca jest podobna do szyfrującej. Różnica tkwi w wyliczaniu znaku końcowego:

  1. char* decipher(char* key, char* txt){
  2.   char* wynik = new char[strlen(txt) + 1];
  3.   for(int i = 0; txt[i]; i++){
  4.     if(txt[i] >= 'A' && txt[i] <= 'Z'){
  5.       if(i % 2 == 1){
  6.         wynik[i] = findChar(key, txt[i]) + 'A';
  7.       } else {
  8.         wynik[i] = 'Z' - findChar(key, txt[i]);
  9.       }
  10.     } else {
  11.       wynik[i] = txt[i];
  12.     }
  13.   }
  14.   wynik[strlen(txt)] = '\0';
  15.   return wynik;
  16. }

Testowanie funkcji

Szyfrowanie tekstu można przetestować przy pomocy poniższej funkcji main():

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

Zadania

Zadanie 1

Napisz funkcję, która przed szyfrowaniem sprawdzi poprawność klucza i będzie potrafiła zaszyfrować zarówno małe jak i duże litery. Zakładamy, że a szyfrujemy tak samo jak A. Zasada ta dotyczy każdej pary małej i dużej litery. Klucz jest nieprawidłowy kiedy nie składa się ze wszystkich dużych liter od A do Z.

Przykładowo dla danych:

  1. RXCZPMOQKHJNABFWUYEVDTIGSL
  2. Tajna informacja

otrzymujemy:

  1. Orubl ybdfkalcur