Sunteți pe pagina 1din 63

INTRODUCERE.................................................................................

CAPITOLUL I. Pirateria software......................................................


CAPITOLUL II. Tabele hash . Scopul tabelelor de dispersie (hash
tables)........................................................................................................
CAPITOLUL III ALGORITMUL MD5......................................................
3.1 Introducere.........................................................................................
3.2 Terminologia i notaiile..................................................................
3.3 Descrierea algoritmului MD5...
3.4 Diferena dintre MD4 i MD5...
Bibliografie..
ANEXA....

INTRODUCERE

1. Programe pentru testarea securitii


Controlul securitii ntr-un sistem UNIX nu este o sarcin uoar. Arborescena de
fiiere i cataloage a devenit din ce n ce mai voluminoas la ultimele versiuni. O simpl
comand:
Find /usr xdev print| wc l
poate avea un rezultat de ordinul zecilor de mii de fiiere. Acest numr imens de fiiere,
programe i cataloage face din sistemul UNIX un colos destul de greu de controlat.
n ultima vreme au aprut multe programe care pot verifica automat dac un sistem
UNIX prezint puncte slabe din punct de vedere al securitii. Aceste programe pot testa un
calculator sau o intreag reea de calculatoare, fcnd o mulime de teste de securitate ntr-un
interval de timp relativ scurt. Cteva dintre programele de acest gen sunt: COPS, SATAN,
ISS, Tiger, PASSWD+, NPASSWD.
Acest tip de programe pot fi folosite att de sprgtorii de sisteme, pentru gsirea
eventualelor, portie de intrare, ct i de ctre administratorii de sistem, ca instrumente
pentru verificarea propriilor sisteme i eliminarea acestor slbiciuni. Multe din aceste
programe sunt freeware, putnd fi procurate de oricine din Internet sau de diferite BBS-uri.
Din acest motiv, este indicat ca administratorul s le foloseasc primul pentru testarea
sistemului su, nainte ca un atacator s o fac.
Instrumentele de testare a securitii realizeaz automat verificarea multor din aspectele
de securitate, alctuind rapoarte cu problemele gsite i dnd astfel posibilitate
administratorului s corecteze aceste probleme. Procurarea acestor programe trebuie fcut
din surse sigure. Altfel, se pot obine programe rau-intenionate, care s pretind a scana
sistemul sau s-i provoace daune. De aceea, se recomand folosirea de ctre administratorii
de sistem doar acelor programe procurate din Internet de la adrese sigure(de exemplu, CERT,
Perdue University, Texas University) i ale cror funcionaliti i rezultate le poi nelege.
Exist i pachete comerciale de programe pentru verificarea sistemului. Avantajul
acestora este acela de a fi precompilate i uor de instalat. Ele sunt proiectate pentru

verificarea unor grupuri de siesteme UNIX care sunt conectate la reea, fcnd sarcina
admnistratorului mai uoar.
1.1

COPS (Computer Oracle and Password System)

Unul dintre cele mai puternice i cunoscute pachete de instrumente pentru verificarea
securitii unui sistem UNIX este COPS (Computer Oracle and Password System), scris de
Dan Framer. COPS este scris n Bourne Shell i n C, fiind portabil atit pe sisteme System V
ct i pe BSD. n plus, are inclus i o versiune Perl, care ofer cteva faciliti suplimentare.
COPS conine un set de programe care fac verificri automate ale securitii sistemului.
Astfel de verificri sunt, deseori, efectuate manual de ctre un administrator de sistem.
Fiecare din utilitarele de verificare din COPS testeaz o anumit arie din securitatea unui
sistem UNIX, care verific urmatoarele:
Permisiunile de acces pentru fiiere, cataloage , dispozitive periferice;
Sigurana parolelor(dac pot fi uor sparte);
Coninutul, formatul i securitatea fiierului de parole i a fiierului de grupuri;
Programe i fiierele ce ruleaz n /etc/rc* i fiierele cron(tab);
Existena fiierelor SUID-root, accesabilitatea lor la scriere si dac acestea sunt sau
nu script-uri Shell;
CRC-ul pentru fiierele binare importante i pentru fiierele cheie, raportndu-se
schimbrile aprute n acestea;
Accesabilitatea la scriere a directoarelor de referin ale utilizatorilor i a fiierelor
lor de configrare(.profile, .cshrc);
Setarea pentru ftp anonim;
tftp nerestricionat, alias pentru decode n sendmail, Shell-uri ascunse n interiorul
fiierului inetd.conf, rexd rulnd n inetd.conf,
diferite verificri la nivel de root directorul curent n calea curent, un + n
fiierul /host/host.equiv, montri nerestricionate de NFS, verificarea c root este
n /etc/ftpusers;
3

sistemul expert Kunag. Acesta ncearc s determine, folosind un set de reguli, dac
sistemul poate fi compromis.
n funcie de configurare, COPS alctuiete un fiier coninnd un raport complet al
problemelor gsite sau trimite un mesaj pe pota electronic, coninnd aceste problme,
unui anumit utilizator. COPS nu ncearc s corecteze problemele gsite. Din acest
motiv, programul nu trebuie rulat neaprat cu privelegii de root. Singurul caz n care
aceste privelegii pot fi necesare este verificarea pentru SUID. Pentru gsirea tuturor
programelor SUID din sistem, COPS trebuie rulat ca root.
COPS include i un instrument pentru a fi folosit de ctre utilizatorii individuali,
numit chkacct. Acesta verific permisiunile de scriere pentru fiierele de configurare,
grup i alte fiiere sensibile. De asemenea, chkacct verific corectitudinea fiierului
.rhosts.
Este recomandat a se ine o eviden foarte precis a modificarilor i corectitudinilor
fcute la sugestiile date de COPS. COPS este foarte flexibil, fiind uor de adugat la
verificrile sale curente noi script-uri de testare.
Pachetul de programe COPS poate fi procurat dintr-o surs sigur, prin ftp anonym,
la adresa:
ftp://info.cert.org/pub/tools/cops/cops_104/cops-104.tar.z
1.2. Programe pentru spart parole
O metod pentru mpiedicarea utilizatorilor de pe un sistem UNIX s aleg parole uor
de ghicit este aceea c administratorul de sistem s ruleze periodic un program de spart
parole, pentru fiierul /etc/passwd de pe sistemul pe care l gestioneaz. Programele din
aceast categorie folosesc unu sau mai multe dicionare, pentru a furniza cuvintele folosite
n ghicirea parolei. Aceste programe folosesc un algoritm eficient pentru criptarea
cuvintelor presupuse a fi parole i apoi, le compar cu variantele criptate din fiierul de
parole.

Dintre cele mai folosite programe pentru spart parole menionm: Crack, PASSWD+,
NPASSWD.
SATAN
Dei numele poate sugera altceva, SATAN (Security Analysis Tool for Auditing
Networks) este un instrument pentru analiza i monitorizarea securitii reelelor, scria Dan
Framer i Wietse Venema.
n modul de funcionare implicit, SATAN colecteaz informaii despre ct mai multe
reele i calculatoare gazd situate la distan, prin examinarea unor servicii de reea cum
ara fi finger, NFS, NIS, ftp, tftp, rexd i altele. Informaia astfel acumulat include
descrierea prezenei diferitelor servicii de informare n reea, ca i a unor posibile probleme
de securitate de obicei sub forma unor definiri incorecte de parametri, a unor configurri
inadecvate a serviciilor de reea, a unor bine cunoscute scame n utilitarele de sistem i de
reea sau a unor decizii strategice luate n necunotin de cauz. Programul poate s
raporteze informaiile astfel obinute sau poate folosi un sistem expert pentru a investiga n
continuare orice probleme posibile de securitate. Utilizatorii pot examina, interoga i
analiza ieirea generat folosind un navigator HTML cum ar fi Mosaic, Netscape sau Lynx.
Se poate obine o mare cantitate de informaii n timpul utilizrii progamului:
topologia reelei, serviciile de reea ce ruleaz, tipurile de hardware i software ce sunt
utilizate n reeaua respectiv. Puterea real a lui SATAN se remarc atunci cnd este folosit
n modul explorare. n acest mod, funcionarea progamului se bazeaz pe o colecie iniial
de date i pe un set de reguli configurabile de ctre utilizator, pe care SATAN le va folosi n
examinarea traseielor de ncredere i a dependenelor, n scopul realizrii a unor colecii de
date suplimentare, ce vor fi rulate pe calculatoarele gazd secundare.
Cu toate c SATAN nu folosete metode posibile pentru a testa neregulile din sistem,
el a reuit cu regularitate s gseasc lipsurile din securitatea site-urilor INTERNET:
A) Cerine de sistem
Dei SATAN nu este universal portabil, el ruleaz pe un numr destul de mare de
sisteme UNIX.
5

La ora actual, SATAN poate rula pe urmtoarele sisteme de operare:


o SunOS 4.1.3_U1 (i alte versiuni);
o SunOS 5.3;
o Irix 5.3;
o AIX;
o Sisteme BSD;
o IRIX 5;
o HP-UX 9.x;
o SYSV-R4;
o Ultrix 4.x;
o Linux (cu puin efort);
SATAN a fost testat pe urmtoarele maini:
o Staii SPARC4/75;
o Staii SPARC 5;
o Indigo 2;
Sunt necesari aproximativ 20MB pe disc pentru a instala toate pachetele suplimentare
i programele SATAN. Cea mai mare parte a acestui spaiu este necesar datorit pachetelor
software, n special Mosaic sau Netscape si Persl5. SATAN singur, inclusiv documentaia
ocup doar 2 MB. Dac programele suplimentare sunt deja instalate, nu mai este necesar
reinstalarea lor. Dac se folosesc doar fiierele binare, pot fi necesari doar 5MB pentru o
instalare complet.
Memoria necesar depinde foarte mult de ct de multe calculatoare gazd sunt
verificate sau se gsesc n baza de date:
Pentru scanarea a aproximativ 1.500 de calculatoare gazd, sunt necesari 14 MB
de memorie pe un Sparc 4/75, rulnd SunOS 4.1.3;
Pentru scanarea a aproximativ 4.700 de calculatoare gazd, sunt necesari 35 MB
de memorie pe un Indigo 2;
6

n cazul unei memorii insuficiente, varinata swapping este nesatisfctoare.


SATAN ruleaz n conjuncie cu alte cteva pachete software. Pentru a putea folosi
programul, este necesar ca n sistemul pe care se instaleaz SATAN s fie prezente i
pachetele:
Perl 5.001
Mosaic 2.5
Netscape 1.0
B) Arhitectura SATAN i modul su de lucru
SATAN are o arhitectur extensibil. Partea central este construit dintr-un nucleu
generic, ce cunoate destul de puine sau nimic despre tipurile de sisteme, numele
serviciilor de reea, vulnerabilitatile sau alte detalii. Cunotine despre acestea sunt
nglobate ntr-o mic colecie de date i de reguli de baza. Comportamentul SATAN este
controlat prin intermediul unui fiier de configurare. Configurrile pot fi modificate prin
opiuni de date din linia de comand sau prin intermediul unei interfee hypertext.
Nucleul SATAN este construit din urmtoarele pari principale:
Maina de operare: determin, folosind setrile din fiierul de configurare, dac un
calculator gazd trebuie verificat sau nu i ce nivel de verificare este adecvat pentru
respectivul calculator;
Achiziia de inte: genereaz o list de verificri ce vor fi rulate pentru calculatoarele
gazd din fiierul de configurare. Aceast list servete ca intrare pentru subsistemul
de achiziie de date i controleaz ramificaia subreelelor;
Achiziia de date: folosind lista de teste furnizat de subsistemul anterior, ruleaz
instrumentele respective pentru colectarea de date i genereaz date noi ce vor servi
ca intrare pentru maina de interfa;
Maina de interfa: folosind datele furnizate de subsistemul anterior, genereaz noi
nume de calculatoare gazd, noi teste i date. Noile calculatoare gazd vor servi ca

intrare pentru subsistemul de achiziie de inte. Noile teste vor fi folosite de


subsistemul de achiziie de date, iar noile date sunt procesate de maina de interfa;
Rapoarte i analiz: acest subsistem ia datele colectate i construiete un hiperspaiu
virtual ce poate fi explorat ca un navigator.
Subsistemul de achiziie de inte folosete fpring pentru a determina dac un
calculator gazd sau o mulime de calculatoare gazd dintr-o subreea sunt active sau nu.
El paseaz aceast list mainii de interferen ce controleaza colecia de date i bucla
principala de analiz. Fiecare calculator gazd este verificat pentru a se vedea dac a mai
fost analizat anterior i dac nu se ruleaz un set de teste pentru el. Testele genereaz o
nregistrare de date ce conine numele calculatorului gazd, testul i alte rezultate ce au
fost gsite n urma verificrilor. Aceste nregistrri sunt salvate n fiier pentru a putea fi
analizate ulterior.
C) Instalarea si configurarea programului.
Pentru instalarea programului, ntr-o prim faz se va folosi comanda make pentru
compilarea programului i obinerea fiierelor binare. Apoi se va edita corespunztor
fiierul de configurare. Dup aceste aciuni, se poate rula SATAN, folosind interfaa
HTML, prin simpla introducere a comenzii SATAN sau din linia de comand. SATAN
trebuie rulat cu drepturi de superuser (root).
Dup ce s-a rulat partea de testare, utilizatorul va lansa din nou intrefaa HTML i
va selecta seciunea de rapoarte i analiz.
Fiierul de configurare pentru SATAN este extrem de important. Apropape orice
aciune a programului n decursul verificrii reelelor i a calculatoarelor gazd este
controlat prin intermediul acestui fiier: la ce nivel se verific intele, ct de departe vor
fi transmise testele fa de calculatorul original. Acest fiier poate fi modificat n 2 feluri:
Prin intermediul interfeei HTML;
Prin editare manual;

Acest fiier conine cod perl ce este rulat la iniailizarea programului. ntelegerea
i modificarea sa sunt destul de uor de realizat, chiar i pentru utilizatorii necunosctori
de Perl.
D) Analiza ie;irii furnizate de SATAN
Interpretarea eficient a rezultatelor oferite de verificrile SATAN este partea cea mai
dificil n utilizarea acestui instrument. Aceasta se datorete n parte i faptului c nu exist
o definiie foarte clar a nivelului de securitate. Obinerea unei securiti bune depinde de
politica folosit i de site-ul sau sistemul analizat. n plus, unele dintre conceptele folosite
n SATAN i multe dintre opiunile sale pot s nu fie familiare multora dintre
administratorii de sistem.
n rapoartele fcute de SATAN, dac exist un calculator gazd marcat cu punct rou,
aceasta nseamn c respectivul calculator prezint o vulnerabilitate ce ar putea s-l
compromit. Un punct negru semnific negsirea nici unui fel de vulnerabilitate pentru
respectivul calculator. Acionarea cu mouse-ul a legturilor va determina oferirea mai
multor informaii despre calculatorul gazd, reea sau vulnerabiliti.
Din panoul de control al interfeei HTML se va selecta SATAN Reporting&Data
Analysis. Aceast selecie va determina afiarea unui numr de opiuni. La prima folosire a
programului SATAN, cel mai mare interes pentru utilizator l va prezenta seciunea
Vulnerabilities. n aceast seciune, punctul de pornire cel mai bun este legptura spre
nivelul de periculozitate. Dac acolo nu se gsesc nici un fel de atenionri, nseamn c
SATAN nu a gsit nici o problem, dar aceasta nu d, totui, sigurana ca respectivul
calculator gazd este sigur.
Cel mai bun mod n care se poate nva SATAN este prin utilizarea lui, verificnd
reele, apoi, examinnd rezultatele cu instrumentele de raportare i analiz. Verificarea
altor calculatoare gazd, fr a avea permisiunea, poate da natere la confuzii,
administratorii acestora putnd suspecta aceste ncercri ca atacuri asupra sistemelor lor.

1.3. ISS
Internet Security Scanner a fost dezvoltat de Christopher Klaus. El a fost lansat ca
produs shareware n 1992. ISS a fost proiectat pentru ai ajuta pe administratorii de sistem i
pentru a monitoriza vulnerabilitile de securitate ale reelei datorate serviciilor TCP/IP ale
calculatorului gazd. De cnd a aprut i pna n prezent, ISS a fost folosit de multe firme i
corporaii pentru detectarea vulnerabilitilor din mediile de operare din reea.
Datorit cererilor multiple din partea utilizatorilor pentru actualizarea ISS, n 1994 a
fost lansat o noua versiune numit Internet Scanner. Aceast versiune comercial, complet
rescris, a fost adaptat pentru a verifica vulnerabilitile recent descoperite. n plus, noua
versiune include o interfa utilizator grafic, raportare mbuntit a evalurilor de risc,
scanare paralel, verificarea vulnerabilitilor pentru web i firewall, pentru Window 95/NT.
Versiunea actual de Internet Scanner este 3.2 i este actualizat de 4-6 ori pe an.
ISS 1.x a fost dezvoltat pentru a asista administratorii de sistem s descopere
vulnerabilitile reelei. ISS 1.x este un instrument elementar, cu mod de lucru din linia de
comand, neavnd o interfa grafic. Ieirea generate reprezint ieirea fiecrui test
efectuat i necesit un administrator de sistem experimentat, pentru a putea interpreta
corespunztor i pentru a putea rezolva probleme de securitate aprute.
Teste efectuate de ISS 1.x:
1) identificarea tipului de calculator gazd;
2) teste sendmail:
alias-uri
depanrea i verificarea ieirilor luntrice
3) FTP
Verificri pentru ftp anonim;
Verificarea permisiunilor de scriere n directorul principal
4) RPC obinerea de informaii portmapper
5) NIS
10

6) Selection_svc-permite obinerea fiierului de parole;


7) Rexd permite accesul la distan;
8) NFS
9) Rusers informaii despre utilizatorii conectai;
10) X25 posibile pori pentru intrui.

11

CAPITOLUL I. Pirateria software


Pirateria software reprezint multiplicarea neautorizat a programelor pentru
calculator. Cu toate c majoritatea utilizatorilor de programe sunt contieni c aceast
multiplicare este ilegal, muli nesocotesc importana tratrii acestor produse ca
proprietate intelectual de valoare i care nu le aparine.
Conform unui raport al Asociaiei pentru Industria de Software i Informaiei, n
anul 2000 s-au vndut, la nivelul mondial, produse software n valoare de 22 miliarde de
dolari, n timp ce, pierderile provocate datorit pirateriei au fost estimate la aproximativ
12 miliarde de dolari.
Dezvoltarea unei aplicaii software implic o investiie major de timp, bani i
munc. Pirateria software priveaz productorul de beneficiile cuvenite, dar poate afecta
i relaiile cu clienii ce pot intra n posesia unor copii ilegale ce nu funcioneaz corect.
Din aceste cauze, o puternic protecie intelectual a produselor software este important
i aduce o serie de beneficii:
ncurajeaz crearea de noi aplicaii software, ct i mbuntirea celor deja
existente;
ncurajeaz dezvoltarea industriei de software, aflat n strns legatur cu
industria de hardware;
ajut la promovarea de noi tehnologii i idei;
promoveaz investiiile n economia naional.
Eliminarea sau reducerea pirateriei software reprezint i creterea veniturilor
companiilor productoare de soft, acestea avnd posibilitatea de a investi mai mult n
imbuntirea propriilor produse, lansarea pe pia la preuri competitive, facndu-le
accesibile unui numr mai mare de utilizatori, crearea de noi locuri de munc etc.

12

1.1. Hardware Against Software Piracy - prezentare generala


Azi, din ce n ce mai multe companii productoare de software aleg o protecie
activ pentru produsele lansate pe piaa, crescndu-i astfel vnzrile i numrul
utilizatorilor nregistrai. Aceste companii folosesc ultima generaie de protecie
hardware mpotriva pirateriei software, denumit Hardware Against Software Piracy
(HASP).
Prin definiie, HASP este un sistem hardware ce protejeaz software-ul unei
companii mpotriva utilizrii i copierii ilegale. Protecia se realizeaz prin prevenirea
accesului neautorizat la execuia programului protejat.
Facilitile avansate de codare ale sistemelor HASP permit o mai bun integrare a
componentelor hardware n programele ce vor fi protejate. Funciile inteligente prezente
n cheia de protecie determin programul codat s devin dependent de prezena
acesteia, n caz contrar, execuia sa fiind oprit. Cu alte cuvinte, la rularea aplicaiei
protejate, aceasta cere sistemului HASP (cheia pentru portul paralel sau USB)
autorizaia de funcionare. Dac algoritmul gsit este cel corect, aplicaia se lanseaz n
execuie. Dac rspunsul primit de la HASP nu este valabil, aplicaia poate refuza s
ruleze sau s o fac n mod Demo, ori s-i limiteze din funcionaliti.
Toate datele folosite de o aplicaie pot fi codate i trimise ctre sistemul HASP
pentru decodare i validare n orice moment, acest sistem de protecie nsemnnd mai
mult dect simpla verificare a prezenei unui dispozitiv ataat computerului.
1.2. Sistemele Hardware Against Software Piracy4
HASP 4 este ultima generaie de sisteme de protecie hardware create de
compania Aladdin, proiectate pentru a stabili noi standarde de performan i siguran.
Aceste sisteme de protecie mpotriva pirateriei i utilizrii ilegale a programelor de
calculator previn accesul neautorizat i execuia aplicaiilor protejate, oferind
13

productorului posibilitatea de a distribui versiuni demo, de a controla cu precizie


procesul de liceniere i chiar a ctiga piee noi de desfacere, n paralel cu creterea
veniturilor.
Sistemele HASP4 sunt disponibile n mai multe versiuni, cu memorie sau fr,
pentru portul paralel sau USB, pentru utilizare n reea sau pe un singur computer. De
asemenea, HASP4 are suport pentru diverse compilatoare ce ruleaz sub Windows
3.x/95/98/ME/2000/NT/XP, DOS, Mac OS X si Linux.
Productorul unei aplicaii software i poate proteja proprietatea intelectual prin
dou metode:
n codul surs al programului se insereaz poriuni de cod HASP care verific
existena sistemului de protecie, oricnd n timpul funcionrii programului. Dup
compilare, rezult un executabil care nu ruleaz fr cheia HASP, sau, dac o
face, va fi n mod Demo sau cu limitri de timp, dup cum hotarte
programatorul. Aceast metod este foarte eficient, protecia implementat n
codul surs i compilat odat cu acesta, fiind aproape imposibil de gsit i
nlturat.
prin folosirea utilitarului HASP Envelope care modific executabilul aplicaiei,
insernd codul necesar sistemului HASP, acionnd ca un scut de protecie
mpotriva atacului hackerilor. Aceast a doua metod nu necesit acces la codul
surs al aplicaiei, fiind, n acelai timp, i foarte rapid, ntregul proces de
protejare durnd cteva minute.
Ambele metode previn accesul neautorizat i spargerea programului protejat,
oferind nivelul maxim de protecie posibil. Din momentul n care aplicaia a fost
modificat, ea mai poate rula doar dac sistemul HASP, livrat mpreun cu aceasta, este
conectat computerului. Aplicaia devine dependent de acest sistem, toate comunicaiile
ntre ea i sistemul de protecie sunt trimise aleatoriu, avnd ca rezultat imposibilitatea
scrierii unei aplicaii pirat care s emuleze cheia HASP.

14

Compania Aladdin a produs trei categorii de chei de protecie HASP4 pentru


diferite porturi:
HASP4 pentru portul paralel se conecteaz la porturile paralele i sunt utilizate
pentru a proteja aplicaiile ce ruleaz pe PC-uri;
HASP4 pentru portul USB se conecteaz la porturile USB i sunt utilizate la
protejarea aplicaiilor ce ruleaz pe platformele PC i Mac;
HASP4 PC-Cards sunt carduri avansate de protecie ce pot fi inserate n slot-urile
PCMCIA ale PC-urilor notebook .
HASP4 Standard cost redus, securitate ridicat. Modelul Standard este cea mai
ieftin soluie de protecie oferit, utilizeaz tehnologia sistemelor HASP i este singurul
fr memorie, dar include un algoritm de protecie surprinztor de puternic comparativ
cu pretul sau:
1. HASP4 M1 i M4 cel mai configurabil i sigur model de protecie combin un
nivel ridicat de criptare a datelor, 496 baii de memorie i un numar de identificare
unic pentru fiecare cheie Modelul permite distribuia produsului software ca
demo, shareware, try-before-you-buy etc
2. HASP4 Time protecie software cu limita de timp. Modelul Time conine un
ceas intern care indic cu precizie data i timpul pn la care o aplicaie va rula,
fiind ideal pentru nchirierea sau leasingul produselor software. HASP4 Time
contine 512 baii de memorie i un numr de identificare pentru fiecare cheie.
3. HASP4 Net ofer licene de funcionare a produselor software n reea. Se poate
conecta o cheie HASP Net la o singur staie din reea pentru a proteja aplicaia i
a limita numrul staiilor care o folosesc simultan. n rest, acest model ofer toate
caracteristicile modelelor HASP4 M1 i M4.
Toate modelele HASP sunt produse pentru portul paralel standard (cu 25 de pini) i
se pot conecta la acesta fr a afecta conectarea i utilizarea altor periferice (imprimant,
scanner). Pentru a satisface cererile tuturor clienilor, compania Aladdin a produs i cele
15

doua variante speciale USB si PC-Card. Modelul USB poate fi conectat la orice port
USB, care folosete un micro-controler cu 496 baii de memorie intern.
n concluzie rezult, c orice sistem de protecie poate fi spart, de aceea, protecia
este inutil. Adevrat i fals, totodat. Sistemul de protecie a produselor software poate
fi depit n faa unui hacker ndeajuns de motivat. Cu toate acestea, scopul proteciei
este s reziste o perioad rezonabil de timp, un produs software neputnd fi protejat
pentru totdeauna. n timp, apar noi versiuni ale programelor, astfel nct versiunile mai
vechi nu mai prezint aa mult interes. Noua versiune a produsului software trebuie, din
nou, protejat cu un sistem care, la rndul su, a evoluat.
Avantajele sistemului HASP includ o pregnant flexibilitate pentru productorul de
software, o extraordinar uurin n folosire pentru client (utilizator) i o avansat
protecie mpotriva pirailor informatici.
Numeroasele faciliti oferite de sistemele HASP, uurin n folosire i nivelul foarte
ridicat de securitate au determinat ca peste 30.000 de firme din ntreaga lume s
foloseasc serviciile companiei Aladdin. Oferind soluii pentru protecie software i
securitate Internet, Aladdin activeaz nc din anul 1985 i a ctigat ncrederea unor
clieni precum AT&T, DEC, IBM, Intel, Quark i Scitex.

16

Capitolul II. Tabele hash . Scopul tabelelor de dispersie (hash tables)


1.1. Apariia coliziunilor i metode de lichidare a lor.
Ne propunem s crem o structur de date eficienta care s poat face urmatoarele
operaii ct mai repede posibil: Insereaz, Caut i terge. Ideea din spatele hashingului este memorarea unui element ntr-un tablou sau list, n funcie de cheia sa. Pe cazul
mediu toate aceste operaii necesit O(n) timp. S vedem cum:
2.1.1. Adresare direct
Elementele sunt puse ntr-un tablou alocat static pe poziiile cheilor lor. Prin
adresare direct, un element cu cheia k va fi memorat n locaia k. Toate cele 3 operaii
sunt extrem de simple (necesit doar o accesare de memorie), dar dezavantajul este c
aceast tehnic "mnnc" foarte mult memorie: O(|U|), unde U este universul de chei.
Standard hashing
Primul pas n a rezolva problema memoriei este de a folosi O(N) memorie n loc
de O(|U|), unde N este numrul de elemente adugate n hash. Astfel, un element cu
cheia k nu va fi memorat n locaia k, ci h(k), unde h: U -> {0, 1, ..., N-1} - o funcie
aleas aleator, dar determinist (h(x) va returna mereu aceeai valoare pentru un anumit
x n cursul rulrii unui program). Dac funcia este aleas aleator, elementele vor fi
"mprtiate" n hash n mod egal. Ideal ar fi ca fiecare element s fie stocat singur n
locaia lui. Acest lucru ns nu este posibil, pentru c N < |U| i, deci, de multe ori mai
multe elemente vor fi repartizate n aceeai locaie. Aceast problema se numeste
coliziune.
Cum rezolvm coliziunile? Unele din cele mai des folosite metode n procesul de
lichidarea a coliziunilor sunt:
17

nlnuire
n fiecare locaie din hash inem o list nlnuit; astfel, la oricare din cele 3
operaii se va parcurge toat lista. Pe un caz pur teoretic, toate cele N elemente ar putea
fi repartizate n aceeai locaie, ns pe cazuri practice lungimea medie a celui mai lung
lan este de lg(N).

Memorie: O(N)

Pointeri: DA
2.1.2. Liste statice
Aceasta metod este o mbuntire a punctului anterior: pentru c lungimea unui

lan este cel mult lg(N), putem s folosim, n loc de liste nlnuite, vectori alocai
dinamic de lungime lg(N) - sau lg(N) + 3, ca s fim siguri. Scpm astfel de lucrul cu
pointerii.

Memorie: O(N*lg(N))

Pointeri: NU
2.2. Adresare deschis
Prin adresare deschis, toate elementele sunt memorate n tabela de hash. Pentru a

realiza operaiile cerute, verificm succesiv tabela de hash pn cnd fie gsim o locaie
liber (n cazul Inserrii), fie gsim elementul cutat (pentru Caut, terge). ns, n loc
s cutm tabela de hash n ordinea 0, 1, ..., N-1, irul de poziii examinate depinde de
cheia ce se insereaz. Pentru a determina locaiile corespunztoare, extindem funcia de
hash astfel nct s conin i numrul de verificare ca un al doilea parametru h: U * {0,
1, ..., N-1} -> {0, 1, ..., N-1}. Astfel, cnd vom insera un element, verificm mai nti
locaia h(k, 0), apoi h(k, 1) etc. Cnd ajungem s verificm h(k, N) putem s ne oprim
pentru c tabela de hash este plin. Pentru cutare aplicm aceeai metod; dac
ajungem la h(k, N) sau la o poziie goalp, nseamn c elementul nu exist. tergerile se
fac ns mai greu, pentru c nu se poate "terge" pur i simplu un element deoarece ar
strica tot hash-ul. n schimb, se marcheaz locaia ce trebuie tears cu o valoare TERS
18

i se modific funcia Insereaz astfel nct s vad locaiile cu valoarea TERS ca


poziii goale.

Memorie: O(N)

Pointeri: NU
2.2.1 Double hashing-ul lui Mihai Patracu
O mbuntire foarte mare la tabela de hashing este adugarea nc a unei tabele

de hashing. Vom avea 2 tabele, fiecare cu propria ei funcie de hash, iar coliziunile le
rezolvm prin nlnuire; cnd inserm un element, l vom aduga n tabela n care
ntra ntr-un lan mai scurt. Cutarea se face n ambele tabele n locaiile returnate de
cele 2 funcii de hash; tergerea la fel. Astfel, lungimea celui mai lung lan va fi, n
medie, lg(lg(N)). Dar, n practic, lungimea unui astfel de lan nu va depi 4
elemente, pentru c cel mai mic N pentru care lg(lg(N)) = 5 este 232 ~
4.000.000.000!!! Deci, n loc de liste folosim vectori statici de dimensiune 4.

Memorie: O(N)

Pointeri: NU
2.2.2. Funcii de hash
Toate funciile de hash ntorc un numr ntre 0 i M-1, unde M este dimensiunea

maxim a tabelei de hash. Este recomandat ca M s fie ales un numr prim i s se evite
alegerea lui M=2k.
Pentru numere ntregi:

h(x) = x % M

h(x) = (x * r) % M, r - numar aleator ales la nceputul programului

Pentru numere reale

h(x) = [ {A * x} * M ], 0 < A < 1

{x} - partea fracionar a lui x


[x] - partea ntreag a lui x
19

[x] + {x} = x - prin definiie A este un numr care trebuie ales nainte sau la nceputul
rulrii programului. Alegerea lui influeneaz eficiena funciei. Knuth propune valoarea

Pentru adresarea deschis:

h(x, i) = (h'(x) + i) % M

h(x, i) = (h'(x) + r1 * i + r2 * i2) % M

h(x, i) = (h1(x) + i * h2(x)) % M, r1, r2 - numere alese aleator la nceputul


programului.
n concluzie dei o tabel hash poate fi implementat n diverse moduri (cu

pointeri sau fr, cu mai mult sau mai puin memorie etc), nu pentru toate situaiile e
la fel de uor de ales o funcie eficient. Implementrile mai complexe necesit mai
multe cutri n adncime pe nivele ntr-un arbore pentru a obine funcii bune. Iar de
multe ori se prefer implementri concise i clare n locul arborescenelor dense care
mresc eficiena, dar nu suficient. De aceea, cel mai frecvent mod de tratare al
coliziunilor ramane nlnuirea. Mai multe detalii despre acesta, precum i anumite
precizri despre cum s alegi o funcie hash bun n cazul diverselor tipuri de date,
care pot fi gsite n bibliografia de referin din tez deasemenea se poate gsi i o
list de aplicaii pentru aceast structur de date eficienta.[9,10]
n multe aplicaii lucrm cu structuri mari de date n care avem nevoie s facem
cutari, inserri, modificri i tergeri. Aceste structuri pot fi vectori, matrici, liste etc. n
cazurile mai fericite ale vectorilor, acetia pot fi sortai, caz n care localizarea unui
element se face prin metoda njumtirii intervalului, adic n timp logaritmic. Chiar
dac nu avem voie s sortm vectorul, tot se pot face anumite optimizri care reduc
foarte mult timpul de cutare. De exemplu, probabil c muli dintre cititori au idee
despre ce nseamn indexarea unei baze de date. Dac avem o baz de date cu patru
elemente de tip string, i anume

20

B = ("bac", "zugrav", "abac", "zarva")


putem construi un vector Ind care s ne indice ordinea n care s-ar cuveni s fie aezate
cuvintele n vectorul sortat. Ordinea alfabetic (din cartea de telefon) a cuvintelor este:
"abac", "bac", "zarva", "zugrav", deci vectorul Ind este:
Ind = (3, 1, 4, 2)
semnificnd c primul cuvnt din vectorul sortat ar trebui s fie al treilea din vectorul B,
respectiv "abac", i aa mai departe. n felul acesta am obinut un vector sortat, care
presupune o indirectare a elementelor. Vectorul sortat este
B' = (B(Ind(1)), B(Ind(2)), B(Ind(3)), B(Ind(4)).
Aceast operaie se numete indexare. Ce-i drept, construcia vectorului Ind nu se
poate face ntr-un timp mai bun dect O(N log N), dar dup ce acest lucru se face (o
singur dat, la nceputul programului), cutrile se pot face foarte repede. Dac pe
parcurs se fac adugri sau tergeri de elemente din baza de date, se va pierde ctva timp
pentru meninerea indexului, dar n practic timpul acesta este mult mai mic dect
timpul care s-ar pierde cu cutarea unor elemente n cazul n care vectorul ar fi
neindexat. Nu vom intra n detalii despre indexare, deoarece nu acesta este obiectul
capitolului de fa.
n unele situaii nu se poate face nici indexarea structurii de date. S considerm
cazul unui program care joac ah. Numrul de poziii posibile ale pieselor pe tabla de
ah este mult prea mare. Nu poate fi vorba nici mcar de reinerea tuturor, cu att mai
puin de indexarea lor. n esen, modul de funcionare al acestui program se reduce la o
rutina care primete o poziie pe tabl i o variabil care indic dac la mutare este albul
sau negrul, rutina intorcnd cea mai bun mutare care se poate efectua din acea poziie.
Majoritatea programelor de ah ncep s expandeze respectiva poziie, examinnd
tot felul de variante ce pot decurge din ea i alegnd-o pe cea mai promitoare, aa cum
21

fac i juctorii umani. Poziiile analizate, fiind mult mai puine dect cele posibile, sunt
stocate n memorie sub forma unei liste.
S ne nchipuim acum urmatoarea situaie. Este posibil c, prin expandarea unei
configuraii iniiale a tablei s se ajung la aceeai configuraie final pe dou ci
diferite. Spre exemplu, dac albul muta nti calul la f3, apoi la c4, pozitia rezultat va fi
aceeai ca i cnd s-ar fi mutat nti c4 i apoi calul (considernd bineinteles c negrul
d n ambele situaii aceeai replic). Dac configuraia final a fost deja analizat
pentru prima variant, este inutil s o mai analizm i pentru cea de-a doua, pentru c
rezultatul (concluzia la care se va ajunge) va fi exact acelai. Dar cum i poate da
programul seama dac poziia pe care are de gnd s-o analizeze a fost analizat deja sau
nu ?
2.2.3. Scanarea unei liste.
Cea mai simpla metod este o scanare a listei de configuraii examinate din memorie.
Dac n aceast list se afl poziia curent de analizat, nseamn c ea a fost deja
analizat i vom renuna la ea. Dac nu, o vom analiza acum. Ideea n mare msur a
algoritmului este:
1. procedura Analizeaz(Pozitie P)
2. caut P n lista de poziii deja analizate
3. dac P nu exist n list
4. expandeaz P i afl cea mai bun mutare M
5. adaug P la lista de poziii analizate
6. ntoarce M
7. altfel
8. ntoarce valoarea M ataat poziiei P gsite n list
9. sfrit

22

Nu vom insista asupra a cum se expandeaz o poziie i cum se calculeaz efectiv cea
mai bun mutare. Noi ne vom interesa de un singur aspect, i anume cutarea unei
poziii n list. Tehnica cea mai "natural" este o parcurgere a listei de la cap la coada,
comparnd pe rand poziia cutat cu fiecare poziie din list. Dac lista are memorate N
poziii, atunci n cazul unei cutari cu succes (poziia este gsit), numrul mediu de
comparaii fcute este N/2, iar numrul cel mai defavorabil ajunge pn la N. n cazul
unei cutri fr succes (poziia nu exist n list), numrul de comparaii este
ntotdeauna N. De altfel, cazul cutarii fr succes este mult mai frecvent pentru
problema jocului de ah, unde numrul de poziii posibile crete exponenial cu numrul
de mutri. Acelai numr de comparaii l presupune i tergerea unei poziii din list
(care presupune nti gsirea ei) i adugarea (care presupune c poziia de adugat s
nu existe deja n list).
Pentru mbuntirea practic a acestui timp sunt folosite tabelele de dispersie sau
tabelele hash (engl. hash = a toca, toctur). Menionm de la bun nceput c tabelele
hash nu au nici o utilitate din punct de vedere teoretic. Dac suntem ru intenionai, este
posibil s gsim exemple pentru care cutarea ntr-o tabel hash s dureze la fel de mult
ca ntr-o list simplu nlnuit, respectiv O(N). Dar n practic timpul cutrii i al
adugrii de elemente ntr-o tabel hash coboar uneori pn la O(1), iar n medie scade
foarte mult (de mii de ori).
Iat despre ce este vorba. S presupunem pentru nceput c n loc de poziii pe tabla
de ah, lista noastr memoreaz numere ntre 0 si 999. n acest caz, tabela hash ar fi un
simplu vector H cu 1000 de elemente booleene. Iniial, toate elementele lui H au
valoarea False (sau 0). Dac numrul 473 a fost gsit n list, nu avem dect s setm
valoarea lui H(473) la True (sau 1). La o noua apariie a lui 473 n list, vom examina
elementul H(473) i, deoarece el este True, nseamn c acest numr a mai fost gsit.
Dac dorim tergerea unui element din hash, vom reseta poziia corespunztoare din H.
Practic, avem de-a face cu un exemplu rudimentar ceea ce se numete funcie de
23

dispersie, adic h(x)=x. O proprietate foarte important a acestei funcii este


injectivitatea; este imposibil ca la doua numere distincte s corespund aceeai intrare n
tabel. S cerc o reprezentare grafic a metodei:

primul set de proceduri de gestionare a unui Hash.


1. const int M = 1000;
2. typedef int DataType;
3. typedef DataType Hash[M];
4. Hash H;
5.
6. void InitHash1(Hash H) {
7.

for (int i=0; i<M; H[i++]=0);

8. }
9.
10. inline int h(DataType K) {
11.

return K;

12. }
13.
14. int Search1(Hash H, DataType K) {
24

15.

// ntoarce -1 daca elementul nu exist n hash

16.

// sau indicele n hash dac el exist

17.

return H[h(K)] ? h(K) : -1;

18. }
19.
20. void Add1(Hash H, DataType K) {
21.

H[h(K)]=1;

22. }
23.
24. void Delete1(Hash H, DataType K) {
25.

H[h(K)]=0;

26. }

Prin "numar de intrari" in tabela se intelege numarul de elemente ale vectorului H; in


general, orice tabela hash este un vector. Pentru ca functiile sa fie cat mai generale, am
dat tipului de data int un nou nume DataType. In principiu, tabelele Hash se aplica
oricarui tip de date. In realitate, fenomenul este tocmai cel invers: orice tip de date
trebuie "convertit" printr-o metoda sau alta la tipul de date int, iar functia de dispersie
primeste ca parametru un intreg. Functiile hash prezentate in viitor nu vor mai lucra
decat cu variabile de tip intreg. Vom vorbi mai tarziu despre cum se poate face
conversia. Acum sa generalizam exemplul de mai sus.
Intr-adevar, cazul anterior este mult prea simplu. Sa ne inchipuim de pilda ca in loc de
numere mai mici ca 1000, avem numere de pana la 2.000.000.000. In aceasta situatie
posibilitatea de a reprezenta tabela ca un vector caracteristic iese din discutie. Numarul
de intrari in tabela este de ordinul miilor, cel mult al zecilor de mii, deci cu mult mai mic
decat numarul total de chei (numere) posibile. Ce avem de facut? Am putea incerca sa
adaugam un numar K intr-o tabela cu M intrari (numerotate de la 0 la M-1) pe pozitia K
25

mod M, adica h(K) = K mod M. Care va fi insa rezultatul? Functia h isi va pierde
proprietatea de injectivitate, deoarece mai multor chei le poate corespunde aceeasi
intrare in tabela, cum ar fi cazul numerelor 1234 si 2001234, ambele dand acelasi rest la
impartirea prin M=1000. Nu putem avea insa speranta de a gasi o functie injectiva,
pentru ca atunci numarul de intrari in tabela ar trebui sa fie cel putin egal cu numarul de
chei distincte. Vrand-nevrand, trebuie sa rezolvam coliziunile (sau conflictele) care apar,
adica situatiile cand mai multe chei distincte sunt repartizate la aceeasi intrare.
Vom reveni ulterior la oportunitatea alegerii functiei modul si a numarului de 1000 de
intrari in tabela. Deocamdata vom folosi aceste date pentru a explica modul de
functionare a tabelei hash pentru functii neinjective. Sa presupunem ca avem doua chei
K1 si K2 care sunt repartizate de functia h la aceeasi intrare X, adica h(K1)=h(K2)=X.
Solutia cea mai comoda este ca H(X) sa nu mai fie un numar, ci o lista liniara simplu
inlantuita care sa contina toate cheile gasite pana acum si repartizate la aceeasi intrare X.
Prin urmare vectorul H va fi un vector de liste:

26

Sa analizam acum complexitatea noilor proceduri de cautare, adaugare si stergere.


Cautarea nu se va mai face in toata lista, ci numai in lista corespunzatoare din H. Altfel
spus, o cheie K se va cauta numai in lista H(h(K)), deoarece daca cheia K a mai aparut,
ea a fost in mod sigur repartizata la intrarea H(h(K)). De aceea, cautarea poate ajunge, in
cazul cel mai defavorabil cand toate cheile din lista se repartizeaza la aceeasi intrare in
hash, la o complexitate O(N). Daca reusim insa sa gasim o functie care sa distribuie
cheile cat mai aleator, timpul de intrare se va reduce de M ori. Avantajele sunt
indiscutabile pentru M=10000 de exemplu.

27

Intrucat operatiile cu liste liniare sunt in general cunoscute, nu vom insista asupra lor.
Prezentam aici numai adaugarea si cautarea, lasandu-va ca tema scrierea functiei de
stergere din tabela.
1. #include <stdio.h>
2. #include <stdlib.h>
3.
4. const int M = 1000;
5. typedef struct List_ {
6.

long P;

7.

struct List_ *Next;

8. } List;
9. typedef List* Hash[M];
10. Hash H;
11.
12. void InitHash2(Hash H){
13.

for (int i=0; i<M; H[i++]=NULL);

14. }
15.
16. int h2(int K) {
17.

return K % M;

18. }
19.
20. int Search2(Hash H, int K) {
21.

// Intoarce 0 daca elementul nu exista in hash

22.

// sau 1 daca el exista

23.

List *L;

24.

for (L=H[h2(K)]; L && (L->P != K); L = L->Next);

25.

return L!=NULL;
28

26. }
27.
28. void Add2(Hash H, int K) {
29.

List *L = (List *) malloc(sizeof(List));

30.

L->P = K;

31.

L->Next = H[h2(K)];

32.

H[h2(K)] = L;

33. }

Am spus ca functiile de dispersie sunt concepute sa lucreze numai pe date de tip


intreg; celelalte tipuri de date trebuie convertite in prealabil la tipuri de date intregi. Iata
cateva exemple:

Variabilele de tip string pot fi transformate in numere in baza 256 prin inlocuirea
fiecarui caracter cu codul sau ASCII. De exemplu, sirul "abac" poate fi privit ca un
numar de 4 cifre in baza 256, si anume numarul (97 98 97 99). Conversia lui in
baza 10 se face astfel:

X = ((97 * 256 + 98) * 256 + 97) * 256 + 99 = 1 633 837 411


Pentru stringuri mai lungi, rezulta numere mai mari. Uneori, ele nici nu mai pot fi
reprezentate cu tipurile de date ordinare. Totusi, acest dezavantaj nu este suparator,
deoarece majoritatea functiilor de dispersie presupun o impartire cu rest, care, indiferent
de marimea numarului de la intrare, produce un numar controlabil.

Variabilele de tip data se pot converti la intreg prin formula:

X = A * 366 + L * 31 + Z
unde A, L si Z sunt respectiv anul, luna si ziua datei considerate. De fapt, aceasta functie
aproximeaza numarul de zile scurse de la inceputul secolului I. Ea nu are pretentii de
29

exactitate (ca dovada, toti anii sunt considerati a fi bisecti si toate lunile a avea 31 de
zile), deoarece s-ar consuma timp inutil cu calcule mai sofisticate, fara ca dispersia
insasi sa fie imbunatatita cu ceva. Conditia care trebuie neaparat respectata este ca
functia de conversie data

intreg sa fie injectiva, adica sa nu se intample ca la doua

date D1 si D2 sa li se ataseze acelasi intreg X; daca acest lucru se intampla, pot aparea
erori la cautarea in tabela (de exemplu, se poate raporta gasirea datei D1 cand de fapt a
fost gasita data D2). Pentru a respecta injectivitatea, s-au considerat coeficientii 366 si
31 in loc de 365 si 30. Daca numarul de zile scurse de la 1 ianuarie anul 1 d.H. ar fi fost
calculat cu exactitate, functia de conversie ar fi fost si surjectiva, dar, dupa cum am mai
spus, acest fapt nu prezinta interes.

Analog, variabilele de tip ora se pot converti la intreg cu formula:

X = (H * 60 + M) * 60 + S
unde H, M si S sunt respectiv ora, minutul si secunda considerate, sau cu formula
X = ((H * 60 + M) * 60 + S) * 100
daca se tine cont si de sutimile de secunda. De data aceasta, functia este surjectiva
(oricarui numar intreg din intervalul 0 - 8.639.999 ii corespunde in mod unic o ora).

In majoritatea cazurilor, datele sunt structuri care contin numere si stringuri. O


buna metoda de conversie consta in alipirea tuturor acestor date si in convertirea la
baza 256. Caracterele se convertesc prin simpla inlocuire cu codul ASCII
corespunzator, iar numerele prin convertirea in baza 2 si taierea in "bucati" de cate
opt biti. Rezulta numere cu multe cifre (prea multe chiar si pentru tipul longint),
care sunt supuse unei operatii de impartire cu rest. Functia de conversie trebuie sa
fie injectiva. De exemplu, in cazul tablei de sah despre care am amintit mai inainte,
ea poate fi transformata intr-un vector cu 64 de cifre in baza 16, cifra 0
semnificand un patrat gol, cifrele 1-6 semnificand piesele albe (pion, cal, nebun,
30

turn, regina, rege), iar cifrele 7-12 semnificand piesele negre. Prin trecerea acestui
vector in baza 256, rezulta un numar cu 32 de cifre. La acesta se mai pot adauga
alte cifre, respectiv partea la mutare (0 pentru alb, 1 pentru negru), posibilitatea de
a efectua rocada mica/mare de catre alb/negru, numarul de mutari scurse de la
inceputul partidei si asa mai departe.
Vom termina prin a prezenta doua functii de dispersie foarte des folosite.
2.3. Metoda impartirii cu rest
Despre aceasta metoda am mai vorbit. Functia hash este: h(x) = x mod M unde M
este numarul de intrari in tabela. Problema care se pune este sa-l alegem pe M cat mai
bine, astfel incat numarul de coliziuni pentru oricare din intrari sa fie cat mai mic. De
asemenea, trebuie ca M sa fie cat mai mare, pentru ca media numarului de chei
repartizate la aceeasi intrare sa fie cat mai mica. Totusi, experiena arata ca nu orice
valoare a lui M este buna.
De exemplu, la prima vedere s-ar putea spune ca o buna valoare pentru M este o
putere a lui 2, cum ar fi 1024, pentru ca operatia de impartire cu rest se poate face foarte
usor in aceasta situatie. Totusi, functia h(x) = x mod 1024 are un mare defect: ea nu tine
cont decat de ultimii 10 biti ai numarului x. Daca datele de intrare sunt numere in mare
majoritate pare, ele vor fi repartizate in aceeasi proportie la intrarile cu numar de ordine
par, pentru ca functia h pastreaza paritatea. Din aceleasi motive, alegerea unei valori ca
1000 sau 2000 nu este prea inspirata, deoarece tine cont numai de ultimele 3-4 cifre ale
reprezentarii zecimale. Multe valori pot da acelasi rest la impartirea prin 1000. De
exemplu, daca datele de intrare sunt anii de nastere ai unor persoane dintr-o agenda
telefonica, iar functia h(x)=x mod 1000, atunci majoritatea cheilor se vor ingramadi
(termenul este sugestiv) intre intrarile 920 si 990, restul ramanand nefolosite.
Practic, trebuie ca M sa nu fie un numar rotund in nicio baza aritmetica, sau cel
putin nu in bazele 2 si 10. O buna alegere pentru M sunt numerele prime care sa nu fie
31

apropiate de nicio putere a lui 2. De exemplu, in locul unei tabele cu M=10000 de


intrari, care s-ar comporta dezastruos, putem folosi una cu 9973 de intrari. Chiar si
aceasta alegere poate fi imbunatatita; intre puterile lui 2 vecine, respectiv 8192 si 16384,
se poate alege un numar prim din zona 11000-12000. Risipa de memorie de circa 10002000 de intrari in tabela va fi pe deplin compensata de imbunatatirea cautarii.
2.4. Metoda inmultirii
Pentru aceasta metoda functia hash este h(x) = [M * {x*A}]. Aici A este un numar
pozitiv subunitar, 0 < A < 1, iar prin {x*A} se intelege partea fractionara a lui x*A,
adica x*A - [x*A]. De exemplu, daca alegem M = 1234 si A = 0.3, iar x = 1997, atunci
avem h(x) = [1234 * {599.1}] = [1234 * 0.1] = 123. Se observa ca functia h produce
numere intre 0 si M-1. Intr-adevar 0 {x*A} < 1

0 M * {x*A} < M.

In acest caz, valoarea lui M nu mai are o mare importanta. O putem deci alege cat de
mare ne convine, eventual o putere a lui 2. In practica, s-a observat ca dispersia este mai
buna pentru unele valori ale lui A si mai proasta pentru altele. Donald Knuth propune
valoarea

Ca o ultima precizare necesara la acest capitol, mentionam ca functia de cautare e


bine sa nu intoarca pur si simplu 0 sau 1, dupa cum cheia cautata a mai aparut sau nu
inainte intre datele de intrare. E recomandabil ca functia sa intoarca un pointer la zona
de memorie in care se afla prima aparitie a cheii cautate. Vom da acum un exemplu in
care aceasta valoare returnata este utila. Daca, in cazul prezentat mai sus al unui
program de sah, se ajunge la o anumita pozitie P dupa ce albul a pierdut dreptul de a face
rocada, aceasta pozitie va fi retinuta in hash. Retinerea nu se va face nicidecum efectiv
(toata tabla), pentru ca s-ar ocupa foarte multa memorie. Se va memora in loc numai un
pointer la pozitia respectiva din lista de pozitii analizate. Pe langa economia de memorie
in cazul cheilor de mari dimensiuni, mai exista si alt avantaj. Sa ne inchipuim ca,
analizand in continuare tabla, programul va ajunge la aceeasi pozitie P, dar in care albul
32

are inca dreptul de a face rocada. E limpede ca aceasta varianta este mai promitatoare
decat precedenta, deoarece albul are o libertate mai mare de miscare. Se impune deci fie
stergerea vechii pozitii P din lista si adaugarea noii pozitii, fie modificarea celei vechi
prin setarea unei variabile suplimentare care indica dreptul albului de a face rocada.
Aceasta modificare este usor de facut, intrucat cautarea in hash va returna chiar un
pointer la pozitia care trebuie modificata. Bineinteles, in cazul in care pozitia cautata nu
se afla in hash, functia de cautare trebuie sa intoarca NULL.
In incheierea capitolului, prezentam un exemplu de functie de dispersie pentru cazul
tablei de sah.
1. const int M = 9973; // Numarul de "intrari".
2. typedef struct {
3.

char b_T[8][8]; // Tabla de joc, cu 0 <= T[i][j] <= 12.

4.
5.

char b_CastleW, b_CastleB; // Ultimii doi biti ai lui b_CastleW

6.

// indica daca albul are dreptul de a

7.

// efectua rocada mare, respectiv pe cea

8.

// mica. Analog pentru b_CastleB.

9.
10.
11.

char b_Side; // 0 sau 1, dupa cum la mutare este albul.


// sau negrul.

12.
13.

char b_EP; // 0..8, indicand coloana (0..7) pe care

14.

// partea la mutare poate efectua o

15.

// captura "en passant". 8 indica ca nu

16.

// exista aceasta posibilitate.

17.
18.

int b_NMoves; // Numarul de mutari efectuate.


33

19. } Board;
20. Board B;
21.
22. int h3(Board *B) {
23.

int i, j;

24.

// Valoarea initiala a lui S este un numar pe 17 biti care

25.

// inglobeaza toate variabilele suplimentare pe langa T.

26.

// S se va lua apoi modulo M.

27.

long S = (B->b_NMoves

// 8 biti

28.

+(B->b_CastleW << 8)

// 2 biti

29.

+(B->b_CastleB << 10) // 2 biti

30.

+(B->b_Side << 12)

31.

+(B->b_EP << 13)) % M; // 4 biti

// 1 bit

32.
33.
34.

for (i=0; i<=7; i++)


for (j=0; j<=7; j++) {

35.
36.

S = (16*S + B->b_T[i][j]) % M;
}

37.
38.

return S;

39. }

Funciile hash

utilizate n criptografie pentru generarea unor rezumate de

lungime redus i relativ mic pentru mesaje de lungime variabil au devenit o


component important a criptografiei n contextul generrii eficiente a semnturilor
digitale. Algoritmii de hashing, la fel ca algoritmii pentru criptare cu cheie public, se

34

bazeaz pe funcii one-way. Aceti algoritmi asigur o securitate condiionat de


dificultatea inversrii funciilor one-way utilizate.
MD5-message digest algoritm, elaborat de Ron Rivest a fost, pn n ultimii ani
cnd au aprut probleme legate de atacul cu for brut, cel mai utilizat algoritm hash.
Algoritmul are ca intrare un mesaj de lungime arbitrar i produce la ieire un bloc de
512 bii; procesarea mesajului se face n blocuri de 512 bii.
SHA secure hash algorithm a fost dezvoltat n SUA de NIST, publicat n 1993 ca
standard federal pentru procesarea informaiei i revizuit n 1995 sub denumirea de
SHA-1. Admite ca intrare un mesaj cu lungime maxim de 264 bii i produce la ieire un
bloc de 160 bii; procesarea mesajului se face n blocuri de 512 bii.

Capitolul III. Algoritmul MD5


Acest document descrie algoritmul de prelucrare a mesajelor. Algoritmul introduce ca
date de intrare un mesaj de lungime arbitrara i informaia afiata ca rspuns este o
amprenta digitala sau un mesaj de sistematizare de 128 biti. Algoritmul MD5 este
folosit pentru aplicatii de semnaturi digitale, in care un fisier voluminous trebuie sa fie
35

compresat intr-un mod ce asigura securitate inainte de a fi criptat cu un cod privat


(secret) al unui criptosistem cu cheie publica cum ar fi RSA
Algoritmul MD5 este proiectat pentru a lucra destul de bine la calculatoare cu 32 biti. In
plus, algoritmul MD5 nu are nevoe de oricare alte tabele de substitutie; algoritmul poate
fi criptat destul de compact.
Algoritmul MD5 este o extensie a algoritmului MD4. MD5 este mult mai incet ca
MD4 dar este mai conservativ in ceea ce priveste designul. MD5 a fost proiectat
deoarece s-a observat ca este MD4 mai mult rapid decit folositor;MD4 a fost proiectat
pentru a fi extreme de rapid, este nesigur in ceea ce priveste inlaturarea atacurilor de
decodificare. MD5 este putin mai lent, el renunta la viteza rapida in favoarea unei
secutirati mai mari. MD5 incorporeaza sugestii facute de diferite reviste, si contine
modificari adaugatoare. Algoritmul MD5 este instalat in locuri publice pentru a fi
revizuit si poasibil pentru a fi adoptat ca un standard.
Pentru aplicatii de tip OSI, Identificatorul de obiecte MD5 este astfel:
md5 OBJECT IDENTIFIER ::=
iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 5}
In varinata X.509 AlgorithmIdentifier [3], parametrii pentru MD5 trebuie sa aiba
valoarea NULL

3.1 Terminologia si notaiile


In acest document cuvintul cuvint reprezinta o cantitate de 32 biti si bait este 8 biti.
Un sir de biti poate fi interpretat drept o succesiune de baiti ,unde fiecare succesiune de
8 biti este un bait ce contine cel mai important bit pe primul loc. In mod similar, o

36

secventa de baiti este

o consecutivitate de cuvinte de 32 biti, unde fiecare grup

consecutive de baiti este vazut ca un cuvint cu baitul cel mai nesimnificativ primul loc.
Fie ca x_I inseamna x sub i. Daca indicele inferior este o expresie, atunci o punem in
paranteze figurate, ca de exemlu x_{i+1}. Tot in asa mod, vom folosi ^ pentru a scrie o
variabila la o putere (exponentialul), asa ca x^I arata ca x este la puterea i.
Simbolul + va semnifica adunarea cuvintelor (ex. Modulo 2^32 adunat). X>>> s va
arata valoarea de 32 biti obtinuta prin mutarea lui X la stinga de pozitia s bit, in mod
circular. Not(X) va reprezenta negatia logica a lui X, si X v Y va reprezenta valoarea
OR(sau) a lui X si Y. X xor Y va fi valoarea logica XOR dintre X si Y, si XY este
valoarea logica AND(si) dintre X si Y.

3. 2 Descrierea algoritmului MD5


Am inceput a face algoritmul prin presupunerea ca avem ca mesaj de intrarea un b-bit,
si ca dorim sa-i gasim mesajul digest. Aici b este un integer arbitrar nenegativ; b poate fi
impartit la 0, nu trebuie sa se imparta la 8 si poate sa fie oricit de mare. Ne inchipuim
mesajul de biti ca fiind scris astfel:
m_0 m_1 ... m_{b-1}
Urmatorii 5 pasi sunt pentru a obtine mesajul digest a mesajului initial.
3.3 Pasul 1. Adaugare de biti
Acest mesaj este extins astfel incit lungime lui in biti este congruenta cu 448, modulo
512. Aceasta inseamna ca mesajul este extins astfel incit sa fie doar 64 biti lungime ca

37

multiplu a lungimii de 512 biti. Extinderea este intotdeauna facuta, chiar daca lungimea
mesajului este deja egala cu 448, modulo 512.
Extinderea este facuta dupa cum urmeaza: un singur bit 1 este adaugat la mesaj,
apoi 0 bit este adaugat astfel incit lungimea in biti a mesajului extins sa devina cegala
cu 448, modulo 512. In fiecare mesaj este adaugat cel putin un bit si cel mult 512 biti.
3.4 Pasul 2. Adaugarea lungimii.
O reprezentare de 64 biti a lui b(lungimea mesajului inainte de adaugarea bitilor) este
adaugat la rezultatul pasului 1. Din cauza ca b este mai mare de 2^64, se folosesc doar
64 de biti.(Acesti biti sunt adaugati sub forma de doua cuvinte de 32 biti si mai intii se
adauga cuvintul cu ordine mai joaasa in concordanta cu prevederile anterioare.)
3.5 Pasul 3. Initializarea Buferului MD
Un buffer de 4 cuvinte (A,B,C,D) este folosit pentru a obtine mesagul digest. Aici
fiecare din A,B,C,D este un contor de 32 biti. Aceste contoare sunt initializate cu
urmatoarele valori hexazecimale:
cuvintul A: 01 23 45 67
cuvintul B: 89 ab cd ef
cuvintul C: fe dc ba 98
cuvintul D: 76 54 32 10
Mai intii definim functiile auxiliare care au ca date de intrare trei cuvinte de 32 biti si
afiseaza un cuvint de 32 biti.
F(X,Y,Z) = XY v not(X) Z
G(X,Y,Z) = XZ v Y not(Z)
H(X,Y,Z) = X xor Y xor Z
I(X,Y,Z) = Y xor (X v not(Z))
38

La fiecare pozitie a unui bit F actioneaza ca o conditie: daca X atunci Y, altfel Z.


Functia F ar fi putut fi definite folosind + in loc de v deoarece XY si not(X)Z
niciodata nu vor avea 1 pe pozitia intii. Este interesant de observat ca bitii lui X, Y sau
Z sunt independenti, atunci fiecare bit al functiei F(X,Y,Z) va fi independent.
Functiile G, H si I sunt similare functiei F, astfel ele lucreaza dupa regulile logicei
pentru a afisa datele de iesire din bitii lui X, Y, Z dupa cum urmeaza: daca bitii
coresunzatori lui X,Y,si Z sunt independenti atunci fiecare bit a functiei G(X,Y,Z),
H(X,Y,Z) si I(X,Y,Z) vor fi independenti. De observat ca functia H este operatia logica
XOR.
Acest pas include si un tablou de 64 elemente T [164] construit dupa functie. T [i]
semnifica elementul i al tabloului, care este egal cu partea intreaga de 4294967296 ori a
abs (sin (i)), unde I este in radiani.

/*Se proceseaza fiecare bloc de 16 biti*/


For i = 0 to N/16-1 do
/*SE copiaza blocul i in X*/
For j = 0 to 15 do
Set X[j] to M[i*16+j].
End

/*ciclul j*/

/*Se salveaza A ca AA, B ca BB, C ca CC, D ca DD. */


AA = A
BB = B

39

CC = C
DD = D
/* Runda 1.*/
/*Fie ca [abcd k s i] executa oparatia

a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s).*/

/*SE efectueaza urmatoarele 16 operatii*/


[ABCD 0 7 1] [DABC 1 12 2] [CDAB 2 17 3] [BCDA 3 22 4]
[ABCD 4 7 5] [DABC 5 12 6] [CDAB 6 17 7] [BCDA 7 22 8]
[ABCD 8 7 9] [DABC 9 12 10] [CDAB 10 17 11] [BCDA 11 22 12]
[ABCD 12 7 13] [DABC 13 12 14] [CDAB 14 17 15] [BCDA 15 22 16]
/*Runda 2*/
/*Fie ca [abcd k s i] executa operatia a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
/*Se efectueaza urmatoarele 16 operatii*/
[ABCD 1 5 17] [DABC 6 9 18] [CDAB 11 14 19] [BCDA 0 20 20]
[ABCD 5 5 21] [DABC 10 9 22] [CDAB 15 14 23] [BCDA 4 20 24]
[ABCD 9 5 25] [DABC 14 9 26] [CDAB 3 14 27] [BCDA 8 20 28]
[ABCD 13 5 29] [DABC 2 9 30] [CDAB 7 14 31] [BCDA 12 20 32]
/*Runda 3*/
/*Fie ca [abcd k s t] executa urmatoarea operatie a = b + ((a + H(b,c,d) + X[k] + T[i])
<<< s).*/
/*Se efectueaza urmatoarele 16 operatii*/
[ABCD 5 4 33] [DABC 8 11 34] [CDAB 11 16 35] [BCDA 14 23 36]
[ABCD 1 4 37] [DABC 4 11 38] [CDAB 7 16 39] [BCDA 10 23 40]
40

[ABCD 13 4 41] [DABC 0 11 42] [CDAB 3 16 43] [BCDA 6 23 44]


[ABCD 9 4 45] [DABC 12 11 46] [CDAB 15 16 47] [BCDA 2 23 48]
/*Runda4*/
/*Fie ca [abcd k s t] reprezinta urmatoarea operatie a = b + ((a + I(b,c,d) + X[k] + T[i])
<<< s).*/
/*Faceti urmatoarele 16 operatii*/
[ABCD 0 6 49] [DABC 7 10 50] [CDAB 14 15 51] [BCDA 5 21 52]
[ABCD 12 6 53] [DABC 3 10 54] [CDAB 10 15 55] [BCDA 1 21 56]
[ABCD 8 6 57] [DABC 15 10 58] [CDAB 6 15 59] [BCDA 13 21 60]
[ABCD 4 6 61] [DABC 11 10 62] [CDAB 2 15 63] [BCDA 9 21 64]
/*Apoi se fac urmatoarele daugari (Aceasta presupune incrementarea fiecarui dintre cele
patru contoare cu valoara pe care o aveau inainte de a incepe acest bloc)*/
A = A + AA
B = B + BB
C = C + CC
D = D + DD
end /* ciclul lui i */

3.6 Pasul 5. Datele de iesire

41

Ceea ce sa obtinut dupa introducerea mesajului digest este A,B,C,D. Ceea ce inseamna
ca se incepe lucrul de la ultimul bit a lui A si se termina cu primul bit a lui D.

Aceasta completeaza descrierea algoritmului MD5.

Iciclu

II ciclu
IIIciclu

IIIIciclu

42

Logica indeplinirii unui singur pas in modul de functionare a algoritmului MD5:

Al K

elea

cuvintY[k], k=0..15

3.7 Diferenta dintre MD4 si MD5


Exista urmatoarele diferente intre MD4 si MD5:
1. Un al 4 tur a fost adaugat
2. Fiecare pas acum are o constanta noua adaugata
43

3. Functia G din runda a 2 a fost schimbata din (XY v XZ v YZ) in (XZ v Y not(Z))
pentru a face functia mai putin simetrica.
4. Rezultatul fiecarui pas anterior este adaugat la pasul ce urmeaza. Aceasta ofera un
efect de avalansa. Schimbarile din fiecare runda sunt diferite.

44

Concluzii
n aceast lucrare sunt expuse principalele probleme de securitate care apar ntun system deschis, avnd n vedere: asocierile ilegale, care permit s se realizeze
legturi logice (asociaii) ntre utilizatorii reelei prin exluderea politici de autorizare i
atentificare, a acceselor neautorizate, care permit unui utilizator, sau process autorizat s
accesese obiecte la care nu are dreptul, excluznd serviciile de control al accesului.
Scopul acestei lucrri este de a prezenta structuri funcionale de protejare a
informaiei de la copierea ilegal a informaiei ct i implementarea criptosistemului
MD5 pentru prezentarea unui program n protejarea informaiei. Programul prezentat
utilizeaz o tehnic a modului de funcionare a algoritmului MD5, plecnd de la scopul
funcional urmrit

i fr ca utilizatorul s cunoasc detalii

privind matematica

specific algoritmilor criptografici precum i modul lor de implementare.


Algoritmii criptografici au un timp de via limitat un algoritm trebuie nlocuit
atunci cnd un atac exhaustiv devine posibil datorit progreselor din tehnologia
calculatoarelor. Algoritmii cu securitate condiionat sunt imuni la creterea puterii de
calcul a atacantului n sensul c este suficient alegerea unor parametri de securitate
superiori, de exemplu un numr de bii mai mare pentru cheia criptografic pentru ca
algoritmul s rmn sigur.
Proiectare i analiza algoritmilor cu securitate condiionat este corelat cu
definirea dificultii problemelor n teoria complexitii. Un algoritm criptografic va fi
aplicat n dou moduri: legal, de un utilizator autorizat, i ilegal, de un adversar;
utilizarea autorizat a algoritmului trebuie s fie ct se poate de eficient, n timp ce
utilizarea neautorizat trebuie s fie dificil.

45

Spargerea unui algoritm este echivalent cu gsirea unui algoritm eficient pentru a
rezolva o problem considerat computaional nerezolvabil (de exemplu factorizarea
numerelor prime, logaritmii discrei etc.) la proiectarea algoritmului de criptare.
Securitatea informaonal este o problem care devine tot mai stringent i mai
actual odat cu dezvoltarea reelelor i industriei sistemelor de calcul. Una din
metodele de baz de asigurare a securitii informaonale este metoda criptografic.
Criptografia, la momentul actual acoper un set de protocoale, algoritmi de criptare,
infrastructuri de manipulare a cheilor criptografice etc.
Pentru obnerea unui sistem sigur de protece a informaei este nevoie de prevzut
toate direcile posibile de atac asupra lui, deoarece este inutil de securizat o latur a
sistemului, aunci cnd atacul poate fi uor realizat pe o latur mai sensibil.
Un sistem criptografic este eficient atunci cnd ine echilibrul ntre ceea ce este
necesar i ceea ce este posibil. Pentru crearea unui astfel de sistem este nevoie de
construit o infrastructur pus bine la punct i care ar conne urmoarele componente:
algoritmi criptografici simetrici, asimetrici, de funci dispersive, de semnur digital i
de o infrastructur a cheilor necesare.
n practic cnd apare problema implementrii unui astfel de sistem, se poate de mers pe
dou ci: alegerea unui sistem existent sau crearea unuia nou. Fiecare dintre aceste cre
are i avantaje i dezavantaje. Soluile existente au fost studiate prezent de specialii n
domeniu i aplicate n practic deci ele sunt mult mai sigure de utilizat, problema este
cnu tot timpul aceste sisteme pot fi ncadrate n sistemul nostru informaonal. Deci de
multe ori apare necesitatea crerii unui sistem acordat la necesitile noastre. Un astfel
de sistem este propus pentru transferul securizat de date tre sisteme distribuite de
informai. Acest sistem este o solue eficient pentru companiile (de diferit profil) care
au o infrastructur distribuit de informai. Avantajele aduse fa de sistemele existente
46

sunt flexibilitate, automatizare n lucru i o securitate crescut prin gestionarea local a


certificatelor digitale).
Sistemul criptografic propus permite crearea unor canale de comunicai criptografiate pe
reaua Internet implementeaz o infrastructur local de certificate digitale. Acest tip
de solue se poate de creat efectiv pe platforme de programare ca Java i Microsoft .Net
Framework , etc.
Pentru care tip de solue n-am pleda, este necesar de tiut, c orict de bun i sigur n-ar fi
sistemul folosit, el este insuficient dac este administrat i utilizat incorect.

47

Bibliografie
1. .., .. .
2. . pp p p. -, ABF,
1996

3. . . - : , 1995
4. .. .
5. .. .
6. I. Schaumuller-Bichl, Cryptanalysis of the Data Encryption Standard by a method
of formal coding, Cryptography, Proc. Burg Feuerstein 1982 149 (1983)

7. K.W. Campbell and M.J. Wiener, DES is not a group, Advances in Cryptology -Crypto '92, Springer-Verlag (1993).
8. B.S. Kaliski Jr., R.L. Rivest, and A.T. Sherman, Is the data encryption standard a
group? Journal of Cryptology 1 (1988).
9. Rivest, R., "The MD4 Message Digest Algorithm", RFC 1320, MIT and
48

RSA Data Security, Inc., April 1992.


10. Rivest, R., "The MD4 message digest algorithm", in A.J. Menezes
and S.A. Vanstone, editors, Advances in Cryptology - CRYPTO '90
Proceedings, pages 303-311, Springer-Verlag, 1991.
11. CCITT Recommendation X.509 (1988), "The Directory Authentication Framework."
12. http://www.intuit.ru/
13. http://ru.wikipedia.org

14. http://userpages.umbc.edu
15. http://www.faqs.org

16. http://msdn2.microsoft.com

49

ANEXA
#include <stdio.h>
#include <string.h>

#define uchar unsigned char


#define uint unsigned int
#define DBL_INT_ADD(a,b,c) if (a > 0xffffffff - c) ++b; a += c;
#define ROTLEFT(a,b) ((a << b) | (a >> (32-b)))
#define F(x,y,z) ((x & y) | (~x & z))
#define G(x,y,z) ((x & z) | (y & ~z))
#define H(x,y,z) (x ^ y ^ z)
#define I(x,y,z) (y ^ (x | ~z))
#define FF(a,b,c,d,m,s,t)

a += F(b,c,d) + m + t;\

a = b + ROTLEFT(a,s); }
50

#define GG(a,b,c,d,m,s,t) {

a += G(b,c,d) + m + t; \

a = b + ROTLEFT(a,s);}
#define HH(a,b,c,d,m,s,t){

a += H(b,c,d) + m + t; \

a = b + ROTLEFT(a,s);}
#define II(a,b,c,d,m,s,t) {

a += I(b,c,d) + m + t; \

a = b + ROTLEFT(a,s);}
typedef struct
{
uchar data[64];
uint datalen;
uint bitlen[2];
uint state[4];
} MD5_CTX;

void md5_transform(MD5_CTX *ctx, uchar data[])


{
uint a,b,c,d,m[16],i,j;

51

for (i=0,j=0; i < 16; ++i, j += 4)


m[i] = (data[j]) + (data[j+1] << 8) + (data[j+2] << 16) + (data[j+3] << 24);
a = ctx->state[0];
b = ctx->state[1];
c = ctx->state[2];
d = ctx->state[3];

FF(a,b,c,d,m[0], 7,0xd76aa478);
FF(d,a,b,c,m[1], 12,0xe8c7b756);
FF(c,d,a,b,m[2], 17,0x242070db);
FF(b,c,d,a,m[3], 22,0xc1bdceee);
FF(a,b,c,d,m[4], 7,0xf57c0faf);
FF(d,a,b,c,m[5], 12,0x4787c62a);
FF(c,d,a,b,m[6], 17,0xa8304613);
FF(b,c,d,a,m[7], 22,0xfd469501);
FF(a,b,c,d,m[8], 7,0x698098d8);
FF(d,a,b,c,m[9], 12,0x8b44f7af);
FF(c,d,a,b,m[10],17,0xffff5bb1);
52

FF(b,c,d,a,m[11],22,0x895cd7be);
FF(a,b,c,d,m[12], 7,0x6b901122);
FF(d,a,b,c,m[13],12,0xfd987193);
FF(c,d,a,b,m[14],17,0xa679438e);
FF(b,c,d,a,m[15],22,0x49b40821);

GG(a,b,c,d,m[1], 5,0xf61e2562);
GG(d,a,b,c,m[6], 9,0xc040b340);
GG(c,d,a,b,m[11],14,0x265e5a51);
GG(b,c,d,a,m[0], 20,0xe9b6c7aa);
GG(a,b,c,d,m[5], 5,0xd62f105d);
GG(d,a,b,c,m[10], 9,0x02441453);
GG(c,d,a,b,m[15],14,0xd8a1e681);
GG(b,c,d,a,m[4], 20,0xe7d3fbc8);
GG(a,b,c,d,m[9], 5,0x21e1cde6);
GG(d,a,b,c,m[14], 9,0xc33707d6);
GG(c,d,a,b,m[3], 14,0xf4d50d87);
GG(b,c,d,a,m[8], 20,0x455a14ed);
53

GG(a,b,c,d,m[13], 5,0xa9e3e905);
GG(d,a,b,c,m[2], 9,0xfcefa3f8);
GG(c,d,a,b,m[7], 14,0x676f02d9);
GG(b,c,d,a,m[12],20,0x8d2a4c8a);

HH(a,b,c,d,m[5], 4,0xfffa3942);
HH(d,a,b,c,m[8], 11,0x8771f681);
HH(c,d,a,b,m[11],16,0x6d9d6122);
HH(b,c,d,a,m[14],23,0xfde5380c);
HH(a,b,c,d,m[1], 4,0xa4beea44);
HH(d,a,b,c,m[4], 11,0x4bdecfa9);
HH(c,d,a,b,m[7], 16,0xf6bb4b60);
HH(b,c,d,a,m[10],23,0xbebfbc70);
HH(a,b,c,d,m[13], 4,0x289b7ec6);
HH(d,a,b,c,m[0], 11,0xeaa127fa);
HH(c,d,a,b,m[3], 16,0xd4ef3085);
HH(b,c,d,a,m[6], 23,0x04881d05);
HH(a,b,c,d,m[9], 4,0xd9d4d039);
54

HH(d,a,b,c,m[12],11,0xe6db99e5);
HH(c,d,a,b,m[15],16,0x1fa27cf8);
HH(b,c,d,a,m[2], 23,0xc4ac5665);

II(a,b,c,d,m[0], 6,0xf4292244);
II(d,a,b,c,m[7], 10,0x432aff97);
II(c,d,a,b,m[14],15,0xab9423a7);
II(b,c,d,a,m[5], 21,0xfc93a039);
II(a,b,c,d,m[12], 6,0x655b59c3);
II(d,a,b,c,m[3], 10,0x8f0ccc92);
II(c,d,a,b,m[10],15,0xffeff47d);
II(b,c,d,a,m[1], 21,0x85845dd1);
II(a,b,c,d,m[8], 6,0x6fa87e4f);
II(d,a,b,c,m[15],10,0xfe2ce6e0);
II(c,d,a,b,m[6], 15,0xa3014314);
II(b,c,d,a,m[13],21,0x4e0811a1);
II(a,b,c,d,m[4], 6,0xf7537e82);
II(d,a,b,c,m[11],10,0xbd3af235);
55

II(c,d,a,b,m[2], 15,0x2ad7d2bb);
II(b,c,d,a,m[9], 21,0xeb86d391);

ctx->state[0] += a;
ctx->state[1] += b;
ctx->state[2] += c;
ctx->state[3] += d;

}
void md5_init(MD5_CTX *ctx)
{
ctx->datalen = 0;
ctx->bitlen[0] = 0;
ctx->bitlen[1] = 0;
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xEFCDAB89;
ctx->state[2] = 0x98BADCFE;
ctx->state[3] = 0x10325476;
56

void md5_update(MD5_CTX *ctx, uchar data[], uint len)


{
uint t,i;
for (i=0; i < len; ++i)
{
ctx->data[ctx->datalen] = data[i];
ctx->datalen++;
if (ctx->datalen == 64)
{
md5_transform(ctx,ctx->data);
DBL_INT_ADD(ctx->bitlen[0],ctx->bitlen[1],512);
ctx->datalen = 0;
}
}
}
void md5_final(MD5_CTX *ctx, uchar hash[])
57

{
uint i;
i = ctx->datalen;
if (ctx->datalen < 56)
{
ctx->data[i++] = 0x80;
while (i < 56)
ctx->data[i++] = 0x00;
}
else if (ctx->datalen >= 56)
{
ctx->data[i++] = 0x80;
while (i < 64)
ctx->data[i++] = 0x00;
md5_transform(ctx,ctx->data);
memset(ctx->data,0,56);
}
DBL_INT_ADD(ctx->bitlen[0],ctx->bitlen[1],8 * ctx->datalen);
58

ctx->data[56] = ctx->bitlen[0];
ctx->data[57] = ctx->bitlen[0] >> 8;
ctx->data[58] = ctx->bitlen[0] >> 16;
ctx->data[59] = ctx->bitlen[0] >> 24;
ctx->data[60] = ctx->bitlen[1];
ctx->data[61] = ctx->bitlen[1] >> 8;
ctx->data[62] = ctx->bitlen[1] >> 16;
ctx->data[63] = ctx->bitlen[1] >> 24;
md5_transform(ctx,ctx->data);
for (i=0; i < 4; ++i)
{
hash[i] = (ctx->state[0] >> (i*8)) & 0x000000ff;
hash[i+4] = (ctx->state[1] >> (i*8)) & 0x000000ff;
hash[i+8] = (ctx->state[2] >> (i*8)) & 0x000000ff;
hash[i+12] = (ctx->state[3] >> (i*8)) & 0x000000ff;
}
}

59

void print_hash(char hash[])


{
int idx;
for (idx=0; idx < 16; idx++)
printf("%02x",hash[idx]);
printf("\n");
}
int main()
{
char hash[16],
in1[]={""},
in2[]={"abc"},
in3_1[]={"ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"},
in3_2[]={"fghijklmnopqrstuvwxyz0123456789"};
unsigned int len;
MD5_CTX ctx;
// First hash
md5_init(&ctx);
60

md5_update(&ctx,in1,strlen(in1));
md5_final(&ctx,hash);
printf("\n mesajul 1 criptat");
print_hash(hash);
// Second hash
md5_init(&ctx);
md5_update(&ctx,in2,strlen(in2));
md5_final(&ctx,hash);
printf("\n mesajul 2 criptat");
print_hash(hash);
// Third hash
md5_init(&ctx);
md5_update(&ctx,in3_1,strlen(in3_1));
md5_update(&ctx,in3_2,strlen(in3_2));
md5_final(&ctx,hash);
printf("\n Mesajul 3 criptat");
print_hash(hash);
getchar();
61

return 0;
}

Rezultatul conpilarii:
mesajul 1 criptatffc0ffc2000052ff970000ffbdffc8000035ffc00000
mesajul 2 criptat24700000ffc0ffc4000021fff60000ff99ffed0000
Mesajul 3 criptat67ffd700001440000064710000ffdcffe80000

62

63