Tworzenie algorytmów kryptograficznych - poza wielką satysfakcją - sprawia jednak wiele trudności. Poniżej znajduje się kilka funkcji kryptograficznych, które napisałem, aby umożliwić zaszyfrowanie dowolnej wiadomości. Funkcje te stworzyłem jeszcze podczas studiów, ale nie straciły one na aktualności i są dobrym materiałem do prac nad własnymi rozwiązaniami.
Tryb blokowy CBC
CBC (Cipher Block Chaining), tryb szyfrowania wiadomości za pomocą szyfru blokowego, w którym przed zaszyfrowaniem każdy z bloków wiadomości jest przekształcany funkcją XOR z szyfrogramem, uzyskanym z szyfrowania poprzedniego bloku wiadomości. Pierwszy blok wiadomości jest szyfrowany za pomocą wylosowanego ciągu bitów (wektor inicjujący), dołączanego do wiadomości.
Poniższy algorytm napisany w języku Pascal, demonstruje działanie trybu blokowego CBC przy użycia dodatkowego autorskiego algorytmu PseudoDES opisanego w dalszej części tego artykułu.
ECB (Electronic CodeBook), tryb elektronicznej książki kodowej jest to najprostszy tryb kodowania dużej wiadomości za pomocą szyfru blokowego. Wiadomość dzielimy na fragmenty odpowiadające wielkości bloku (M1, M2, M3, ..., Mn) i szyfrujemy każdy blok osobno: Ci = E(Mi). Do zaszyfrowania bloków można użyć dowolnego algorytmu kryptograficznego (np. Pseudo DES lub Vigenere opisanych w dalszej części).
Tryb ECB napisany w języku Pascal.
functionecb(sTekst:string;sKlucz:string;byDlugoscBloku:byte):string;variX,iY:integer;sA,sB:string;beginiX:=0;sA:='';sB:='';repeatinc(iX,byDlugoscBloku);foriY:=iX-byDlugoscBloku+1toiXdoifiY<=Length(sTekst)thensA:=sA+sTekst[iY];// tutaj nastepuje szyfrowanie bloku przy uzyciu dowolnego
// algorytmu kryptograficznego (np. pseudoDES)
sB:=sB+pseudoDES(sA,sKlucz);sA:='';until(iX>=Length(sTekst));result:=sB;end;
Tryb ECB napisany w PHP.
/**
* @param string $text tekst do przetworzenia
* @param string $key klucz
* @param int $block ilosc blokow
* @param bool $crypt szyfruj lub odszyfruj
*
* @return string
*/functionecb($text,$key,$block,$crypt){$x=0;$a='';$b='';do{$x+=$block;for($y=$x-$block;$y<$x;$y++){if($y<=strlen($text)){$a.=$text[$y];}}// tutaj nastepuje szyfrowanie bloku przy uzyciu dowolnego// algorytmu kryptograficznego (np. Vigenere)$b.=vigenere($a,$key,$crypt);$a=null;}while($x<strlen($text));return$b;}
Tryb ECB napisany w C#.
stringecb(stringText,stringKey,intBlock,boolCrypt){intx=0;inty=0;stringa=string.Empty;stringb=string.Empty;do{x+=Block;for(y=x-Block;y<x;y++){if(y<Text.Length){a+=Text[y];}}// tutaj nastepuje szyfrowanie bloku przy uzyciu dowolnego// algorytmu kryptograficznego (np. Vigenere)b+=Vigenere(a,Key,Crypt);a=null;}while(x<Text.Length);returnb;}
Szyfr Cezara
Nazwa szyfru pochodzi od Juliusza Cezara, rzymskiego wodza i polityka. Szyfrował on listy o znaczeniu wojskowym do swoich generałów, używając szyfru przesuwającego z przesunięciem 3. Z tego powodu niekiedy szyfrem Cezara określa się wyłącznie szyfr przesuwający o przesunięciu 3 (symetryczny), zaś termin "szyfr przesuwający" jest zarezerwowany dla przypadku ogólnego.
Poniższy algorytm napisany w języku Pascal umożliwa przesunięcie o dowolną ilość znaków.
functionSzyfrujCezarem(bOdszyfruj:boolean;cZnak:char;iPrzesuniecie:integer):char;varsTablicaZnakow:string;iX,iY:byte;begin// tablica znakow (w oryginalnej wersji 26 znakow lacinskich)
sTablicaZnakow:='!@#$%^&*()-_=+[];,./?\|"ABCDEFGHIJKLMNOPQRSTUWXYZabcdefghijklmnopqrstuwxyz1234567890 ';// w przypadku odszyfrowywania zmieniamy pozycje przesuniecia
ifbOdszyfrujtheniPrzesuniecie:=(length(sTablicaZnakow))-iPrzesuniecie;iX:=ansipos(cZnak,sTablicaZnakow);ifiX<>0thenbeginifiX+iPrzesuniecie>length(sTablicaZnakow)thenbeginiY:=length(sTablicaZnakow)-iX;iY:=iPrzesuniecie-iY;result:=sTablicaZnakow[iY];endelseresult:=sTablicaZnakow[iX+iPrzesuniecie];endelseresult:=cZnak;end;
Prosta funkcja skrótu
Zaprezentowana funkcja skrótu napisana w języku Pascal umożliwia wygenerowanie dowolnej długości ciąg znaków, zbudowany z wcześniej zadeklarowanej tablicy znakowej. Wykonana przeze mnie funkcja skrótu opiera się na porównywaniu wartości kodów ASCII wprowadzonych znaków oraz ich przesuwaniu względem obliczonej pozycji, wykorzystując przy tym zadeklarowaną tablicę znaków, z której ma zostać zbudowany hash. Testy, które przeprowadziłem na moim algorytmie, doprowadziły mnie do kilku wniosków:
większą skuteczność algorytmu osiąga się poprzez wprowadzenie minimum takiej ilości znaków, jaka ma powstać na wyjściu (w przypadku opisanego poniżej algorytmu jest to 16 znaków),
prędkość działania algorytmu uzależniona jest od długości tekstu, z którego ma być wygenerowany hash - im dłuższy tekst tym dłuższy czas operacji. Słabość ta niestety wyklucza algorytm do pracy z plikami w celu obliczania sum kontrolnych.
// funkcja pomocnicza, ktorej zadaniem jest pobranie znaku z tablicy przesunietego
// o podana ilosc miejsc (szyfr Cezara)
function_obliczPrzesuniecie(sTablica:string;cLitera:char;iPrzesuniecie:integer):char;variX,iY:integer;beginiX:=AnsiPos(cLitera,sTablica);ifiX+iPrzesuniecie>Length(sTablica)thenbeginiY:=iX+iPrzesuniecie;repeatiY:=abs(Length(sTablica)-(iY));until(iY<Length(sTablica));ifiY=0theniY:=Length(sTablica);result:=sTablica[iY];endelseresult:=sTablica[iX+iPrzesuniecie];end;functionutworzSkrot(sTekst:string):string;varsTablica,sA,sB:string;iIlosc,iX,iY:integer;begin// ilosc znakow na wyjsciu funkcji
iIlosc:=16;// tablica znakow, z ktorych ma zostac wygenerowany skrot
sTablica:='ABCDEFGHIJKLMNOPQRSTUWXYZabcdefghijklmnopqrstuwxyz1234567890';ifLength(sTekst)<=iIloscthenbeginsA:=sTekst;repeatsA:=sA+sTablica[Length(sA)];until(Length(sA)>iIlosc);sTekst:=sA;end;sA:=sTekst;iY:=1;repeatsB:='';foriX:=1toLength(sA)-1dobeginifOrd(sA[iX])>Ord(sA[iX+1])thenbeginiY:=iY+Ord(sA[iX]);sB:=sB+_obliczPrzesuniecie(sTablica,_obliczPrzesuniecie(sTablica,sTablica[1],iY),Ord(sA[iX+1]))endelsebeginiY:=iY+Ord(sA[iX+1]);sB:=sB+_obliczPrzesuniecie(sTablica,_obliczPrzesuniecie(sTablica,sTablica[1],iY),Ord(sA[iX]));end;end;sA:=sB;until(Length(sA)<=iIlosc);result:=sA;end;
Szyfr Vigenere'a
Jeden z pierwszych algorytmów kryptograficznych (symetryczny). Zasada działania opiera się na tablicy, w której każdy z wierszy odpowiada szyfrowi Cezara, przy czym w pierwszym wierszu przesunięcie wynosi 0, w drugim 1 itd. Aby zaszyfrować tekst potrzebne jest słowo kluczowe. Słowo kluczowe jest tajne i mówi, z którego wiersza (lub kolumny) należy w danym momencie skorzystać.
Szyfr Vigenere'a napisany w języku Pascal.
functionSzyfrujVigenere(sTekst:string;sKlucz:string;bSzyfruj:boolean):string;variX,iY,iZ,iI:integer;sTablicaZnakow,sWynik,sNowyKlucz:string;begin// tablica znakow (w oryginalnej wersji 26 znakow lacinskich)
sTablicaZnakow:='!@#$%^&*()-_=+[];,./?\|"ABCDEFGHIJKLMNOPQRSTUWXYZabcdefghijklmnopqrstuwxyz1234567890 ';// obliczamy znak odwrotny na podstawie
// oryginalnego wzoru: K2(i) = 26 - K(i) mod 26
ifnotbszyfrujthenbeginforiI:=1tolength(sKlucz)dosNowyKlucz:=sNowyKlucz+sTablicaZnakow[(length(sTablicaZnakow)-ansipos(sKlucz[iI],sTablicaZnakow)+2)modlength(sTablicaZnakow)];sKlucz:=sNowyKlucz;end;// jesli klucz jest krotszy od dlugosci tekstu
// uzupelniamy go o odpowiednia wielokrotnosc
sNowyKlucz:=sKlucz;iflength(sTekst)>length(sKlucz)thenforiI:=0to(length(sTekst)divlength(sKlucz))dosNowyKlucz:=sNowyKlucz+sKlucz;sKlucz:=sNowyKlucz;foriI:=1tolength(sTekst)dobeginiX:=ansipos(sTekst[iI],sTablicaZnakow);iY:=ansipos(sKlucz[iI],sTablicaZnakow);if(iX+iY>length(sTablicaZnakow))thenbeginifiX+iY-length(sTablicaZnakow)-1<>0thensWynik:=sWynik+sTablicaZnakow[(iX+iY)-length(sTablicaZnakow)-1]elsesWynik:=sWynik+sTablicaZnakow[length(sTablicaZnakow)];endelsesWynik:=sWynik+sTablicaZnakow[iX+iY-1];end;result:=sWynik;end;
Szyfr Vigenere'a napisany w PHP.
/**
* @param string $text tekst do zaszyfrowania
* @param string $key klucz szyfrujacy
* @param bool $crypt szyfruj lub odszyfruj tekst
*
* @return string
*/functionvigenere($text,$key,$crypt){$availableCharacters="!@#$%^&*()-_=+[];,./?\|\"ABCDEFGHIJKLMNOPQRSTUWXYZabcdefghijklmnopqrstuwxyz1234567890 ";// obliczamy znak odwrotny na podstawie// oryginalnego wzoru: K2(i) = 26 - K(i) mod 26if(!$crypt){$newKey='';for($i=0;$i<strlen($key);$i++){$newKey.=$availableCharacters[(strlen($availableCharacters)-strpos($availableCharacters,$key[$i])+2)%strlen($availableCharacters)];}$key=$newKey;}// jesli klucz jest krotszy od dlugosci tekstu// uzupelniamy go o odpowiednia wielokrotnosc$newKey=$key;if(strlen($text)>strlen($key)){for($i=0;$i<strlen($text)/strlen($key);$i++){$newKey.=$key;}}$key=$newKey;$results='';for($i=0;$i<strlen($text);$i++){$x=strpos($availableCharacters,$text[$i]);$y=strpos($availableCharacters,$key[$i]);if($x+$y>strlen($availableCharacters)){if($x+$y-strlen($availableCharacters)!=0){$results.=$availableCharacters[$x+$y-strlen($availableCharacters)-1];}else{$results.=$availableCharacters[strlen($availableCharacters)];}}else{$results.=$availableCharacters[$x+$y-1];}}return$results;}
Szyfr Vigenere'a napisany w C#.
stringVigenere(stringText,stringKey,boolCrypt){intx;inty;stringNewKey=string.Empty;stringResults=string.Empty;stringAvailableCharacters="!@#$%^&*()-_=+[]:;,./?\\|\"ABCDEFGHIJKLMNOPQRSTUWXYZabcdefghijklmnopqrstuwxyz1234567890 ";// obliczamy znak odwrotny na podstawie// oryginalnego wzoru: K2(i) = 26 - K(i) mod 26if(!Crypt){for(inti=0;i<Key.Length;i++){NewKey+=AvailableCharacters[(AvailableCharacters.Length-AvailableCharacters.IndexOf(Key[i])+2)%AvailableCharacters.Length];}Key=NewKey;}// jesli klucz jest krotszy od dlugosci tekstu// uzupelniamy go o odpowiednia wielokrotnoscNewKey=Key;if(Text.Length>Key.Length){for(inti=0;i<Text.Length/Key.Length;i++){NewKey+=Key;}}Key=NewKey;for(inti=0;i<Text.Length;i++){x=AvailableCharacters.IndexOf(Text[i]);y=AvailableCharacters.IndexOf(Key[i]);if(x+y>AvailableCharacters.Length){if(x+y-AvailableCharacters.Length!=0){Results+=AvailableCharacters[x+y-AvailableCharacters.Length-1];}else{Results+=AvailableCharacters[AvailableCharacters.Length];}}else{Results+=AvailableCharacters[x+y-1];}}returnResults;}
Pseudo DES
Prosty algorytm kryptograficzny (symetryczny) napisany w języku Pascal, którego zadaniem jest XOR-owanie dowolnego tekstu z kluczem. Proszę pamiętać, że ciąg znaków uzyskany na wyjściu jest w formacie ASCII. Odszyfrowanie następuję poprzez ponowne zaszyfrowanie tekstu z tym samym kluczem.