Here's an alternative that's a bit faster. The structure of the code is based on the SHA code from Netmaestro.
Code: Select all
;================================================================
;
; Library Commands: MD5_FingerPrint()
; MD5_FileFingerPrint()
;
;================================================================
;
;
; Usage:
;
; result$ = MD5_Fingerprint(*address, length)
; result$ = MD5_FileFingerprint(file$, [,*progress])
;
; Progress callback function:
;
; ProcedureC MyCallBack(value.i)
; ; value is 0 to 100 representing percentage completed
; Endprocedure
;================================================================
; STRUCTURE
;================================================================
Structure md5_context
state.l [4]
buffer.a [64]
padding.a [64]
processed.q
jobsize.q
callback.l
EndStructure
;================================================================
; HELPER MACROS
;================================================================
; 0 - 15 f = d xor (b and (c xor d))
Macro P0(a,b,c,d, r, w, k)
!mov ebp, c
!xor ebp, d
!and ebp, b
!xor ebp, d
!add a, ebp
!add a, k
!add a, [edi + (w * 4)]
!rol a, r
!add a, b
EndMacro
; 16 - 31 f = c xor (d and (b xor c))
Macro P1(a,b,c,d, r, w, k)
!mov ebp, b
!xor ebp, c
!and ebp, d
!xor ebp, c
!add a, ebp
!add a, k
!add a, [edi + (w * 4)]
!rol a, r
!add a, b
EndMacro
; 32 - 47 f = b xor c xor d
Macro P2(a,b,c,d, r, w, k)
!mov ebp, d
!xor ebp, b
!xor ebp, c
!add a, ebp
!add a, k
!add a, [edi + (w * 4)]
!rol a, r
!add a, b
EndMacro
; 48 - 63 f = c xor (b or (not d))
Macro P3(a,b,c,d, r, w, k)
!mov ebp, d
!not ebp
!or ebp, b
!xor ebp, c
!add a, ebp
!add a, k
!add a, [edi + (w * 4)]
!rol a, r
!add a, b
EndMacro
;================================================================
; LOCAL FUNCTIONS
;================================================================
Procedure md5_starts(*ctx.md5_context)
*ctx\state[0] = $67452301
*ctx\state[1] = $efcdab89
*ctx\state[2] = $98badcfe
*ctx\state[3] = $10325476
EndProcedure
Procedure md5_process_addr__()
!mov eax, md5_process_start
ProcedureReturn
!md5_process_start:
!sub esp, 16
!mov [esp ], ebx
!mov [esp + 4], esi
!mov [esp + 8], edi
!mov [esp + 12], ebp
!mov esi, [esp + 20] ; *ctx
!mov edi, [esp + 24] ; *bytes
!mov eax, [esi ]
!mov ebx, [esi + 4]
!mov ecx, [esi + 8]
!mov edx, [esi + 12]
!md5_process_loop:
P0(eax, ebx, ecx, edx, 7, 0, 0xd76aa478)
P0(edx, eax, ebx, ecx, 12, 1, 0xe8c7b756)
P0(ecx, edx, eax, ebx, 17, 2, 0x242070db)
P0(ebx, ecx, edx, eax, 22, 3, 0xc1bdceee)
P0(eax, ebx, ecx, edx, 7, 4, 0xf57c0faf)
P0(edx, eax, ebx, ecx, 12, 5, 0x4787c62a)
P0(ecx, edx, eax, ebx, 17, 6, 0xa8304613)
P0(ebx, ecx, edx, eax, 22, 7, 0xfd469501)
P0(eax, ebx, ecx, edx, 7, 8, 0x698098d8)
P0(edx, eax, ebx, ecx, 12, 9, 0x8b44f7af)
P0(ecx, edx, eax, ebx, 17, 10, 0xffff5bb1)
P0(ebx, ecx, edx, eax, 22, 11, 0x895cd7be)
P0(eax, ebx, ecx, edx, 7, 12, 0x6b901122)
P0(edx, eax, ebx, ecx, 12, 13, 0xfd987193)
P0(ecx, edx, eax, ebx, 17, 14, 0xa679438e)
P0(ebx, ecx, edx, eax, 22, 15, 0x49b40821)
P1(eax, ebx, ecx, edx, 5, 1, 0xf61e2562)
P1(edx, eax, ebx, ecx, 9, 6, 0xc040b340)
P1(ecx, edx, eax, ebx, 14, 11, 0x265e5a51)
P1(ebx, ecx, edx, eax, 20, 0, 0xe9b6c7aa)
P1(eax, ebx, ecx, edx, 5, 5, 0xd62f105d)
P1(edx, eax, ebx, ecx, 9, 10, 0x02441453)
P1(ecx, edx, eax, ebx, 14, 15, 0xd8a1e681)
P1(ebx, ecx, edx, eax, 20, 4, 0xe7d3fbc8)
P1(eax, ebx, ecx, edx, 5, 9, 0x21e1cde6)
P1(edx, eax, ebx, ecx, 9, 14, 0xc33707d6)
P1(ecx, edx, eax, ebx, 14, 3, 0xf4d50d87)
P1(ebx, ecx, edx, eax, 20, 8, 0x455a14ed)
P1(eax, ebx, ecx, edx, 5, 13, 0xa9e3e905)
P1(edx, eax, ebx, ecx, 9, 2, 0xfcefa3f8)
P1(ecx, edx, eax, ebx, 14, 7, 0x676f02d9)
P1(ebx, ecx, edx, eax, 20, 12, 0x8d2a4c8a)
P2(eax, ebx, ecx, edx, 4, 5, 0xfffa3942)
P2(edx, eax, ebx, ecx, 11, 8, 0x8771f681)
P2(ecx, edx, eax, ebx, 16, 11, 0x6d9d6122)
P2(ebx, ecx, edx, eax, 23, 14, 0xfde5380c)
P2(eax, ebx, ecx, edx, 4, 1, 0xa4beea44)
P2(edx, eax, ebx, ecx, 11, 4, 0x4bdecfa9)
P2(ecx, edx, eax, ebx, 16, 7, 0xf6bb4b60)
P2(ebx, ecx, edx, eax, 23, 10, 0xbebfbc70)
P2(eax, ebx, ecx, edx, 4, 13, 0x289b7ec6)
P2(edx, eax, ebx, ecx, 11, 0, 0xeaa127fa)
P2(ecx, edx, eax, ebx, 16, 3, 0xd4ef3085)
P2(ebx, ecx, edx, eax, 23, 6, 0x04881d05)
P2(eax, ebx, ecx, edx, 4, 9, 0xd9d4d039)
P2(edx, eax, ebx, ecx, 11, 12, 0xe6db99e5)
P2(ecx, edx, eax, ebx, 16, 15, 0x1fa27cf8)
P2(ebx, ecx, edx, eax, 23, 2, 0xc4ac5665)
P3(eax, ebx, ecx, edx, 6, 0, 0xf4292244)
P3(edx, eax, ebx, ecx, 10, 7, 0x432aff97)
P3(ecx, edx, eax, ebx, 15, 14, 0xab9423a7)
P3(ebx, ecx, edx, eax, 21, 5, 0xfc93a039)
P3(eax, ebx, ecx, edx, 6, 12, 0x655b59c3)
P3(edx, eax, ebx, ecx, 10, 3, 0x8f0ccc92)
P3(ecx, edx, eax, ebx, 15, 10, 0xffeff47d)
P3(ebx, ecx, edx, eax, 21, 1, 0x85845dd1)
P3(eax, ebx, ecx, edx, 6, 8, 0x6fa87e4f)
P3(edx, eax, ebx, ecx, 10, 15, 0xfe2ce6e0)
P3(ecx, edx, eax, ebx, 15, 6, 0xa3014314)
P3(ebx, ecx, edx, eax, 21, 13, 0x4e0811a1)
P3(eax, ebx, ecx, edx, 6, 4, 0xf7537e82)
P3(edx, eax, ebx, ecx, 10, 11, 0xbd3af235)
P3(ecx, edx, eax, ebx, 15, 2, 0x2ad7d2bb)
P3(ebx, ecx, edx, eax, 21, 9, 0xeb86d391)
!add eax, [esi ]
!mov [esi ], eax
!add ebx, [esi + 4]
!mov [esi + 4], ebx
!add ecx, [esi + 8]
!mov [esi + 8], ecx
!add edx, [esi + 12]
!mov [esi + 12], edx
!add edi, 64
!dec dword [esp + 28]
!jnz md5_process_loop
!mov ebx, [esp ]
!mov esi, [esp + 4]
!mov edi, [esp + 8]
!mov ebp, [esp + 12]
!add esp, 16
!ret
EndProcedure
Procedure md5_set_digest_addr__()
!mov eax, md5_set_digest_start
ProcedureReturn
!md5_set_digest_start:
!push ebx
!mov ebx, [esp + 8]
!mov edx, [esp + 12]
!mov ecx, 15
!md5_set_digest_loop:
!mov al, [ebx + ecx]
!mov ah, al
!shr ah, 4
!and ax, 0x0f0f
!or ax, 0x9090
!daa
!adc al, 0x40
!daa
!ror ax, 8
!daa
!adc al, 0x40
!daa
!or ax, 0x2020
!mov [edx + ecx * 2], ax
!sub ecx, 1
!jnc md5_set_digest_loop
!pop ebx
!ret
EndProcedure
PrototypeC md5_process_proto(*ctx, *bytes, blocks)
PrototypeC md5_set_digest_proto(*ctx, *output)
Global md5_process.md5_process_proto = md5_process_addr__()
Global md5_set_digest.md5_set_digest_proto = md5_set_digest_addr__()
Procedure md5_update(*ctx.md5_context, *input, length)
Protected left, fill, blocks
If length = 0 : ProcedureReturn : EndIf
left = *ctx\processed & $3f
fill = 64 - left
*ctx\processed + length
If left And length >= fill
CopyMemory(*input, @*ctx\buffer + left, fill)
md5_process(*ctx, @*ctx\buffer, 1)
length - fill
*input + fill
left = 0
EndIf
blocks = length >> 6
length & $3f
If blocks
md5_process(*ctx, *input, blocks)
*input + blocks << 6
EndIf
If length
CopyMemory(*input, @*ctx\buffer + left, length)
EndIf
EndProcedure
Procedure md5_finish(*ctx.md5_context, *output)
Protected msglen.q, padn
*ctx\padding[0] = $80
padn = 56 - *ctx\processed & 63
If padn <= 0 : padn + 64 : EndIf
msglen = *ctx\jobsize << 3
md5_update(*ctx, @*ctx\padding, padn)
md5_update(*ctx, @msglen, 8)
md5_set_digest(*ctx, *output)
If *ctx\callback
CallCFunctionFast(*ctx\callback, 100)
EndIf
EndProcedure
;================================================================
; EXPORTED FUNCTIONS
;================================================================
ProcedureDLL.s MD5_Fingerprint(*datapointer, length) ; Data address, data size
Protected digest.s
Protected *output, *ctx.md5_context
*ctx = AllocateMemory(SizeOf(md5_context))
*ctx\jobsize = length
*output = AllocateMemory(32)
md5_starts(*ctx)
md5_update(*ctx, *datapointer, length)
md5_finish(*ctx, *output)
digest = PeekS(*output, 32, #PB_Ascii)
FreeMemory(*output)
FreeMemory(*ctx)
ProcedureReturn digest
EndProcedure
ProcedureDLL.s MD5_FileFingerprint(filename.s, *callback = 0) ; filename$, [ ,<procaddress> ]
Protected digest.s
Protected *datapointer, *output, *ctx.md5_context
Protected bytesread, fresult
fresult = OpenFile(#PB_Any, filename)
If fresult
*ctx = AllocateMemory(SizeOf(md5_context))
*ctx\jobsize = Lof(fresult)
*ctx\callback = *callback
*datapointer = AllocateMemory($40000)
*output = AllocateMemory(32)
md5_starts(*ctx)
While Not Eof(fresult)
bytesread = ReadData(fresult, *datapointer, $40000)
md5_update(*ctx, *datapointer, bytesread)
If *ctx\callback
CallCFunctionFast(*ctx\callback, 100 * *ctx\processed / *ctx\jobsize)
EndIf
Wend
CloseFile(fresult)
md5_finish(*ctx, *output)
digest = PeekS(*output, 32, #PB_Ascii)
FreeMemory(*output)
FreeMemory(*datapointer)
FreeMemory(*ctx)
EndIf
ProcedureReturn digest
EndProcedure