Szyfr Cezara

Szyfr Cezara to jeden z najprostszych szyfrów w historii kryptografii.
Legenda mówi, że używał go Juliusz Cezar, aby wysyłać tajne wiadomości do swoich dowódców.

Zasada jest bardzo prosta:

  • mamy alfabet, np. ABCDEFGHIJKLMNOPQRSTUVWXYZ

  • wybieramy przesunięcie, np. o 3 litery

  • każdą literę zastępujemy literą oddaloną o 3 pozycje w prawo

Przykład (przesunięcie o 3):

  • A → D

  • B → E

  • C → F

  • X → A

  • Y → B

  • Z → C

Słowo ALA po zaszyfrowaniu może wyglądać np. tak: DOD.

To oznacza, że każda litera w tekście jawnym jest zamieniana na inną literę według prostego, powtarzalnego wzoru (przesunięcie w alfabecie).

Ten typ szyfrowania nazywamy monoalfabetycznym szyfrem podstawieniowym – każda litera ma zawsze tę samą „zaszyfrowaną odpowiedniczkę”.


2. Jak to się ma do naszego programu?

Twój program nie realizuje dokładnie „klasycznego” przesunięcia o 3 litery, ale robi coś bardzo podobnego:

  • mamy alfabet1 – litery, które wolno wpisywać

  • mamy alfabet2 – znaki szyfrujące, które odpowiadają tym literom

  • każdą literę z name (podany tekst) zamieniasz na inny znak z alfabet2 na tej samej pozycji.

Czyli:

  • zamiast „przesuwać literę o kilka miejsc w alfabecie”,

  • Ty mapujesz litery z jednego „alfabetu” na drugi.

To nadal jest szyfr podstawieniowy – idea ta sama:

Znak jawny → zawsze ten sam znak zaszyfrowany.

Możesz uczniom powiedzieć tak:

„Klasyczny szyfr Cezara przesuwa litery o kilka miejsc, a nasz program robi podobną rzecz, tylko zamiast przesuwania używa gotowej tabelki zamian (alfabet1 → alfabet2).”


3. Kod programu – przegląd

Twój kod:

#include <iostream>
#include <string>

int main()
{
  std::string name,szyfr;
  int nr = 0;
  std::string alfabet1 = "abcdefghijklmnoprstuw";
  std::string alfabet2 = "1234567890!@#$%^&*()Q";
  std::cout << "Tekst do zaszyfrowania? \n";
  getline (std::cin, name); 
  for(int i =0; i< name.size();i++) {
      nr = alfabet1.find(name[i]);
      szyfr += alfabet2[nr];
      }
       std::cout << szyfr;
}

Spróbujmy go rozbić na kawałki i przy okazji podpiąć pod Twoje pytania.


4. Nagłówki – dlaczego są potrzebne?

#include <iostream>
#include <string>
  • #include <iostream> – udostępnia strumienie wejścia/wyjścia, m.in.

    • std::cout – wypisywanie na ekran

    • std::cin – wczytywanie z klawiatury

  • #include <string> – udostępnia typ std::string, czyli:

    • ciąg znaków (tekst),

    • na którym mamy metody typu size(), find(), at(), itp.

To łączy się z Twoimi pytaniami:
„Tekst to jaki typ zmiennej?” – w tym programie to właśnie std::string.


5. Funkcja main i deklaracja zmiennych

int main()
{
  std::string name,szyfr;
  int nr = 0;
  std::string alfabet1 = "abcdefghijklmnoprstuw";
  std::string alfabet2 = "1234567890!@#$%^&*()Q";
  ...
}
  • int main() – główna funkcja programu. Tutaj wszystko się zaczyna.

  • std::string name, szyfr;

    • name – tekst, który użytkownik wpisze z klawiatury,

    • szyfr – wynik zaszyfrowania (początkowo pusty string).

Na pytanie: „Jakie wartości może przyjmować string?” –
std::string może przechowywać dowolny ciąg znaków, np. "Ala", "test123", "ala ma kota", nawet pusty tekst "".

  • int nr = 0;

    • nr to zmienna typu int – przechowuje numer pozycji litery w alfabecie (index w alfabet1).

  • std::string alfabet1 = "abcdefghijklmnoprstuw";

    • to „zwykły” alfabet, ale uproszczony (bez wszystkich liter, np. bez „q”, „y”, „z”).

  • std::string alfabet2 = "1234567890!@#$%^&*()Q";

    • alfabet szyfrujący – każdy znak ma indeks odpowiadający literze w alfabet1.

Czyli:

  • alfabet1[0] → alfabet2[0]

  • alfabet1[1] → alfabet2[1]

  • itd.

To jest Twoja tabelka podstawień – odpowiednik „przesunięcia” w szyfrze Cezara.


6. Wczytywanie tekstu – getline(std::cin, name);

std::cout << "Tekst do zaszyfrowania? \n";
getline (std::cin, name); 
  • std::cout << "Tekst do zaszyfrowania? \n";

    • wypisuje pytanie na ekran,

    • \n – znak nowej linii.

  • getline(std::cin, name);

    • wczytuje całą linię tekstu (aż do naciśnięcia ENTER),

    • zapisuje ją do zmiennej name.

To jest odpowiedź na Twoje pytanie:
„Co znaczy getline (std::cin, name);?”

Wczytaj cały wiersz tekstu z klawiatury (łącznie ze spacjami) i zapisz go jako string w zmiennej name.

Różnica do std::cin >> name; jest taka, że cin >> zatrzymuje się na pierwszej spacji, a getline bierze wszystko do końca linii.


7. Pętla for i name.size()

for(int i =0; i< name.size();i++) {
    nr = alfabet1.find(name[i]);
    szyfr += alfabet2[nr];
}

7.1. Nagłówek pętli

for(int i = 0; i < name.size(); i++)
  • int i = 0; – zmienna sterująca pętlą, startuje od 0.

  • i < name.size(); – warunek kontynuowania:

    • name.size() zwraca długość stringa (liczbę znaków),

    • jeśli name ma np. 5 znaków, name.size() = 5,

    • indeksy znaków to: 0,1,2,3,4,

    • dlatego warunek jest i < size(), a nie <=.

To odpowiada na pytanie:
„name.size() co otrzymamy?”

name.size() zwraca liczbę znaków w stringu name (typu std::size_t, ale w praktyce traktujemy to jak liczbę całkowitą).

Przykłady:

  • name = "ala" → name.size() == 3

  • name = "" → name.size() == 0

7.2. name[i] – pojedynczy znak

W środku pętli używasz:

name[i]
  • name[i] oznacza i-ty znak w stringu,

  • przy i = 0 – pierwszy znak,

  • przy i = 1 – drugi znak itd.


8. Szukanie znaku w alfabecie – alfabet1.find(name[i])

nr = alfabet1.find(name[i]);

To jest kluczowa linijka dla szyfrowania.

  • alfabet1.find(name[i]) szuka znaku name[i] w stringu alfabet1.

  • Jeśli znajdzie, zwraca numer pozycji (indeks) tego znaku.

  • Ten numer zapisujemy do zmiennej nr.

Możesz to tłumaczyć uczniom tak:

alfabet1.find(name[i]) mówi nam: „którą literą w alfabecie jest aktualny znak?”.
To dokładnie Twoje pytanie:
„zwraca która litera jest w alfabecie alfabet1.find(name[i])” – TAK, właśnie to robi.

Przykład, jeśli:

std::string alfabet1 = "abcdefghijklmnoprstuw";
  • alfabet1.find('a') → 0

  • alfabet1.find('b') → 1

  • alfabet1.find('c') → 2

Jeśli znak nie istnieje w alfabet1, metoda find() zwróci specjalną wartość std::string::npos (bardzo dużą liczbę).
W Twoim kodzie zakładamy, że użytkownik wpisuje tylko litery znajdujące się w alfabet1.


9. Budowanie zaszyfrowanego tekstu – szyfr += alfabet2[nr];

szyfr += alfabet2[nr];
  • alfabet2[nr] – bierzemy znak z alfabet2 o tym samym indeksie, który znaleźliśmy w alfabet1.

  • szyfr += ... – dopisujemy ten znak na koniec stringa szyfr.

To oznacza:

„Zamień literę z alfabet1 na odpowiadający jej znak z alfabet2 i dołóż do końca zaszyfrowanego tekstu”.

Przykład:

alfabet1 = "abc..."
alfabet2 = "123..."
name = "ab"

Iteracje:

  • dla i = 0 → name[0] = 'a'

    • alfabet1.find('a') → 0

    • alfabet2[0] → '1′

    • szyfr = "1"

  • dla i = 1 → name[1] = 'b'

    • alfabet1.find('b') → 1

    • alfabet2[1] → '2′

    • szyfr = "12"

Na końcu:

std::cout << szyfr;

wypisze zaszyfrowany tekst.


10. Połączenie z szyfrem Cezara

Klasyczny szyfr Cezara:

  • alfabet: ABCDEFGHIJKLMNOPQRSTUVWXYZ

  • przesunięcie: np. o 3 w prawo

  • każda litera ma zaszyfrowaną odpowiedniczkę na podstawie przesunięcia

Twój program:

  • ma alfabet1 i alfabet2,

  • każda litera z alfabet1 ma stałą odpowiedniczkę w alfabet2,

  • zamiast przesuwać, korzystasz z „tabelki zamian”.

Możesz powiedzieć uczniom:

Nasz kod realizuje szyfr podstawieniowy taki jak Cezara, tylko zamiast przesunięcia o 3 litery mamy ręcznie przygotowane odpowiadające sobie znaki w dwóch stringach.

Chcesz klasycznego Cezara w tej samej konwencji?
Możesz ustawić:

std::string alfabet1 = "abcdefghijklmnopqrstuvwxyz";
std::string alfabet2 = "defghijklmnopqrstuvwxyzabc"; // przesunięcie o 3

I reszta programu będzie działać tak samo – to już będzie „prawie podręcznikowy” szyfr Cezara.


11. Pytania kontrolne do tego artykułu

Na koniec możesz wykorzystać część z Twoich 60 pytań – tu masz mały pakiet „pod lekcję”:

60 pytań – szyfr Cezara i kod w C++

  1. Jakie wartości może przyjmować zmienna typu std::string w C++?

  2. „Tekst” w tym programie jest przechowywany w jakim typie zmiennej?

  3. Co oznacza instrukcja std::string imie = "olek";?

  4. Po co w programie jest dyrektywa #include <string>?

  5. Do czego służy #include <iostream> w tym kodzie?

  6. Co robi instrukcja std::cout << "Tekst do zaszyfrowania? \n";?

  7. Co znaczy wywołanie getline(std::cin, name); w programie?

  8. Czym różni się getline(std::cin, name) od std::cin >> name;?

  9. Jakiego typu są zmienne name i szyfr w podanym kodzie?

  10. Jaką wartość początkową ma zmienna szyfr po uruchomieniu programu?

  11. Co przechowuje zmienna alfabet1?

  12. Co przechowuje zmienna alfabet2?

  13. Dlaczego w programie używane są dwa różne „alfabety”: alfabet1 i alfabet2?

  14. Co oznacza, że std::string jest typem złożonym (klasą), a nie prostym typem jak int?

  15. Co oznacza std w zapisie std::string i std::cout?

  16. Jak można uprościć zapis std::string używając using namespace std;?

  17. Jakie podstawowe operacje można wykonywać na zmiennej typu std::string (wymień przykłady)?

  18. Co oznacza nagłówek pętli for(int i = 0; i < name.size(); i++)?

  19. Co oznacza zapis i++ w pętli for?

  20. Jakiego typu jest wartość zwracana przez name.size()?

  21. Co otrzymamy z wyrażenia name.size() dla tekstu "ala"?

  22. Dlaczego w warunku pętli użyto i < name.size(), a nie i <= name.size()?

  23. Co oznacza zapis name[i] wewnątrz pętli?

  24. Co to znaczy, że name jest indeksowany od zera?

  25. Jakie indeksy mają znaki w stringu "abc"?

  26. Co robi instrukcja nr = alfabet1.find(name[i]);?

  27. Co dokładnie zwraca alfabet1.find(name[i]), gdy znak istnieje w alfabet1?

  28. Co zwróci alfabet1.find(name[i]), gdy znak NIE występuje w alfabet1?

  29. Jaką rolę pełni zmienna nr w programie?

  30. Co robi instrukcja szyfr += alfabet2[nr];?

  31. Co oznacza operator += w kontekście typu std::string?

  32. Jak sprawdzić długość łańcucha alfabet1 w programie?

  33. Dlaczego długość alfabet1 i alfabet2 powinna być taka sama?

  34. Co się stanie, jeśli name[i] będzie spacją, a w alfabet1 nie ma spacji?

  35. Jak można zabezpieczyć program przed sytuacją, gdy alfabet1.find(name[i]) nic nie znajdzie?

  36. Czy program poprawnie zaszyfruje wielkie litery (np. A, B)? Uzasadnij.

  37. Jak można zmodyfikować program, aby ignorował wielkość liter (małe/wielkie)?

  38. Jak można zmodynić program, aby znaki, których nie ma w alfabet1, przepisywał bez szyfrowania?

  39. W jaki sposób można wypisać również oryginalny tekst obok zaszyfrowanego?

  40. Co się stanie z wynikiem szyfrowania, jeśli zmienisz kolejność znaków w alfabet1?

  41. Co się stanie z wynikiem szyfrowania, jeśli zmienisz kolejność znaków w alfabet2?

  42. Co krok po kroku robi funkcja std::getline, gdy użytkownik wpisuje tekst i naciska ENTER?

  43. Jak można sprawdzić w programie, czy zmienna name jest pusta (nie zawiera znaków)?

  44. Jak można policzyć, ile znaków ma zaszyfrowany tekst zapisany w zmiennej szyfr?

  45. Czym różni się użycie name[i] od name.at(i)?

  46. Co robiłaby instrukcja return 0; na końcu funkcji main()?

  47. Co to znaczy, że string jest sekwencją znaków ułożonych „jeden po drugim” w pamięci?

  48. W jaki sposób można na podstawie tego programu zrealizować operację „deszyfrowania” (powrotu z szyfr do zwykłego tekstu)?

  49. Czy zmienna typu std::string może przechowywać polskie znaki (ą, ę, ł, ś itd.)? Omów to krótko.

  50. Co to jest szyfr Cezara w teorii kryptografii?

  51. Na czym polega klasyczny mechanizm szyfru Cezara (co robimy z literami)?

  52. Czym szyfr Cezara różni się od ogólnego „szyfru podstawieniowego”?

  53. W jaki sposób podany program realizuje ideę szyfru Cezara lub szyfru podstawieniowego?

  54. Jak można zmodyfikować program tak, aby użyć klasycznego przesunięcia o 3 litery (typowy szyfr Cezara)?

  55. Jak możemy opisać rolę „indeksu litery w alfabecie” w szyfrowaniu Cezara?

  56. Dlaczego szyfr Cezara nie jest bezpieczny we współczesnej kryptografii?

  57. Jak można zmienić program, aby użytkownik sam podawał wartość przesunięcia (np. o ile liter szyfrować)?

  58. Jakie są zalety używania typu std::string przy implementacji szyfru, zamiast tablicy char[]?

  59. W jaki sposób można wykorzystać ten program jako przykład na lekcji o podstawach kryptografii?

  60. Dlaczego szyfrowanie typu Cezara (i Twój program) nazywamy szyfrowaniem przez podstawienie jednej litery inną literą?

Sprawdź, co pamiętasz

Pytania kontrolne

1. Jaki jest główny temat artykułu „Szyfr Cezara”?

Wskazówka: Odpowiedz własnymi słowami i wskaż najważniejszy cel lub problem opisany w materiale.

2. Które trzy pojęcia, zasady albo etapy z artykułu warto zapamiętać?

Wskazówka: Wybierz informacje potrzebne do wykonania zadania lub wyjaśnienia tematu innej osobie.

3. Jak można wykorzystać tę wiedzę w praktyce?

Wskazówka: Podaj konkretny przykład z lekcji, pracy przy komputerze albo codziennej sytuacji.

4. Jakie kroki należy wykonać, aby poprawnie zrealizować opisane zadanie?

Wskazówka: Ułóż najważniejsze czynności we właściwej kolejności.

5. Jakich narzędzi, funkcji lub materiałów potrzeba do wykonania zadania?

Wskazówka: Wymień elementy wskazane w artykule i krótko opisz ich rolę.

6. Która zasada opisana w artykule jest najważniejsza i dlaczego?

Wskazówka: Uzasadnij wybór przykładem z materiału.

7. Jaki błąd można popełnić podczas wykonywania zadania i jak go uniknąć?

Wskazówka: Wskaż możliwą trudność oraz sposób jej rozwiązania.

8. Jak wyjaśnisz ten temat osobie, która poznaje go po raz pierwszy?

Wskazówka: Użyj prostych słów i najważniejszych pojęć z artykułu.

9. Co zmieniłoby się, gdyby pominąć jeden z opisanych etapów lub zasad?

Wskazówka: Przewidź skutek i uzasadnij odpowiedź.

10. Jakie własne ćwiczenie lub przykład można przygotować na podstawie artykułu?

Wskazówka: Zaproponuj zadanie, które sprawdza zrozumienie materiału.

Komentarze

Dodaj komentarz