background image

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.

background image

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.jsBar-
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

background image

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

>

background image

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

)

;

$email

 = 

$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

,

$email

,

$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-

background image

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.phpindex.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

)

;

    

}

  })

;

}

background image

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