News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

MD5 is byte-reversed

Started by jj2007, August 27, 2016, 10:55:17 AM

Previous topic - Next topic

jj2007

This proggie uses the Crypt* functions to calculate the MD5 checksum for qEditor.exe
Everything works fine, except that the result is reversed at byte level, when compared to Jotti's presentation:
CGHP
eax             1
x:xmm0          A6869EAB 7FF88A6B 4E1F20CC 4F8E7DF7
x:xmm1          F77D8E4F CC201F4E 6B8AF87F AB9E86A6


Which one is correct?? I looked into Why do all hash functions use big-endian data? but they don't mention the Windows functions.

include \masm32\MasmBasic\MasmBasic.inc      ; download
uselib advapi32
.data
md5qe      OWORD 0f77d8e4fcc201f4e6b8af87fab9e86a6h            ; Jotti

  SetGlobals hProv, hHash, dwDataLen=OWORD, bData:OWORD
  Init
  Let esi=FileRead$("\Masm32\qEditor.exe")                  ; binary read is OK
  .if rv(CryptAcquireContext, addr hProv, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)
      deb 4, "OK", hProv
      ALG_CLASS_HASH = 4 shl 13                  ; missing constant
      .if rv(CryptCreateHash, hProv, CALG_MD5, 0, 0, addr hHash)
            deb 4, "OK", hHash
            .if rv(CryptHashData, hHash, esi, LastFileSize, 0)
                  deb 4, "CHD OK", eax, LastFileSize
                  .if rv(CryptGetHashParam, hHash, HP_HASHVAL, addr bData, addr dwDataLen, 0)
                        movups xmm0, oword ptr bData
                        movups xmm1, md5qe
                        deb 4, "CGHP", eax, x:xmm0, x:xmm1
                        ; int 3
                  .else
                        deb 4, "CGHP failed", eax
                  .endif
            .else
                  deb 4, "CCH failed", eax
            .endif
            invoke CryptDestroyHash, hHash
      .else
            deb 4, "CCH failed", eax
      .endif
      invoke CryptReleaseContext, hProv, 0
  .else
      deb 4, "CAC failed", eax
  .endif
EndOfCode

ragdog

#1
Hello jochen

The Md5  checksum of C:\masm32\qeditor.exe is 60499945df274484e5e59d476459cb60

Why use you the Windows crypto povider

here is a working code what i use

locals
hProv dd ?
hHash dd ?
endl

lea eax,[hProv]
invoke  CryptAcquireContext,eax,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT + CRYPT_MACHINE_KEYSET
.if eax
push 0 ; ret
lea eax,[hHash]
invoke  CryptCreateHash,[hProv],CALG_MD5,NULL,0,eax
.if eax
invoke  CryptHashData,[hHash],[lpBlock],[iSize],0
.if eax
push 16
mov eax,esp
invoke  CryptGetHashParam,[hHash],HP_HASHVAL,[lpMD5],eax,0
pop eax
.if eax = 16
mov eax,[lpMD5]
mov [esp],eax
.endif
.endif
invoke  CryptDestroyHash,[hHash]
.endif
invoke  CryptReleaseContext,[hProv],0
pop eax
.endif


Or you can use advapi32

MD5_CTX context;
MD5Init (&context);
MD5Update (&context, str, len);
MD5Final (digest, &context);


I hope it helps

Vortex

Hi ragdog,

MD5_CTX context;
MD5Init (&context);
MD5Update (&context, str, len);
MD5Final (digest, &context);


Those MD5 functions are the member of the OpenSSL library :

https://www.openssl.org/docs/manmaster/crypto/MD5.html

ragdog

Hello Vortex

QuoteYou can use advapi32

Md5 support advapi32 5.1 and higher  or cryptdll.inc from Masm32 package

Here i have translate my Cpp code to Masm.


.686
.model flat,stdcall
option casemap:none

include \masm32\include\windows.inc
include \masm32\macros\macros.asm
uselib masm32
uselib user32
uselib kernel32
uselib msvcrt ; crt_*
uselib cryptdll

MD5Hash Proto :dword,:dword

; MD5 state
MD5_state STRUCT
    _A DWORD ?
    _B DWORD ?
    _C DWORD ?
    _D DWORD ?
MD5_state ENDS

; MD5 count
MD5_count STRUCT
    LSB DWORD ?
    MSB DWORD ?
MD5_count ENDS

MD5_CTX STRUCT
    state MD5_state {?}     ; state (ABCD)
    count MD5_count {?}     ; number of bits, modulo 2^64 (lsb first)
    buffer BYTE 64 DUP(?)   ; input buffer
    digest db 16 dup(?)
MD5_CTX ENDS

.data?

hInstance dd ?
szHash db 33 dup (?)

.code
start:
invoke MD5Hash,chr$ ("Masm32"),6
invoke crt_printf,eax
invoke wait_key
    invoke ExitProcess, 0

MD5Hash proc szString:DWORD,nSize:DWORD
LOCAL Context:MD5_CTX
invoke RtlZeroMemory,addr szHash,sizeof szHash
invoke MD5Init,addr Context
invoke MD5Update,addr Context,szString,nSize
invoke MD5Final,addr Context
;-- Convert digest to hexChar
lea esi,Context.digest
lea edi,szHash
xor ebx,ebx
.repeat
movzx   eax, byte ptr [esi+ebx]
invoke wsprintf,edi,chr$ ("%02X"),eax
add edi,2
inc ebx
.until (ebx==16)
mov byte ptr [edi],0
lea edi,szHash
mov eax,edi
ret
MD5Hash endp

end start


Md5 Paras is is almost similar to OpenSSl or other Library´s like drizz or any other.

Here is a other code
http://forum.pellesc.de/index.php?topic=3257.0

I use it on Xp or Win7.

Greets,
Raggy

Vortex

Hi ragdog,

Thanks for the info.

Here is a MSDN example built with Pelles C :

// https://msdn.microsoft.com/en-us/library/windows/desktop/aa382380%28v=vs.85%29.aspx

#include <stdio.h>
#include <windows.h>
#include <Wincrypt.h>

#define BUFSIZE 1024
#define MD5LEN  16

int main(int argc,char *argv[])
{
    DWORD dwStatus = 0;
    BOOL bResult = FALSE;
    HCRYPTPROV hProv = 0;
    HCRYPTHASH hHash = 0;
    HANDLE hFile = NULL;
    BYTE rgbFile[BUFSIZE];
    DWORD cbRead = 0;
    BYTE rgbHash[MD5LEN];
    DWORD cbHash = 0;
    CHAR rgbDigits[] = "0123456789abcdef";
    LPCSTR filename=argv[1];
    // Logic to check usage goes here.

    hFile = CreateFile(filename,
        GENERIC_READ,
        FILE_SHARE_READ,
        NULL,
        OPEN_EXISTING,
        FILE_FLAG_SEQUENTIAL_SCAN,
        NULL);

    if (INVALID_HANDLE_VALUE == hFile)
    {
        dwStatus = GetLastError();
        printf("Error opening file %s\nError: %d\n", filename,
            dwStatus);
        return dwStatus;
    }

    // Get handle to the crypto provider
    if (!CryptAcquireContext(&hProv,
        NULL,
        NULL,
        PROV_RSA_FULL,
        CRYPT_VERIFYCONTEXT))
    {
        dwStatus = GetLastError();
        printf("CryptAcquireContext failed: %d\n", dwStatus);
        CloseHandle(hFile);
        return dwStatus;
    }

    if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash))
    {
        dwStatus = GetLastError();
        printf("CryptAcquireContext failed: %d\n", dwStatus);
        CloseHandle(hFile);
        CryptReleaseContext(hProv, 0);
        return dwStatus;
    }

    while (bResult = ReadFile(hFile, rgbFile, BUFSIZE,
        &cbRead, NULL))
    {
        if (0 == cbRead)
        {
            break;
        }

        if (!CryptHashData(hHash, rgbFile, cbRead, 0))
        {
            dwStatus = GetLastError();
            printf("CryptHashData failed: %d\n", dwStatus);
            CryptReleaseContext(hProv, 0);
            CryptDestroyHash(hHash);
            CloseHandle(hFile);
            return dwStatus;
        }
    }

    if (!bResult)
    {
        dwStatus = GetLastError();
        printf("ReadFile failed: %d\n", dwStatus);
        CryptReleaseContext(hProv, 0);
        CryptDestroyHash(hHash);
        CloseHandle(hFile);
        return dwStatus;
    }

    cbHash = MD5LEN;
    if (CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0))
    {
        printf("MD5 hash of file %s is: ", filename);
        for (DWORD i = 0; i < cbHash; i++)
        {
            printf("%c%c", rgbDigits[rgbHash[i] >> 4],
                rgbDigits[rgbHash[i] & 0xf]);
        }
        printf("\n");
    }
    else
    {
        dwStatus = GetLastError();
        printf("CryptGetHashParam failed: %d\n", dwStatus);
    }

    CryptDestroyHash(hHash);
    CryptReleaseContext(hProv, 0);
    CloseHandle(hFile);

    return dwStatus;
}   


calcmd5.exe calcmd5.exe
MD5 hash of file calcmd5.exe is: acf2ce72a851c10ebc7a0256a7fdcf45

ragdog

My Masm code with  Cryptp provider works too.

Personly use i my last code with Cryptdll or Advapi32 is easier to use,
for a fast writing if I need a function md5.

Many years have i use 3rd party libs like Drizz (Masm32) or other in Cpp.

jj2007

Quote from: ragdog on August 29, 2016, 04:17:42 AM
Why use you the Windows crypto povider

here is a working code what i use

I use the same code that you and Erol use. The only problem is the order of the bytes in the result.
My order is identical to what I see as xmm0 in OllyDbg. Your order is inversed.

include \masm32\MasmBasic\MasmBasic.inc
  Init
  Let esi=FileRead$("calcmd5.exe")
  void GetHash(esi, LastFileSize)
  Print "MD5 hash of file calcmd5.exe is: ", Hex$(xmm0)
EndOfCode


MD5 hash of file calcmd5.exe is: 3D0A6105 3510A45E 5C1DCFDC CEE42EF1    my result
MD5 hash of file calcmd5.exe is: f12ee4cedccf1d5c5ea4103505610a3d      your result


Here is the "culprit" in Erol's code:        printf("MD5 hash of file %s is: ", filename);
        for (DWORD i = 0; i < cbHash; i++)
        {
            printf("%c%c", rgbDigits[rgbHash[i] >> 4],
                rgbDigits[rgbHash[i] & 0xf]);
        }
        printf("\n");


But which order is "correct", and why?

With...  mov ecx, dword ptr bData
  invoke crt_printf, cfm$("\n%x\n"), ecx)

... I get my order.

ragdog

Hello Jochen

What is that for a hash what for a calcmd5.exe from Erol or Yours from first post

From your first post the calcmd5.exe



I understand not MMx but i think you must change the endian

from
3D0A6105 3510A45E 5C1DCFDC CEE42EF1

to

f12ee4cedccf1d5c5ea4103505610a3d 

Your problem is this call (bytes to hex) it change the byte order

00401542 MOVUPS DQWORD PTR DS:[EAX],XMM0          ; |  6F642267003AB405FB636B36B2AF9655 
00401545 PUSH EAX                                 ; |Arg1 = 0041C6EC ASCII "5596AFB2 366B63FB 05B43A00 6722646F"
00401546 CALL CalcMD52.00404EC0                   ; \CalcMD52.00404EC0


00404F1E  |.  66:89045F     |MOV WORD PTR DS:[EDI+EBX*2],AX

You use dec ebx and store the hex bytes (MOV WORD PTR DS:[EDI+EBX*2],AX)  backward .



TWell

QuoteRFC 1321              MD5 Message-Digest Algorithm            April 1992





3.5 Step 5. Output



   The message digest produced as output is A, B, C, D. That is, we

   begin with the low-order byte of A, and end with the high-order byte

   of D.

jj2007

Quote from: TWell on August 29, 2016, 07:00:19 PMRFC 1321              MD5 Message-Digest Algorithm            April 1992

Mystery solved, thanks :t