; _______________________________________________________________________________________
;|                                                                                       |
;| ..::FreshLib::..  Free, open source. Licensed under "Fresh artistic license."         |
;|_______________________________________________________________________________________|
;
;  Description: OS independent MD5 library.
;
;  Target OS: Any
;
;  Dependencies: memory.asm
;
;  Notes: The original code is from iblis. I changed it a bit, maybe losing performance,
;         but making it more structured.
;
;_________________________________________________________________________________________

module "MD5 library"

struct TContextMD5
    .__cntx rb 88
    .value  rb 16
ends


iglobal
  if used ___MD5InternalData
    ___MD5InternalData db     0,1,1,5,5,3,0,7, \
                              7,5,5,5,5,4,5,6, \
                              4,7,5,7,6,4,5,6
  end if
endg


uglobal
  if used ___MD5SineTable
    ___MD5SineTable  rd       65
  end if
endg



if used md5_open
initialize ___md5_init
begin
        xor     eax, eax
        finit
        pushd   4F800000h
        pushd   0
        fstcw   word [esp+2]
        fstcw   word [esp]
        or      word [esp], 0F3Fh
        fldcw   word [esp]
        push    1
    @@: fild    dword [esp]
        fsin
        fabs
        fmul    dword [esp+8]
        fistp   qword [eax*4+___MD5SineTable]
        inc     dword [esp]
        inc     eax
        test    al, 40h
        jz      @b
        fldcw   word [esp+6]
        add     esp, 12
        return
endp
end if




;******************************************************
; Computes MD5 hash of the data block from [.pData] with
; length in [.pLen]
; Returns new string handle in eax containing the hash of
; the data.
;******************************************************
proc DataMD5, .pData, .pLen
begin
        push    ebx esi edi

        stdcall md5_open
        mov     ebx, eax

        stdcall md5_read, ebx, [.pData], [.pLen]
        stdcall md5_getvalue, ebx

        stdcall StrNew
        mov     edi, eax
        lea     esi, [ebx+TContextMD5.value]
        mov     ecx, 16

.loop:
        movzx   eax, byte [esi]
        inc     esi
        stdcall NumToStr, eax, ntsUnsigned or ntsHex or ntsFixedWidth + 2
        push    eax
        stdcall StrCat, edi, eax
        stdcall StrDel ; from the stack
        loop    .loop

        stdcall StrLCase, edi
        stdcall FreeMem, ebx

        mov     eax, edi
        pop     edi esi ebx
        return
endp






;............................................................................
; md5_open is  used to allocate and initialize TContextMD5 structure for use with
; subsequent processing.
;
; Arguments:
;   no
;
; Return Value: EAX - pointer to the allocated TContextMD5 structure.
;
; Modifies Registers: EAX
;............................................................................
proc md5_open
begin
        push    edi

        stdcall GetMem, sizeof.TContextMD5
        mov     edi, eax
        push    eax

        mov     al, 01h

    @@: stosb
        add     al, 22h
        jnc     @b

        mov     al, 0FEh
    @@: stosb
        sub     al, 22h
        jnc     @b

        xor     eax, eax
        stosd
        stosd

        pop     eax edi
        return
endp




;............................................................................
; MD5_Read scans a  block of data and  updates the  working context.  Call it
; once on a single  block of data, or  call it multiple  times on consecutive
; blocks of data, before retrieving the MD5 signature with MD5_Digest
;
; Arguments:
;   lpMD5CTXT - address of an initialized MD5CTXT structure
;   lpBuf     - address of a contiguous block of data
;   bufLen    - the size, in bytes, of the block of data
;
; Return Value: None
;
; Modifies Registers: None
;............................................................................
proc md5_read ;, .lpMD5CTXT, .lpBuf, .bufLen
begin
        pushad
        mov     esi, [esp+40]
        mov     ebp, [esp+36]
        lea     edi, [ebp+24]
        mov     edx, [esp+44]
        mov     ebx, edi
        mov     eax, edx
        shl     eax, 3
        mov     ecx, edx
        shr     ecx, 29
        push    dword [ebp+16]
        add     [ebp+16], eax
        adc     [ebp+20], ecx
        pop     eax
        shr     eax, 3
        and     eax, 3Fh
   .mn: xor     ecx, ecx
        mov     cl, 40h
        sub     ecx, eax
        cmp     ecx, edx
        jbe     @f
        mov     ecx, edx
    @@: sub     edx, ecx
        add     edi, eax
        add     eax, ecx
        rep     movsb
        mov     edi, ebx
        cmp     eax, 40h
        jb      @f

        stdcall ___md5_BTrnsf, ebx, edi

    @@: xor     eax, eax
        or      edx, edx
        jnz     .mn
        popad
        ret     12
endp




;............................................................................
; md5_getvalue is used to retrieve the MD5 hash for the working context. It may
; be called at any point during a buffer read to get the current MD5 hash for
; all data scanned up to that point.  It does not modify the contexutal data,
; so this procedure may be called as many times as needed.
; The value is stored in the context structure TContextMD5.value
;
; Arguments:
;   .pContextMD5 - address of an TContextMD5 structure
;
; Return Value: None
;
; Modifies Registers: None
;............................................................................
proc md5_getvalue   ;, .pContextMD5
begin
        pushad
        mov     esi, dword [esp+36]
        lea     edi, [esi+TContextMD5.value]
        lea     ebp, [esi+16]
        mov     ebx, edi
        sub     esp, 64
        movsd
        movsd
        movsd
        movsd
        lodsd
        shr     eax, 3
        add     esi, 4
        and     eax, 3Fh
        mov     edi, esp
        mov     ecx, eax
        rep     movsb
        inc     eax
        sub     ecx, eax
        mov     al, 80h
        stosb
        xor     eax, eax
        cmp     ecx, -56
        jae     @f
        xor     eax, eax
        add     ecx, 64
        rep     stosb
        mov     edi, esp

        stdcall ___md5_BTrnsf, ebx, edi

    @@: xor     eax, eax
        add     ecx, 56
        rep     stosb
        mov     esi, ebp
        movsd
        movsd

        stdcall ___md5_BTrnsf, ebx, esp

        add     esp, 64
        popad
        ret     4
endp




proc ___md5_BTrnsf   ;, .phash, .lpBlock
begin
        pushad
        mov     eax, dword [esp+36]
        xor     ecx, ecx
        mov     cl, 4
    @@: push    dword [eax]
        add     eax, 4
        loop    @b
   .mn: mov     ebp, ecx
        shr     ebp, 12
        add     dl, dh
        and     dl, 0Fh
        test    ch, 03h
        jnz     @f
        xor     cl, cl
        test    ch, 0Fh
        jnz     @f
        mov     esi, ___MD5InternalData
        mov     edx, dword [esi+ebp*2]
        mov     ebx, dword [esi+ebp*4+8]
    @@: add     cl, bl
        ror     ebx, 8
        push    edx
        push    ecx
        push    ebx
        mov     ebx, dword [esp+20]
        mov     ecx, dword [esp+16]
        mov     edx, dword [esp+12]
        test    ebp, 02h
        jnz     .hi
        test    ebp, 01h
        jnz     @f
        mov     eax, ebx
        and     ebx, ecx
        not     eax
        and     eax, edx
        or      eax, ebx
        jmp     .fghi
    @@: mov     eax, edx
        and     edx, ebx
        not     eax
        and     eax, ecx
        or      eax, edx
        jmp     .fghi
   .hi: test    ebp, 01h
        jnz     @f
        mov     eax, ebx
        xor     eax, ecx
        xor     eax, edx
        jmp     .fghi
    @@: mov     eax, edx
        not     eax
        or      eax, ebx
        xor     eax, ecx
 .fghi: pop     ebx
        pop     ecx
        pop     edx
        add     eax, dword [esp+12]
        mov     esi, dword [esp+56]
        movzx   edi, dl
        add     eax, dword [esi+edi*4]
        movzx   esi, ch
        add     eax, dword [___MD5SineTable+esi*4]
        rol     eax, cl
        add     eax, dword [esp+8]
        mov     dword [esp+12], eax
        mov     esi, esp
        mov     edi, esp
        lodsd
        movsd
        movsd
        movsd
        stosd
        inc     ch
        test    ch, 40h
        jz      .mn
        mov     eax, dword [esp+52]
        xor     ecx, ecx
        mov     cl, 4
        sub     eax, ecx
    @@: pop     edx
        add     dword [eax+ecx*4], edx
        loop    @b
        popad
        ret     8
endp


endmodule