Szyfry symetryczne dzielimy na dwie grupy: szyfry strumieniowe i szyfry blokowe. W szyfrze blokowym wiadomość dzieli się na bloki o określonej długości, a następnie fragmenty te są szyfrowane z użyciem klucza. W szyfrze strumieniowym natomiast klucz używany jest do wygenerowania strumienia bitów, który wykorzystuje się do zaszyfrowania jednego bitu/bajtu informacji na raz. W tym e‑materiale zaimplementujemy oba rodzaje szyfru symetrycznego.
Szyfr strumieniowy
Stosując szyfry strumieniowe, należy pamiętać, że okres generowanego strumienia powinien być możliwie długi (termin okres w tym kontekście odnosi się do okresu ciąguokres ciąguokresu ciągu). Dlatego ważny jest algorytm generowania strumienia.
W implementacjach szyfru strumieniowego stosowane są najczęściej generatory liczb pseudolosowych, np. funkcja rand(), dostępna w języku C++ w bibliotece standardowej.
Przeanalizujemy przykładową implementację szyfru strumieniowego w języku C++. Zaszyfrujemy, a później – w ramach sprawdzenia – odszyfrujemy wybrany ciąg znaków.
Specyfikacja problemu:
Dane:
kluczGlowny – wykorzystywany w procesie szyfrowania klucz, na podstawie którego generowany jest strumień bitów; liczba całkowita
slowoDoZaszyfrowania – tekst jawny przekazany do zakodowania; ciąg znaków
Wynik:
zaszyfrowaneSlowo – zaszyfrowany tekst jawny; ciąg znaków
W celu szyfrowania bitów wiadomości możemy posłużyć się różnymi operacjami. Wykorzystamy operator XOR.
Ważne!
W procesie szyfrowania wykorzystamy operator XOR, czyli operator różnicy symetrycznej. W języku C++ odpowiada mu znak ^, natomiast w zapisie matematycznym wykorzystuje się zazwyczaj symbol .
Opisywany operator opiera się na następującej logice:
Wynikiem operacji będzie – należy pamiętać, że operacje wykonujemy tylko na odpowiadających sobie bitach. Warto tutaj dodać, że wynikiem operacji będzie , a wynikiem operacji będzie .
Do szyfrowania pojedynczych bajtów informacji wykorzystamy funkcję zaszyfrujZnak(), która jako parametry przyjmuje zmienne znak oraz klucz. Zdefiniujemy również tablicę o nazwie ustring do przechowywania zmiennych typu unsigned char, co pozwoli na zapisywanie wartości w zakresie <0; 255>.
Domyślnie zmienna typu basic_string pozwala przechowywać znaki typu signed char, co oznacza, że maksymalną wartością jest 127. Dzięki nim można kodować siedmiobitowy standard ASCII. W omawianym przykładzie szyfrowania potrzebny jest standard Extended ASCII, w którym wartością maksymalną jest 255, czyli ośmiobitowa liczba binarna 11111111.
Linia 1. typedef basic podkreślnik string otwórz nawias ostrokątny unsigned char zamknij nawias ostrokątny ustring średnik.
Linia 3. unsigned char zaszyfrujZnak otwórz nawias okrągły unsigned char znak przecinek unsigned char klucz zamknij nawias okrągły otwórz nawias klamrowy.
Linia 4. return znak kareta klucz średnik.
Linia 5. zamknij nawias klamrowy.
Funkcja ta będzie przydatna w implementacji szyfru blokowego i strumieniowego.
Przykład 1
Generator bitów generuje kolejne wyrazy ciągu Fibonacciego. Wiadomością, którą chcemy zaszyfrować, jest DodaDodaDodatki. Każdej literze szyfrowanego tekstu odpowiada pewien kod ASCII. Konwertując go na system binarny, dla każdego znaku otrzymamy ciągi składające się z ośmiu bitów.
Znaki wiadomości szyfrujemy kolejnymi wyrazami ciągu Fibonacciego w następujący sposób:
i^377Indeks dolny (10)(10) = 01101001Indeks dolny (2)(2) ^ 101111001Indeks dolny (2)(2) = 00010000Indeks dolny (2)(2) = 16Indeks dolny (10)(10) (wynikiem ostatniej operacji jest liczba dziewięciobitowa, z której odrzucamy najbardziej znaczący bit, otrzymujemy bajt o dziesiętnej wartości 16 – jest to kod znaku kontrolnego bez wizualnej reprezentacji w kodzie ASCII)
Każda litera została zaszyfrowana jako osobny znak, a złamanie szyfrogramu byłoby problematyczne, ponieważ występujące w nim znaki są nieodróżnialne od losowego ciągu symboli.
Proces szyfrowania rozpoczynamy od przygotowania klucza szyfrującego oraz inicjalizacji zmiennej przechowującej tekst jawny ciągiem znaków DodaDodaDodatki. Następnie tworzymy kolejną zmienną zaszyfrowaneSlowo, która zawierać będzie szyfrogram złożony jedynie z liter „x”.
Ważne!
Funkcja srand() jako parametr przyjmuje tak zwane ziarno (z ang. seed), czyli pewną wartość, na podstawie której generator będzie obliczał kolejną losową liczbę. W przypadku analizowanego szyfru strumieniowego ziarno będzie stanowić klucz szyfrujący.
Jeśli spróbujemy użyć funkcji rand() bez jawnego wywoływania funkcji srand(), to wyniki losowania będą identyczne dla każdego uruchomienia programu, ponieważ funkcja srand() wykona się z argumentem 1. Dlatego najczęściej wywołuje się funkcję srand() z argumentem time(NULL), który odczytuje liczbę sekund, jaka upłynęła od godziny 00:00:00 stycznia r. – to gwarantuje, że dla każdego uruchomienia programu ziarno będzie unikalne.
Funkcja srand() potrzebuje ziarna, ponieważ współczesne komputery są deterministycznedeterminizmdeterministyczne i z poziomu programu nie jesteśmy w stanie wprowadzić prawdziwej losowości.
Linia 1. int main otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 2. int kluczGlowny znak równości 1234567890 średnik prawy ukośnik prawy ukośnik przykładowy klucz przecinek za pomocą którego kodujemy i dekodujemy wiadomość.
Linia 3. srand otwórz nawias okrągły kluczGlowny zamknij nawias okrągły średnik prawy ukośnik prawy ukośnik ustawienie ziarna i cudzysłów wyzerowanie generatora liczb pseudolosowych cudzysłów.
Linia 4. string slowoDoZaszyfrowania znak równości cudzysłów DodaDodaDodatki cudzysłów średnik.
Linia 5. string zaszyfrowaneSlowo otwórz nawias okrągły slowoDoZaszyfrowania kropka size otwórz nawias okrągły zamknij nawias okrągły przecinek apostrof x apostrof zamknij nawias okrągły średnik.
Linia 6. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Slowo do zaszyfrowania dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 8. for otwórz nawias okrągły int i znak równości 0 średnik i otwórz nawias ostrokątny slowoDoZaszyfrowania kropka size otwórz nawias okrągły zamknij nawias okrągły średnik i plus plus zamknij nawias okrągły otwórz nawias klamrowy.
Linia 9. cout otwórz nawias ostrokątny otwórz nawias ostrokątny slowoDoZaszyfrowania otwórz nawias kwadratowy i zamknij nawias kwadratowy średnik.
Linia 10. zamknij nawias klamrowy.
Linia 12. cout otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 13. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Tablica przecinek w ktorej bedzie zaszyfrowane slowo dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 15. for otwórz nawias okrągły int i znak równości 0 średnik i otwórz nawias ostrokątny zaszyfrowaneSlowo kropka size otwórz nawias okrągły zamknij nawias okrągły średnik i plus plus zamknij nawias okrągły otwórz nawias klamrowy.
Linia 16. cout otwórz nawias ostrokątny otwórz nawias ostrokątny zaszyfrowaneSlowo otwórz nawias kwadratowy i zamknij nawias kwadratowy średnik.
Linia 17. zamknij nawias klamrowy.
Linia 19. cout otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 20. zamknij nawias klamrowy.
Po implementacji opisanych operacji możemy przejść do samego szyfrowania. Wykorzystujemy przygotowaną wcześniej funkcję zaszyfrujZnak.
Linia 1. for otwórz nawias okrągły int i znak równości 0 średnik i otwórz nawias ostrokątny zaszyfrowaneSlowo kropka size otwórz nawias okrągły zamknij nawias okrągły średnik i plus plus zamknij nawias okrągły otwórz nawias klamrowy.
Linia 2. zaszyfrowaneSlowo otwórz nawias kwadratowy i zamknij nawias kwadratowy znak równości zaszyfrujZnak otwórz nawias okrągły slowoDoZaszyfrowania otwórz nawias kwadratowy i zamknij nawias kwadratowy przecinek rand otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły średnik.
Linia 3. zamknij nawias klamrowy.
Linia 5. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Zaszyfrowane slowo dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 7. for otwórz nawias okrągły int i znak równości 0 średnik i otwórz nawias ostrokątny zaszyfrowaneSlowo kropka size otwórz nawias okrągły zamknij nawias okrągły średnik i plus plus zamknij nawias okrągły otwórz nawias klamrowy.
Linia 8. cout otwórz nawias ostrokątny otwórz nawias ostrokątny zaszyfrowaneSlowo otwórz nawias kwadratowy i zamknij nawias kwadratowy średnik.
Linia 9. zamknij nawias klamrowy.
Linia 11. cout otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Dodatkowo program możemy uzupełnić o deszyfrowanie utworzonego szyfrogramu. Ponownie wymagane będzie wykorzystanie funkcji zaszyfrujZnak.
Linia 1. string odszyfrowaneSlowo otwórz nawias okrągły zaszyfrowaneSlowo kropka size otwórz nawias okrągły zamknij nawias okrągły przecinek apostrof x apostrof zamknij nawias okrągły średnik.
Linia 2. srand otwórz nawias okrągły kluczGlowny zamknij nawias okrągły średnik prawy ukośnik prawy ukośnik Ponowne ustawienie generatora liczb pseudolosowych kluczem.
Linia 4. for otwórz nawias okrągły int i znak równości 0 średnik i otwórz nawias ostrokątny odszyfrowaneSlowo kropka size otwórz nawias okrągły zamknij nawias okrągły średnik i plus plus zamknij nawias okrągły otwórz nawias klamrowy.
Linia 5. odszyfrowaneSlowo otwórz nawias kwadratowy i zamknij nawias kwadratowy znak równości zaszyfrujZnak otwórz nawias okrągły zaszyfrowaneSlowo otwórz nawias kwadratowy i zamknij nawias kwadratowy przecinek rand otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły średnik.
Linia 6. zamknij nawias klamrowy.
Linia 8. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Odszyfrowane slowo dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 10. for otwórz nawias okrągły int i znak równości 0 średnik i otwórz nawias ostrokątny odszyfrowaneSlowo kropka size otwórz nawias okrągły zamknij nawias okrągły średnik i plus plus zamknij nawias okrągły otwórz nawias klamrowy.
Linia 11. cout otwórz nawias ostrokątny otwórz nawias ostrokątny odszyfrowaneSlowo otwórz nawias kwadratowy i zamknij nawias kwadratowy średnik.
Linia 12. zamknij nawias klamrowy.
Gotowy program wygląda następująco:
Linia 1. kratka include otwórz nawias ostrokątny iostream zamknij nawias ostrokątny.
Linia 2. kratka include otwórz nawias ostrokątny cstdlib zamknij nawias ostrokątny.
Linia 3. kratka include otwórz nawias ostrokątny string zamknij nawias ostrokątny.
Linia 5. using namespace std średnik.
Linia 7. typedef basic podkreślnik string otwórz nawias ostrokątny unsigned char zamknij nawias ostrokątny ustring średnik.
Linia 9. unsigned char zaszyfrujZnak otwórz nawias okrągły unsigned char znak przecinek unsigned char klucz zamknij nawias okrągły otwórz nawias klamrowy.
Linia 10. return znak kareta klucz średnik.
Linia 11. zamknij nawias klamrowy.
Linia 13. int main otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 14. int kluczGlowny znak równości 1234567890 średnik prawy ukośnik prawy ukośnik przykładowy klucz przecinek za pomocą którego kodujemy i dekodujemy wiadomość.
Linia 15. srand otwórz nawias okrągły kluczGlowny zamknij nawias okrągły średnik prawy ukośnik prawy ukośnik ustawienie ziarna i cudzysłów wyzerowanie generatora liczb pseudolosowych cudzysłów.
Linia 16. string slowoDoZaszyfrowania znak równości cudzysłów DodaDodaDodatki cudzysłów średnik.
Linia 17. ustring zaszyfrowaneSlowo otwórz nawias okrągły slowoDoZaszyfrowania kropka size otwórz nawias okrągły zamknij nawias okrągły przecinek apostrof x apostrof zamknij nawias okrągły średnik.
Linia 18. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Slowo do zaszyfrowania dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 20. for otwórz nawias okrągły int i znak równości 0 średnik i otwórz nawias ostrokątny slowoDoZaszyfrowania kropka size otwórz nawias okrągły zamknij nawias okrągły średnik i plus plus zamknij nawias okrągły otwórz nawias klamrowy.
Linia 21. cout otwórz nawias ostrokątny otwórz nawias ostrokątny slowoDoZaszyfrowania otwórz nawias kwadratowy i zamknij nawias kwadratowy średnik.
Linia 22. zamknij nawias klamrowy.
Linia 24. cout otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 25. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Tablica przecinek w ktorej bedzie zaszyfrowane slowo dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 27. for otwórz nawias okrągły int i znak równości 0 średnik i otwórz nawias ostrokątny zaszyfrowaneSlowo kropka size otwórz nawias okrągły zamknij nawias okrągły średnik i plus plus zamknij nawias okrągły otwórz nawias klamrowy.
Linia 28. cout otwórz nawias ostrokątny otwórz nawias ostrokątny zaszyfrowaneSlowo otwórz nawias kwadratowy i zamknij nawias kwadratowy średnik.
Linia 29. zamknij nawias klamrowy.
Linia 31. cout otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 33. for otwórz nawias okrągły int i znak równości 0 średnik i otwórz nawias ostrokątny zaszyfrowaneSlowo kropka size otwórz nawias okrągły zamknij nawias okrągły średnik i plus plus zamknij nawias okrągły otwórz nawias klamrowy.
Linia 34. zaszyfrowaneSlowo otwórz nawias kwadratowy i zamknij nawias kwadratowy znak równości zaszyfrujZnak otwórz nawias okrągły slowoDoZaszyfrowania otwórz nawias kwadratowy i zamknij nawias kwadratowy przecinek rand otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły średnik.
Linia 35. zamknij nawias klamrowy.
Linia 37. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Zaszyfrowane slowo dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 39. for otwórz nawias okrągły int i znak równości 0 średnik i otwórz nawias ostrokątny zaszyfrowaneSlowo kropka size otwórz nawias okrągły zamknij nawias okrągły średnik i plus plus zamknij nawias okrągły otwórz nawias klamrowy.
Linia 40. cout otwórz nawias ostrokątny otwórz nawias ostrokątny zaszyfrowaneSlowo otwórz nawias kwadratowy i zamknij nawias kwadratowy średnik.
Linia 41. zamknij nawias klamrowy.
Linia 43. cout otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 44. ustring odszyfrowaneSlowo otwórz nawias okrągły zaszyfrowaneSlowo kropka size otwórz nawias okrągły zamknij nawias okrągły przecinek apostrof x apostrof zamknij nawias okrągły średnik.
Linia 45. srand otwórz nawias okrągły kluczGlowny zamknij nawias okrągły średnik prawy ukośnik prawy ukośnik Ponowne ustawienie generatora liczb pseudolosowych kluczem.
Linia 47. for otwórz nawias okrągły int i znak równości 0 średnik i otwórz nawias ostrokątny odszyfrowaneSlowo kropka size otwórz nawias okrągły zamknij nawias okrągły średnik i plus plus zamknij nawias okrągły otwórz nawias klamrowy.
Linia 48. odszyfrowaneSlowo otwórz nawias kwadratowy i zamknij nawias kwadratowy znak równości zaszyfrujZnak otwórz nawias okrągły zaszyfrowaneSlowo otwórz nawias kwadratowy i zamknij nawias kwadratowy przecinek rand otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły średnik.
Linia 49. zamknij nawias klamrowy.
Linia 51. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Odszyfrowane slowo dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 53. for otwórz nawias okrągły int i znak równości 0 średnik i otwórz nawias ostrokątny odszyfrowaneSlowo kropka size otwórz nawias okrągły zamknij nawias okrągły średnik i plus plus zamknij nawias okrągły otwórz nawias klamrowy.
Linia 54. cout otwórz nawias ostrokątny otwórz nawias ostrokątny odszyfrowaneSlowo otwórz nawias kwadratowy i zamknij nawias kwadratowy średnik.
Linia 55. zamknij nawias klamrowy.
Linia 57. return 0 średnik.
Linia 58. zamknij nawias klamrowy.
A oto przykładowy wynik pracy programu:
Linia 1. Slowo do zaszyfrowania dwukropek.
Linia 2. DodaDodaDodatki.
Linia 3. Tablica przecinek w ktorej będzie zaszyfrowane slowo dwukropek.
Linia 4. xxxxxxxxxxxxxxx.
Linia 5. Zaszyfrowane slowo dwukropek.
Linia 6. Ů procent ďj╠╣5■ýN├Uą5.
Linia 7. Odszyfrowane slowo dwukropek.
Linia 8. DodaDodaDodatki.
W przedstawionym przykładzie szyfrowaliśmy całe bajty informacji. Przypomnijmy, że każdy znak w Extended ASCII kodowany jest na jednym bajcie, czyli na zmiennej typu char.
Warto zwrócić uwagę, że choć w szyfrowanej wiadomości występują:
trzy znaki D,
trzy znaki o,
trzy znaki d,
trzy znaki a,
jeden znak t,
jeden znak k,
jeden znak i,
nie ma to jednak przełożenia na zaszyfrowaną wiadomość – wszystkie znaki występujące w szyfrogramie wydają się losowe.
Otrzymany ciąg znaków może różnić się w zależności od użytego standardu dekodowania. Ten z kolei zależy między innymi od wykorzystywanego systemu operacyjnego. Jeżeli w ramach swojej implementacji otrzymasz inne rozwiązanie, nie oznacza to, że jest ono błędne. W przypadku wątpliwości warto sprawdzić uzyskane kody w systemie dziesiętnym.
Szyfr blokowy
Szyfrowanie blokowe zaprezentujemy z wykorzystaniem trybu szyfrowania ECB (ang. Electronic Codebook). Tryb ten polega na szyfrowaniu po kolei bloków tekstu jawnego w kolejne bloki szyfrogramu. W ramach przedstawionej implementacji najpierw zaszyfrujemy, a później odszyfrujemy wybrany ciąg znaków.
Specyfikacja problemu:
Dane:
kluczGlowny – klucz wykorzystywany w procesie szyfrowania; tablica trzech liczb całkowitych (składających się na klucz), które można przedstawić na ośmiu bitach
slowoDoZaszyfrowania – tekst jawny przekazany do zakodowania; ciąg znaków
Wynik:
zaszyfrowaneSlowo – zaszyfrowany tekst jawny; ciąg znaków
Podczas implementacji algorytmu dzielimy tekst jawny na bloki. Następnie każdy z bloków szyfrujemy kluczem, dzięki operatorowi XOR.
Przykład 2
Mamy przekazać wiadomość DodaDodaDodatki. Podczas szyfrowania znaków posługujemy się kodem Extended ASCII. Kluczem są kody ASCII trzech znaków: a, b, c, co oznacza, że blok będzie miał długość bitów, a klucz w postaci binarnej będzie następujący: 01100001 01100010 01100011Indeks dolny (2)(2). Należy więc podzielić wiadomość na pięć bloków, zawierających po trzy znaki:
Dod, aDo, daD, oda, tki.
Operacja XOR polega na porównywaniu bitów dwóch liczb binarnych, a następnie ustaleniu na ich podstawie wartości bitów w liczbie wynikowej. Opisaną operację będziemy wykonywać jednocześnie na dwóch pojedynczych znakach: znaku bloku oraz znaku klucza, przekonwertowanych na wartości binarne.
W tym przypadku nie zapiszemy ich odpowiedników w kodzie ASCII, ponieważ większość z uzyskanych znaków ich nie ma.
Warto jednak zwrócić uwagę, że symbole są za każdym razem szyfrowane przez inny fragment kodu.
Jak pokazaliśmy w przykładzie, szyfr blokowy jest w stanie zaszyfrować jeden znak na wiele różnych znaków. Jednak aby tak się stało, klucz musi być dłuższy od jednego bajta.
Istnieje również możliwość szyfrowania blokowego z użyciem klucza o liczbie bitów niepodzielnej przez osiem. Jego implementacja jest jednak znacznie bardziej skomplikowana i nie będziemy się nią teraz zajmować.
Przykład 3
Zaszyfrujmy ponownie wiadomość: DodaDodaDodatki, tym razem używając jako klucza wartości 234, która mieści się na jednym bajcie.
W wyniku otrzymaliśmy następującą kombinację symboli szyfrogramu:
«ůÄő«ůÄő«ůÄő×üâ
odpowiadającą wiadomości:
DodaDodaDodatki.
Po przeanalizowaniu przykładu możemy stwierdzić, że każdemu znakowi tekstu jawnego odpowiada tylko jeden konkretny znak, co powoduje, że szyfr ten jest – przynajmniej teoretycznie – prostszy do złamania i nie zapewnia praktycznie żadnego bezpieczeństwa.
Po analizie szyfrogramu z przykładu można zauważyć, że w wiadomości występuje kilka powtarzających się znaków. Podobnego efektu nie uzyskaliśmy w szyfrze strumieniowym oraz w szyfrze blokowym, wykorzystującym klucz dłuższy niż jeden bajt.
Trzy bajty klucza (przykład nr 2) w przypadku wiadomości wystarczyły do bezpiecznego jej zaszyfrowania. Przy szyfrowaniu dłuższych tekstów mogłoby się jednak okazać, że wybrany klucz jest zbyt krótki, by zapewnić pożądany poziom bezpieczeństwa (prawdopodobieństwo złamania szyfru byłoby wysokie).
ECB jest najprostszym koncepcyjnie algorytmem blokowym, którego jednak z tego właśnie powodu nie używa się w praktycznych zastosowaniach.
Przedstawiony program jest implementacją szyfru blokowego, opartego na szyfrowaniu tekstu jawnego kluczem o długości trzech bajtów (rozdzielonym na trzy liczby całkowite, gdzie każdą z nich możemy przedstawić za pomocą ośmiu bitów). Działa on podobnie do przedstawionego wcześniej algorytmu szyfrowania strumieniowego, z tą różnicą, że każdy blok wiadomości szyfrowany jest tym samym kluczem (a nie losowym strumieniem danych).
Linia 1. kratka include otwórz nawias ostrokątny iostream zamknij nawias ostrokątny.
Linia 2. kratka include otwórz nawias ostrokątny cstdlib zamknij nawias ostrokątny.
Linia 3. kratka include otwórz nawias ostrokątny string zamknij nawias ostrokątny.
Linia 5. using namespace std średnik.
Linia 7. typedef basic podkreślnik string otwórz nawias ostrokątny unsigned char zamknij nawias ostrokątny ustring średnik.
Linia 9. unsigned char zaszyfrujZnak otwórz nawias okrągły unsigned char znak przecinek int klucz zamknij nawias okrągły otwórz nawias klamrowy.
Linia 10. return znak kareta klucz średnik.
Linia 11. zamknij nawias klamrowy.
Linia 13. int main otwórz nawias okrągły zamknij nawias okrągły otwórz nawias klamrowy.
Linia 14. int kluczGlowny otwórz nawias kwadratowy 3 zamknij nawias kwadratowy znak równości otwórz nawias klamrowy 234 przecinek 255 przecinek 165 zamknij nawias klamrowy średnik prawy ukośnik prawy ukośnik przykładowy klucz przecinek za pomocą którego kodujemy i dekodujemy wiadomość.
Linia 15. string slowoDoZaszyfrowania znak równości cudzysłów DodaDodaDodatki cudzysłów średnik.
Linia 16. ustring zaszyfrowaneSlowo otwórz nawias okrągły slowoDoZaszyfrowania kropka size otwórz nawias okrągły zamknij nawias okrągły przecinek apostrof x apostrof zamknij nawias okrągły średnik.
Linia 17. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Slowo do zaszyfrowania dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 19. for otwórz nawias okrągły int i znak równości 0 średnik i otwórz nawias ostrokątny slowoDoZaszyfrowania kropka size otwórz nawias okrągły zamknij nawias okrągły średnik i plus plus zamknij nawias okrągły otwórz nawias klamrowy.
Linia 20. cout otwórz nawias ostrokątny otwórz nawias ostrokątny slowoDoZaszyfrowania otwórz nawias kwadratowy i zamknij nawias kwadratowy średnik.
Linia 21. zamknij nawias klamrowy.
Linia 23. cout otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 24. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Tablica przecinek w ktorej bedzie zaszyfrowane slowo dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 26. for otwórz nawias okrągły int i znak równości 0 średnik i otwórz nawias ostrokątny zaszyfrowaneSlowo kropka size otwórz nawias okrągły zamknij nawias okrągły średnik i plus plus zamknij nawias okrągły otwórz nawias klamrowy.
Linia 27. cout otwórz nawias ostrokątny otwórz nawias ostrokątny zaszyfrowaneSlowo otwórz nawias kwadratowy i zamknij nawias kwadratowy średnik.
Linia 28. zamknij nawias klamrowy.
Linia 30. cout otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 32. for otwórz nawias okrągły int i znak równości 0 średnik i otwórz nawias ostrokątny zaszyfrowaneSlowo kropka size otwórz nawias okrągły zamknij nawias okrągły średnik i plus plus zamknij nawias okrągły otwórz nawias klamrowy.
Linia 33. zaszyfrowaneSlowo otwórz nawias kwadratowy i zamknij nawias kwadratowy znak równości zaszyfrujZnak otwórz nawias okrągły slowoDoZaszyfrowania otwórz nawias kwadratowy i zamknij nawias kwadratowy przecinek kluczGlowny otwórz nawias kwadratowy i procent 3 zamknij nawias kwadratowy zamknij nawias okrągły średnik.
Linia 34. zamknij nawias klamrowy.
Linia 36. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Zaszyfrowane slowo dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 38. for otwórz nawias okrągły int i znak równości 0 średnik i otwórz nawias ostrokątny zaszyfrowaneSlowo kropka size otwórz nawias okrągły zamknij nawias okrągły średnik i plus plus zamknij nawias okrągły otwórz nawias klamrowy.
Linia 39. cout otwórz nawias ostrokątny otwórz nawias ostrokątny zaszyfrowaneSlowo otwórz nawias kwadratowy i zamknij nawias kwadratowy średnik.
Linia 40. zamknij nawias klamrowy.
Linia 42. cout otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 43. ustring odszyfrowaneSlowo otwórz nawias okrągły zaszyfrowaneSlowo kropka size otwórz nawias okrągły zamknij nawias okrągły przecinek apostrof x apostrof zamknij nawias okrągły średnik.
Linia 45. for otwórz nawias okrągły int i znak równości 0 średnik i otwórz nawias ostrokątny odszyfrowaneSlowo kropka size otwórz nawias okrągły zamknij nawias okrągły średnik i plus plus zamknij nawias okrągły otwórz nawias klamrowy.
Linia 46. odszyfrowaneSlowo otwórz nawias kwadratowy i zamknij nawias kwadratowy znak równości zaszyfrujZnak otwórz nawias okrągły zaszyfrowaneSlowo otwórz nawias kwadratowy i zamknij nawias kwadratowy przecinek kluczGlowny otwórz nawias kwadratowy i procent 3 zamknij nawias kwadratowy zamknij nawias okrągły średnik.
Linia 47. zamknij nawias klamrowy.
Linia 49. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów Odszyfrowane slowo dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 51. for otwórz nawias okrągły int i znak równości 0 średnik i otwórz nawias ostrokątny odszyfrowaneSlowo kropka size otwórz nawias okrągły zamknij nawias okrągły średnik i plus plus zamknij nawias okrągły otwórz nawias klamrowy.
Linia 52. cout otwórz nawias ostrokątny otwórz nawias ostrokątny odszyfrowaneSlowo otwórz nawias kwadratowy i zamknij nawias kwadratowy średnik.
Linia 53. zamknij nawias klamrowy.
Linia 55. return 0 średnik.
Linia 56. zamknij nawias klamrowy.
Program na wyjściu standardowym wypisze:
Linia 1. Slowo do zaszyfrowania dwukropek.
Linia 2. DodaDodaDodatki.
Linia 3. Tablica przecinek w ktorej bedzie zaszyfrowane slowo dwukropek.
Linia 4. xxxxxxxxxxxxxxx.
Linia 5. Zaszyfrowane slowo dwukropek.
Linia 6. «É┴ő╗╩Ä×ßůŤ─×ö╠.
Linia 7. Odszyfrowane slowo dwukropek.
Linia 8. DodaDodaDodatki.
Podobnie jak w przypadku szyfru strumieniowego, otrzymany wynik może się różnić w zależności od przyjętego typu kodowania.
Dla zainteresowanych
Wyszukaj w internecie frazy „ECB Penguin” – czyli przykładu obrazka linuksowego pingwina, który został zaszyfrowany za pomocą ECB. Jest to świetny dowód ilustrujący, dlaczego szyfr ten jest nieskuteczny.
Szyfr asymetryczny
Omówimy koncepcję szyfrów asymetrycznych, korzystając z protokołu Diffiego‑Hellmana. Jest on używany w protokole TLS/SSL, służącym do szyfrowania wiadomości wysyłanych drogą internetową, w celu asymetrycznego negocjowania sekretnego klucza.
W trakcie omawiania działania algorytmu użyjemy imion: Alicja i Bob – są to fikcyjne postacie, przywoływane podczas omawiania wielu algorytmów asymetrycznych. Z tymi imionami skojarzone są role dwóch osób, które chcą wymienić się wiadomością lub kluczem.
Algorytm można uprościć do następującej listy kroków:
Użytkownicy uzgadniają liczbę pierwszą i bazę – są to elementy publiczne i teoretycznie każdy może mieć do nich dostęp, co dla bezpieczeństwa szyfru nie stanowi żadnego problemu.
Alicja wybiera liczbę całkowitą , a następnie przesyła Bobowi liczbę: .
Bob wykonuje identyczną operację i również wybiera dowolną liczbę całkowitą , a następnie wysyła liczbę .
Ważne!
Liczby oraz są tajne i znane odpowiednio jedynie Alicji i Bobowi.
Następnie Alicja oblicza liczbę . Bob oblicza tę samą liczbę: .
Liczba jest wynegocjowanym sekretnym kluczem (znanym Alicji i Bobowi), który może być następnie wykorzystany do szyfrowania symetrycznego. Ponieważ szyfrowanie asymetryczne jest zbyt zasobo- i czasochłonne, wykorzystamy jedynie asymetryczny schemat do negocjacji klucza, używanego do szyfrowania symetrycznego. Możemy więc stwierdzić, że używamy schematów asymetrycznych do wynegocjowania klucza, aby był on tajny. Ale sam klucz stosujemy w algorytmie symetrycznym, aby ograniczyć czas procesu szyfrowania.
Równe wartości wyznaczonych tajnych kluczy możemy udowodnić matematycznie. Kluczowy jest fakt, że dzielenie i modulo zwróci w obu przypadkach tę samą wartość.
Alicja odbierająca wiadomość ma klucz publiczny składający się z trzech elementów: , oraz . Dysponuje ona również kluczem prywatnym oraz wyznaczonym tajnym kluczem . Bob wysyłający wiadomość używa klucza publicznego, składającego się z trzech elementów: , oraz . Ma on również klucz prywatny oraz wyznaczony tajny klucz .
Przyjrzyjmy się implementacji opisanego algorytmu.
Specyfikacja problemu:
Dane:
p – pierwszy element klucza publicznego Alicji; liczba pierwsza
g – drugi element klucza publicznego Alicji – baza; liczba całkowita
a – klucz prywatny Alicji; liczba całkowita
b – klucz prywatny Boba; liczba całkowita
Wynik:
s – obliczony sekretny klucz; liczba całkowita
Program rozpoczyna się od utworzenia trzech zmiennych: p, g oraz a, przechowujących opisane wcześniej wartości, czyli odpowiednio: liczbę pierwszą, bazę oraz liczbę całkowitą wybraną przez Alicję. Następnie obliczamy wartość zmiennej A według wzoru przedstawionego w drugim kroku przebiegu algorytmu.
Ważne!
Operacja modulo (w języku C++ reprezentowana za pomocą znaku %) jest operacją wyznaczania reszty. Przykładowo: 21 % 2 = 1, ponieważ 21 / 2 = 10, reszty 1.
Linia 1. kratka include otwórz nawias ostrokątny iostream zamknij nawias ostrokątny.
Linia 2. kratka include otwórz nawias ostrokątny cmath zamknij nawias ostrokątny.
Linia 4. using namespace std średnik.
Linia 6. int main otwórz nawias okrągły int argc przecinek char asterysk asterysk argv zamknij nawias okrągły otwórz nawias klamrowy.
Linia 7. int p znak równości 29 średnik prawy ukośnik prawy ukośnik element klucza publicznego Alicji.
Linia 8. int g znak równości 9 średnik prawy ukośnik prawy ukośnik element klucza publicznego Alicji.
Linia 9. int a znak równości 7 średnik prawy ukośnik prawy ukośnik klucz prywatny Alicji.
Linia 10. unsigned int A znak równości otwórz nawias okrągły otwórz nawias okrągły unsigned int zamknij nawias okrągły pow otwórz nawias okrągły g przecinek a zamknij nawias okrągły zamknij nawias okrągły procent p średnik prawy ukośnik prawy ukośnik element klucza publicznego Alicji.
Linia 12. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów A Alicji wynosi dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny A otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 13. zamknij nawias klamrowy.
Następnie tworzymy kolejną zmienną b, która przechowywać będzie liczbę całkowitą wybraną przez Boba. Wyliczamy także wartość zmiennej B (wzór w kroku trzecim opisu algorytmu).
Linia 1. int b znak równości 3 średnik prawy ukośnik prawy ukośnik klucz prywatny Boba.
Linia 2. unsigned int B znak równości otwórz nawias okrągły otwórz nawias okrągły unsigned int zamknij nawias okrągły pow otwórz nawias okrągły g przecinek b zamknij nawias okrągły zamknij nawias okrągły procent p średnik prawy ukośnik prawy ukośnik element klucza publicznego Boba przecinek który obliczany jest na podstawie klucza publicznego Alicji.
Linia 4. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów B Boba wynosi dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny B otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Ostatnim krokiem algorytmu jest wyznaczenie wartości zmiennej s, zarówno według wzoru wykorzystywanego przez Alicję, jak i przez Boba.
Linia 1. unsigned int s znak równości otwórz nawias okrągły otwórz nawias okrągły unsigned int zamknij nawias okrągły pow otwórz nawias okrągły B przecinek a zamknij nawias okrągły zamknij nawias okrągły procent p średnik prawy ukośnik prawy ukośnik Alicja oblicza s.
Linia 3. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów s obliczone przez Alicje wynosi dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny s otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 5. s znak równości otwórz nawias okrągły otwórz nawias okrągły unsigned int zamknij nawias okrągły pow otwórz nawias okrągły A przecinek b zamknij nawias okrągły zamknij nawias okrągły procent p średnik prawy ukośnik prawy ukośnik Bob oblicza s.
Linia 7. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów s obliczone przez Boba wynosi dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny s otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Gotowy program wygląda następująco:
Linia 1. kratka include otwórz nawias ostrokątny iostream zamknij nawias ostrokątny.
Linia 2. kratka include otwórz nawias ostrokątny cmath zamknij nawias ostrokątny.
Linia 4. using namespace std średnik.
Linia 6. int main otwórz nawias okrągły int argc przecinek char asterysk asterysk argv zamknij nawias okrągły otwórz nawias klamrowy.
Linia 7. int p znak równości 29 średnik prawy ukośnik prawy ukośnik element klucza publicznego Alicji.
Linia 8. int g znak równości 9 średnik prawy ukośnik prawy ukośnik element klucza publicznego Alicji.
Linia 9. int a znak równości 7 średnik prawy ukośnik prawy ukośnik klucz prywatny Alicji.
Linia 10. unsigned int A znak równości otwórz nawias okrągły otwórz nawias okrągły unsigned int zamknij nawias okrągły pow otwórz nawias okrągły g przecinek a zamknij nawias okrągły zamknij nawias okrągły procent p średnik prawy ukośnik prawy ukośnik element klucza publicznego Alicji.
Linia 12. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów A Alicji wynosi dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny A otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 14. int b znak równości 3 średnik prawy ukośnik prawy ukośnik klucz prywatny Boba.
Linia 15. unsigned int B znak równości otwórz nawias okrągły otwórz nawias okrągły unsigned int zamknij nawias okrągły pow otwórz nawias okrągły g przecinek b zamknij nawias okrągły zamknij nawias okrągły procent p średnik prawy ukośnik prawy ukośnik element klucza publicznego Boba przecinek który obliczany jest na podstawie klucza publicznego Alicji.
Linia 17. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów B Boba wynosi dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny B otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 19. unsigned int s znak równości otwórz nawias okrągły otwórz nawias okrągły unsigned int zamknij nawias okrągły pow otwórz nawias okrągły B przecinek a zamknij nawias okrągły zamknij nawias okrągły procent p średnik prawy ukośnik prawy ukośnik Alicja oblicza s.
Linia 21. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów s obliczone przez Alicje wynosi dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny s otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 23. s znak równości otwórz nawias okrągły otwórz nawias okrągły unsigned int zamknij nawias okrągły pow otwórz nawias okrągły A przecinek b zamknij nawias okrągły zamknij nawias okrągły procent p średnik prawy ukośnik prawy ukośnik Bob oblicza s.
Linia 25. cout otwórz nawias ostrokątny otwórz nawias ostrokątny cudzysłów s obliczone przez Boba wynosi dwukropek cudzysłów otwórz nawias ostrokątny otwórz nawias ostrokątny s otwórz nawias ostrokątny otwórz nawias ostrokątny endl średnik.
Linia 27. return 0 średnik.
Linia 28. zamknij nawias klamrowy.
Wynikiem działania programu byłoby wypisanie następujących wiadomości:
Linia 1. A Alicji wynosi dwukropek 28.
Linia 2. B Boba wynosi dwukropek 4.
Linia 3. s obliczone przez Alicje wynosi dwukropek 28.
Linia 4. s obliczone przez Boba wynosi dwukropek 28.
Ważne!
Ze względu na sposób typowania zmiennych w języku C++ szyfrowanie asymetryczne nie jest proste do zaimplementowania, a na potrzeby tego e‑materiału korzystaliśmy z małych wartości p, g, a i b. Duże wartości, wykorzystywane w realnych sytuacjach, doprowadziłyby do przekroczenia zakresu zmiennej typu unsigned int.
Słownik
determinizm
determinizm
algorytm deterministyczny jest całkowicie określony przez warunki początkowe (parametry); oznacza to, że kilkukrotne uruchomienie algorytmu doprowadzi za każdym razem do takiego samego wyniku
generator liczb pseudolosowych
generator liczb pseudolosowych
funkcja (lub program) generująca na podstawie ziarna (z ang. seed) deterministyczny ciąg bitów, który wydaje się losowy
okres ciągu
okres ciągu
liczba taka, że dla wszystkich indeksów prawdziwe jest stwierdzenie, że – oznacza to, że wartości ciągu powtarzają się co pozycji