Nowa Enigma

Jednym z najstarszych i po dziś dzień najlepszych sposobów ukrywania informacji przed oczami niepowołanych osób jest jej zaszyfrowanie. Metody kodowania np. ważnych listów były znane już od starożytności – przykładem może być omawiany w dalszej części tekstu tzw. szyfr Cezara. Pierwsze “poważne” (czyli wymagające sporo pracy nad ich złamaniem nawet od niezłego matematyka) techniki kryptograficzne zaczęto jednak stosować dopiero w trakcie i po II wojnie światowej. Warto przy tym zauważyć, że termin “bezpieczne szyfrowanie” bardzo szybko zaczął zmieniać swoje znaczenie wraz z rozwojem techniki komputerowej. Wynikało to głównie z faktu, że większość szyfrów da się złamać tzw. metodą siłową (brute force) – inaczej mówiąc, każdy szyfrogram można odkodować, jest to jedynie kwestią czasu i wykorzystanego do tego celu sprzętu.

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 .

Więcej:bezcatnews