;Copyright (C) 1999 Cecchinel Stephan ; ;$Id: rmd.asm,v 1.3 2000/12/10 08:20:36 konst Exp $ ; ;calculate the RIPEMD-160 checksum ; ;this code is free, you can eat it, drink it, fuck it , as you want... ;just send me a mail if you use it, if you find bugs, or anything else... ; ;The RIPEMD-160 algorithm is a 160bit checksum algorithm, it is more ;secure than MD5 algo at the time I write this 7 oct 1999 01:31 am. ;No weakness in this algorithm has been found and the creators ;of the algo tell that for some years it will stay enough secure. ;MD5 algorithm has been proven to be insecure, and should not be ;used anymore for sensible information... ; ;usage is very simple: ;first you call RMD_Init for initialisation of the engine (no input) ;then you call RMD_Update with esi=buffer, ecx=number of bytes to process ; ;RMD_Update calculates the checksum of data block, you can process a file ;in one block or in several blocks, you just have to call RMD_Init to ;re-initialise the RMD engine at the beginning of each new checksum ; ;When you have processed all the file, just call RMD_Final with edi=checksum, ;edi points to 40 byte long buffer to store the 160 bit resulting checksum. ; ;10-Sep-2000 (KB): ; serious cleanup and rearrangement ; speed optimized version merged %include "system.inc" CODESEG global RMD_Init global RMD_Update global RMD_Final ;size of incoming data buffer ;needs to be fixed for RMD_Final ;needs to be a power of two %assign BUFSIZE 0x2000 ;magic initialization constants %assign _A 0x67452301 %assign _B 0xefcdab89 %assign _C 0x98badcfe %assign _D 0x10325476 %assign _E 0xc3d2e1f0 %if __OPTIMIZE__ = __O_SIZE__ ;RMD-160 core constants, bit shifts, offsets ;Never change the order Round1: dd FF,0 db 0,11,1,14,2,15,3,12 db 4,5,5,8,6,7,7,9 db 8,11,9,13,10,14,11,15 db 12,6,13,7,14,9,15,8 Round2: dd GG,0x5a827999 db 7,7,4,6,13,8,1,13 db 10,11,6,9,15,7,3,15 db 12,7,0,12,9,15,5,9 db 2,11,14,7,11,13,8,12 Round3: dd HH,0x6ed9eba1 db 3,11,10,13,14,6,4,7 db 9,14,15,9,8,13,1,15 db 2,14,7,8,0,13,6,6 db 13,5,11,12,5,7,12,5 Round4: dd II,0x8f1bbcdc db 1,11,9,12,11,14,10,15 db 0,14,8,15,12,9,4,8 db 13,9,3,14,7,5,15,6 db 14,8,5,6,6,5,2,12 Round5: dd JJ,0xa953fd4e db 4,9,0,15,5,5,9,11 db 7,6,12,8,2,13,10,12 db 14,5,1,12,3,13,8,14 db 11,11,6,8,15,5,13,6 Round6: dd JJJ,0x50a28be6 db 5,8,14,9,7,9,0,11 db 9,13,2,15,11,15,4,5 db 13,7,6,7,15,8,8,11 db 1,14,10,14,3,12,12,6 Round7: dd III,0x5c4dd124 db 6,9,11,13,3,15,7,7 db 0,12,13,8,5,9,10,11 db 14,7,15,7,8,12,12,7 db 4,6,9,15,1,13,2,11 Round8: dd HHH,0x6d703ef3 db 15,9,5,7,1,15,3,11 db 7,8,14,6,6,6,9,14 db 11,12,8,13,12,5,2,14 db 10,13,0,13,4,7,13,5 Round9: dd GGG,0x7a6d76e9 db 8,15,6,5,4,8,1,11 db 3,14,11,14,15,6,0,14 db 5,6,12,9,2,12,13,9 db 9,12,7,5,10,15,14,8 Round10: dd FFF,0 db 12,8,15,5,10,12,4,9 db 1,12,5,5,8,14,7,6 db 6,8,2,13,13,6,14,5 db 0,15,3,13,9,11,11,11 ;----------------------------------------- ; return: eax=(b)^(c)^(d) FF: FFF: xor ecx,ebx xor ecx,edx jmps endf2 ;---------------------------------------- ; return: eax= ( (b)&(c) | (~b)&(d) ) %define var dword [ebp-24] GGG: GG: and ecx,ebx not ebx and edx,ebx or ecx,edx jmps endf ;---------------------------------------- ; return: eax=( (b)&(d) | (c)&(~d) ) III: II: and ebx,edx not edx and ecx,edx or ecx,ebx jmps endf ;------------------------------------------ ; return: (b)^(c)|(~d) JJJ: JJ: not edx or ecx,edx xor ecx,ebx jmps endf ;------------------------------------------ ; II: return eax=( (b)| ((~c)^(d) ) HHH: HH: not ecx or ecx,ebx xor ecx,edx endf: add ecx,[esi+4] endf2: movzx edx,byte[esi+8] add ecx,[edi+edx*4] add eax,ecx mov cl,byte[esi+9] rol eax,cl add esi,byte 10 ret %endif ;__OPTIMIZE__ ;RMD-160 core hashing function ; ;do the calculation in 5 rounds of 16 calls to in order FF,GG,HH,II,JJ ;then one parallel pass of 5 rounds of 16 calls to JJJ,III,HHH,GGG,FFF ;don't try to understand the code, ;it extensively uses black magic and Voodoo incantations ; ;input: edi: buffer to process %define ee dword [ebp-4] ;local vars on the stack %define dd dword [ebp-8] %define cc dword [ebp-12] %define bb dword [ebp-16] %define aa dword [ebp-20] %if __OPTIMIZE__ = __O_SIZE__ %define e dword [ebp-24] %define d dword [ebp-28] %define c dword [ebp-32] %define b dword [ebp-36] %define a dword [ebp-40] %define eee e %define ddd d %define ccc c %define bbb b %define aaa a ; ;macro for calling the FF,GG,HH,II functions ; %macro invoke_f 5 mov eax,%1 mov ebx,%2 mov ecx,%3 mov edx,%4 call dword [esi] add eax,%5 mov %1,eax rol %3,10 %endmacro %else ;__O_SPEED__ %define eee dword [ebp-24] %define ddd dword [ebp-28] %define ccc dword [ebp-32] %define bbb dword [ebp-36] %define aaa dword [ebp-40] %define a eax %define b ebx %define c ecx %define d edx %define e ebp %macro invokeff 7 mov esi,%2 xor esi,%3 xor esi,%4 add esi,[edi+(%6*4)] add %1,esi rol %1,%7 add %1,%5 rol %3,10 %endmacro %macro invokegg 7 push %2 ;3 (micro-ops for PII family) mov esi,%2 ;1 and esi,%3 ;1 not %2 ;1 and %2,%4 ;1 or esi,%2 ;1 add esi,[edi+(%6*4)] ;2 lea %1,[%1+esi+0x5a827999] ;1 rol %1,%7 ;1 pop %2 ;2 rol %3,10 ;1 add %1,%5 ;1 %endmacro %macro invokehh 7 mov esi,%3 ;1 not esi ;1 or esi,%2 ;1 xor esi,%4 ;1 add esi,[edi+(%6*4)] ;2 lea %1,[%1+esi+0x6ed9eba1] ;1 rol %1,%7 ;1 rol %3,10 ;1 add %1,%5 ;1 %endmacro %macro invokeii 7 push %4 ;3 mov esi,%4 ;1 and esi,%2 ;1 not %4 ;1 and %4,%3 ;1 or esi,%4 ;1 add esi,[edi+(%6*4)] ;2 lea %1,[%1+esi+0x8f1bbcdc] ;1 rol %1,%7 ;1 pop %4 ;2 rol %3,10 ;1 add %1,%5 ;1 %endmacro %macro invokejj 7 mov esi,%4 ;1 not esi ;1 or esi,%3 ;1 xor esi,%2 ;1 add esi,[edi+(%6*4)] ;2 lea %1,[%1+esi+0xa953fd4e] ;1 rol %1,%7 ;1 rol %3,10 ;1 add %1,%5 ;1 %endmacro %macro invokejjj 7 mov esi,%4 not esi or esi,%3 xor esi,%2 add esi,[edi+(%6*4)] lea %1,[%1+esi+0x50a28be6] rol %1,%7 rol %3,10 add %1,%5 %endmacro %macro invokeiii 7 push %4 ;3 mov esi,%4 ;1 and esi,%2 ;1 not %4 ;1 and %4,%3 ;1 or esi,%4 ;1 add esi,[edi+(%6*4)] ;2 lea %1,[%1+esi+0x5c4dd124] ;1 rol %1,%7 ;1 pop %4 ;2 rol %3,10 ;1 add %1,%5 ;1 %endmacro %macro invokehhh 7 mov esi,%3 not esi or esi,%2 xor esi,%4 add esi,[edi+(%6*4)] lea %1,[%1+esi+0x6d703ef3] rol %1,%7 rol %3,10 add %1,%5 %endmacro %macro invokeggg 7 push %2 ;3 mov esi,%2 ;1 and esi,%3 ;1 not %2 ;1 and %2,%4 ;1 or esi,%2 ;1 add esi,[edi+(%6*4)] ;2 lea %1,[%1+esi+0x7a6d76e9] ;1 rol %1,%7 ;1 pop %2 ;2 rol %3,10 ;1 add %1,%5 ;1 %endmacro %endif RMD_Transform: pusha mov ebp,esp sub esp,byte 40 ;protect the local vars space cld push edi mov esi,A lea edi,[ebp-40] push esi _mov ecx,5 push ecx rep movsd pop ecx ;copy A to E in a-d and aa-dd pop esi rep movsd pop edi %if __OPTIMIZE__ = __O_SIZE__ add esi,byte (Rounds-LoPart);esi=Rounds _mov ecx,2 .round0: push ecx _mov ecx,16 .round1: push ecx invoke_f a,b,c,d,e invoke_f e,a,b,c,d invoke_f d,e,a,b,c ;do the jerk invoke_f c,d,e,a,b invoke_f b,c,d,e,a pop ecx loop .round1 pop ecx add ebp,byte 20 dec ecx jnz near .round0 sub ebp,byte 40 %else push ebp mov eax,aaa mov ebx,bbb mov ecx,ccc mov edx,ddd mov ebp,eee ;Round 1 invokeff a,b,c,d,e,0,11 invokeff e,a,b,c,d,1,14 invokeff d,e,a,b,c,2,15 invokeff c,d,e,a,b,3,12 invokeff b,c,d,e,a,4,5 invokeff a,b,c,d,e,5,8 invokeff e,a,b,c,d,6,7 invokeff d,e,a,b,c,7,9 invokeff c,d,e,a,b,8,11 invokeff b,c,d,e,a,9,13 invokeff a,b,c,d,e,10,14 invokeff e,a,b,c,d,11,15 invokeff d,e,a,b,c,12,6 invokeff c,d,e,a,b,13,7 invokeff b,c,d,e,a,14,9 invokeff a,b,c,d,e,15,8 ;Round 2 invokegg e,a,b,c,d,7,7 invokegg d,e,a,b,c,4,6 invokegg c,d,e,a,b,13,8 invokegg b,c,d,e,a,1,13 invokegg a,b,c,d,e,10,11 invokegg e,a,b,c,d,6,9 invokegg d,e,a,b,c,15,7 invokegg c,d,e,a,b,3,15 invokegg b,c,d,e,a,12,7 invokegg a,b,c,d,e,0,12 invokegg e,a,b,c,d,9,15 invokegg d,e,a,b,c,5,9 invokegg c,d,e,a,b,2,11 invokegg b,c,d,e,a,14,7 invokegg a,b,c,d,e,11,13 invokegg e,a,b,c,d,8,12 ;Round 3 invokehh d,e,a,b,c,3,11 invokehh c,d,e,a,b,10,13 invokehh b,c,d,e,a,14,6 invokehh a,b,c,d,e,4,7 invokehh e,a,b,c,d,9,14 invokehh d,e,a,b,c,15,9 invokehh c,d,e,a,b,8,13 invokehh b,c,d,e,a,1,15 invokehh a,b,c,d,e,2,14 invokehh e,a,b,c,d,7,8 invokehh d,e,a,b,c,0,13 invokehh c,d,e,a,b,6,6 invokehh b,c,d,e,a,13,5 invokehh a,b,c,d,e,11,12 invokehh e,a,b,c,d,5,7 invokehh d,e,a,b,c,12,5 ;Round 4 invokeii c,d,e,a,b,1,11 invokeii b,c,d,e,a,9,12 invokeii a,b,c,d,e,11,14 invokeii e,a,b,c,d,10,15 invokeii d,e,a,b,c,0,14 invokeii c,d,e,a,b,8,15 invokeii b,c,d,e,a,12,9 invokeii a,b,c,d,e,4,8 invokeii e,a,b,c,d,13,9 invokeii d,e,a,b,c,3,14 invokeii c,d,e,a,b,7,5 invokeii b,c,d,e,a,15,6 invokeii a,b,c,d,e,14,8 invokeii e,a,b,c,d,5,6 invokeii d,e,a,b,c,6,5 invokeii c,d,e,a,b,2,12 ;Round 5 invokejj b,c,d,e,a,4,9 invokejj a,b,c,d,e,0,15 invokejj e,a,b,c,d,5,5 invokejj d,e,a,b,c,9,11 invokejj c,d,e,a,b,7,6 invokejj b,c,d,e,a,12,8 invokejj a,b,c,d,e,2,13 invokejj e,a,b,c,d,10,12 invokejj d,e,a,b,c,14,5 invokejj c,d,e,a,b,1,12 invokejj b,c,d,e,a,3,13 invokejj a,b,c,d,e,8,14 invokejj e,a,b,c,d,11,11 invokejj d,e,a,b,c,6,8 invokejj c,d,e,a,b,15,5 invokejj b,c,d,e,a,13,6 ;000ooo=======--------------- mov [var1],ebp pop ebp mov aaa,eax mov bbb,ebx mov ccc,ecx mov ddd,edx mov eax,[var1] mov eee,eax push ebp mov eax,aa mov ebx,bb mov ecx,cc mov edx,dd mov ebp,ee ;Round 6 invokejjj a,b,c,d,e,5,8 invokejjj e,a,b,c,d,14,9 invokejjj d,e,a,b,c,7,9 invokejjj c,d,e,a,b,0,11 invokejjj b,c,d,e,a,9,13 invokejjj a,b,c,d,e,2,15 invokejjj e,a,b,c,d,11,15 invokejjj d,e,a,b,c,4,5 invokejjj c,d,e,a,b,13,7 invokejjj b,c,d,e,a,6,7 invokejjj a,b,c,d,e,15,8 invokejjj e,a,b,c,d,8,11 invokejjj d,e,a,b,c,1,14 invokejjj c,d,e,a,b,10,14 invokejjj b,c,d,e,a,3,12 invokejjj a,b,c,d,e,12,6 ;Round 7 invokeiii e,a,b,c,d,6,9 invokeiii d,e,a,b,c,11,13 invokeiii c,d,e,a,b,3,15 invokeiii b,c,d,e,a,7,7 invokeiii a,b,c,d,e,0,12 invokeiii e,a,b,c,d,13,8 invokeiii d,e,a,b,c,5,9 invokeiii c,d,e,a,b,10,11 invokeiii b,c,d,e,a,14,7 invokeiii a,b,c,d,e,15,7 invokeiii e,a,b,c,d,8,12 invokeiii d,e,a,b,c,12,7 invokeiii c,d,e,a,b,4,6 invokeiii b,c,d,e,a,9,15 invokeiii a,b,c,d,e,1,13 invokeiii e,a,b,c,d,2,11 ;Round 8 invokehhh d,e,a,b,c,15,9 invokehhh c,d,e,a,b,5,7 invokehhh b,c,d,e,a,1,15 invokehhh a,b,c,d,e,3,11 invokehhh e,a,b,c,d,7,8 invokehhh d,e,a,b,c,14,6 invokehhh c,d,e,a,b,6,6 invokehhh b,c,d,e,a,9,14 invokehhh a,b,c,d,e,11,12 invokehhh e,a,b,c,d,8,13 invokehhh d,e,a,b,c,12,5 invokehhh c,d,e,a,b,2,14 invokehhh b,c,d,e,a,10,13 invokehhh a,b,c,d,e,0,13 invokehhh e,a,b,c,d,4,7 invokehhh d,e,a,b,c,13,5 ;Round 9 invokeggg c,d,e,a,b,8,15 invokeggg b,c,d,e,a,6,5 invokeggg a,b,c,d,e,4,8 invokeggg e,a,b,c,d,1,11 invokeggg d,e,a,b,c,3,14 invokeggg c,d,e,a,b,11,14 invokeggg b,c,d,e,a,15,6 invokeggg a,b,c,d,e,0,14 invokeggg e,a,b,c,d,5,6 invokeggg d,e,a,b,c,12,9 invokeggg c,d,e,a,b,2,12 invokeggg b,c,d,e,a,13,9 invokeggg a,b,c,d,e,9,12 invokeggg e,a,b,c,d,7,5 invokeggg d,e,a,b,c,10,15 invokeggg c,d,e,a,b,14,8 ;Round 10 invokeff b,c,d,e,a,12,8 invokeff a,b,c,d,e,15,5 invokeff e,a,b,c,d,10,12 invokeff d,e,a,b,c,4,9 invokeff c,d,e,a,b,1,12 invokeff b,c,d,e,a,5,5 invokeff a,b,c,d,e,8,14 invokeff e,a,b,c,d,7,6 invokeff d,e,a,b,c,6,8 invokeff c,d,e,a,b,2,13 invokeff b,c,d,e,a,13,6 invokeff a,b,c,d,e,14,5 invokeff e,a,b,c,d,0,15 invokeff d,e,a,b,c,3,13 invokeff c,d,e,a,b,9,11 invokeff b,c,d,e,a,11,11 ;000ooo===---------------------------- mov [var1],ebp pop ebp mov aa,eax mov bb,ebx mov cc,ecx mov dd,edx mov eax,[var1] mov ee,eax %endif ;__OPTIMIZE__ mov edi,A mov eax,dd add eax,ccc add eax,[edi+4] push eax mov eax,ee add eax,ddd add eax,[edi+8] mov [edi+4],eax mov eax,aa add eax,eee add eax,[edi+12] mov [edi+8],eax mov eax,bb add eax,aaa add eax,[edi+16] mov [edi+12],eax mov eax,cc add eax,bbb add eax,[edi] mov [edi+16],eax pop eax mov [edi],eax add esp,byte 40 popa ret ;--------------------------------------------- ; initialize the RIPEMD-160 engine with the 5 magic constants(_A to _E) ; and clear the LowPart & HighPart counters & the calculation buffer ; then generate the Rounds table from the Round1 to Round8 tables ; ; 1st function to call to calc.RMD160 RMD_Init: pusha cld mov edi,A mov eax,_A stosd mov eax,_B stosd mov eax,_C stosd mov eax,_D stosd mov eax,_E stosd xor eax,eax stosd stosd _mov ecx,16 rep stosd ;clear the buffer %if __OPTIMIZE__ = __O_SIZE__ ;build Rounds table mov esi,Round1 _mov ecx,10 .in1: push ecx mov ebx,[esi] ; get func. mov edx,[esi+4] ; get var. add esi,byte 8 _mov ecx,16 .in2: lodsw mov [edi],ebx mov [edi+4],edx mov [edi+8],ax add edi,byte 10 loop .in2 pop ecx loop .in1 %else ;__O_SPEED__ mov [length],eax %endif ;__OPTIMIZE__ popa ret ;----------------------------------------------- ; the most of the job is done here ; process ecx bytes from esi input buffer ; ; input: esi=input ; ecx=number of bytes RMD_Update: pusha mov edi,esi mov edx,ecx shr ecx,6 jz .upd1a .upd1: call RMD_Transform add edi,byte 64 loop .upd1 .upd1a: mov esi,LoPart mov eax,[esi] mov ecx,eax add eax,edx cmp eax,ecx jge .upd2 inc dword[esi+4] .upd2: mov [esi],eax popa ret ;-------------------------------------------------------------------- ; finalize the job, and write the resulting 160 bits digest RMD code ; in edi buffer (20 bytes length) ; ; RMD_Final: ; input: edi=digest RMD_Final: pusha push edi %if __OPTIMIZE__ = __O_SPEED__ _mov ecx,16 mov edi,buff1 xor eax,eax rep stosd %endif mov esi,buffer mov eax,[LoPart] push eax mov ecx,eax mov edx,eax and eax,(BUFSIZE-64) add esi,eax and ecx,byte 63 mov edi,buff1 push edi rep movsb mov ebx,edx mov ecx,edx shr edx,2 and edx,byte 15 and ecx,byte 3 lea ecx,[ecx*8+7] xor eax,eax inc eax shl eax,cl pop edi xor [edi+edx*4],eax and ebx,byte 63 cmp ebx,byte 55 jle .fin2 call RMD_Transform push edi xor eax,eax _mov ecx, 16 rep stosd pop edi .fin2: pop eax shl eax,3 mov [edi+(14*4)],eax mov eax,[HiPart] shr eax,29 mov [edi+(15*4)],eax call RMD_Transform pop edi _mov ecx,5 mov esi,A rep movsd popa ret UDATASEG ;RMD-160 core registers & buffer ;don't change the order 'cause RMD engine is based on this order A resd 1 B resd 1 C resd 1 D resd 1 E resd 1 LoPart resd 1 HiPart resd 1 buff1 resd 16 ;calculation buffer %if __OPTIMIZE__ = __O_SIZE__ Rounds resb (10*16*10) ;to store the expanded Round1 to Round8 tables %else ;__O_SPEED__ var1 resd 1 length resd 1 %endif ;__OPTIMIZE__ buffer resd BUFSIZE END