Na szczęście postęp w matematyce i kryptografii jest równie nieustanny co w konstruowaniu coraz szybszych procesorów. Na horyzoncie pojawił się wprawdzie komputer kwantowy, oferujący teoretycznie możliwość błyskawicznego łamania współczesnych szyfrów, jednak na jego pojawienie się – nawet w ściśle strzeżonych serwerowniach rządów największych mocarstw – musimy jeszcze długo zaczekać. Dlatego proponujemy naszym Czytelnikom krótką wycieczkę w świat kluczy i kryptogramów. Będzie to podróż o tyle ciekawa, że pozwalająca własnoręcznie spróbować sił w trudnym rzemiośle przechytrzania złodziei informacji. Spróbujemy mianowicie napisać w popularnym Delphi kilka programów ilustrujących proste techniki kryptologiczne. Używając opisywanych tu algorytmów, nie zaskoczymy wprawdzie NSA ani BSA, jednak nabyte doświadczenia pozwolą poznać podstawy konstruowania programów szyfrujących i deszyfrujących dane. Potrzebna będzie w zasadzie dowolna wersja wspomnianego środowiska programistycznego Borlanda – w tym również darmowa edycja Personal. Z ramki na końcu tekstu można się dowiedzieć, jak znaleźć np. Delphi 7 Personal.
Czy Czarek “rotował”?
Jeden z pierwszych szyfrów w dziejach ludzkości (a przynajmniej pierwszy znany historykom) ochrzczono mianem szyfru Cezara. Nazwa pochodzi oczywiście od imienia jego użytkownika, rzymskiego wodza Juliusza Cezara. Algorytm kodowania był bardzo prosty – polegał na zamianie każdej litery alfabetu łacińskiego na występującą trzy znaki dalej (“A” zamieniano więc na “D”, “B” na “E”, “C” na “F” itd.). Metoda, choć nieskomplikowana, sprawdzała się w owych czasach znakomicie.
Każdy, kto zna internetowy sposób “ukrywania” treści postów na grupach dyskusyjnych (czyli ROT-13), stwierdzi z pewnością, że szyfr Cezara to nic innego, jak kodowanie ROT-3. Jedyna różnica jest taka, że szyfrowanie i deszyfrowanie w ROT-13 wygląda identycznie (angielski alfabet ma 26 liter), a adresaci listów Cezara, chcąc przeczytać korespondencję, musieli się “cofać” w alfabecie o trzy litery.
Choć szyfr ROT-13 nie ma dziś żadnej wartości kryptograficznej, zaczniemy naszą naukę od utworzenia aplikacji kodującej tekst zgodnie ze wspomnianym algorytmem. Będziemy ją potem wzbogacać nieco bardziej zaawansowanymi możliwościami.
Otwieramy nowy projekt w
Delphi
(
File | New | Application
) i dodajemy do formularza komponenty Edit, Memo i cztery przyciski (
Button
). Potrzebny jeszcze będzie komponent OpenDialog z palety Dialogs. Okno naszej przyszłej aplikacji może wyglądać tak jak na sąsiedniej ilustracji.
Będziemy szyfrowali zawartość pliku tekstowego, który przed i po zakodowaniu załadujemy – dla celów poglądowych – do komponentu TMemo. Samo szyfrowanie wykonamy, korzystając z obiektów strumieniowych typu
TFileStream
– taka metoda obsługi plików przyda się nam w kolejnych omawianych przykładach. Najpierw w polu typu TEdit wpisujemy (lub wybieramy, korzystając z okna dialogowego typu
TOpenFile
) ścieżkę do zbioru z tekstem. Kolejny krok to skorzystanie z procedury ROT13Cipher, wywoływanej po kliknięciu przycisku Zaszyfruj. Procedura ta w przykładowym programie (można go znaleźć na dołączonym krążku CD, w katalogu przyklad_1 z archiwum
przyklady.zip
– patrz:
ramka “Więcej informacji”
) ma następującą postać:
procedure TForm1.ROT13Cipher
(FileName: String);
var
IOFile: TFileStream;
buf: char;
begin
IOFile:= TFileStream.Create
(FileName, fmOpenReadWrite);
try
while IOFile.Position <
IOFile.Size do begin
IOFile.ReadBuffer(buf, 1);
if buf in [‘A’..’Z’] then
buf:= char(((ord(buf) – 65
+ 13) mod 26) + 65);
if buf in [‘a’..’z’] then
buf:= char(((ord(buf) – 97
+ 13) mod 26) + 97);
IOFile.Seek(-1, soFromCurrent);
IOFile.WriteBuffer(buf, 1);
end;
finally
IOFile.Free;
end;
Memo1.Lines.LoadFromFile
(Edit1.Text);
end;
Strumień IOFile tworzymy za pomocą metody TFileStream.Create. Zasadnicza część procedury to instrukcja try… finally… end. Pobieramy w niej kolejne bajty ze strumienia reprezentującego nasz plik tekstowy (metodą
IOFile.ReadBuffer
) i zmieniamy kody znaków. Pozornie zagmatwane polecenie kodujące znaki w alfabecie pozwala bezpośrednio zastosować operację dzielenia modulo 26. “Przesuwamy” tablice małych i dużych liter do pozycji zerowej, odejmując odpowiednio 65 i 97 od kodu znaku, szyfrujemy, dodając do kodu 13, po czym dodajemy wcześniej odjętą wartość przesunięcia w tablicy ASCII. Wszystko staje się jasne, gdy rzucimy okiem na tabelę kodów znaków w tablicy ASCII (można ją znaleźć w wielu książkach dla programistów i w Internecie). Ważne jest jedynie to, że nasz algorytm (podobnie jak oryginalny ROT-13) nie modyfikuje polskich znaków diakrytycznych – przepisujemy je bez zmian do pliku wyjściowego.
Teraz pozostaje tylko cofnąć metodą TFileStream.Seek wskaźnik pliku (zapisujemy dane do tego samego strumienia, z którego je odczytujemy) i zapisać zmodyfikowany znak (
IOFile.WriteBuffer
). Na koniec ładujemy zaszyfrowany plik na powrót do komponentu TMemo. Drobna uwaga: przed utworzeniem strumienia IOFile warto sprawdzić (np. funkcją FileExist z modułu
SysUtils Delphi
), czy użytkownik wpisał poprawną nazwę pliku do zaszyfrowania.
Ponieważ algorytm ROT-13 działa symetrycznie, możemy użyć tej samej procedury do kodowania i odszyfrowywania tekstu. Drobna przeróbka przykładowego programu (skorzystanie bezpośrednio z właściwości TMemo.Lines zamiast z zawartości pliku i obiektu
TFileStream
) pozwoli kodować zawartość tekstu wklejanego przez Schowek systemowy do pola Memo1 .