Bezpieczeństwo
www.phpsolmag.org
32
PHP Solutions Nr 6/2006
RSA w PHP
Bezpieczeństwo
www.phpsolmag.org
33
PHP Solutions Nr 6/2006
N
ieodłączną częścią każdego me-
chanizmu logowania użytkowni-
ków jest przesyłanie hasła wpi-
sanego na komputerze klienta (w przy-
padku aplikacji webowych – w przeglą-
darce internetowej) na serwer, na którym
(przeważnie w bazie danych) przechowy-
wane są skróty MD5 haseł (zob. Ramka
Podstawy MD5). Ponieważ te skróty są
jednokierunkowe i odtworzenie haseł na
ich podstawie nie jest możliwe, więc kra-
dzież bazy nie da sprawcy wielu możli-
wości włamania. Poważnym problemem
jest natomiast wspomniane już przesyła-
nie hasła jako czystego tekstu: wystarczy,
aby intruz podsłuchał transmisję pomiędzy
klientem a serwerem (np. za pomocą snif-
fera), a będzie mógł bez problemu doko-
nać agresji.
W poprzednim numerze PHP So-
lutions, w artykule Kryptografia w PHP
prezentowaliśmy rozwiązanie tego pro-
blemu przy użyciu algorytmu HMAC-
MD5 po stronie klienta na wpisywanym
Zabezpieczenie aplikacji PHP przed włamaniami
to nie wsystko: jeżeli przesyłamy dane czystym
tekstem, zawsze może się znależć ktoś,
kto je przechwyci podsłuchując transmisję
w Internecie. Aby zadbać o bezpieczeństwo
danych, musimy więc sięgnąc po kryptografię
asymetryczną RSA, która daje obecnie
największą pewność jego ochrony i zastosować
ją zarówno po stronie serwera, jak i klienta.
haśle. Algorytm ten (w naszym przy-
padku zaimplementowany w języku Ja-
vaScript i działający na przeglądarce
internetowej) zamienia hasło na spe-
cjalny hash, podczas generowania któ-
rego używany jest również tajny klucz.
Następnie, otrzymany skrót jest wysy-
łany do serwera, gdzie – podobnie jak
przy sprawdzaniu hasła przesyłanego
czystym tekstem – jest porównywany
z hashami zapisanymi w bazie danych.
Korzystając z tej metody wyeliminuje-
my ryzyko podsłuchu (nie przesyłamy
RSA w PHP: chronimy nasze
dane przy użyciu kryptografii
asymetrycznej
Kamil Karczmarczyk
W SIECI
1. http://pear.php.net/package/
Crypt_RSA/ – klasa
Crypt_RSA (PHP)
2. http://pear.php.net/package/
Crypt_Blowfish/ – klasa
Crypt_Blowfish (PHP)
3. http://ohdave.com/rsa/ – Im-
plementacja RSA (JS)
4. http://en.wikipedia.org/wiki/
RSA – Opis algorytmu RSA
5. http://en.wikipedia.org/wiki/
Blowfish_(cipher) – Opis
algorytmu Blowfish
6. http://advajax.anakin.us/
– Obiekt advancedAJAX
Stopień trudności: ll
l
Co należy wiedzieć...
Należy znać podstawy programowania
w PHP oraz AJAX. Przydatna będzie też
podstawowa wiedza na temat kryptografii.
Co obiecujemy...
Pokażemy zasadę działania algorytmu
asymetrycznego RSA i zademonstruje-
my, jak przy jego użyciu stworzyć system
bezpiecznego logowania.
Bezpieczeństwo
www.phpsolmag.org
32
PHP Solutions Nr 6/2006
RSA w PHP
Bezpieczeństwo
www.phpsolmag.org
33
PHP Solutions Nr 6/2006
samego hasła, lecz jego skrót), ale mo-
żemy jej użyć wyłącznie wobec już ist-
niejących haseł, których skróty zostały
utworzone i zapisane w bazie na ser-
werze. W jaki sposób więc przeprowa-
dzimy proces rejestracji nowego kon-
ta na serwerze? Musimy w końcu prze-
słać na serwer informacje o nowym ha-
śle: z oczywistych powodów nie chce-
my tego robić przy użyciu czystego
tekstu; przesyłanie skrótu takiego ha-
sła również nie uchroni nas przed nie-
bezpieczeństwem podsłuchu: ktoś, kto
w tym momencie przechwyci ten skrót
(rozpozna, że chodzi o dodawanie no-
wego konta np. po danych wysyłanych
z formularza), będzie mógł go potem
zwyczajnie wykorzystać przy logowa-
niu się na serwerze. Szyfrowanie da-
nych za pomocą klucza symetryczne-
go (np.3DES lub twofish) również nie
wchodzi w grę, gdyż taki klucz musiał-
by być znany zarówno klientowi, jak i
serwerowi, co oznacza konieczność je-
go transmisji przez Internet oraz czy-
ni go podatnym na podsłuch. Jedy-
nym sensownym rozwiązaniem proble-
mu zabezpieczenia hasła będzie uży-
cie asymetrycznego algorytmu szy-
frującego RSA. Algorytm ten działa w
oparciu o dwa klucze: publiczny (który
jest ogólnie dostępny) i prywatny (do-
stępny wyłącznie na serwerze). Wię-
cej informacji na temat algorytmu RSA
zamieściliśmy w Ramce RSA: Zasada
działania.
Tworzymy system
bezpiecznego logowania
dla aplikacji „Notatki
osobiste”
Pokażemy teraz, jak wykorzystać algorytm
szyfrujący RSA w PHP, tworząc system
bezpiecznego logowania dla aplikacji
Notatki osobiste, która będzie służyła jako
nasz osobisty notatnik online.
Założenia
Chcemy, aby nasza aplikacja posiadała
system logowania poszczególnych użyt-
kowników oraz możliwość dodawania no-
wych kont. Każdy posiadacz konta będzie
mógł wyświetlać swoje notatki, a także do-
dawać nowe. Cała komunikacja pomiędzy
klientem a serwerem będzie szyfrowana.
Przygotowania
Tworząc nasz system bezpiecznego
logowania skorzystamy z gotowych
implementacji algorytmów szyfrowania,
zarówno tych działających po stronie
serwera (w PHP), jak i klienta (w języku
JavaScript). W pierwszym przypadku,
do szyfrowania za pomocą RSA posłuży
nam klasa Crypt_RSA z repozytorium
PEAR (pear.php.net). Po stronie klienta
użyjemy natomiast implementacji algo-
rytmu RSA w języku JavaScript umiesz-
czonej na stronie http://ohdave.com/rsa/.
Musimy z niej pobrać pliki: BigInt.js, Bar-
rett.js oraz RSA.js. Wymianę danych
będziemy obsługiwać przy pomocy
technologii AJAX, a konkretnie projektu
advAJAX (zarówno o tym projekcie, jak
i o technologii AJAX pisaliśmy w nume-
rze 1/2006). Pobieramy więc plik adva-
jax.js ze strony http://advajax.anakin.us
i zabieramy się do pracy.
Rejestracja kont
Obsługą procesu rejestracji nowych kont
zajmą się trzy pliki:
register.php – będzie odpowiadał za
wyświetlenie formularza zakładania
konta wraz z wygenerowanym wcze-
śniej kluczem publicznym,
Podstawy MD5
MD5 jest algorytmem haszującym, zwa-
nym również jednokierunkową funkcją
skrótu. W wyniku jego działania, w
oparciu o podstawione dane powstaje
unikalny 128-bitowy skrót. Odtworze-
nie danych na jego podstawie nie jest
możliwe. Unikalność i jednokierunko-
wość działania MD5 umożliwia jego za-
stosowanie np. przy sprawdzaniu haseł
(na serwerze zamieszczane są jedynie
skróty haseł, aby uniemożliwić prze-
chwycenie samych haseł w razie kra-
dzieży danych), podpisywaniu plików
– umieszczanym w wielu repozytoriach
plikom towarzyszą skróty MD5: oblicza-
jąc skrót pobranego pliku i porównując
go z tym zamieszczonym na serwerze
możemy sprawdzić, czy archiwum nie
jest uszkodzone (to samo da się zasto-
sować np. przy porównywaniu zawar-
tości wypalonej płyty CD lub DVD z jej
obrazem, choć trwa to dość długo).
RSA: Zasada działania
RSA to pierwszy (wynaleziony w 1977 roku) i obecnie najpopularniejszy algorytm szyfro-
wania asymetrycznego, używany powszechnie np. w handlu elektronicznym czy w celu
podpisywania emaili. Zasadę działania algorytmu RSA przedstawiamy na Rysunku 1. Je-
go idea (jak każdego szyfru asymetrycznego) polega na użyciu dwóch k luczy: publiczne-
go i prywatnego. Oba z nich są generowane przez odbiorcę wiadomości, po czym klucz
publiczny jest jawnie przesyłany nadawcy wiadomości, może też być zamieszczony np. na
stronie WWW do pobrania. Nadawca szyfruje tekst za pomocą klucza publicznego i wysy-
ła go odbiorcy. Zaszyfrowany tekst można z kolei odszyfrować tylko kluczem prywatnym,
który posiada odbiorca. Nie wnikając w teorię matematyczną, która leży u podstaw RSA,
warto zapamiętać, że klucz publiczny składa się z dwóch części: wykładnika publicznego
(ang. public exponent) i modułu (ang. modulus), a klucz prywatny – z wykładnika prywat-
nego (ang. private exponent) i tego samego modułu – te informacje będą nam potrzebne
później, gdy będziemy korzystali z klas PEAR-owych do obsługi RSA.
Rysunek 1.
Schemat działania RSA
RSA w PHP
Bezpieczeństwo
www.phpsolmag.org
34
PHP Solutions Nr 6/2006
register.js – będzie w nim następo-
wało szyfrowanie danych zawartych
w formularzu oraz ich wysyłanie na
serwer,
register2.php – w tym pliku nastą-
pi odszyfrowanie danych i założenie
konta.
Generowanie kluczy
Spójrzmy na Listing 1, na którym za-
mieściliśmy plik register.php. Zacznie-
my od wygenerowania pary kluczy
(publicznego i prywatnego) poprzez
utworzenie obiektu
$key_pair
klasy
Crypt_RSA_KeyPair
oraz użycie jej me-
tod
getPublicKey()
i
getPrivateKey()
.
Oba wygenerowane klucze stanowią
osobne obiekty, z których następnie
wydobywamy oba wspomniane wcze-
śniej (zob. Ramka RSA: zasada dzia-
łania) wykładniki (
getExponent()
) oraz
moduł (
getModulus()
). Następnie se-
rializujemy (serialize()) i zapisujemy w
sesji obiekt
$key_pair
do późniejszego
wykorzystania oraz konwertujemy klucz
publiczny (a właściwie jego wykładnik i
moduł) z postaci binarnej na wartość
szesnastkową (
bin2hex()
), ponieważ
algorytm RSA, z którego będziemy ko-
rzystać po stronie przeglądarki, wyma-
ga podania danych dotyczących klucza
właśnie w takim formacie. Po wykona-
niu tych operacji przechodzimy do ge-
nerowania formularza dodawania kon-
ta (kod HTML). Jedynym dynamicznym
elementem, który umieścimy w tym ko-
dzie, będzie osadzony w prezentowa-
nym pliku fragment skryptu JavaScript,
który odpowiada za dołączenie plików:
advajax.js, BigInt.js, Barrett.js i RSA.js
oraz utworzenie zmiennych JavaScript
enc_exp
i
modulus
, przechowujących
wartość wykładnika publicznego (szy-
frującego) i modułu.
Szyfrowanie
Spójrzmy teraz na Listing 2, na którym
przedstawiamy napisany w języku Ja-
vaScript obiekt
updateObjects()
(pa-
miętajmy, że w JavaScript nie ma klas,
tylko pojedyncze obiekty, definiowane
analogicznie, jak funkcje). Będzie on
wywoływany przy wystąpieniu zdarze-
nia
onload
zdefiniowanego w znacz-
niku
<body>
, czyli po każdym załado-
waniu strony WWW umieszczonej po-
między
<body>
a
</body>
. Wewnątrz
updateObjects()
tworzymy parę kluczy
RSA, czyli obiekt
RSAKeyPair
, na pod-
Listing 1.
Plik register.php – generowanie kluczy i wyswietlenie formularza
<?
php
session_start
()
;
// generowanie pary kluczy
require_once
'Crypt/RSA.php'
;
$key_pair
=
new
Crypt_RSA_KeyPair
(
512
)
;
$public_key
=
$key_pair
-
>
getPublicKey
()
;
$private_key
=
$key_pair
-
>
getPrivateKey
()
;
$enc_exp
=
$public_key
-
>
getExponent
()
;
$dec_exp
=
$private_key
-
>
getExponent
()
;
$modulus
=
$public_key
-
>
getModulus
()
;
// zapamiętanie danych do późniejszego dekodowania
$_SESSION
[
'rsa'
]
=serialize
(
$key_pair
)
;
// konwersja danych do szyfrowania na kod szesnastkowy (heksadecymalny)
$enc_exponent
= bin2hex
(
$enc_exp
)
;
$mod
= bin2hex
(
$modulus
)
;
?>
<
html
>
<
head
>
<
title
>
MyNotes - registration
<
/title
>
<
meta http-equiv=
"Content-type"
content=
"text/html; charset=utf-8"
/
>
<
script type=
"text/javascript"
src=
"advajax.js"
><
/script
>
<
script type=
"text/javascript"
src=
"BigInt.js"
><
/script
>
<
script type=
"text/javascript"
src=
"Barrett.js"
><
/script
>
<
script type=
"text/javascript"
src=
"RSA.js"
><
/script
>
<!-- skrypt obsługujący formularz za pomocą AJAX -->
<
script type=
"text/javascript"
src=
"register.js"
><
/script
>
<
script type=
"text/javascript"
>
var
enc_exp =
"<?=
$enc_exponent
?>"
;
var
modulus =
"<?=
$mod
?>"
;
<
/script
>
<
/head
>
<
body onload=
"updateObjects()"
>
<
b
>
MyNotes - Registration
<
/b
><
br/
>
<
form method=
"post"
action=
"register2.php"
id=
"registerForm"
>
<
label for=
"username"
>
Login:
<
/label
>
<
input type=
"text"
name=
"username"
id=
"username"
/
><
br/
>
<
label for=
"password"
>
Password:
<
/label
>
<
input type=
"password"
name=
"password"
id=
"password"
/
><
br/
>
<
label for=
"name"
>
e-mail:
<
/label
>
<
input type=
"text"
name=
"email"
id=
"email"
/
><
br/
>
<
label for=
"name"
>
Name:
<
/label
>
<
input type=
"text"
name=
"name"
id=
"name"
/
><
br/
>
<
label for=
"surname"
>
Surname:
<
/label
>
<
input type=
"text"
name=
"surname"
id=
"surname"
/
><
br/
>
<
input type=
"submit"
value=
"Register"
id=
"submitBtn"
/
>
<
/form
>
<
div style=
"margin-top: 10px"
id=
"response"
><
/div
>
<
/body
>
<
/html
>
RSA w PHP
Bezpieczeństwo
www.phpsolmag.org
35
PHP Solutions Nr 6/2006
stawie publicznego wykładnika i modu-
łu. Prywatny wykładnik nie jest nam po-
trzebny, więc wpisujemy 0. Następnie
wdrażamy obsługę formularza za po-
mocą obiektu
advAJAX
. Metoda
assign
pobiera (jako parametr) nazwę formula-
rza oraz obiekt zawierający metody je-
go obsługi. Funkcja
OnInitialization
jest wykonywana jeszcze przed wysła-
niem formularza. To w niej następuje
Listing 2.
Plik register.js – szyfrowanie i wysyłanie danych
function
updateObjects
() {
var
key;
key =
new
RSAKeyPair
(
enc_exp,
0
,modulus
)
;
function
$
(
id
) {
return
document.getElementById
(
id
)
;
}
advAJAX.assign
(
$
(
"registerForm"
)
,
{
onInitialization :
function
(
obj
) {
// szyfrowanie danych z formularza
obj.parameters
[
"username"
]
=encryptedString
(
key,obj.parameters
[
"username"
])
;
obj.parameters
[
"password"
]
=encryptedString
(
key,obj.parameters
[
"password"
])
;
obj.parameters
[
"email"
]
=encryptedString
(
key,obj.parameters
[
"email"
])
;
obj.parameters
[
"name"
]
=encryptedString
(
key,obj.parameters
[
"name"
])
;
obj.parameters
[
"surname"
]
=encryptedString
(
key,obj.parameters
[
"surname"
])
;
}
,
onSuccess :
function
(
obj
) {
$
(
"response"
)
.innerHTML=obj.responseText;
}
,
onError :
function
() {
alert
(
"Can't connect to server."
)
;
}
})
;
}
Listing 3.
Plik register2.php – deszyfrowanie i zapisanie danych nowego usera
<?
php
session_start
()
;
require_once
'Crypt/RSA.php'
;
// odczytanie przechowywanego obiektu (kluczy)
$rsa_keys
= unserialize
(
$_SESSION
[
'rsa'
])
;
$priv
=
$rsa_keys
-
>
getPrivateKey
()
;
$rsa_obj
=
new
Crypt_RSA;
// deszyfrowanie
$username
=
$rsa_obj
-
>
decryptBinary
(
hex2bin
(
$_POST
[
'username'
])
,
$priv
)
;
$password
=
$rsa_obj
-
>
decryptBinary
(
hex2bin
(
$_POST
[
'password'
])
,
$priv
)
;
=
$rsa_obj
-
>
decryptBinary
(
hex2bin
(
$_POST
[
'email'
])
,
$priv
)
;
$name
=
$rsa_obj
-
>
decryptBinary
(
hex2bin
(
$_POST
[
'name'
])
,
$priv
)
;
$surname
=
$rsa_obj
-
>
decryptBinary
(
hex2bin
(
$_POST
[
'surname'
])
,
$priv
)
;
// tworzenie nowego konta
$user
=
new
user;
$result
=
$user
-
>
register
(
$username
,
$password
,
,
$name
,
$surname
)
;
if
(
$result
)
{
echo
"Your account are successfully created."
;
}
else
{
echo
"error: your account can't created!"
;
}
?>
Listing 4.
Funkcja hex2bin
function
hex2bin
(
$hex
)
{
$str
=
""
;
for
(
$i
=
0
;
$i
<
strlen
(
$hex
)
;
$i
=
$i
+
2
)
{
$str
.=
chr
(
hexdec
(
substr
(
$hex
,
$i
,
2
)))
;
}
return
$str
;
}
szyfrowanie przesyłanych danych, czyli
wartości wszystkich pól formularza (na-
zwy użytkownika, hasła, adresu ema-
il, imienia i nazwiska) za pomocą al-
gorytmu RSA. Funkcja
onSuccess
wy-
świetla wewnątrz znacznika
<div>
(o
id=”response”
) dane zwrócone przez
plik register2.php, do którego wysłali-
śmy wprowadzone w formularzu war-
tości.
Deszyfrowanie i tworzenie konta
Przejdźmy do omówienia zawartości
wspomnianego już pliku register2.php
(Listing 3). Otrzymuje on przekazane za
pomocą advAJAX dane z formularza,
które musimy teraz odszyfrować. Posłu-
żymy się do tego zapisanym wcześniej
w sesji jako
rsa
obiektem
$key_pair
,
który nazwiemy
$rsa_keys
i zdeseria-
lizujemy (
unserialize()
). Następnie
wydobędziemy z tego obiektu klucz
prywatny, który także będzie obiektem
o nazwie
$priv
. Potem utworzymy nowy
obiekt
$rsa_obj
klasy
Crypt_
RSA i wy-
wołujemy jego metodę
DecryptBinary()
odpowiedzialną
za
deszyfrowanie
danych (każdego z przesłanych pól for-
mularza z osobna). Metoda ta przyjmuje
dwa parametry: zaszyfrowany tekst oraz
utworzony przez nas wcześniej klucz
prywatny
$priv
(obiekt klasy
Crypt_RSA_
KeyPair
). Ponieważ dane pochodzące
z formularza zostały po zaszyfrowaniu
przekonwertowane na system szesnast-
kowy, więc musimy je przywrócić do
formy binarnej przy użyciu funkcji he-
x2bin(), którą napiszemy sami (Listing 4),
gdyż nie została ona zaimplementowana
w PHP.
Mając odszyfrowane dane użyt-
kownika, możemy przystąpić do jego
rejestracji w serwisie. Robimy to np.
przy pomocy klasy
user
, której imple-
mentację pominęliśmy, gdyż nie jest
ona istotna dla ukazania technik kryp-
tograficznych.
Kryptografia hybrydowa
Jako kryptografia hybrydowa rozumiane
jest jednoczesne użycie kryptografii sy-
metrycznej i asymetrycznej. Dotychczas
szyfrowaliśmy dane tylko w jednym kie-
runku: od użytkownika do serwera. Aby
zrealizować nasz projekt, będziemy jed-
nak potrzebowali szyfrowania dwukierun-
kowego, gdyż w jedną stronę będziemy
wysyłali nasz login i hasło oraz dodawali
nowe notatki, a w drugą – wyświetlali ist-
niejące notatki. Zabezpieczenie danych
przy tych czynnościach za pomoca sa-
mego RSA byłoby trudne, wykorzystamy
więc dodatkowo symetryczny algorytm
blowfish.
Przygotowania
Będziemy więc potrzebowali implemen-
tacji algorytmu blowfish. W PHP posłu-
żymy się do tego klasą Crypt_Blowfish
z repozytorium PEAR. Po stronie prze-
RSA w PHP
Bezpieczeństwo
www.phpsolmag.org
36
PHP Solutions Nr 6/2006
glądarki internetowej, obsługą blowfisha
zajmie się plik encrypt.js, który możemy
pobrać ze strony www.farfarfar.com lub
bezpośrednio z http://limak.blg.pl/crypto/
encrypt.js. Cała nasza aplikacja, podob-
nie jak to było w przypadku rejestracji,
będzie się składała z trzech plików:
index.php, index.js i index2.php, których
zadanie jest analogiczne do plików z po-
przedniego przykładu.
Logowanie
Spójrzmy na Listing 5. Przedstawia-
my na nim fragment pliku index.php
– w miejscu, w którym różni się on
od register.php. Dołączamy w nim też
skrypt encrypt.js w języku JavaScript,
który odpowiada za szyfrowanie i de-
szyfrowanie algorytmem blowfish. Tym
razem zagnieździmy nasz formularz
wewnątrz znacznika
<div>
, któremu
nadamy id
html
: później będziemy dy-
namicznie zastępowali ten fragment
kodu inną treścią.
Obsługa AJAX
Różnice między plikiem index.js a regi-
ster.js są znacznie większe, niż pomię-
dzy index.php a register.php. Na Listin-
gu 6 prezentujemy obsługę praktycznie
całej szyfrowanej wymiany pomiędzy
plikami index.php i index2.php. Tworzy-
my w nim zarówno klucz asymetrycz-
ny dla algorytmu RSA, jak i losowy ciąg
znaków będący kluczem symetrycznym
blowfish.
Następnie korzystamy ze znanego
już nam obiektu
advAJAX
, który wystę-
puje trzykrotnie. Pierwszy raz odwołu-
je się do formularza
loginForm
(
advA-
JAX.assign
) i za pomocą RSA szyfru-
je login, hasło oraz dodatkowo wyge-
nerowany klucz blowfish, a następnie
przekazuje je do pliku login2.php. Od
tej pory, po otrzymaniu klucza blow-
fish przez serwer, wymiana szyfrowa-
nych danych odbywa się przy pomo-
cy algorytmu symetrycznego. RSA było
potrzebne jedynie do przesłania syme-
trycznego klucza.
Gdy teraz będziemy chcieli wyświe-
tlić wszystkie nasze notatki, wywoła-
my funkcję
goto()
z parametrem
note
,
aby w odpowiedzi z pliku index2.php
otrzymać zaszyfrowany fragment ko-
du odpowiedzialny za ich wyświetle-
nie. To, w jaki sposób plik index2.php
szyfruje dane, widzimy na Listingu 7.
Aby odpowiednio zaszyfrować i odszy-
Listing 5.
Formularz logowania
// ...
<
script type=
"text/javascript"
src=
"encrypt.js"
><
/script
>
//...
<
body onload=
"updateObjects()"
>
<
b
>
MyNotes - Your own on-line notices
<
/b
><
br/
>
<
div id=
"html"
>
<
form method=
"post"
action=
"index2.php"
id=
"loginForm"
>
<
label for=
"username"
>
Login:
<
/label
>
<
input type=
"text"
name=
"username"
id=
"username"
/
><
br/
>
<
label for=
"password"
>
Password:
<
/label
>
<
input type=
"password"
name=
"password"
id=
"password"
/
><
br/
>
<
input type=
"hidden"
name=
"blowfish"
id=
"blowfish"
value=
""
/
>
<
input type=
"submit"
value=
"Login"
id=
"submitBtn"
/
>
<
/div
>
Listing 6.
index.js – obsługa AJAX
function
updateObjects
() {
// tworzenie klucza publicznego
var
key;
key =
new
RSAKeyPair
(
enc_exp,
0
,modulus
)
;
// tworzenie klucza symetrycznego
var
blowfishKey =
""
;
var
chars=
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
var
i;
for
(
i=
0
; i<
25
; i++
) {
blowfishKey += chars.charAt
(
Math.floor
(
Math.random
()
*
62
))
}
document.forms
[
"loginForm"
]
.elements
[
"blowfish"
]
.value=blowfishKey;
function
$
(
id
) {
return
document.getElementById
(
id
)
;
}
advAJAX.assign
(
$
(
"loginForm"
)
,
{
onInitialization :
function
(
obj
) {
// szyfrowanie danych z formularza (RSA))
obj.parameters
[
"username"
]
= encryptedString
(
key, obj.parameters
[
"username"
])
;
obj.parameters
[
"password"
]
= encryptedString
(
key, obj.parameters
[
"password"
])
;
obj.parameters
[
"blowfish"
]
= encryptedString
(
key, blowfishKey
)
;
}
,
onSuccess :
function
(
obj
) {
// deszyfrowanie blowfish
$
(
"html"
)
.innerHTML = secureDecrypt
(
obj.responseText, blowfishKey
)
;
}
})
;
advAJAX.assign
(
$
(
"addNoteForm"
)
,
{
onInitialization :
function
(
obj
) {
// szyfrowanie blowfish
obj.parameters
[
"title"
]
= secureEncrypt
(
obj.parameters
[
"title"
]
,
blowfishKey
)
;
obj.parameters
[
"note"
]
= secureEncrypt
(
obj.parameters
[
"note"
]
,
blowfishKey
)
;
}
,
onSuccess :
function
(
obj
) {
$
(
"html"
)
.innerHTML = obj.responseText;
}
})
;
}
function goto
(
page, pageid=
0
) {
advAJAX.post
({
url :
"index2.php?page="
+page+
"&pageid="
+pageid,
onSuccess :
function
(
obj
) {
$
(
"html"
)
.innerHTML = secureDecrypt
(
obj.responseText, blowfishKey
)
;
}
})
;
}
RSA w PHP
Bezpieczeństwo
www.phpsolmag.org
37
PHP Solutions Nr 6/2006
frować dane, po stronie przeglądarki
używamy w skrypcie JavaScript funk-
cji
secureEncrypt()
i
secureDecrypt()
,
natomiast w PHP wykorzystujemy PE-
AR-ową klasę
Crypt_Blowfish
, która
jest bardzo intuicyjna i prosta w uży-
ciu. Z listingów możemy wywniosko-
wać, że sam proces przesyłania nowej
notatki w formie zaszyfrowanej (obiekt
advAJAX z parametrem odwołującym
się do formularza
AddNoteForm
) oraz
jej deszyfrowanie z poziomu PHP jest
praktycznie identyczny, jak w przypad-
ku pobierania istniejącej notatki z ser-
wera, tyle że kolejność wykonywania
czynności jest odwrotna.
Podsumowanie
W przedstawionej aplikacji pokazali-
śmy, w jaki sposób można skorzystać
z dwóch metod kryptograficznych (asy-
metrycznej i symetrycznej) oraz poda-
liśmy przykładowe zastosowanie tych
technik. Potęga RSA w połączeniu z
prostotą języka PHP jak też z całkiem
niezłą funkcjonalnością JavaScrip-
tu umożliwia tworzenie naprawdę bez-
piecznych aplikacji, które będą odpor-
ne na podsłuch i przechwytywanie da-
nych.
Zachęcamy do korzystania z krypto-
grafii we własnych projektach – zwłasz-
cza tam, gdzie poufność przesyłanych i
gromadzonych danych jest szczególnie
istotna, poczynając od aplikacji do gro-
madzenia prywatnych notatek i syste-
mów przekazywania wiadomości osobi-
stych, poprzez narzędzia używane we-
wnątrz firmy (np. do zarządzania pro-
jektem, danymi księgowymi czy biz-
nesplanem), po dostępne dla tysię-
cy użytkowników jednocześnie syste-
my e-commerce, takie jak sklepy inter-
netowe czy pasaże aukcyjne. Na pohy-
bel intruzom!
n
Kamil Karczmarczyk jest uczniem Li-
ceum Ogólnokształcącego. Od kilku lat
hobbystycznie zajmuje się programowa-
niem, między innymi w PHP. Interesuje
się bezpieczeństwem sieci, kryptografią
oraz matematyką.
Kontakt z autorem:
limak@mmj.pl
Listing 7.
Zawartość pliku index2.php
<?
php
session_start
()
;
require_once
'Crypt/RSA.php'
;
require_once
'Crypt/Blowfish.php'
;
echo
"<a href=\"javascript:goto('notes')\">my notes</a> | "
;
echo
"<a href=\"javascript:goto('addnote')\">add note</a> | "
;
echo
"<a href=\"javascript:goto('logout')\">logout</a><br/><br/>"
;
if
(
!
isset
(
$_GET
[
'page'
]))
{
// logowanie
$rsa_keys
= unserialize
(
$_SESSION
[
'rsa'
])
;
$priv
=
$rsa_keys
-
>
getPrivateKey
()
;
$rsa_obj
=
new
Crypt_RSA;
$username
=
$rsa_obj
-
>
decryptBinary
(
hex2bin
(
$_POST
[
'username'
])
,
$priv
)
;
$password
=
$rsa_obj
-
>
decryptBinary
(
hex2bin
(
$_POST
[
'password'
])
,
$priv
)
;
$blowfishKey
=
$rsa_obj
-
>
decryptBinary
(
hex2bin
(
$_POST
[
'blowfish'
])
,
$priv
)
;
$_SESSION
[
'username'
]
=
$username
;
$_SESSION
[
'password'
]
=
$password
;
$_SESSION
[
'blowfishKey'
]
=
$blowfishKey
;
$user
=
new
user
(
$username
,
$password
)
;
$notes
=
$user
-
>
getNotes
()
;
$html
=
""
;
foreach
(
$notes
as
$note
)
{
$html
.="
<
a href=\
"javascript:goto('note','"
.$note[
'id'
].
"')\"
>
";
$html
.=
$note
[
'title'
]
."
<
/a
><
br/
>
";
}
$blowfish
=
new
Crypt_Blowfish
(
$blowfishKey
)
;
echo
(
base64_encode
(
$blowfish
-
>
Encrypt
(
$html
)))
;
}
else
if
(
$_GET
[
'page'
]
==
"addnote"
)
{
// wyświetlanie formularza
$html
=
<<<
heredochtml
<
form method=
"post"
action=
"index2.php=addnote2"
id=
"addNoteForm"
>
<
label for=
"title"
>
title:
<
/label
>
<
input type=
"text"
name=
"title"
id=
"title"
/
><
br/
>
<
textarea name=
"note"
id=
"note"
><
/textarea
><
br/
>
<
input type=
"submit"
value=
"add"
id=
"submitBtn"
/
>
<
/form
>
heredochtml;
$blowfish
=
new
Crypt_Blowfish
(
$_SESSION
[
'blowfishKey'
])
;
echo
(
base64_encode
(
$blowfish
-
>
Encrypt
(
$html
)))
;
}
else
if
(
$_GET
[
'page'
]
==
"addnote2"
)
{
// dodawanie notatki
$user
=
new
user
(
$_SESSION
[
'username'
]
,
$_SESSION
[
'password'
])
;
// ustawienie klucza blowfish
$blowfish
=
new
Crypt_Blowfish
(
$_SESSION
[
'blowfishKey'
])
;
//deszyfrowanie blowfish
$title
=
$blowfish
-
>
decrypt
(
base64_decode
(
$_POST
[
'title'
]))
;
$noteText
=
$blowfish
-
>
decrypt
(
base64_decode
(
$_POST
[
'note'
]))
;
//dodawanie notki
$user
-
>
addNote
(
$title
,
$noteText
)
;
echo
"new note added"
;
}
else
if
((
$_GET
[
'page'
]
==
"note"
)
&&
(
isset
(
$_GET
[
'pageid'
])))
{
// wyświetlanie notki
$user
=
new
user
(
$_SESSION
[
'username'
]
,
$_SESSION
[
'password'
])
;
$note
=
$user
-
>
getNoteById
(
$_GET
[
'pageid'
])
;
$html
= "
<
b
>
".$note['title']."
<
/b
><
br/
>
";
$html
.= "
<
p
>
".$note['text']."
<
/p
>
";
$blowfish
=
new
Crypt_Blowfish
(
$_SESSION
[
'blowfishKey'
])
;
echo
(
base64_encode
(
$blowfish
-
>
Encrypt
(
$html
)))
;
}
?>
O autorze