Arsip: Membuat sendiri UDF library bag.1


by _aa_ in TipDanTrik more 16 years ago 3499
  • judul: Membuat User Defined Function (UDF) untuk firebird 2+
    • add/modify/delete user
    • md4/md5 hash
    • non-null string encryption and helper
      translasi string dari/ke octets, XOR32, nzEncrypt, nzidEncrypt
    • blob handling/info
    • null parameter detection (firebird 2+)
  • kategori: Advanced delphi, advanced TASM, advanced firebird UDF Library programming
  • target audience: experienced delphi programmer, expert, master

Artikel ini disertai dengan source code komplit, plit... (saking komplitnya, sampai harus dibagi jadi 3 bagian) mulai dari konsep sampai implementasi/deklarasi fungsi external dalam kode SQL. Jadi, jika ada masalah, lihat saja source-code-nya; kalau "eni question", tanyakan saja kepada rumput yang bergoyang.

  1. MD4/MD5 Hash
    • MDX5.ASM
      source code asm berisi fungsi hash md4/md5
      (menggunakan fitur makro yang hanya bisa diassembly oleh tasm 4+)
    • mdx5u.pas
      interface pascal untuk fungsi hash md4/md5
  2. Non-null encryption
    • NONZERO.TXT
      artikel tentang natural number rebase,
      konsep yang diimpementasikan oleh dbzCrypt
    • dbzCrypt.pas
      fungsi-fungsi enkripsi spesifik untuk database
      (tidak menghasilkan null-char, tidak merubah index/urutan)
  3. UDF library
    • sec_h.pas
      pascal interface untuk modul isc_sec (modifikasi user)
    • ass.dpr
      contoh project UDF library berisi:
      - add/modify/delete user
      - md4/md5 hash
      - non-null string encryption
      - blob handling/info
      semua rutin telah mengakomodasi udf null parameter detection
      (fitur ini hanya terdapat di firebird 2+)
    • ass.SQL
      deklarasi UDF untuk firebird 2+
MDX5.ASM
PAGE 255,240
%BIN 0
.386
;---------------------------------------------
; this is the real  FAST md4/md5 hash
; assembler: turbo assembler tasm/tasm32
; version: 1.0.0.2
;
; important! using register calling convention
;
; copyright 2005, aa, Adrian Hafizh & Inge DR.
; Property of PT SOFTINDO Jakarta.
; All rights reserved.
;
; mail,to:@[zero_inge]AT@-y.a,h.o.o.@DOTcom,
; mail,to:@[aa]AT@-s.o.f.t,i.n.d.o.@DOTnet
; http://delphi.softindo.net
;---------------------------------------------
; USAGE
; 1. call __mdxinit
;      argument is pointer to 16 bytes MD4/MD5 digest, passed via EAX
; 2. call __mdx5fetch/__mdx4fetch for every integral chunks of 64 bytes
;    do not call it if the length of the chunk is less than 64 bytes
;      arguments are:
;        pointer to 16 bytes MD4/MD5 digest, passed via EAX
;        pointer to 64 bytes data chunk, passed via EDX
;    call after here also any tracking/gauge/progress function you wish
;    do not worry, all registers are preserved here
; 3. call __mdx5finalize/__mdx4finalize for the last chunk whose length
;    less than 64 bytes (including 0 length chunk, if total size is perfectly
;    64 bytes fold or the total length itself was 0)
;      arguments are:
;        pointer to 16 bytes MD4/MD5 digest, passed via EAX
;        pointer to 0-63 bytes data chunk tail (last), passed via EDX
;        Original/Total Data Size/Length in bytes (up to 72057594037927935 bytes)
;          passed via stack as a pair of DWORDs, intel's BigEndian scheme, which
;          is simply an int64 type in Delphi
; 4. done. result in 16 bytes MD4/MD5 digest
;
;--------------------------------------------------------
; 2006.1.1 fixed bug: bad passing parameters by dirty trick in md[4/5/x]finalize,
;                     now using clean and obvious way
;; MAGIC NUMBERS1
A00 = 067452301h
B00 = 0efcdab89h
C00 = 098badcfeh
D00 = 010325476h
;; MAGIC NUMBERS2
;; 4294967296 times abs(sin(i)), where i is in radians
;; grouped according to associated macro's block
;; MD5:  A = B + ((A + FUNC(b, c, d) + X + t) <<< s)
;; MD4:  A = A + FUNC(b, c, d) + X + t) <<< s
ENTRANCE macro @@A, @@B, @@X, @@t ;; modified: @@A, saved: @@B, @@A + @@X + @@t
ifnb <;@@t>
add   @@A, @@t
endif
add   @@A, @@X
mov   tmp, @@A
push  @@B
endm
DEPART macro @@A, @@B, @@s ;; modified: @@A, restored: @@B
mov   @@B, tmp
add   @@A, @@B
rol   @@A, @@s
pop   @@B
add   @@A, @@B
endm
F5 macro  @@A, @@B, @@C, @@D, @@X, @@s, @@t ;; Result in: @@A, Modified: @@B
; A = B + ((A + FUNC(b, c, d) + X + t) <<< s)
ENTRANCE @@A, @@B, <;@@X>, @@t
; FUNC1(b, c, d) = (b and c) or ((not b) and d)
mov   @@A, @@B
and   @@A, @@C
not   @@B
and   @@B, @@D
or    @@A, @@B
DEPART  @@A, @@B, @@s
endm
G5 macro  @@A, @@B, @@C, @@D, @@X, @@s, @@t
; A = B + ((A + FUNC(b, c, d) + X + t) <<< s)
ENTRANCE @@A, @@B, <;@@X>, @@t
; FUNC2(b, c, d) = (b and d) or (c and (not d))
and   @@B, @@D
mov   @@A, @@B
mov   @@B, @@D
not   @@B
and   @@B, @@C
or    @@A, @@B
DEPART  @@A, @@B, @@s
endm
H5 macro  @@A, @@B, @@C, @@D, @@X, @@s, @@t
; A = B + ((A + FUNC(b, c, d) + X + t) <<< s)
;;ENTRANCE @@A, @@B, <;@@X>, @@t
;;  ; FUNC3(b, c, d) = b xor c xor d
;;  mov   @@A, @@B
;;  xor   @@A, @@C
;;  xor   @@A, @@D
;;DEPART  @@A, @@B, @@s
HX @@A, @@B, @@C, @@D, @@X, @@s, @@t
add @@A, @@B
endm
I5 macro  @@A, @@B, @@C, @@D, @@X, @@s, @@t
; A = B + ((A + FUNC(b, c, d) + X + t) <<< s)
ENTRANCE @@A, @@B, <;@@X>, @@t
; FUNC4(b, c, d) = c xor (b or (not d))
mov   @@A, @@D
not   @@A
or    @@A, @@B
xor   @@A, @@C
DEPART  @@A, @@B, @@s
endm
;MD4
ENTRANCE4 macro @@A, @@B, @@X, @@t ;; modified: @@A, saved: @@B, @@A + @@X + @@t
ifnb <;@@t>
ENTRANCE @@A, @@B, <;@@X>, @@t
else
ENTRANCE @@A, @@B, <;@@X>
endif
mov   @@A, @@B
endm
DEPART4 macro @@A, @@B, @@s ;; modified: @@A, restored: @@B
mov   @@B, tmp
add   @@A, @@B
rol   @@A, @@s
pop   @@B
;add   @@A, @@B
endm
F4 macro  @@A, @@B, @@C, @@D, @@X, @@s ;; Result in: @@A, Modified: @@B
; A = (A + func(B, C, D) + X[i]) <<< s
ENTRANCE4 @@A, @@B, <;@@X>
; FUNC1(b, c, d) = (b and c) or ((not b) and d)
and   @@A, @@C
not   @@B
and   @@B, @@D
or    @@A, @@B
DEPART4 @@A, @@B, @@s
endm
G4 macro  @@A, @@B, @@C, @@D, @@X, @@s, @@t
; A = (A + func(B, C, D) + X[i] + 5A827999h) <<< s
ENTRANCE4 @@A, @@B, <;@@X>, @@t
; FUNC2(b, c, d) = (b and c) or (b and d) or (c and d))
and   @@B, @@C
and   @@A, @@D
or    @@A, @@B
;
mov   @@B, @@C
and   @@B, @@D
or    @@A, @@B
DEPART4 @@A, @@B, @@s
endm
H4 macro  @@A, @@B, @@C, @@D, @@X, @@s, @@t
; A = (A + func(B, C, D) + X[i] + 6ED9EBA1) <<< s
;;ENTRANCE4 @@A, @@B, <;@@X>, @@t
;;  ; FUNC3(b, c, d) = b xor c xor d
;;  xor   @@A, @@C
;;  xor   @@A, @@D
;;DEPART4 @@A, @@B, @@s
HX @@A, @@B, @@C, @@D, @@X, @@s, @@t
endm
HX macro  @@A, @@B, @@C, @@D, @@X, @@s, @@t
push @@B
xor @@B, @@C
xor @@B, @@D
add @@B, @@t
add @@B, @@A
mov @@A, @@X
add @@A, @@B
rol @@A, @@s
pop @@B
endm
.model FLAT
.code
PUBLIC __mdxInit
TDigest struc
dtA dd ?
dtB dd ?
dtC dd ?
dtD dd ?
TDigest ends
__mdxInit proc near ;; (var PDigest:eax)
; Param1:PDigest:DWORD
; arg PDigest:dword = ArgSize // not used, using register instead
%BIN 24
XDigest equ <[eax].TDigest>
mov XDigest.dtA, A00
mov XDigest.dtB, B00
mov XDigest.dtC, C00
mov XDigest.dtD, D00
ret; //ArgSize
%BIN 0
__mdxInit endp
A equ eax
B equ ebx
C equ ecx
D equ edx
E equ dword ptr [edi]
align 4
PUBLIC __MDX5fetch ; ALL registers are preserved
__MDX5fetch proc near ;; (var PDigest:eax; const PBuffer64:edx)
; ==================================================================
; Param1:PDigest:DWORD, Param2:PBuffer64:DWORD
; arg PDigest: dword, PBuffer64:dword = ArgSize // not used, using register instead
; DO NOT call under pascal calling convention! use explicit register directive if had to
; (the caller must not push anything into the stack, pass the args via registers instead)
; ==================================================================
%BIN 24
local tmp:dword, Algo:dword = LocalSize
push ebp              ; since we're using local storage
mov ebp, esp          ; stack-pointer must be adjusted here
add esp, -LocalSize   ;
pushad
mov esi, eax
mov edi, edx
mov A, [esi.TDigest.dtA]
mov B, [esi.TDigest.dtB]
mov C, [esi.TDigest.dtC]
mov D, [esi.TDigest.dtD]
S0 = 07h
S1 = 0Ch
S2 = 11h
S3 = 16h
F5 A, B, C, D, 00]>, S0, 0d76aa478h ; Step 1
F5 D, A, B, C,  01]>, S1, 0e8c7b756h ; Step 2
F5 C, D, A, B, 02]>, S2, 0242070dbh ; Step 3
F5 B, C, D, A,  03]>, S3, 0c1bdceeeh ; Step 4
F5 A, B, C, D, 04]>, S0, 0f57c0fafh ; Step 5
F5 D, A, B, C,  05]>, S1, 04787c62ah ; Step 6
F5 C, D, A, B, 06]>, S2, 0a8304613h ; Step 7
F5 B, C, D, A,  07]>, S3, 0fd469501h ; Step 8
F5 A, B, C, D, 08]>, S0, 0698098d8h ; Step 9
F5 D, A, B, C,  09]>, S1, 08b44f7afh ; Step 10
F5 C, D, A, B, 10]>, S2, 0ffff5bb1h ; Step 11
F5 B, C, D, A,  11]>, S3, 0895cd7beh ; Step 12
F5 A, B, C, D, 12]>, S0, 06b901122h ; Step 13
F5 D, A, B, C,  13]>, S1, 0fd987193h ; Step 14
F5 C, D, A, B, 14]>, S2, 0a679438eh ; Step 15
F5 B, C, D, A,  15]>, S3, 049b40821h ; Step 16
S0 = 05h
S1 = 09h
S2 = 0Eh
S3 = 14h
G5 A, B, C, D, 01]>, S0, 0f61e2562h ; Step 17
G5 D, A, B, C,  06]>, S1, 0c040b340h ; Step 18
G5 C, D, A, B, 11]>, S2, 0265e5a51h ; Step 19
G5 B, C, D, A,  00]>, S3, 0e9b6c7aah ; Step 20
G5 A, B, C, D, 05]>, S0, 0d62f105dh ; Step 21
G5 D, A, B, C,  10]>, S1, 002441453h ; Step 22
G5 C, D, A, B, 15]>, S2, 0d8a1e681h ; Step 23
G5 B, C, D, A,  04]>, S3, 0e7d3fbc8h ; Step 24
G5 A, B, C, D, 09]>, S0, 021e1cde6h ; Step 25
G5 D, A, B, C,  14]>, S1, 0c33707d6h ; Step 26
G5 C, D, A, B, 03]>, S2, 0f4d50d87h ; Step 27
G5 B, C, D, A,  08]>, S3, 0455a14edh ; Step 28
G5 A, B, C, D, 13]>, S0, 0a9e3e905h ; Step 29
G5 D, A, B, C,  02]>, S1, 0fcefa3f8h ; Step 30
G5 C, D, A, B, 07]>, S2, 0676f02d9h ; Step 31
G5 B, C, D, A,  12]>, S3, 08d2a4c8ah ; Step 32
S0 = 04h
S1 = 0Bh
S2 = 10h
S3 = 17h
H5 A, B, C, D, 05]>, S0, 0fffa3942h ; Step 33
H5 D, A, B, C,  08]>, S1, 08771f681h ; Step 34
H5 C, D, A, B, 11]>, S2, 06d9d6122h ; Step 35
H5 B, C, D, A,  14]>, S3, 0fde5380ch ; Step 36
H5 A, B, C, D, 01]>, S0, 0a4beea44h ; Step 37
H5 D, A, B, C,  04]>, S1, 04bdecfa9h ; Step 38
H5 C, D, A, B, 07]>, S2, 0f6bb4b60h ; Step 39
H5 B, C, D, A,  10]>, S3, 0bebfbc70h ; Step 30
H5 A, B, C, D, 13]>, S0, 0289b7ec6h ; Step 41
H5 D, A, B, C,  00]>, S1, 0eaa127fah ; Step 42
H5 C, D, A, B, 03]>, S2, 0d4ef3085h ; Step 43
H5 B, C, D, A,  06]>, S3, 004881d05h ; Step 44
H5 A, B, C, D, 09]>, S0, 0d9d4d039h ; Step 45
H5 D, A, B, C,  12]>, S1, 0e6db99e5h ; Step 46
H5 C, D, A, B, 15]>, S2, 01fa27cf8h ; Step 47
H5 B, C, D, A,  02]>, S3, 0c4ac5665h ; Step 48
S0 = 06h
S1 = 0Ah
S2 = 0Fh
S3 = 15h
I5 A, B, C, D, 00]>, S0, 0f4292244h ; Step 49
I5 D, A, B, C,  07]>, S1, 0432aff97h ; Step 50
I5 C, D, A, B, 14]>, S2, 0ab9423a7h ; Step 51
I5 B, C, D, A,  05]>, S3, 0fc93a039h ; Step 52
I5 A, B, C, D, 12]>, S0, 0655b59c3h ; Step 53
I5 D, A, B, C,  03]>, S1, 08f0ccc92h ; Step 54
I5 C, D, A, B, 10]>, S2, 0ffeff47dh ; Step 55
I5 B, C, D, A,  01]>, S3, 085845dd1h ; Step 56
I5 A, B, C, D, 08]>, S0, 06fa87e4fh ; Step 57
I5 D, A, B, C,  15]>, S1, 0fe2ce6e0h ; Step 58
I5 C, D, A, B, 06]>, S2, 0a3014314h ; Step 59
I5 B, C, D, A,  13]>, S3, 04e0811a1h ; Step 50
I5 A, B, C, D, 04]>, S0, 0f7537e82h ; Step 61
I5 D, A, B, C,  11]>, S1, 0bd3af235h ; Step 62
I5 C, D, A, B, 02]>, S2, 02ad7d2bbh ; Step 63
I5 B, C, D, A,  09]>, S3, 0eb86d391h ; Step 64
;@@DoneTransform:
add [esi.TDigest.dtA], A
add [esi.TDigest.dtB], B
add [esi.TDigest.dtC], C
add [esi.TDigest.dtD], D
popad
mov esp, ebp
pop ebp
ret; //ArgSize
%BIN 0
__MDX5fetch endp
align 4
PUBLIC __MDX4fetch ; ALL registers are preserved
__MDX4fetch proc near ;; (var PDigest:eax; const PBuffer64:edx)
; ==================================================================
; Param1:PDigest:DWORD, Param2:PBuffer64:DWORD
; arg PDigest: dword, PBuffer64:dword = ArgSize // not used, using register instead
; DO NOT call under pascal calling convention! use explicit register directive if had to
; (the caller must not push anything into the stack, pass the args via registers instead)
; ==================================================================
%BIN 24
local tmp:dword, Algo:dword = LocalSize
push ebp              ; since we're using local storage
mov ebp, esp          ; stack-pointer must be adjusted
add esp, -LocalSize   ;
pushad
mov esi, eax
mov edi, edx
mov A, [esi.TDigest.dtA]
mov B, [esi.TDigest.dtB]
mov C, [esi.TDigest.dtC]
mov D, [esi.TDigest.dtD]
S0 = 03h
S1 = 07h
S2 = 0Bh
S3 = 13h
F4x = 0
rept 4
F4 A, B, C, D, (F4x+0)]>, S0
F4 D, A, B, C,  (F4x+1)]>, S1
F4 C, D, A, B, (F4x+2)]>, S2
F4 B, C, D, A,  (F4x+3)]>, S3
F4x = (F4x + 4)
endm
S0 = 03h
S1 = 05h
S2 = 09h
S3 = 0Dh
G4t = 5A827999h
G4 A, B, C, D, 00]>, S0, G4t
G4 D, A, B, C,  04]>, S1, G4t
G4 C, D, A, B, 08]>, S2, G4t
G4 B, C, D, A,  12]>, S3, G4t
G4 A, B, C, D, 01]>, S0, G4t
G4 D, A, B, C,  05]>, S1, G4t
G4 C, D, A, B, 09]>, S2, G4t
G4 B, C, D, A,  13]>, S3, G4t
G4 A, B, C, D, 02]>, S0, G4t
G4 D, A, B, C,  06]>, S1, G4t
G4 C, D, A, B, 10]>, S2, G4t
G4 B, C, D, A,  14]>, S3, G4t
G4 A, B, C, D, 03]>, S0, G4t
G4 D, A, B, C,  07]>, S1, G4t
G4 C, D, A, B, 11]>, S2, G4t
G4 B, C, D, A,  15]>, S3, G4t
S0 = 03h
S1 = 09h
S2 = 0Bh
S3 = 0Fh
H4t = 6ED9EBA1h
H4 A, B, C, D, 00]>, S0, H4t
H4 D, A, B, C,  08]>, S1, H4t
H4 C, D, A, B, 04]>, S2, H4t
H4 B, C, D, A,  12]>, S3, H4t
H4 A, B, C, D, 02]>, S0, H4t
H4 D, A, B, C,  10]>, S1, H4t
H4 C, D, A, B, 06]>, S2, H4t
H4 B, C, D, A,  14]>, S3, H4t
H4 A, B, C, D, 01]>, S0, H4t
H4 D, A, B, C,  09]>, S1, H4t
H4 C, D, A, B, 05]>, S2, H4t
H4 B, C, D, A,  13]>, S3, H4t
H4 A, B, C, D, 03]>, S0, H4t
H4 D, A, B, C,  11]>, S1, H4t
H4 C, D, A, B, 07]>, S2, H4t
H4 B, C, D, A,  15]>, S3, H4t
;@@DoneTransform:
add [esi.TDigest.dtA], A
add [esi.TDigest.dtB], B
add [esi.TDigest.dtC], C
add [esi.TDigest.dtD], D
popad
mov esp, ebp
pop ebp
ret; //ArgSize
%BIN 0
__MDX4fetch endp
align 4
PUBLIC __mdx5Finalize
;__mdx5Finalize proc near ;; (var PDigest, PBuffer64: pointer; Length: int64)
; ==================================================================
; Param1:eax:DWORD, Param2:edx:DWORD, Param3:[esp-4]:[esp-8] (High:Low)
; only ActualLength pushed into stack; note: [esp] contains return eip!
; (push ONLY Length into the stack, pass the first 2 arguments via register)
; DO NOT call under pascal calling convention!
; use explicit 'register' compiler directive if it had to
; ==================================================================
;%BIN 24
;arg LengthLo:DWORD, LengthHi:DWORD = ArgSize
;push LengthHi
;push LengthLo
;push 5  ;; means MD5
;call __mdxFinalize
;ret ArgSize
;__mdx5Finalize endp
;%BIN 0
PUBLIC __mdx4Finalize
;__mdx4Finalize proc near ;; (var PDigest, PBuffer64: pointer; Length: int64)
; ==================================================================
; comments equ ABOVE
; ==================================================================
;%BIN 24
;arg LengthLo:DWORD, LengthHi:DWORD = ArgSize
;push LengthHi
;push LengthLo
;push 4  ;; means MD4
;call __mdxFinalize
;ret ArgSize
;__mdx4Finalize endp
;%BIN 0
PUBLIC __mdxFinalize
TRUE = 1
FALSE = 0
MDxCSize = size TMDxChunk
MDxCMask = MDxCSize - 1
%BIN 24
TMDxChunk struc
DataPadding    db 56 dup (?)
DataLength_Lo  dd ?
DataLength_Hi  dd ?
TMDxChunk ends
%BIN 0
__mdxFinalize proc near ; (var PDigest, PBuffer64: pointer; Algo: integer; Length: int64)
; ActualLengthHi, ActualLengthLo and Algorithm respectively, had been
; pushed into stack in that order, the stack contents then:
;                                - ebp
;   [ESP] = EIP (return address) - ebp +4
;   [ESP+04] = LLo               - ebp +c
;   [ESP+08] = LHi               - ebp +10
; (bottom = 00000000)
%BIN 24
;arg Algo:dword, LengthHi:DWORD, LengthLo:DWORD = ArgSize
arg LengthLo:DWORD, LengthHi:DWORD = ArgSize
local Extend:byte, Algo:byte, Buf:TMDxChunk:2 = LocalSize
jmp short @@mdxFinalizeStart
__mdx4Finalize label near
mov cl,4
jmp short @@mdxFinalizeStart
__mdx5Finalize label near
mov cl,5
;jmp short @@mdxFinalizeStart
@@mdxFinalizeStart:
push ebp             ; since we're using local storage
mov ebp, esp         ; stack-pointer must be adjusted here
sub esp, LocalSize   ; add esp, -LocalSize
cmp cl,4             ; anything not equal 4 means MD5
setne Algo
add Algo,4
push esi
push edi
mov esi, eax
mov edi, edx
mov eax, LengthLo
mov edx, LengthHi
mov ecx, eax
shld eax, edx, 3
mov dword ptr Buf.DataLength_Hi, edx            ; Buf[00+56+4]
mov dword ptr Buf[+MDxCSize].DataLength_Hi, edx ; Buf[64+56+4]
mov dword ptr Buf.DataLength_Lo, eax            ; Buf[00+56]
mov dword ptr Buf[+MDxCSize].DataLength_Lo, eax ; Buf[64+56]
mov eax, ecx
and eax, MDxCMask ;; 64 bytes/512bits block, size of TBuffer64
push eax
mov byte ptr Buf[eax], 80h
dec eax
jl short @@movedone
@@L_MoveData:
mov dl, edi[eax]
mov byte ptr Buf[eax], dl
dec eax
jge short @@L_MoveData
@@movedone:
pop eax
xor edx, edx
mov Extend, dl
push edi
lea edi, Buf.DataLength_Lo
sub eax, 56 ;; congruent 448 bits check
jl short @@goon
@@extend:
mov Extend, TRUE
lea edi, edi[+MDxCSize]
sub eax, MDxCSize
@@goon:
inc eax
jz short @@done
@@fillblank:
inc eax
mov edi[eax-1], dl
jl short @@fillblank
@@done:
pop edi
mov eax, esi
lea edx, Buf
cmp Algo, 4
je short @@md4
call __MDX5fetch
test Extend, 1
jz short @@end
add edx, 64
call __MDX5fetch
jmp short @@end
@@md4:
call __MDX4fetch
test Extend, 1
jz short @@end
add edx, 64
call __MDX4fetch
jmp short @@end
@@end:
pop edi
pop esi
mov esp, ebp
pop ebp
ret ArgSize
%BIN 0
__mdxFinalize endp
END
mdx5u.pas
unit mdx5u; // no file support
//{$D+}
// sample interface to mdx5.obj
// this is the real  FAST md4/md5 hashing
// capable checksuming filesize upto 72057594037927935 bytes
// (that is more than 72 'peta' bytes)
//
{
; copyright 2005, aa, Adrian Hafizh & Inge DR.
; Property of PT SOFTINDO Jakarta.
; All rights reserved.
;
; mail,to:@[zero_inge]AT@-y.a,h.o.o.@DOTcom,
; mail,to:@[aa]AT@-s.o.f.t,i.n.d.o.@DOTnet
; http://delphi.softindo.net
}
// see also our real  FAST cxpos search/replace string
interface
type
  tmdxAlgorithm = (mda4, mda5);
  tmdxSum = type string; // string[16];
  pmdxDigest = ^tmdxDigest;
  tmdxDigest = packed record
    case integer of
      1: (A, B, C, D: Cardinal);
      2: (I64Lo, I64Hi: int64);
      3: (Dump: array[1..16] of char);
  end;
// return string (32 bytes)
function md4Sum(const S: string): tmdxSum; overload;
function md4Sum(const Buffer: pointer; const Length: Longword): tmdxSum; overload;
function md5Sum(const S: string): tmdxSum; overload;
function md5Sum(const Buffer: pointer; const Length: Longword): tmdxSum; overload;
function mdxSum(const S: string; const Algorithm: tmdxAlgorithm): tmdxSum; overload;
function mdxSum(const Buffer: pointer; const Length: Longword; const Algorithm: tmdxAlgorithm): tmdxSum; overload;
// returns mdxDigest (16bytes)
function md4Digest(const S: string): tmdxDigest; overload;
function md4Digest(const Buffer: pointer; const Length: Longword): tmdxDigest; overload;
function md5Digest(const S: string): tmdxDigest; overload;
function md5Digest(const Buffer: pointer; const Length: Longword): tmdxDigest; overload;
function mdxDigest(const Buffer: pointer; const Length: Longword; const Algorithm: tmdxAlgorithm): tmdxDigest; overload;
// totalDataLen must not exceed 7 Peta (72057594037927935) bytes
procedure md4tail(var Digest: tmdxDigest; Buffer: pointer; const BufLen: cardinal; const totalDataLen: int64); overload;
procedure md5tail(var Digest: tmdxDigest; Buffer: pointer; const BufLen: cardinal; const totalDataLen: int64); overload;
procedure mdxinit(var Digest: tmdxDigest);
procedure mdxClear(var Digest: tmdxDigest);
function mdxDigesttoStr(const Digest: tmdxDigest): tmdxSum;
{$L mdx5.obj}
// if your data all fits in Buffer (max.4G), you never need fetch routines.
// use mdxinit followed by mdxtail instead
procedure __mdx5fetch(var Digest: tmdxDigest; const Chunk: pointer); register; external;
procedure __mdx4fetch(var Digest: tmdxDigest; const Chunk: pointer); register; external;
const
  MDXBLOCK = 64;
  MDXBLOCKMASK = MDXBLOCK - 1;
implementation
//uses ordinals; // our nice hex-conversion routine :)
{
; USAGE
; 1. call __mdxinit
;      argument is pointer to 16 bytes MD4/MD5 digest, passed via EAX
; 2. call __mdx5fetch/__mdx4fetch for every integral chunks of 64 bytes
;    do not call it if the length of the chunk is less than 64 bytes
;      arguments are:
;        pointer to 16 bytes MD4/MD5 digest, passed via EAX
;        pointer to 64 bytes data chunk, passed via EDX
;    call after here also any tracking/gauge/progress function you wish
;    do not worry, all registers are preserved here
; 3. call __mdx5finalize/__mdx4finalize for the last chunk whose length
;    less than 64 bytes (including 0 length chunk, if total size is perfectly
;    64 bytes fold or the total length itself was 0)
;      arguments are:
;        pointer to 16 bytes MD4/MD5 digest, passed via EAX
;        pointer to 0-63 bytes data chunk tail (last), passed via EDX
;        Original/Total Data Size/Length in bytes (up to 72057594037927935 bytes)
;          passed via stack as a pair of DWORDs, High Significant dword first (are they?)
;          which is simply an int64 type in Delphi
; 4. done. result in 16 bytes MD4/MD5 digest
;
; update:
:   there is a bug in mdxfinalize routine's arguments passing (mdx5 ver 1.0.0.0r),
;   fixed in version 1.0.0.2. if you are still using old version, here's the workaround
;   (you MUST call function mdxtail, rather than separate fetch and finalize from Delphi)
;
}
{.$L mdx5.obj}
procedure __mdxinit(var Digest: tmdxDigest); register; external;
//procedure __mdx5fetch(var Digest: tmdxDigest; const Chunk: pointer); register; external;
//procedure __mdx4fetch(var Digest: tmdxDigest; const Chunk: pointer); register; external;
procedure __mdx5Finalize(var Digest: tmdxDigest; const endOfChunk: pointer; const ActualLength: int64); register; external;
procedure __mdx4Finalize(var Digest: tmdxDigest; const endOfChunk: pointer; const ActualLength: int64); register; external;
const
  PAGESIZE = MDXBLOCK  MDXBLOCK;
type
  TPageBlock = packed array[1..PAGESIZE] of byte;
{
procedure mdxinit(var Digest: tmdxDigest);
const
  A = $67452301; B = $EFCDAB89;
  C = $98BADCFE; D = $10325476;
begin
  Digest.A := A; Digest.B := B;
  Digest.C := C; Digest.D := D;
end;
}
procedure mdxClear(var Digest: tmdxDigest); asm fldz; fst qword ptr [eax]; fstp qword ptr [eax+8]; end;
procedure mdxinit(var Digest: tmdxDigest);
const
  init: packed array[boolean] of int64 = ($EFCDAB8967452301, $1032547698BADCFE);
asm
  fild qword ptr [init];
  fild qword ptr init+8;
  fxch;
  fistp qword ptr [eax];
  fistp qword ptr eax+8;
end;
function mdxDigesttoStr(const Digest: tmdxDigest): tmdxSum;
const
  DigestLen = sizeof(Digest);
  HexChars: pChar = '0123456789ABCDEF';
asm
  push eax; mov eax,edx; call System.@LStrClr;
  push DigestLen 2; pop edx; call System.@LStrSetLength;
  pop edx; push edi; mov edi,[eax];
  push DigestLen; pop ecx;
  push esi; mov esi,HexChars;
  push ebx; lea edi,edi+ecx*2-1;
  sub ecx,1;
  @@Loop:
    movzx eax,[edx+ecx]; mov ebx,eax;
    and eax,$0f; shr ebx,4;
    mov al,esi+eax; mov bl,esi+ebx
    mov [edi],al; mov [edi-1],bl;
    lea edi,edi-2; sub ecx,1;
  jge @@Loop
  pop ebx; pop esi; pop edi;
end;
// workaround for mdx5.obj ver 1.0.0.0r parameter passing bug (fixed in ver 1.0.0.2)
procedure md4tail(var Digest: tmdxDigest; Buffer: pointer;
  const BufLen: cardinal; const totalDataLen: int64); overload;
var
  i: integer;
begin
  for i := 1 to BufLen div MDXBLOCK do begin
    __mdx4fetch(Digest, Buffer);
    inc(integer(Buffer), MDXBLOCK);
  end;
  __mdx4finalize(Digest, Buffer, totalDataLen);
end;
procedure md5tail(var Digest: tmdxDigest; Buffer: pointer;
  const BufLen: cardinal; const totalDataLen: int64); overload;
var
  i: integer;
begin
  for i := 1 to BufLen div MDXBLOCK do begin
    __mdx5fetch(Digest, Buffer);
    inc(integer(Buffer), MDXBLOCK);
  end;
  __mdx5finalize(Digest, Buffer, totalDataLen);
end;
function mdxDigest(const Buffer: pointer; const Length: longword;
  const Algorithm: tmdxAlgorithm): tmdxDigest; overload;
begin
  mdxClear(Result);
  if Buffer <> nil then begin
    __mdxinit(Result);
    if Algorithm = mda5 then
      md5tail(Result, Buffer, length, length)
    else if Algorithm = mda4 then
      md4tail(Result, Buffer, length, length)
  end;
end;
function md4Digest(const S: string): tmdxDigest; overload; begin
  Result := mdxDigest(PChar(S), length(S), mda4)
end;
function md4Digest(const Buffer: pointer; const Length: Longword): tmdxDigest; overload; begin
  Result := mdxDigest(Buffer, Length, mda4)
end;
function md5Digest(const S: string): tmdxDigest; overload; begin
  Result := mdxDigest(PChar(S), length(S), mda5)
end;
function md5Digest(const Buffer: pointer; const Length: Longword): tmdxDigest; overload; begin
  Result := mdxDigest(Buffer, Length, mda4)
end;
function mdxSum(const Buffer: pointer; const Length: longword; const Algorithm: tmdxAlgorithm): tmdxSum; overload; begin
  Result := mdxDigesttoStr(mdxDigest(Buffer, Length, Algorithm))
end;
function mdxSum(const S: string; const Algorithm: tmdxAlgorithm): tmdxSum; overload; begin
  Result := mdxDigesttoStr(mdxDigest(pchar(S), Length(S), Algorithm));
end;
function md5Sum(const Buffer: pointer; const Length: longword): tmdxSum; overload; begin
  Result := mdxDigesttoStr(mdxDigest(Buffer, Length, mda5))
end;
function md5Sum(const S: string): tmdxSum; overload; begin
  Result := md5Sum(pchar(S), Length(S));
end;
function md4Sum(const Buffer: pointer; const Length: longword): tmdxSum; overload; begin
  Result := mdxDigesttoStr(mdxDigest(Buffer, Length, mda5))
end;
function md4Sum(const S: string): tmdxSum; overload; begin
  Result := md5Sum(pchar(S), Length(S));
end;
end.
Local Business Directory, Search Engine Submission & SEO Tools FreeWebSubmission.com SonicRun.com