
Опытный
 
Профиль
Группа: Участник
Сообщений: 313
Регистрация: 22.9.2009
Репутация: нет Всего: 4
|
Здравствуйте. Реализовал класс, протестировав его с разными входными данными получаю правильный результат. Однако не вполне уверен в "нормальности" реализации, хоть "косяков" и не выявил. Буду благодарен, за указания на ошибки, грубые ошибки, технологические неправильности и прочее: | Код | unit HashMd5;
{$mode objfpc}{$H+}
interface
uses SysUtils; //<-- от сюда понадобится только IntToHex type Thashmd5 = class private digest:array[0..3] of DWord; //4 ячейки по 32 бит. Для вычисления хэша buf:array[0..63] of byte; //буфер для помещения данных, для которых рассчитывается хэш. 512 бит. T:array[1..64] of DWord; //массив, в котором хранятся значения 2^32*|sin(i)| bytescount:DWord; //если размер блока будет < 448 по модулю 512, то //будет указывать на смещение, с которого надо //начинать дополнение. В противном случае равно нулю procedure get_sin_values(); //заполняет массив Т целой частью от 2^32*|sin(i)| procedure init(); //осуществляет инициализацию при каждом вычислении хэша function lcs(a,b:DWord):DWord; //lcs - left cyclic shift (возвращает результат //циклического сдвига влево а на b разрядов {элементарные функции(одноименно с названиями в алгоритме получения хэша} function Ff(v1,v2,v3:DWord):DWord; function Fg(v1,v2,v3:DWord):DWord; function Fh(v1,v2,v3:DWord):DWord; function Fi(v1,v2,v3:DWord):DWord;
{4 раунда вычислений} procedure first_round(var A,B,C,D:DWord; var X:array of DWord); procedure second_round(var A,B,C,D:dWORD; var X:array of DWord); procedure third_round(var A,B,C,D:dWORD; var X:array of DWord); procedure fourth_round(var A,B,C,D:dWORD; var X:array of DWord);
{процедура, выполняющая вычисления для каждого блока по 512 байт} procedure hmd5(); public constructor create; //конструктор, выполняющий начальную инициализацию объекта} function get_md5(const source; _size:int64):string; //принимает нетипизированный блок байтов //и размер этого блока, возвращает хэш в виде строки end;
implementation
constructor Thashmd5.create; begin get_sin_values; end;
procedure THashmd5.get_sin_values; var i:integer; begin for i:=1 to 64 do T[i] := trunc(4294967296*abs(sin(i))); //2^32 = 4294967296. берем только целую часть end;
procedure Thashmd5.init; begin FillChar(digest,sizeof(digest),0); //заполняем дайджест нулями FillChar(buf,sizeof(buf),0); //заполняем буфер нулями bytescount:=0; //далее инициализация дайджеста начальными значениями digest[0]:=$67452301; digest[1]:=$efcdab89; digest[2]:=$98badcfe; digest[3]:=$10325476; end;
function Thashmd5.lcs(a,b:DWord):DWord; begin result := (a shl b) or (a shr (32-b)); //32 - размер DWord end;
function Thashmd5.Ff(v1,v2,v3:DWord):DWord; begin Ff:= (v1 and v2) or ((not v1) and v3); end;
function THashmd5.Fg(v1,v2,v3:DWord):DWord; begin Fg := (v1 and v3) or (v2 and (not v3)); end;
function THashmd5.Fh(v1,v2,v3:DWord):DWord; begin Fh := v1 xor v2 xor v3; end;
function THashmd5.Fi(v1,v2,v3:DWord):DWord; begin Fi := v2 xor (v1 or (not v3)); end;
procedure Thashmd5.first_round(var A,B,C,D:DWord; var X:array of DWord); //вспомогательые процедуры, для вычислений в цикле procedure ABCD(k,s,i:integer); begin A := B+lcs((A+Ff(B,C,D)+X[k]+T[i]),s); end; procedure DABC(k,s,i:integer); begin D := A+lcs((D+Ff(A,B,C)+X[k]+T[i]),s); end; procedure CDAB(k,s,i:integer); begin C := D+lcs((C+Ff(D,A,B)+X[k]+T[i]),s); end; procedure BCDA(k,s,i:integer); begin B := C+lcs((B+Ff(C,D,A)+X[k]+T[i]),s); end; begin { первый раунд [abcd k s i] a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s) где, k — номер 32-битного слова из n-го 512-битного блока сообщения s — циклический сдвиг влево на s бит полученого 32-битного аргумента. i - индекс 32-битного слова в матрице Т.
[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]} 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); end;
procedure THashmd5.second_round(var A,B,C,D:DWord; var X:array of DWord); procedure ABCD(k,s,i:integer); begin A := B+lcs((A+Fg(B,C,D)+X[k]+T[i]),s); end; procedure DABC(k,s,i:integer); begin D := A+lcs((D+Fg(A,B,C)+X[k]+T[i]),s); end; procedure CDAB(k,s,i:integer); begin C := D+lcs((C+Fg(D,A,B)+X[k]+T[i]),s); end; procedure BCDA(k,s,i:integer); begin B := C+lcs((B+Fg(C,D,A)+X[k]+T[i]),s); end; begin { второй раунд [abcd k s i] a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s) [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] } 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); end;
procedure THashmd5.third_round(var A,B,C,D:DWord; var X:array of DWord); procedure ABCD(k,s,i:integer); begin A := B+lcs((A+Fh(B,C,D)+X[k]+T[i]),s); end; procedure DABC(k,s,i:integer); begin D := A+lcs((D+Fh(A,B,C)+X[k]+T[i]),s); end; procedure CDAB(k,s,i:integer); begin C := D+lcs((C+Fh(D,A,B)+X[k]+T[i]),s); end; procedure BCDA(k,s,i:integer); begin B := C+lcs((B+Fh(C,D,A)+X[k]+T[i]),s); end; begin {третий раунд [abcd k s i] a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s) [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] [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]} 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); 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); end;
procedure THashmd5.fourth_round(var A,B,C,D:DWord; var X:array of DWord); procedure ABCD(k,s,i:integer); begin A := B+lcs((A+Fi(B,C,D)+X[k]+T[i]),s); end; procedure DABC(k,s,i:integer); begin D := A+lcs((D+Fi(A,B,C)+X[k]+T[i]),s); end; procedure CDAB(k,s,i:integer); begin C := D+lcs((C+Fi(D,A,B)+X[k]+T[i]),s); end; procedure BCDA(k,s,i:integer); begin B := C+lcs((B+Fi(C,D,A)+X[k]+T[i]),s); end; begin { четвертый раунд [abcd k s i] a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s) [ABCD 0 6 49][0DABC 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]} 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); end;
procedure Thashmd5.hmd5; var TMP:array[0..15] of DWord; //промежуточное "хранилище" для блока в 512 бит //удобно хранить в таком формате, что бы прибавлять //значения к вычислениям по индексу A, B, C, D:DWord; begin move(buf,tmp,sizeof(tmp)); A:=digest[0]; B:=digest[1]; C:=digest[2]; D:=digest[3];
first_round(A,B,C,D,TMP); second_round(A,B,C,D,TMP); third_round(A,B,C,D,TMP); fourth_round(A,B,C,D,TMP);
inc(digest[0],A); inc(digest[1],B); inc(digest[2],C); inc(digest[3],D);
fillchar(buf,sizeof(buf),0); end;
function Thashmd5.get_md5(const source; _size:int64):string; var psource:^byte; //указатель на источник. Для более удобного получения блоков по 512 бит hash:array [0..15] of byte; //сюда будет скопирован дайджест, что бы иметь //возможность вывести побайтово представление //хэша в виде hex size:int64; sizeinbits:int64; //размер в битах (в процедуру move можно передать только переменную) i:integer; begin init; size := _size; sizeinbits:=_size*8; psource := @source; while(size > 0) do begin if(size >= 64) then begin move(psource^,buf[bytescount],sizeof(buf)-bytescount); //помещаем в буфер 64байта //из истточника dec(size,sizeof(buf)-bytescount); inc(psource,sizeof(buf)-bytescount); //перемещаем указатель вперед на 64 байта hmd5; end else begin move(psource^,buf[bytescount],size); inc(bytescount,size); size := 0; end; end; {последняя фаза обработки. Здесь осуществляется выравнивание данных. выравнивание состояит в дополнении исходного буфера таким образом, что бы его длина стала равной 448 по модулю 512. Добовление состоит из единицы, за которой следует необходимое количество нулей. в случае, если оставшейся незаполненой длины буфера будет не достаточно, что бы разместить int64+1 байт, через hmd5 будет пропущено еще 2 пакета. Иначе 1} buf[bytescount] := $80; //80hex = 1000 0000bin if bytescount>= 56 then hmd5; move(sizeinbits,buf[56],8); //int64 = 8 байт hmd5; //обработка последнего пакета move(digest,hash,sizeof(digest)); //полученный Хэш находится в массиве digest, копируем его в //hash для более удобного вывода result:=''; for i:=0 to 15 do result:=result+inttohex(hash[i],2); end;
end.
|
на всякий случай все подробно откомментировал. В процессе написания опирался на http://base.vingrad.ru/view/1154-Algoritm-shifrovaniya-MD5потому код выглядит похожим  . Конечно, можно было бы функции и процедуры целиком скопипастить в методы, но я решил сделать немного по-своему, что бы разобраться в том, как происходит вычисление. пример использования: | Код | procedure TForm1.Button1Click(Sender: TObject); var h:THashmd5; begin try h:=THashmd5.create; edit1.text := h.get_md5(Memo1.lines.Text[1],length(memo1.Lines.text)); finally h.free; end; end;
|
Это сообщение отредактировал(а) Чoо - 23.12.2010, 21:16
--------------------
 OS: Debian Squeeze (kernel 3.8.2) IDE: qtCreator 1.3.1; Eclipse SDK 3.5.2
|