MD4 (Message Digest 4) - хеш-функция, разработанная профессором Рональдом Ривестом в 1990 году. Для произвольных входных данных функция MD4 генерирует 128-разрядный хеш. Функция MD4 является предшественником MD5 и до настоящего времени применяется в некоторых сетевых технологиях Windows. В реализации обоих алгоритмов очень много общего, поэтому точно так же в сегменте данных надо подготовить следующие массивы и переменные:
; Сегмент данных
section '.data' data readable writeable
...
; Шаблоны функции wsprintf для перевода хеша в строковый вид,
; при необходимости можно оставить только какой-нибудь один
szMD4Format1 db '%.8X%.8X%.8X%.8X',0 ; Для получения заглавных букв
szMD4Format2 db '%.8x%.8x%.8x%.8x',0 ; Для маленьких букв в строке хеша
stMD4Result:
stdtA dd ? ; Переменные для получения и хранения
stdtB dd ? ; результата хеширования
stdtC dd ?
stdtD dd ?
stMD4Hash rb 33 ; Буфер для строки хеша в формате ASCIIZ
Основная и вспомогательные функции более простые и компактные, к тому же вспомогательных функций всего три, по количеству используемых раундов хеширования.
;-------------------------------------------------------
; Процедура расчета хеша MD4
; На входе:
; dta, dtb, dtc, dtd - начальные значения MD4, по умолчанию = 0
; ptBuffer - указатель на буфер от которого считается хеш
; dtBufferLength - длина буфера в байтах
; На выходе:
; Заполненные переменные stdtA, stdtB, stdtC, stdtD
;-------------------------------------------------------
proc procMD4hash dta, dtb, dtc, dtd, ptBuffer, dtBufferLength
push eax ebx ecx edx edi esi
; phase 1 - padding
mov edi,[ptBuffer]
mov eax,[dtBufferLength]
inc eax
add edi,eax
mov byte [edi-1],080h
xor edx,edx
mov ebx,64
div ebx
neg edx
add edx,64
cmp edx,8
jae @f
add edx,64
@@:
mov ecx,edx
xor al,al
rep stosb
mov eax,[dtBufferLength]
inc edx
add [dtBufferLength],edx
xor edx,edx
mov ebx,8
mul ebx
mov dword [edi-8],eax
mov dword [edi-4],edx
mov edx,[dtBufferLength]
mov edi,[ptBuffer]
; phase II - chaining variables initialization
mov [stdtA],067452301h
mov [stdtB],0efcdab89h
mov [stdtC],098badcfeh
mov [stdtD],010325476h
; phase III - hashing
hashloop:
mov eax,[stdtA]
mov [dta],eax
mov eax,[stdtB]
mov [dtb],eax
mov eax,[stdtC]
mov [dtc],eax
mov eax,[stdtD]
mov [dtd],eax
; round 1
stdcall FF,[dta],[dtb],[dtc],[dtd],dword [edi+00*4],03
mov [dta],eax
stdcall FF,[dtd],[dta],[dtb],[dtc],dword [edi+01*4],07
mov [dtd],eax
stdcall FF,[dtc],[dtd],[dta],[dtb],dword [edi+02*4],11
mov [dtc],eax
stdcall FF,[dtb],[dtc],[dtd],[dta],dword [edi+03*4],19
mov [dtb],eax
stdcall FF,[dta],[dtb],[dtc],[dtd],dword [edi+04*4],03
mov [dta],eax
stdcall FF,[dtd],[dta],[dtb],[dtc],dword [edi+05*4],07
mov [dtd],eax
stdcall FF,[dtc],[dtd],[dta],[dtb],dword [edi+06*4],11
mov [dtc],eax
stdcall FF,[dtb],[dtc],[dtd],[dta],dword [edi+07*4],19
mov [dtb],eax
stdcall FF,[dta],[dtb],[dtc],[dtd],dword [edi+08*4],03
mov [dta],eax
stdcall FF,[dtd],[dta],[dtb],[dtc],dword [edi+09*4],07
mov [dtd],eax
stdcall FF,[dtc],[dtd],[dta],[dtb],dword [edi+10*4],11
mov [dtc],eax
stdcall FF,[dtb],[dtc],[dtd],[dta],dword [edi+11*4],19
mov [dtb],eax
stdcall FF,[dta],[dtb],[dtc],[dtd],dword [edi+12*4],03
mov [dta],eax
stdcall FF,[dtd],[dta],[dtb],[dtc],dword [edi+13*4],07
mov [dtd],eax
stdcall FF,[dtc],[dtd],[dta],[dtb],dword [edi+14*4],11
mov [dtc],eax
stdcall FF,[dtb],[dtc],[dtd],[dta],dword [edi+15*4],19
mov [dtb],eax
; round 2
stdcall GG,[dta],[dtb],[dtc],[dtd],dword [edi+00*4],03
mov [dta],eax
stdcall GG,[dtd],[dta],[dtb],[dtc],dword [edi+04*4],05
mov [dtd],eax
stdcall GG,[dtc],[dtd],[dta],[dtb],dword [edi+08*4],09
mov [dtc],eax
stdcall GG,[dtb],[dtc],[dtd],[dta],dword [edi+12*4],13
mov [dtb],eax
stdcall GG,[dta],[dtb],[dtc],[dtd],dword [edi+01*4],03
mov [dta],eax
stdcall GG,[dtd],[dta],[dtb],[dtc],dword [edi+05*4],05
mov [dtd],eax
stdcall GG,[dtc],[dtd],[dta],[dtb],dword [edi+09*4],09
mov [dtc],eax
stdcall GG,[dtb],[dtc],[dtd],[dta],dword [edi+13*4],13
mov [dtb],eax
stdcall GG,[dta],[dtb],[dtc],[dtd],dword [edi+02*4],03
mov [dta],eax
stdcall GG,[dtd],[dta],[dtb],[dtc],dword [edi+06*4],05
mov [dtd],eax
stdcall GG,[dtc],[dtd],[dta],[dtb],dword [edi+10*4],09
mov [dtc],eax
stdcall GG,[dtb],[dtc],[dtd],[dta],dword [edi+14*4],13
mov [dtb],eax
stdcall GG,[dta],[dtb],[dtc],[dtd],dword [edi+03*4],03
mov [dta],eax
stdcall GG,[dtd],[dta],[dtb],[dtc],dword [edi+07*4],05
mov [dtd],eax
stdcall GG,[dtc],[dtd],[dta],[dtb],dword [edi+11*4],09
mov [dtc],eax
stdcall GG,[dtb],[dtc],[dtd],[dta],dword [edi+15*4],13
mov [dtb],eax
; round 3
stdcall HH,[dta],[dtb],[dtc],[dtd],dword [edi+00*4],03
mov [dta],eax
stdcall HH,[dtd],[dta],[dtb],[dtc],dword [edi+08*4],09
mov [dtd],eax
stdcall HH,[dtc],[dtd],[dta],[dtb],dword [edi+04*4],11
mov [dtc],eax
stdcall HH,[dtb],[dtc],[dtd],[dta],dword [edi+12*4],15
mov [dtb],eax
stdcall HH,[dta],[dtb],[dtc],[dtd],dword [edi+02*4],03
mov [dta],eax
stdcall HH,[dtd],[dta],[dtb],[dtc],dword [edi+10*4],09
mov [dtd],eax
stdcall HH,[dtc],[dtd],[dta],[dtb],dword [edi+06*4],11
mov [dtc],eax
stdcall HH,[dtb],[dtc],[dtd],[dta],dword [edi+14*4],15
mov [dtb],eax
stdcall HH,[dta],[dtb],[dtc],[dtd],dword [edi+01*4],03
mov [dta],eax
stdcall HH,[dtd],[dta],[dtb],[dtc],dword [edi+09*4],09
mov [dtd],eax
stdcall HH,[dtc],[dtd],[dta],[dtb],dword [edi+05*4],11
mov [dtc],eax
stdcall HH,[dtb],[dtc],[dtd],[dta],dword [edi+13*4],15
mov [dtb],eax
stdcall HH,[dta],[dtb],[dtc],[dtd],dword [edi+03*4],03
mov [dta],eax
stdcall HH,[dtd],[dta],[dtb],[dtc],dword [edi+11*4],09
mov [dtd],eax
stdcall HH,[dtc],[dtd],[dta],[dtb],dword [edi+07*4],11
mov [dtc],eax
stdcall HH,[dtb],[dtc],[dtd],[dta],dword [edi+15*4],15
mov [dtb],eax
mov eax,[dta]
add [stdtA],eax
mov eax,[dtb]
add [stdtB],eax
mov eax,[dtc]
add [stdtC],eax
mov eax,[dtd]
add [stdtD],eax
add edi,64
sub edx,64
jnz hashloop
; phase IV - results
mov ecx,4
mov esi,stMD4Result
@@:
mov eax,dword [esi]
xchg al,ah
rol eax,16
xchg al,ah
mov dword [esi],eax
add esi,4
loop @b
pop esi edi edx ecx ebx eax
ret
endp
; a = (a + F(b,c,d) + X[k]) <<< s
proc FF var1,var2,var3,var4,k,s
push ebx ecx
mov eax,[var2]
and eax,[var3]
mov ebx,[var2]
not ebx
and ebx,[var4]
or eax,ebx
add eax,[k]
add eax,[var1]
mov ecx,[s]
rol eax,cl
pop ecx ebx
ret
endp
;a = (a + G(b,c,d) + X[k] + 5A827999) <<< s
proc GG var1,var2,var3,var4,k,s
push ebx ecx
mov eax,[var2]
mov ebx,[var3]
or ebx,[var4]
and eax,ebx
mov ebx,[var3]
and ebx,[var4]
or eax,ebx
add eax,5A827999h
add eax,[k]
add eax,[var1]
mov ecx,[s]
rol eax,cl
pop ecx ebx
ret
endp
; a = (a + H(b,c,d) + X[k] + 6ED9EBA1) <<< s
proc HH var1,var2,var3,var4,k,s
push ecx
mov eax,[var2]
xor eax,[var3]
xor eax,[var4]
add eax,6ED9EBA1h
add eax,[k]
add eax,[var1]
mov ecx,[s]
rol eax,cl
pop ecx
ret
endp
Для накопительного расчета при каждом следующем вызове начальные значения MD4 должны быть проинициализированы результатами предыдущего расчета. Пример использования для одиночной стоки (блока данных):
; Сегмент данных
section '.data' data readable writeable
...
somedata db 'Yeah! I like Flat Assembler!',0 ; Исходные данные для хеширования
; Сегмент кода
section '.code' code readable executable
...
; Расчет длины строки. Для бинарных данных lstrlen лучше не использовать
invoke lstrlen,somedata
; Расчет MD4
stdcall procMD4hash,0,0,0,0,somedata,eax
; Перевод в строку, буквы заглавные
invoke wsprintf,stMD4Hash,szMD4Format1,[stdtA],[stdtB],[stdtC],[stdtD]
...
После выполнения приведенного пример в текстовом буфере
stMD4Hash будет строка хеша MD4 "
87BBCCB2145ACDE7272EA8EDF7184920" в формате ASCIIZ.
Первые уязвимости алгоритма и коллизии были найдены уже через год после его опубликования, но MD4 создавался прежде всего как очень быстрый алгоритм хеширования, поэтому он не является достаточно хорошим в плане криптостойкости. В приложении пример программы с исходным текстом, считающей хеш MD4 от введенной строки.