fbpx

Szyfr Cezara będzie pierwszym tego typu artykułem na blogu. Do tej pory nie zajmowałem się tu aspektami związanymi z kryptografią. Oczywiście takie szyfry to bardziej ciekawostka i przyjemne wprowadzenie do prawdziwych zagadnień z tego ogromnego działu IT. 

W ramach dzisiejszego tematu odpowiemy sobie na szereg pytań:

  • Czym jest szyfr Cezara?
  • Czy zapewnia bezpieczeństwo zaszyfrowanych danych?
  • Jak wygląda implementacja w językach Python, C#, Java,  C++ oraz JavaScript?
  • Skąd wzięła się nazwa tego tytułowego szyfru?

Pytania postawione, czas przejść do przyjemnej pracy!

Szyfr Cezara — wprowadzenie

Zacznijmy od definicji szyfru i zapoznania się z jego historią. Szyfr Cezara jest najpopularniejszą techniką szyfrowania, a co za tym idzie, ma niemal zerowy poziom bezpieczeństwa. Wystarczy znaleźć schemat deszyfracji kilku pierwszych znaków tekstu i można uznać, że szyfr został złamany. 

Schemat szyfrowania jest banalny. Każdy znak tekstu jawnego (niezaszyfrowanego) zastępujemy inną literą, która oddalona jest o pewną liczbę znaków od litery tekstu niezaszyfrowanego. Oddalenie to nazywamy kluczem.

Dokładnie zobrazuję to na zdjęciu poniżej. Każda litera ze słowa PROGRAM została przesunięta i stworzyła ciąg znaków TVSKVEM. Posługiwałem się w tym przypadku alfabetem bez polskich znaków.

Ważne jest to, by kierunek był z góry określony. Przesuwamy zawsze do przodu lub do tyłu, jednak bardziej popularna jest ta pierwsza wersja szyfru. I taką też będziemy implementować za chwilę.

Szyfr Cezara - rysunek 1

Nazwa szyfru pochodzi od Juliusza Cezara, który szyfrował swoją korespondencję z Cyceronem. Przez to uważany jest on za najstarszy szyfr, jaki istnieje. 

Z matematycznego punktu widzenia szyfr Cezara można wyrazić za pomocą mapowania liter na cyfry, gdzie odpowiednio

A = 0

B = 1

C = 2

i tak dalej aż do 

Z = 25.

Zapis taki w matematyce jest częścią systemu liczb naturalnych zwanych arytmetyką modularną.

Szyfr Cezara — implementacja

Skupię się teraz na dokładnym opisaniu implementacji szyfru Cezara w pięciu językach — Python, Java, C#, JavaScript oraz C++. Każdy ze skryptów będzie zawierał te same dwie metody — encrypt do szyfrowania oraz decrypt do deszyfrowania. Zarówno jedna, jak i druga metoda dostaną na wejście dwie zmienne, czyli tekst do szyfrowania/odszyfrowania oraz klucz, według którego operacja szyfrowania lub odszyfrowania będzie następować.

encrypt

W metodzie encrypt deklarujemy zmienną encrypted, w której zostanie przechowana wartość zakodowanego tekstu. Następnie w pętli for następuje przejście po każdym pojedynczym znaku w tekście. Aby program był w miarę uniwersalny, musimy zapewnić mu ważny aspekt, czyli rozpoznawanie wielkości i rodzaju znaku. W przypadku dużej litery program będzie operował na innych wartościach z tabeli ASCII (więcej o ASCII we wpisie numer 1) niż w przypadku litery małej czy cyfry. Pętla będzie więc zawierać trzy warunki, na dużą literę, małą oraz właśnie cyfrę. W przypadku, gdy wstawimy dowolny inny znak, to po prostu algorytm go przepisze.

W przypadku litery dużej i małej na początku sprawdzamy wartość litery zgodnie z tabelą ASCII i odejmujemy od niej literę A. Tak otrzymany indeks następnie powiększamy o klucz oraz wykonujemy operację modulo. Po dodaniu odjętej wartości małej lub dużej litery A z tablicy ASCII otrzymamy właściwy znak przesunięty o klucz. Jest to mało intuicyjne, więc zobaczmy rysunek.

Szyfr Cezara - rysunek 2

Jak można się domyślać, stosowanie we wzorze modulo (%) jest kluczowe, ponieważ zapobiega przekroczeniu zakresu w tabeli ASCII. Jako zadanie rozpisz sobie wyznaczenie nowego znaku z litery Z. Dla bardziej ambitnych polecam obsłużenie polskich znaków.

Wracając do kodu, w przypadku cyfr stosujemy podobne przesunięcie, również posługując się wspomnianym modulo, tym razem jednak o wartości 10, ponieważ tyle posiadamy cyfr w systemie dziesiętnym. Na końcu, jeżeli przesyłamy inny znak niż litera lub cyfra to po prostu przepisujemy go bez szyfrowania.

decrypt

Funkcja deszyfrująca będzie lustrzanym odbiciem funkcji powyżej. Jedyną różnicą w kodzie będzie to, by klucz posłużył na do przesunięcia w lewo, co odwzoruje w algorytmie znak minus. Szyfr Cezara może zostać stworzony w odwrotny sposób, czyli możemy szyfrować znaki, przesuwając w lewo, natomiast deszyfrować przesuwając w prawo. To zadanie również pozostawiam Tobie drogi czytelniku. Możesz do tej implementacji rozszerzyć metody o dodatkowy, trzeci parametr, w którym przekażesz informacje, czy będziesz przesuwać w lewo, czy w prawo.

Python

def encrypt(txt, key):
    encrypted = ""
    for character in txt:
        if character.isupper():
            characterIndex = ord(character) - ord('A')
            characterShifted = (characterIndex + key) % 26 + ord('A')
            encrypted += chr(characterShifted)
        elif character.islower():
            characterIndex = ord(character) - ord('a')
            characterShifted = (characterIndex + key) % 26 + ord('a')
            encrypted += chr(characterShifted)
        elif character.isdigit():
            characterNew = (int(character) + key) % 10
            encrypted += str(characterNew)
        else:
            encrypted += character
    return encrypted


def decrypt(txt, key):
    decrypted = ""
    key = key % 26
    for character in txt:
        if character.isupper():
            characterIndex = ord(character) - ord('A')
            characterOrgPos = (characterIndex - key) % 26 + ord('A')
            decrypted +=  chr(characterOrgPos)
        elif character.islower():
            characterIndex = ord(character) - ord('a')
            characterOrgPos = (characterIndex - key) % 26 + ord('a')
            decrypted += chr(characterOrgPos)
        elif character.isdigit():
            characterOrgPos = (int(character) - key) % 10
            decrypted += str(characterOrgPos)

        else:
            decrypted += character
    return decrypted

def main(args):
    print("Ciąg zaszyfrowany:\n", encrypt("PROGRAM", 4))
    print("Ciąg odszyfrowany:\n", decrypt("TVSKVEQ", 4))
    return 0


if __name__ == '__main__':
    import sys
    sys.exit(main(sys.argv))

Java

package com.company;

public class Main {

    private static String encrypt(String txt, int key ) {
        String encrypted = "";

        for (int i = 0; i < txt.length(); i++)
        {
           if (Character.isUpperCase(txt.charAt(i)))
           {
               int characterIndex = (char)(txt.charAt(i)) - (char)('A');
               int characterShifted = (characterIndex + key) % 26 +  (char)('A');
               encrypted += (char)(characterShifted);
           }
           else if (Character.isLowerCase(txt.charAt(i)))
           {
                int characterIndex = (char)(txt.charAt(i)) - (char)('a');
                int characterShifted = (characterIndex + key) % 26 +  (char)('a');
                encrypted += (char)(characterShifted);
           }
           else if (Character.isDigit(txt.charAt(i)))
           {
               int  characterNew = ((int)(txt.charAt(i)) + key) % 10;
               encrypted += (char)(characterNew);
           }
           else
           {
               encrypted += txt.charAt(i);
           }
        }
        return encrypted;
    }

    private static String decrypt(String txt, int key ) {
        String decrypted = "";
        key = key % 26;

        for (int i = 0; i < txt.length(); i++)
        {
            if (Character.isUpperCase(txt.charAt(i)))
            {
                int characterIndex = (char)(txt.charAt(i)) - (char)('A');
                int characterOrgPos = (characterIndex - key) % 26 +  (char)('A');
                decrypted += (char)(characterOrgPos);
            }
            else if (Character.isLowerCase(txt.charAt(i)))
            {
                int characterIndex = (char)(txt.charAt(i)) - (char)('a');
                int characterOrgPos = (characterIndex - key) % 26 +  (char)('a');
                decrypted += (char)(characterOrgPos);
            }
            else if (Character.isDigit(txt.charAt(i)))
            {
                int  characterOrgPos = ((int)(txt.charAt(i)) - key) % 10;
                decrypted += (char)(characterOrgPos);
            }
            else
            {
                decrypted += txt.charAt(i);
            }
        }
        return decrypted;
    }
    public static void main(String[] args) {
        String encryptedTxt = encrypt("PROGRAM", 4);
        String decryptedTxt = decrypt("TVSKVEQ", 4);
        System.out.println(encryptedTxt);
        System.out.println(decryptedTxt);
    }
}

C#

using System;

public class Program
{	
	public static void Main()
	{
		string encryptedTxt = encrypt("PROGRAM", 4);
        string decryptedTxt = decrypt("TVSKVEQ", 4);
  		Console.WriteLine(encryptedTxt);
  		Console.WriteLine(decryptedTxt);
	}
		
    private static String encrypt(String txt, int key ) {
        String encrypted = "";

        for (int i = 0; i < txt.Length; i++)
        {
           if (Char.IsUpper(txt[i]))
           {
               int characterIndex = txt[i] - (char)('A');
               int characterShifted = (characterIndex + key) % 26 +  (char)('A');
               encrypted += (char)(characterShifted);
           }
           else if (Char.IsUpper(txt[i]))
           {
                int characterIndex = txt[i]- (char)('a');
                int characterShifted = (characterIndex + key) % 26 +  (char)('a');
                encrypted += (char)(characterShifted);
           }
           else if (Char.IsDigit(txt[i]))
           {
               int  characterNew = (int)(txt[i] + key) % 10;
               encrypted += (char)(characterNew);
           }
           else
           {
               encrypted += txt[i];
           }
        }
        return encrypted;
    }

    private static String decrypt(String txt, int key ) {
        String decrypted = "";
        key = key % 26;

        for (int i = 0; i < txt.Length; i++)
        {
             if (Char.IsUpper(txt[i]))
            {
                int characterIndex = txt[i] - (char)('A');
                int characterOrgPos = (characterIndex - key) % 26 +  (char)('A');
                decrypted += (char)(characterOrgPos);
            }
            else if (Char.IsLower(txt[i]))
            {
                int characterIndex = txt[i] - (char)('a');
                int characterOrgPos = (characterIndex - key) % 26 +  (char)('a');
                decrypted += (char)(characterOrgPos);
            }
            else if (Char.IsDigit(txt[i]))
            {
                int  characterOrgPos = (txt[i] - key) % 10;
                decrypted += (char)(characterOrgPos);
            }
            else
            {
                decrypted += txt[i];
            }
        }
        return decrypted;
    }
}

C++

#include <iostream>
using namespace std;
		
string encrypt(string txt, int key ) {
  string encrypted = "";

  for (int i = 0; i < txt.size(); i++)
  {
    if (isupper(txt[i]))
    {
      int characterIndex = txt[i] - (char)('A');
      int characterShifted = (characterIndex + key) % 26 +  (char)('A');
      encrypted += (char)(characterShifted);
    }
    else if (islower(txt[i]))
    {
      int characterIndex = txt[i]- (char)('a');
      int characterShifted = (characterIndex + key) % 26 +  (char)('a');
      encrypted += (char)(characterShifted);
    }
    else if (isdigit(txt[i]))
    {
      int  characterNew = (int)(txt[i] + key) % 10;
      encrypted += (char)(characterNew);
    }
    else
    {
      encrypted += txt[i];
    }
  }
  return encrypted;
}

string decrypt(string txt, int key ) {
  string decrypted = "";
  key = key % 26;

  for (int i = 0; i < txt.size(); i++)
  {
    if (isupper(txt[i]))
    {
      int characterIndex = txt[i] - (char)('A');
      int characterOrgPos = (characterIndex - key) % 26 +  (char)('A');
      decrypted += (char)(characterOrgPos);
    }
    else if (islower(txt[i]))
    {
      int characterIndex = txt[i] - (char)('a');
      int characterOrgPos = (characterIndex - key) % 26 +  (char)('a');
      decrypted += (char)(characterOrgPos);
    }
    else if (isdigit(txt[i]))
    {
      int  characterOrgPos = (txt[i] - key) % 10;
      decrypted += (char)(characterOrgPos);
    }
    else
    {
      decrypted += txt[i];
    }
  }
  return decrypted;
}

int main() {
  string encryptedTxt = encrypt("PROGRAM", 4);
  string decryptedTxt = decrypt("TVSKVEQ", 4);
  cout << encryptedTxt << endl;
  cout << decryptedTxt;
  return 0;
}

JavaScript

var encrypt = function(txt, key) { 
   var encrypted = ""
      
   for (var i = 0; i < txt.length; i++)
   {        
      if(txt[i] == txt[i].toUpperCase())
      {
      	 var characterIndex = txt[i].charCodeAt(0) - 'A'.charCodeAt(0);
      	 var characterShifted = (characterIndex + key) % 26 +  'A'.charCodeAt(0); 
      	 encrypted += String.fromCharCode(characterShifted);
      }
      else if(txt[i] == txt[i].toLowererCase())
      {
      	 var characterIndex = txt[i].charCodeAt(0) + 'a'.charCodeAt(0);         
      	 var characterShifted = (characterIndex - key) % 26 +  'a'.charCodeAt(0);
      	 encrypted += String.fromCharCode(characterShifted);
      }
      else if(txt[i] == txt[i].toDigit())
      {
          var characterShifted = (txt[i].charCodeAt(0) - key) % 10;
          encrypted +=  String.fromCharCode(characterShifted);
      }
      else
      {
          encrypted += txt[i]
      }
    }
	return encrypted;
};

var decrypt = function(txt, key) { 
   var decrypted = ""
   
   key = key % 26;
   
   for (var i = 0; i < txt.length; i++)
   {        
      if(txt[i] == txt[i].toUpperCase())
      {
      	 var characterIndex = txt[i].charCodeAt(0) - 'A'.charCodeAt(0);
      	 var characterOrgPos = (characterIndex - key) % 26 +  'A'.charCodeAt(0); 
      	 decrypted += String.fromCharCode(characterOrgPos);
      }
      else if(txt[i] == txt[i].toLowererCase())
      {
      	 var characterIndex = txt[i].charCodeAt(0) - 'a'.charCodeAt(0);         
      	 var characterOrgPos = (characterIndex - key) % 26 +  'a'.charCodeAt(0);
      	 decrypted += String.fromCharCode(characterOrgPos);
      }
      else if(txt[i] == txt[i].toDigit())
      {
          var characterOrgPos = (txt[i].charCodeAt(0) - key) % 10;
          decrypted +=  String.fromCharCode(characterOrgPos);
      }
      else
      {
          decrypted += txt[i]
      }
    }
	return decrypted;
};

Szyfr Cezara — podsumowanie

Bardzo się cieszę, że doszliśmy do końca i mogę pochwalić się kolejnym algorytmem na moim blogu. Myślę, że szyfr Cezara to tylko przedsmak, jaki czeka mnie podczas analizy kolejnych algorytmów kryptograficznych. Możesz zauważyć, że dziś zastosowaliśmy niewiele matematyki, a jak już to zrobiliśmy to tylko z zakresu szkoły podstawowej.

W kolejnych algorytmach z tej rodziny wejdziemy w nieco bardziej poważną matematykę, więc już na tym etapie zachęcam Cię do tego, byś dokładnie przeanalizował/a przykład dzisiejszy wraz z kilkoma małymi zadaniami, które w trakcie artykułu przemyciłem. Ich samodzielne wykonanie pozwoli Ci na lepsze zrozumienie tematu.

W przypadku problemów pisz w komentarzu poniżej. Oczywiście zachęcam Cię również do tego, by pochwalić się swoim rozwiązaniem poniżej!

Zostawiam na koniec dwie książki do tego, by efektywnie pouczyć się programowania!

PS. Będę wdzięczny za komentarze pod tym postem!

PS2. Czeka też na Ciebie prezent. Wystarczy, że zapiszesz się na Newsletter poniżej!

PS3. Dołącz do naszej grupy na Facebook!

PS4. Dołącz do naszego serwera na Discord!

Subskrybuj

Zapisz się na Newsletter, odbierz NAGRODĘ w postaci e-booka z 10 omówionymi algorytmami pojawiającymi się w pytaniach podczas REKRUTACJI.

Dodatkowo otrzymuj co niedzielę informacje na temat nowych wpisów, wiadomości ze świata IT i matematyki oraz ciekawych wydarzeniach. Nie przegap i dołącz już dziś do 463 osób!.
Autor

👨‍💻 .NET and Python programming passionate 🏦 Digtial Banking Solutions 🎓 Student 📊 Psychology 📚 Bookworm 🏠 Warsaw

1 Komentarz

  1. Fajny artykuł.

    W zasadzie jakby tak spojrzeć na Szyfr Ceasara to teraz o tym myślę że jest bardzo proste do zaimplementowania. Kiedyś było to coś dla mnie trudnego.

    Pisałem też na swoim blogu o tym zagadnieniu:

    1. https://mstem.net/pl/szyfr-cezara-python/

    Warto by od Szyfru Ceasara przejść do bardziej zaawansowanej wersji tego szyfru czyli takiego szyfru gdzie szyfrowanie następuje nie po kluczu ale po jakimś słowie lub zdaniu. Podejrzewam że w filmie Imitation Games o Alanie Turingu i Enigmie, sowiecki szpieg który pracował między innymi z Alanem korzystał z tego szyfru. Taki tam jest wątek.

    W zasadzie taki szyfr też nie byłby trudny do zaimplementowania. Kluczem wpierw jest różnica między pierwszą literą słowa a literą szyfrowanego tekstu, później przychodzi kolej na drugą literę i kolejną i tak dalej. Tak to sobie wstępnie wyobrażam.

    Też mam zamiar o tym napisać artykuł na swoim blogu jak znajdę czas 😋.

    Dzięki Mateusz za ten artykuł i za implementację aż w 5 językach. Super sprawa 😌.

    Pozdrawiam 👋 .

Napisz komentarz

Witryna wykorzystuje Akismet, aby ograniczyć spam. Dowiedz się więcej jak przetwarzane są dane komentarzy.