PowerBASIC Forums
  Source Code
  MD5

Post New Topic  Post A Reply
profile | register | preferences | faq | search

UBBFriend: Email This Page to Someone! next newest topic | next oldest topic
Author Topic:   MD5
Florent Heyworth
Member
posted April 08, 2000 08:19 PM     Click Here to See the Profile for Florent Heyworth     Edit/Delete Message   Reply w/Quote
[UPDATED 11-APR-2000]: REASON - posted a somewhat optimised version and added a routine to check file MD5 fingerprints - the speed of this version is close/comparable to the C reference
implementation

[UPDATED 10-APR-2000]: REASON - while checking my implementation
for correctness I used the C executable by mistake instead of my
own and so thought my implementation was correct - it wasn't. So
I've updated the code so that it NOW WORKS and have
added the MD5 test suite so its correctness can be verified.

The code below is equivalent to RSA's implementation - but different copyright notices apply (public domain) - see the source for details

----------------------------------
Hi

I've translated RSA's MD5 source code. Note that the version is not optimised but is fast enough for what I use it for: HTTP basic authentification.


#IF 0
********************************************************************
* '
* ' MD5.BAS - Original code notice:
* '
* 'This code implements the MD5 message-digest algorithm.
* 'The algorithm is due TO Ron Rivest. This code was
* 'written by Colin Plumb IN 1993, no copyright is claimed.
* 'This code is IN the public domain; DO WITH it what you wish.
* '
* 'Equivalent code is available FROM RSA DATA Security, Inc.
* 'This code has been tested against that, AND is equivalent,
* 'except that you don't need to include two pages of legalese
* 'WITH every copy.
* '
* 'TO compute the message digest of a chunk of bytes, DECLARE an
* 'MD5Context structure, pass it TO MD5Init, CALL MD5Update AS
* 'needed ON buffers full of bytes, AND THEN CALL MD5Final, which
* 'will fill a supplied 16-BYTE ARRAY WITH the digest.
* '
* '-----------------------------------------------------------
* 'Translated to Powerbasic by Florent Heyworth - 10-APR-2000
* '-----------------------------------------------------------
* '
********************************************************************
#ENDIF

#COMPILE EXE
#REGISTER NONE

#INCLUDE "WIN32API.INC"
#IF NOT %DEF(%NULL)
%NULL = 0
#ENDIF

DECLARE SUB ZeroMemory LIB "KERNEL32.DLL" ALIAS "RtlZeroMemory" ( BYVAL lDestination AS LONG, BYVAL dwLen AS DWORD)
DECLARE SUB FillMemory LIB "KERNEL32.DLL" ALIAS "RtlFillMemory" ( BYVAL lDestination AS LONG, BYVAL dwLen AS DWORD, BYVAL bFill AS BYTE)

' Constants FOR md5_Transform routine.
%S11 = 7
%S12 = 12
%S13 = 17
%S14 = 22
%S21 = 5
%S22 = 9
%S23 = 14
%S24 = 20
%S31 = 4
%S32 = 11
%S33 = 16
%S34 = 23
%S41 = 6
%S42 = 10
%S43 = 15
%S44 = 21

TYPE MD5_CTX
lState(4) AS LONG 'state (ABCD)
lCount(2) AS LONG 'number of bits modulo 2^64 (lsp first)
bBuf AS ASCIIZ * 64 'input buffer
END TYPE

' PB really should have BUILT-IN function for shift instead of SHIFT LEFT|RIGHT semantics....
FUNCTION md5_shiftRight(BYVAL lThis AS LONG, BYVAL lBits AS LONG) AS LONG

SHIFT RIGHT lThis, lBits

FUNCTION = lThis

END FUNCTION

FUNCTION md5_shiftLeft(BYVAL lThis AS LONG, BYVAL lBits AS LONG) AS LONG

SHIFT LEFT lThis, lBits

FUNCTION = lThis

END FUNCTION

SUB md5_init( BYVAL dwContext AS DWORD )
'MD5 initialization. Begins an MD5 operation, writing a new context
DIM tContext AS MD5_CTX PTR

tContext = dwContext

@tContext.lCount(0) = 0
@tContext.lCount(1) = 0

' Load magic initialization constants.
@tContext.lState(0) = &H67452301
@tContext.lState(1) = &HEFCDAB89
@tContext.lState(2) = &H98BADCFE
@tContext.lState(3) = &H10325476

END SUB

SUB md5_Transform ( tContext AS MD5_CTX PTR,BYVAL dwBuf AS DWORD )
LOCAL a AS LONG
LOCAL b AS LONG
LOCAL c AS LONG
LOCAL d AS LONG
LOCAL bBuf AS LONG PTR

bBuf = dwBuf
a = @tContext.lState(0)
b = @tContext.lState(1)
c = @tContext.lState(2)
d = @tContext.lState(3)

'ROUND 1
a = a + ((((b)) AND ((c))) OR ((NOT (b)) AND ((d)))) + (@bBuf[ 0]) +&Hd76aa478
ROTATE LEFT a, %S11: a = a + b
d = d + ((((a)) AND ((b))) OR ((NOT (a)) AND ((c)))) + (@bBuf[ 1]) +&He8c7b756
ROTATE LEFT d, %S12: d = d + a
c = c + ((((d)) AND ((a))) OR ((NOT (d)) AND ((b)))) + (@bBuf[ 2]) +&H242070db
ROTATE LEFT c, %S13: c = c + d
b = b + ((((c)) AND ((d))) OR ((NOT (c)) AND ((a)))) + (@bBuf[ 3]) +&Hc1bdceee
ROTATE LEFT b, %S14: b = b + c
'
a = a + ((((b)) AND ((c))) OR ((NOT (b)) AND ((d)))) + (@bBuf[ 4]) +&Hf57c0faf
ROTATE LEFT a, %S11: a = a + b
d = d + ((((a)) AND ((b))) OR ((NOT (a)) AND ((c)))) + (@bBuf[ 5]) +&H4787c62a
ROTATE LEFT d, %S12: d = d + a
c = c + ((((d)) AND ((a))) OR ((NOT (d)) AND ((b)))) + (@bBuf[ 6]) +&Ha8304613
ROTATE LEFT c, %S13: c = c + d
b = b + ((((c)) AND ((d))) OR ((NOT (c)) AND ((a)))) + (@bBuf[ 7]) +&Hfd469501
ROTATE LEFT b, %S14: b = b + c
'
a = a + ((((b)) AND ((c))) OR ((NOT (b)) AND ((d)))) + (@bBuf[ 8]) +&H698098d8
ROTATE LEFT a, %S11: a = a + b
d = d + ((((a)) AND ((b))) OR ((NOT (a)) AND ((c)))) + (@bBuf[ 9]) +&H8b44f7af
ROTATE LEFT d, %S12: d = d + a
c = c + ((((d)) AND ((a))) OR ((NOT (d)) AND ((b)))) + (@bBuf[10]) +&Hffff5bb1
ROTATE LEFT c, %S13: c = c + d
b = b + ((((c)) AND ((d))) OR ((NOT (c)) AND ((a)))) + (@bBuf[11]) +&H895cd7be
ROTATE LEFT b, %S14: b = b + c
'
a = a + ((((b)) AND ((c))) OR ((NOT (b)) AND ((d)))) + (@bBuf[12]) +&H6b901122
ROTATE LEFT a, %S11: a = a + b
d = d + ((((a)) AND ((b))) OR ((NOT (a)) AND ((c)))) + (@bBuf[13]) +&Hfd987193
ROTATE LEFT d, %S12: d = d + a
c = c + ((((d)) AND ((a))) OR ((NOT (d)) AND ((b)))) + (@bBuf[14]) +&Ha679438e
ROTATE LEFT c, %S13: c = c + d
b = b + ((((c)) AND ((d))) OR ((NOT (c)) AND ((a)))) + (@bBuf[15]) +&H49b40821
ROTATE LEFT b, %S14: b = b + c

'ROUND 2
a = a + ((((b)) AND ((d))) OR (((c)) AND (NOT (d)))) + (@bBuf[ 1]) +&Hf61e2562
ROTATE LEFT a, %S21: a = a + b
d = d + ((((a)) AND ((c))) OR (((b)) AND (NOT (c)))) + (@bBuf[ 6]) +&Hc040b340
ROTATE LEFT d, %S22: d = d + a
c = c + ((((d)) AND ((b))) OR (((a)) AND (NOT (b)))) + (@bBuf[11]) +&H265e5a51
ROTATE LEFT c, %S23: c = c + d
b = b + ((((c)) AND ((a))) OR (((d)) AND (NOT (a)))) + (@bBuf[ 0]) +&He9b6c7aa
ROTATE LEFT b, %S24: b = b + c
'
a = a + ((((b)) AND ((d))) OR (((c)) AND (NOT (d)))) + (@bBuf[ 5]) +&Hd62f105d
ROTATE LEFT a, %S21: a = a + b
d = d + ((((a)) AND ((c))) OR (((b)) AND (NOT (c)))) + (@bBuf[10]) +&H2441453
ROTATE LEFT d, %S22: d = d + a
c = c + ((((d)) AND ((b))) OR (((a)) AND (NOT (b)))) + (@bBuf[15]) +&Hd8a1e681
ROTATE LEFT c, %S23: c = c + d
b = b + ((((c)) AND ((a))) OR (((d)) AND (NOT (a)))) + (@bBuf[ 4]) +&He7d3fbc8
ROTATE LEFT b, %S24: b = b + c
'
a = a + ((((b)) AND ((d))) OR (((c)) AND (NOT (d)))) + (@bBuf[ 9]) +&H21e1cde6
ROTATE LEFT a, %S21: a = a + b
d = d + ((((a)) AND ((c))) OR (((b)) AND (NOT (c)))) + (@bBuf[14]) +&Hc33707d6
ROTATE LEFT d, %S22: d = d + a
c = c + ((((d)) AND ((b))) OR (((a)) AND (NOT (b)))) + (@bBuf[ 3]) +&Hf4d50d87
ROTATE LEFT c, %S23: c = c + d
b = b + ((((c)) AND ((a))) OR (((d)) AND (NOT (a)))) + (@bBuf[ 8]) +&H455a14ed
ROTATE LEFT b, %S24: b = b + c
'
a = a + ((((b)) AND ((d))) OR (((c)) AND (NOT (d)))) + (@bBuf[13]) +&Ha9e3e905
ROTATE LEFT a, %S21: a = a + b
d = d + ((((a)) AND ((c))) OR (((b)) AND (NOT (c)))) + (@bBuf[ 2]) +&Hfcefa3f8
ROTATE LEFT d, %S22: d = d + a
c = c + ((((d)) AND ((b))) OR (((a)) AND (NOT (b)))) + (@bBuf[ 7]) +&H676f02d9
ROTATE LEFT c, %S23: c = c + d
b = b + ((((c)) AND ((a))) OR (((d)) AND (NOT (a)))) + (@bBuf[12]) +&H8d2a4c8a
ROTATE LEFT b, %S24: b = b + c

'ROUND 3
a = a + (((b)) XOR ((c)) XOR ((d))) + (@bBuf[ 5]) +&Hfffa3942
ROTATE LEFT a, %S31: a = a + b
d = d + (((a)) XOR ((b)) XOR ((c))) + (@bBuf[ 8]) +&H8771f681
ROTATE LEFT d, %S32: d = d + a
c = c + (((d)) XOR ((a)) XOR ((b))) + (@bBuf[11]) +&H6d9d6122
ROTATE LEFT c, %S33: c = c + d
b = b + (((c)) XOR ((d)) XOR ((a))) + (@bBuf[14]) +&Hfde5380c
ROTATE LEFT b, %S34: b = b + c
'
a = a + (((b)) XOR ((c)) XOR ((d))) + (@bBuf[ 1]) +&Ha4beea44
ROTATE LEFT a, %S31: a = a + b
d = d + (((a)) XOR ((b)) XOR ((c))) + (@bBuf[ 4]) +&H4bdecfa9
ROTATE LEFT d, %S32: d = d + a
c = c + (((d)) XOR ((a)) XOR ((b))) + (@bBuf[ 7]) +&Hf6bb4b60
ROTATE LEFT c, %S33: c = c + d
b = b + (((c)) XOR ((d)) XOR ((a))) + (@bBuf[10]) +&Hbebfbc70
ROTATE LEFT b, %S34: b = b + c
'
a = a + (((b)) XOR ((c)) XOR ((d))) + (@bBuf[13]) +&H289b7ec6
ROTATE LEFT a, %S31: a = a + b
d = d + (((a)) XOR ((b)) XOR ((c))) + (@bBuf[ 0]) +&Heaa127fa
ROTATE LEFT d, %S32: d = d + a
c = c + (((d)) XOR ((a)) XOR ((b))) + (@bBuf[ 3]) +&Hd4ef3085
ROTATE LEFT c, %S33: c = c + d
b = b + (((c)) XOR ((d)) XOR ((a))) + (@bBuf[ 6]) +&H4881d05
ROTATE LEFT b, %S34: b = b + c
'
a = a + (((b)) XOR ((c)) XOR ((d))) + (@bBuf[ 9]) +&Hd9d4d039
ROTATE LEFT a, %S31: a = a + b
d = d + (((a)) XOR ((b)) XOR ((c))) + (@bBuf[12]) +&He6db99e5
ROTATE LEFT d, %S32: d = d + a
c = c + (((d)) XOR ((a)) XOR ((b))) + (@bBuf[15]) +&H1fa27cf8
ROTATE LEFT c, %S33: c = c + d
b = b + (((c)) XOR ((d)) XOR ((a))) + (@bBuf[ 2]) +&Hc4ac5665
ROTATE LEFT b, %S34: b = b + c


'ROUND 4
a = a + (((c)) XOR (((b)) OR (NOT (d)))) + (@bBuf[ 0]) +&Hf4292244
ROTATE LEFT a, %S41: a = a + b
d = d + (((b)) XOR (((a)) OR (NOT (c)))) + (@bBuf[ 7]) +&H432aff97
ROTATE LEFT d, %S42: d = d + a
c = c + (((a)) XOR (((d)) OR (NOT (b)))) + (@bBuf[14]) +&Hab9423a7
ROTATE LEFT c, %S43: c = c + d
b = b + (((d)) XOR (((c)) OR (NOT (a)))) + (@bBuf[ 5]) +&Hfc93a039
ROTATE LEFT b, %S44: b = b + c
'
a = a + (((c)) XOR (((b)) OR (NOT (d)))) + (@bBuf[12]) +&H655b59c3
ROTATE LEFT a, %S41: a = a + b
d = d + (((b)) XOR (((a)) OR (NOT (c)))) + (@bBuf[ 3]) +&H8f0ccc92
ROTATE LEFT d, %S42: d = d + a
c = c + (((a)) XOR (((d)) OR (NOT (b)))) + (@bBuf[10]) +&Hffeff47d
ROTATE LEFT c, %S43: c = c + d
b = b + (((d)) XOR (((c)) OR (NOT (a)))) + (@bBuf[ 1]) +&H85845dd1
ROTATE LEFT b, %S44: b = b + c
'
a = a + (((c)) XOR (((b)) OR (NOT (d)))) + (@bBuf[ 8]) +&H6fa87e4f
ROTATE LEFT a, %S41: a = a + b
d = d + (((b)) XOR (((a)) OR (NOT (c)))) + (@bBuf[15]) +&Hfe2ce6e0
ROTATE LEFT d, %S42: d = d + a
c = c + (((a)) XOR (((d)) OR (NOT (b)))) + (@bBuf[ 6]) +&Ha3014314
ROTATE LEFT c, %S43: c = c + d
b = b + (((d)) XOR (((c)) OR (NOT (a)))) + (@bBuf[13]) +&H4e0811a1
ROTATE LEFT b, %S44: b = b + c
'
a = a + (((c)) XOR (((b)) OR (NOT (d)))) + (@bBuf[ 4]) +&Hf7537e82
ROTATE LEFT a, %S41: a = a + b
d = d + (((b)) XOR (((a)) OR (NOT (c)))) + (@bBuf[11]) +&Hbd3af235
ROTATE LEFT d, %S42: d = d + a
c = c + (((a)) XOR (((d)) OR (NOT (b)))) + (@bBuf[ 2]) +&H2ad7d2bb
ROTATE LEFT c, %S43: c = c + d
b = b + (((d)) XOR (((c)) OR (NOT (a)))) + (@bBuf[ 9]) +&Heb86d391
ROTATE LEFT b, %S44: b = b + c

@tContext.lState(0) = @tContext.lState(0) + a
@tContext.lState(1) = @tContext.lState(1) + b
@tContext.lState(2) = @tContext.lState(2) + c
@tContext.lState(3) = @tContext.lState(3) + d

END SUB

' Update context TO reflect the concatenation of another buffer full
' of bytes.
SUB md5_Update( ctx AS MD5_CTX PTR, BYVAL bBuf AS BYTE PTR, BYVAL dwLen AS DWORD )
LOCAL t AS DWORD

' Update bitcount
t = @ctx.lCount(0)
@ctx.lCount(0) = t + md5_shiftLeft( dwLen, 3 )
IF @ctx.lCount(0) < t THEN
INCR @ctx.lCount(1) 'carry from low to high
END IF

@ctx.lCount(1) = @ctx.lCount(1) + md5_shiftRight( dwLen, 29 )

t = ( md5_shiftRight( t, 3) AND &H3F ) 'Bytes already IN shsInfo->DATA

'handle any leading odd-sized chunks
IF ISTRUE(t) THEN
LOCAL p AS BYTE PTR

p = VARPTR(@ctx.bBuf)
p = p + t
t = 64 - t
IF dwLen < t THEN
CALL MoveMemory( p, bBuf, dwLen )
EXIT SUB
END IF
CALL MoveMemory( p, bBuf, t )
CALL md5_Transform( @ctx, VARPTR(@ctx.bBuf) )
bBuf = bBuf + t
dwLen = dwLen - t
END IF

'Process DATA IN 64-BYTE chunks
DO WHILE (dwLen >= 64)
CALL MoveMemory( VARPTR(@ctx.bBuf), bBuf, 64)
CALL md5_Transform( @ctx, VARPTR(@ctx.bBuf) )
bBuf = bBuf + 64
dwLen = dwLen - 64
LOOP

'handle any remaining bytes of data
CALL MoveMemory( VARPTR(@ctx.bBuf), bBuf, dwLen )
END SUB

' Final wrapup - pad TO 64-BYTE boundary WITH the BIT pattern
' 1 0* (64-BIT count of bits processed, MSB-first)
SUB md5_Final( BYVAL dwDigest AS BYTE PTR, ctx AS MD5_CTX PTR )
LOCAL lCount AS DWORD
LOCAL p AS BYTE PTR
LOCAL bDigest AS BYTE PTR
LOCAL bBuffer AS BYTE PTR

bDigest = dwDigest
bBuffer = VARPTR(@ctx.bBuf)
'Compute number of bytes MOD 64
lCount = (md5_shiftRight( @ctx.lCount(0), 3) AND &H3F )

'set the first char of padding to &H80. This is safe since there is
'always AT least one BYTE free
p = VARPTR(@ctx.bBuf)
p = p + lCount
@p = &H80
INCR p

' Bytes of padding needed TO make 64 bytes
lCount = 64 - 1 - lCount

' Pad out TO 56 MOD 64
IF lCount < 8 THEN
'two lots of padding: pad the first block to 64 bytes
CALL FillMemory( p, lCount, 0 )
CALL md5_Transform( @ctx, VARPTR(@ctx.bBuf) )
CALL FillMemory( VARPTR(@ctx.bBuf), 56, 0 )
ELSE
'pad block to 56 bytes
CALL FillMemory( p, (lCount - 8), 0)
END IF

'append length IN bits and transform
CALL MoveMemory( VARPTR(@bBuffer[14 * SIZEOF(lCount)]), VARPTR(@ctx.lCount(0)), SIZEOF(lCount))
CALL MoveMemory( VARPTR(@bBuffer[15 * SIZEOF(lCount)]), VARPTR(@ctx.lCount(1)), SIZEOF(lCount))

CALL md5_Transform( @ctx, VARPTR(@ctx.bBuf) )
CALL MoveMemory( bDigest, VARPTR(@ctx.lState(0)), 16)
'Zeroise sensitive information
CALL FillMemory( ctx, SIZEOF(@ctx), 0)

END SUB

FUNCTION md5_Digest( BYVAL dwContext AS DWORD ) AS STRING
'returns the MD5 digest as a hex string
DIM sHex AS STRING
DIM pContext AS MD5_CTX PTR
DIM szDigest AS ASCIIZ * 16
DIM bDigest AS BYTE PTR
DIM sCheck AS STRING
DIM i AS LONG

bDigest = VARPTR(szDigest)
pContext = dwContext

CALL md5_Final( bDigest, @pContext )

IF bDigest <> %NULL THEN
FOR i = 0 TO 15
sHex = sHex + HEX$(@bDigest[i],2)
NEXT
END IF
FUNCTION = sHex

END FUNCTION

SUB md5_readFile( BYVAL dwContext AS DWORD, szFile AS ASCIIZ )
'reads a file and calls md5_Update on the buffer
'md5_Init() MUST have been called prior to calling
'this function - call md5_Digest() afterwards to
'get the fingerprint
LOCAL lHandle AS LONG
LOCAL szBuffer AS ASCIIZ * 1024
LOCAL lBufLen AS LONG
LOCAL lLen AS LONG
LOCAL lResult AS LONG
LOCAL lToRead AS LONG
LOCAL lToReadHigh AS LONG
LOCAL pContext AS MD5_CTX PTR
LOCAL lpBuffer AS LONG

pContext = dwContext
lBufLen = SIZEOF(szBuffer)

lpBuffer = VARPTR(szBuffer)
lHandle = CreateFile( szFile, %GENERIC_READ, %FILE_SHARE_READ, _
BYVAL %NULL, %OPEN_EXISTING, %FILE_ATTRIBUTE_NORMAL, 0& )

IF lHandle <> %INVALID_HANDLE_VALUE THEN
lToRead = GetFileSize(lHandle, lToReadHigh)
DO WHILE lToRead > 0
lResult = ReadFile( lHandle, BYVAL lpBuffer, lBufLen, lLen , BYVAL %NULL )
CALL md5_Update(@pContext, lpBuffer, lLen)
! cmp lResult, 0
! je md5_readFile_close
! mov eax, lToRead
! sub eax, lLen
! mov lToRead, eax
LOOP
md5_readFile_close:
CALL CloseHandle(lHandle)
END IF
END SUB

SUB test()
'implements the Md5 test suite to make sure that the
'implementation is correct
DIM md5_ctx_test AS MD5_CTX
DIM szText AS ASCIIZ * 300

CALL md5_Init( VARPTR(md5_ctx_test) ) 'call md5_Init each time to calculate a new digest

szText = ""
CALL md5_Update( md5_ctx_test, VARPTR(szText), LEN(szText) )

MSGBOX "Fingerprint for '': " _
+ md5_Digest( VARPTR(md5_ctx_test) ) _ 'call md5_Digest to return the result
+ CHR$(13) + "Reference for '': " + UCASE$("d41d8cd98f00b204e9800998ecf8427e")

CALL md5_Init( VARPTR(md5_ctx_test) ) 'call md5_Init each time to calculate a new digest

szText = "a"
CALL md5_Update( md5_ctx_test, VARPTR(szText), LEN(szText) )
MSGBOX "Fingerprint for 'a': " + md5_Digest( VARPTR(md5_ctx_test) ) + CHR$(13) _
+ "Reference for 'a': " + UCASE$("0cc175b9c0f1b6a831c399e269772661")

CALL md5_Init( VARPTR(md5_ctx_test) ) 'call md5_Init each time to calculate a new digest

szText = "abc"
CALL md5_Update( md5_ctx_test, VARPTR(szText), LEN(szText) )
MSGBOX "Fingerprint for 'abc': " + md5_Digest( VARPTR(md5_ctx_test) ) + CHR$(13) _
+ "Reference for 'abc': " + UCASE$("900150983cd24fb0d6963f7d28e17f72")

CALL md5_Init( VARPTR(md5_ctx_test) ) 'call md5_Init each time to calculate a new digest

szText = "message digest"
CALL md5_Update( md5_ctx_test, VARPTR(szText), LEN(szText) )
MSGBOX "Fingerprint for 'message digest': " + md5_Digest( VARPTR(md5_ctx_test) ) + CHR$(13) _
+ "Reference for 'message digest': " + UCASE$("f96b697d7cb7938d525a2f31aaf161d0")

CALL md5_Init( VARPTR(md5_ctx_test) ) 'call md5_Init each time to calculate a new digest

szText = "abcdefghijklmnopqrstuvwxyz"
CALL md5_Update( md5_ctx_test, VARPTR(szText), LEN(szText) )
MSGBOX "Fingerprint for 'abcdefghijklmnopqrstuvwxyz': " + md5_Digest( VARPTR(md5_ctx_test) ) + CHR$(13) _
+ "Reference for 'abcdefghijklmnopqrstuvwxyz': " + UCASE$("c3fcd3d76192e4007dfb496cca67e13b")

CALL md5_Init( VARPTR(md5_ctx_test) ) 'call md5_Init each time to calculate a new digest

szText = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
CALL md5_Update( md5_ctx_test, VARPTR(szText), LEN(szText) )
MSGBOX "Fingerprint for 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789': " _
+ md5_Digest( VARPTR(md5_ctx_test) ) + CHR$(13) _
+ "Reference for 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789': " _
+ UCASE$("d174ab98d277d9f5a5611c2c9f419d9f")

CALL md5_Init( VARPTR(md5_ctx_test) ) 'call md5_Init each time to calculate a new digest

szText = "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
CALL md5_Update( md5_ctx_test, VARPTR(szText), LEN(szText) )
MSGBOX "Fingerprint for '12345678901234567890123456789012345678901234567890123456789012345678901234567890': " _
+ md5_Digest( VARPTR(md5_ctx_test) ) + CHR$(13) _
+ "Reference for '12345678901234567890123456789012345678901234567890123456789012345678901234567890': " _
+ UCASE$("57edf4a22be3c955ac49da2e2107b67a")

END SUB

FUNCTION PBMAIN() AS LONG

call Test()

END FUNCTION

[This message has been edited by Florent Heyworth (edited April 11, 2000).]

IP: Logged

Scott Turchin
Member
posted April 08, 2000 11:25 PM     Click Here to See the Profile for Scott Turchin     Edit/Delete Message   Reply w/Quote
Question...

Given a certificate from a server for example, it should contain a public key for the client to use to encrypt data...

The browser etc has to have a CA for the server side authentication, but the CERTIFICATE that comes down, how would one apply it to this and decrypt it to obtain the server information, verification of the certificate date, etc...


Scott

------------------
Scott
tngbbs@sinclair.net

IP: Logged

Florent Heyworth
Member
posted April 10, 2000 07:50 AM     Click Here to See the Profile for Florent Heyworth     Edit/Delete Message   Reply w/Quote
Hi Scott

first of all: if you've copied the MD5 code above you should
copy the present one again since the original code I posted DID
NOT WORK... I only realised it later as I figured out why I kept
getting incorrect results when the test suite had worked fine: I
tested the MD5 test suite with the wrong executable (original C
reference implementation)!!!

As to your question - I'll start a topic in the "Programming"
section to answer it - otherwise I'm pretty sure Lance or Dave
will warn us about off-topic discussions in the "Source code Forum"

Cheers

Florent

[This message has been edited by Florent Heyworth (edited April 10, 2000).]

IP: Logged

Matthew Grace
Member
posted June 12, 2003 01:11 PM     Click Here to See the Profile for Matthew Grace     Edit/Delete Message   Reply w/Quote
Floren, that code is not compiling, there are a lot of problems with it on my end, using PB7, for instance, Call MoveMemory( VarPtr(@ctx.bBuf), bBuf, dwLen ) return a 'variable expected' compiler error, Call md5_Transform( @ctx, VarPtr(@ctx.bBuf) ) returns a "relational operator expected", any insight, anyone?

------------------

IP: Logged

Thomas Gohel
Member
posted June 14, 2003 10:19 AM     Click Here to See the Profile for Thomas Gohel     Edit/Delete Message   Reply w/Quote

On 12 Jun 03, in article "Re: MD5", Matthew Grace wrote:

Hello Matthew,

> Floren, that code is not compiling, there are a lot of problems with
> it on my end, using PB7, for instance, Call MoveMemory(
> VarPtr(@ctx.bBuf), bBuf, dwLen ) return a 'variable expected'
> compiler error, Call md5_Transform( @ctx, VarPtr(@ctx.bBuf) )
> returns a "relational operator expected", any insight, anyone?

Search for these articles on the PowerBASIC WebBBS:


Pop3/Smtp/Imap MD5 sources for APOP, SASL/Digest-MD5 and SASL/CRAM-MD5

The sources are compatible and hard tested in practice with PB/DOS,
PB/CC and PB/WIN (including newer versions).

Regards,

--------------
/ h o m a s
------------------
email : support@gohel.de / gohel@basicguru.com (PGP-Key available)
www : www.gohel.de / http://pbsound.basicguru.com (PowerBASIC)
fax/bbs: +49-30-47300910 (VFC, V34+, X75, ISDN, CCB, 9600-128000bps)
## CrossPoint [XP2] v3.31.003 Beta DOS/16 R/C2478, via PBNEWS v0.18g

IP: Logged

Ibrahim Mohammad
Member
posted June 25, 2003 04:12 AM     Click Here to See the Profile for Ibrahim Mohammad     Edit/Delete Message   Reply w/Quote
Can anybody tell me how to use this without the API calls.
How can we do this if we compile it in any compiler for Linux.

IP: Logged

Florent Heyworth
Member
posted February 09, 2004 05:13 AM     Click Here to See the Profile for Florent Heyworth     Edit/Delete Message   Reply w/Quote
Here an update for PBCC3.x and PBWIN7.x


#IF 0
**********************************************************************************************
* '
* ' MD5.BAS - Original code notice:
* '
* 'This code implements the MD5 message-digest algorithm.
* 'The algorithm is due TO Ron Rivest. This code was
* 'written by Colin Plumb IN 1993, no copyright is claimed.
* 'This code is IN the public domain; DO WITH it what you wish.
* '
* 'Equivalent code is available FROM RSA DATA Security, Inc.
* 'This code has been tested against that, AND is equivalent,
* 'except that you don't need to include two pages of legalese
* 'WITH every copy.
* '
* 'TO compute the message digest of a chunk of bytes, DECLARE an
* 'MD5Context structure, pass it TO MD5Init, CALL MD5Update AS
* 'needed ON buffers full of bytes, AND THEN CALL MD5Final, which
* 'will fill a supplied 16-BYTE ARRAY WITH the digest.
* '
* '-----------------------------------------------------------
* 'Translated to Powerbasic by Florent Heyworth - 10-APR-2000
* '-----------------------------------------------------------
* '
*********************************************************************************************
#ENDIF

#REGISTER NONE

#if not %DEF(%WINAPI_INC)
#INCLUDE "WIN32API.INC"
#ENDIF

MACRO HHANDLE = dword

' Constants FOR md5_Transform routine.
%S11 = 7
%S12 = 12
%S13 = 17
%S14 = 22
%S21 = 5
%S22 = 9
%S23 = 14
%S24 = 20
%S31 = 4
%S32 = 11
%S33 = 16
%S34 = 23
%S41 = 6
%S42 = 10
%S43 = 15
%S44 = 21

TYPE MD5_CTX
lState(4) AS LONG 'state (ABCD)
lCount(1) AS LONG 'number of bits modulo 2^64 (lsp first)
bBuf AS ASCIIZ * 64 'input buffer
END TYPE

MACRO TELL( msg )
#IF %DEF(%PB_CC32)
STDOUT msg
#ELSEIF %DEF(%PB_DLL32)
MSGBOX msg
#ENDIF
END MACRO

' PB really should have BUILT-IN function for shift instead of SHIFT LEFT|RIGHT semantics....
FUNCTION md5_shiftRight(BYVAL lThis AS LONG, BYVAL lBits AS LONG) AS LONG

SHIFT RIGHT lThis, lBits

FUNCTION = lThis

END FUNCTION

FUNCTION md5_shiftLeft(BYVAL lThis AS LONG, BYVAL lBits AS LONG) AS LONG

SHIFT LEFT lThis, lBits

FUNCTION = lThis

END FUNCTION

SUB md5_init( byref ctx AS MD5_CTX )
'MD5 initialization. Begins an MD5 operation, writing a new context

ctx.lCount(0) = 0
ctx.lCount(1) = 0

' Load magic initialization constants.
ctx.lState(0) = &H67452301
ctx.lState(1) = &HEFCDAB89
ctx.lState(2) = &H98BADCFE
ctx.lState(3) = &H10325476

END SUB

SUB md5_Transform ( byref ctx AS MD5_CTX, BYVAL bBuf as long PTR )
LOCAL a AS LONG
LOCAL b AS LONG
LOCAL c AS LONG
LOCAL d AS LONG

a = ctx.lState(0)
b = ctx.lState(1)
c = ctx.lState(2)
d = ctx.lState(3)

'ROUND 1
a = a + ((((b)) AND ((c))) OR ((NOT (b)) AND ((d)))) + (@bBuf[ 0]) +&Hd76aa478
ROTATE LEFT a, %S11: a = a + b
d = d + ((((a)) AND ((b))) OR ((NOT (a)) AND ((c)))) + (@bBuf[ 1]) +&He8c7b756
ROTATE LEFT d, %S12: d = d + a
c = c + ((((d)) AND ((a))) OR ((NOT (d)) AND ((b)))) + (@bBuf[ 2]) +&H242070db
ROTATE LEFT c, %S13: c = c + d
b = b + ((((c)) AND ((d))) OR ((NOT (c)) AND ((a)))) + (@bBuf[ 3]) +&Hc1bdceee
ROTATE LEFT b, %S14: b = b + c
'
a = a + ((((b)) AND ((c))) OR ((NOT (b)) AND ((d)))) + (@bBuf[ 4]) +&Hf57c0faf
ROTATE LEFT a, %S11: a = a + b
d = d + ((((a)) AND ((b))) OR ((NOT (a)) AND ((c)))) + (@bBuf[ 5]) +&H4787c62a
ROTATE LEFT d, %S12: d = d + a
c = c + ((((d)) AND ((a))) OR ((NOT (d)) AND ((b)))) + (@bBuf[ 6]) +&Ha8304613
ROTATE LEFT c, %S13: c = c + d
b = b + ((((c)) AND ((d))) OR ((NOT (c)) AND ((a)))) + (@bBuf[ 7]) +&Hfd469501
ROTATE LEFT b, %S14: b = b + c
'
a = a + ((((b)) AND ((c))) OR ((NOT (b)) AND ((d)))) + (@bBuf[ 8]) +&H698098d8
ROTATE LEFT a, %S11: a = a + b
d = d + ((((a)) AND ((b))) OR ((NOT (a)) AND ((c)))) + (@bBuf[ 9]) +&H8b44f7af
ROTATE LEFT d, %S12: d = d + a
c = c + ((((d)) AND ((a))) OR ((NOT (d)) AND ((b)))) + (@bBuf[10]) +&Hffff5bb1
ROTATE LEFT c, %S13: c = c + d
b = b + ((((c)) AND ((d))) OR ((NOT (c)) AND ((a)))) + (@bBuf[11]) +&H895cd7be
ROTATE LEFT b, %S14: b = b + c
'
a = a + ((((b)) AND ((c))) OR ((NOT (b)) AND ((d)))) + (@bBuf[12]) +&H6b901122
ROTATE LEFT a, %S11: a = a + b
d = d + ((((a)) AND ((b))) OR ((NOT (a)) AND ((c)))) + (@bBuf[13]) +&Hfd987193
ROTATE LEFT d, %S12: d = d + a
c = c + ((((d)) AND ((a))) OR ((NOT (d)) AND ((b)))) + (@bBuf[14]) +&Ha679438e
ROTATE LEFT c, %S13: c = c + d
b = b + ((((c)) AND ((d))) OR ((NOT (c)) AND ((a)))) + (@bBuf[15]) +&H49b40821
ROTATE LEFT b, %S14: b = b + c


'ROUND 2
a = a + ((((b)) AND ((d))) OR (((c)) AND (NOT (d)))) + (@bBuf[ 1]) +&Hf61e2562
ROTATE LEFT a, %S21: a = a + b
d = d + ((((a)) AND ((c))) OR (((b)) AND (NOT (c)))) + (@bBuf[ 6]) +&Hc040b340
ROTATE LEFT d, %S22: d = d + a
c = c + ((((d)) AND ((b))) OR (((a)) AND (NOT (b)))) + (@bBuf[11]) +&H265e5a51
ROTATE LEFT c, %S23: c = c + d
b = b + ((((c)) AND ((a))) OR (((d)) AND (NOT (a)))) + (@bBuf[ 0]) +&He9b6c7aa
ROTATE LEFT b, %S24: b = b + c
'
a = a + ((((b)) AND ((d))) OR (((c)) AND (NOT (d)))) + (@bBuf[ 5]) +&Hd62f105d
ROTATE LEFT a, %S21: a = a + b
d = d + ((((a)) AND ((c))) OR (((b)) AND (NOT (c)))) + (@bBuf[10]) +&H2441453
ROTATE LEFT d, %S22: d = d + a
c = c + ((((d)) AND ((b))) OR (((a)) AND (NOT (b)))) + (@bBuf[15]) +&Hd8a1e681
ROTATE LEFT c, %S23: c = c + d
b = b + ((((c)) AND ((a))) OR (((d)) AND (NOT (a)))) + (@bBuf[ 4]) +&He7d3fbc8
ROTATE LEFT b, %S24: b = b + c
'
a = a + ((((b)) AND ((d))) OR (((c)) AND (NOT (d)))) + (@bBuf[ 9]) +&H21e1cde6
ROTATE LEFT a, %S21: a = a + b
d = d + ((((a)) AND ((c))) OR (((b)) AND (NOT (c)))) + (@bBuf[14]) +&Hc33707d6
ROTATE LEFT d, %S22: d = d + a
c = c + ((((d)) AND ((b))) OR (((a)) AND (NOT (b)))) + (@bBuf[ 3]) +&Hf4d50d87
ROTATE LEFT c, %S23: c = c + d
b = b + ((((c)) AND ((a))) OR (((d)) AND (NOT (a)))) + (@bBuf[ 8]) +&H455a14ed
ROTATE LEFT b, %S24: b = b + c
'
a = a + ((((b)) AND ((d))) OR (((c)) AND (NOT (d)))) + (@bBuf[13]) +&Ha9e3e905
ROTATE LEFT a, %S21: a = a + b
d = d + ((((a)) AND ((c))) OR (((b)) AND (NOT (c)))) + (@bBuf[ 2]) +&Hfcefa3f8
ROTATE LEFT d, %S22: d = d + a
c = c + ((((d)) AND ((b))) OR (((a)) AND (NOT (b)))) + (@bBuf[ 7]) +&H676f02d9
ROTATE LEFT c, %S23: c = c + d
b = b + ((((c)) AND ((a))) OR (((d)) AND (NOT (a)))) + (@bBuf[12]) +&H8d2a4c8a
ROTATE LEFT b, %S24: b = b + c


'ROUND 3
a = a + (((b)) XOR ((c)) XOR ((d))) + (@bBuf[ 5]) +&Hfffa3942
ROTATE LEFT a, %S31: a = a + b
d = d + (((a)) XOR ((b)) XOR ((c))) + (@bBuf[ 8]) +&H8771f681
ROTATE LEFT d, %S32: d = d + a
c = c + (((d)) XOR ((a)) XOR ((b))) + (@bBuf[11]) +&H6d9d6122
ROTATE LEFT c, %S33: c = c + d
b = b + (((c)) XOR ((d)) XOR ((a))) + (@bBuf[14]) +&Hfde5380c
ROTATE LEFT b, %S34: b = b + c
'
a = a + (((b)) XOR ((c)) XOR ((d))) + (@bBuf[ 1]) +&Ha4beea44
ROTATE LEFT a, %S31: a = a + b
d = d + (((a)) XOR ((b)) XOR ((c))) + (@bBuf[ 4]) +&H4bdecfa9
ROTATE LEFT d, %S32: d = d + a
c = c + (((d)) XOR ((a)) XOR ((b))) + (@bBuf[ 7]) +&Hf6bb4b60
ROTATE LEFT c, %S33: c = c + d
b = b + (((c)) XOR ((d)) XOR ((a))) + (@bBuf[10]) +&Hbebfbc70
ROTATE LEFT b, %S34: b = b + c
'
a = a + (((b)) XOR ((c)) XOR ((d))) + (@bBuf[13]) +&H289b7ec6
ROTATE LEFT a, %S31: a = a + b
d = d + (((a)) XOR ((b)) XOR ((c))) + (@bBuf[ 0]) +&Heaa127fa
ROTATE LEFT d, %S32: d = d + a
c = c + (((d)) XOR ((a)) XOR ((b))) + (@bBuf[ 3]) +&Hd4ef3085
ROTATE LEFT c, %S33: c = c + d
b = b + (((c)) XOR ((d)) XOR ((a))) + (@bBuf[ 6]) +&H4881d05
ROTATE LEFT b, %S34: b = b + c
'
a = a + (((b)) XOR ((c)) XOR ((d))) + (@bBuf[ 9]) +&Hd9d4d039
ROTATE LEFT a, %S31: a = a + b
d = d + (((a)) XOR ((b)) XOR ((c))) + (@bBuf[12]) +&He6db99e5
ROTATE LEFT d, %S32: d = d + a
c = c + (((d)) XOR ((a)) XOR ((b))) + (@bBuf[15]) +&H1fa27cf8
ROTATE LEFT c, %S33: c = c + d
b = b + (((c)) XOR ((d)) XOR ((a))) + (@bBuf[ 2]) +&Hc4ac5665
ROTATE LEFT b, %S34: b = b + c


'ROUND 4
a = a + (((c)) XOR (((b)) OR (NOT (d)))) + (@bBuf[ 0]) +&Hf4292244
ROTATE LEFT a, %S41: a = a + b
d = d + (((b)) XOR (((a)) OR (NOT (c)))) + (@bBuf[ 7]) +&H432aff97
ROTATE LEFT d, %S42: d = d + a
c = c + (((a)) XOR (((d)) OR (NOT (b)))) + (@bBuf[14]) +&Hab9423a7
ROTATE LEFT c, %S43: c = c + d
b = b + (((d)) XOR (((c)) OR (NOT (a)))) + (@bBuf[ 5]) +&Hfc93a039
ROTATE LEFT b, %S44: b = b + c
'
a = a + (((c)) XOR (((b)) OR (NOT (d)))) + (@bBuf[12]) +&H655b59c3
ROTATE LEFT a, %S41: a = a + b
d = d + (((b)) XOR (((a)) OR (NOT (c)))) + (@bBuf[ 3]) +&H8f0ccc92
ROTATE LEFT d, %S42: d = d + a
c = c + (((a)) XOR (((d)) OR (NOT (b)))) + (@bBuf[10]) +&Hffeff47d
ROTATE LEFT c, %S43: c = c + d
b = b + (((d)) XOR (((c)) OR (NOT (a)))) + (@bBuf[ 1]) +&H85845dd1
ROTATE LEFT b, %S44: b = b + c
'
a = a + (((c)) XOR (((b)) OR (NOT (d)))) + (@bBuf[ 8]) +&H6fa87e4f
ROTATE LEFT a, %S41: a = a + b
d = d + (((b)) XOR (((a)) OR (NOT (c)))) + (@bBuf[15]) +&Hfe2ce6e0
ROTATE LEFT d, %S42: d = d + a
c = c + (((a)) XOR (((d)) OR (NOT (b)))) + (@bBuf[ 6]) +&Ha3014314
ROTATE LEFT c, %S43: c = c + d
b = b + (((d)) XOR (((c)) OR (NOT (a)))) + (@bBuf[13]) +&H4e0811a1
ROTATE LEFT b, %S44: b = b + c
'
a = a + (((c)) XOR (((b)) OR (NOT (d)))) + (@bBuf[ 4]) +&Hf7537e82
ROTATE LEFT a, %S41: a = a + b
d = d + (((b)) XOR (((a)) OR (NOT (c)))) + (@bBuf[11]) +&Hbd3af235
ROTATE LEFT d, %S42: d = d + a
c = c + (((a)) XOR (((d)) OR (NOT (b)))) + (@bBuf[ 2]) +&H2ad7d2bb
ROTATE LEFT c, %S43: c = c + d
b = b + (((d)) XOR (((c)) OR (NOT (a)))) + (@bBuf[ 9]) +&Heb86d391
ROTATE LEFT b, %S44: b = b + c

ctx.lState(0) = ctx.lState(0) + a
ctx.lState(1) = ctx.lState(1) + b
ctx.lState(2) = ctx.lState(2) + c
ctx.lState(3) = ctx.lState(3) + d

END SUB

' Update context TO reflect the concatenation of another buffer full
' of bytes.
SUB md5_Update(byref ctx AS MD5_CTX, BYVAL bBuf AS BYTE PTR, BYVAL dwLen AS DWORD )
LOCAL t AS DWORD

' Update bitcount
t = ctx.lCount(0)
ctx.lCount(0) = t + md5_shiftLeft( dwLen, 3 )
IF ctx.lCount(0) < t THEN
INCR ctx.lCount(1) 'carry from low to high
END IF

ctx.lCount(1) = ctx.lCount(1) + md5_shiftRight( dwLen, 29 )

t = ( md5_shiftRight( t, 3) AND &H3F ) 'Bytes already IN shsInfo->DATA

'handle any leading odd-sized chunks
IF ISTRUE(t) THEN
LOCAL p AS BYTE PTR

p = VARPTR(ctx.bBuf)
p = p + t
t = 64 - t
IF dwLen < t THEN
CALL MoveMemory( BYVAL p, BYVAL bBuf, dwLen )
EXIT SUB
END IF
CALL MoveMemory( BYVAL p, BYVAL bBuf, t )
CALL md5_Transform( ctx, VARPTR(ctx.bBuf) )
bBuf = bBuf + t
dwLen = dwLen - t
END IF

'Process DATA IN 64-BYTE chunks
DO WHILE (dwLen >= 64)
CALL MoveMemory( BYVAL VARPTR(ctx.bBuf), BYVAL bBuf, 64)
CALL md5_Transform( ctx, VARPTR(ctx.bBuf) )
bBuf = bBuf + 64
dwLen = dwLen - 64
LOOP

'handle any remaining bytes of data
CALL MoveMemory( BYVAL VARPTR(ctx.bBuf), BYVAL bBuf, dwLen )
END SUB

' Final wrapup - pad TO 64-BYTE boundary WITH the BIT pattern
' 1 0* (64-BIT count of bits processed, MSB-first)
SUB md5_Final( BYVAL bDigest AS BYTE PTR, ctx AS MD5_CTX)
LOCAL lCount AS DWORD
LOCAL p AS BYTE PTR
LOCAL bBuffer AS BYTE PTR

bBuffer = VARPTR(ctx.bBuf)
'Compute number of bytes MOD 64
lCount = (md5_shiftRight(ctx.lCount(0), 3) AND &H3F )

'set the first char of padding to &H80. This is safe since there is
'always AT least one BYTE free
p = VARPTR(ctx.bBuf)
p = p + lCount
@p = &H80
INCR p

' Bytes of padding needed TO make 64 bytes
lCount = 64 - 1 - lCount

' Pad out TO 56 MOD 64
IF lCount < 8 THEN
'two lots of padding: pad the first block to 64 bytes
CALL FillMemory( p, lCount, 0 )
CALL md5_Transform( ctx, VARPTR(ctx.bBuf) )
CALL FillMemory( byval VARPTR(ctx.bBuf), 56, 0 )
ELSE
'pad block to 56 bytes
CALL FillMemory( byval p, (lCount - 8), 0)
END IF

'append length IN bits and transform
CALL MoveMemory( BYVAL VARPTR(@bBuffer[14 * SIZEOF(lCount)]), BYVAL VARPTR(ctx.lCount(0)), SIZEOF(lCount))
CALL MoveMemory( BYVAL VARPTR(@bBuffer[15 * SIZEOF(lCount)]), BYVAL VARPTR(ctx.lCount(1)), SIZEOF(lCount))

CALL md5_Transform( ctx, VARPTR(ctx.bBuf) )
CALL MoveMemory( BYVAL bDigest, BYVAL VARPTR(ctx.lState(0)), 16)
'Zeroise sensitive information
CALL FillMemory( byval varptr(ctx), SIZEOF(ctx), 0)

END SUB

FUNCTION md5_Digest( byref ctx AS MD5_CTX) AS STRING
'returns the MD5 digest as a hex string
DIM sHex AS STRING
DIM szDigest AS ASCIIZ * 16
DIM bDigest AS BYTE PTR
DIM sCheck AS STRING
DIM i AS LONG

bDigest = VARPTR(szDigest)
CALL md5_Final( bDigest, ctx)

IF bDigest <> %NULL THEN
FOR i = 0 TO 15
sHex = sHex + HEX$(@bDigest[i],2)
NEXT
END IF
FUNCTION = sHex

END FUNCTION

SUB md5_readFile( byref ctx AS MD5_CTX, szFile AS ASCIIZ )
'reads a file and calls md5_Update on the buffer
'md5_Init() MUST have been called prior to calling
'this function - call md5_Digest() afterwards to
'get the fingerprint
LOCAL hFile AS HHANDLE
LOCAL szBuffer AS ASCIIZ * 1024
LOCAL lBufLen AS LONG
LOCAL lLen AS LONG
LOCAL lResult AS LONG
LOCAL lToRead AS LONG
LOCAL lToReadHigh AS LONG
LOCAL lpBuffer AS LONG

lBufLen = SIZEOF(szBuffer)

lpBuffer = VARPTR(szBuffer)
hFile = CreateFile( szFile, %GENERIC_READ, %FILE_SHARE_READ, _
BYVAL %NULL, %OPEN_EXISTING, %FILE_ATTRIBUTE_NORMAL, 0& )

IF hFile <> %INVALID_HANDLE_VALUE THEN
lToRead = GetFileSize(hFile, lToReadHigh)
md5_readFile_loop:
lResult = ReadFile( hFile, BYVAL lpBuffer, lBufLen, lLen , BYVAL %NULL )
IF lResult = 0 THEN GOTO md5_readFile_close
CALL md5_Update(ctx, lpBuffer, lLen)
lToRead = lToRead - lLen
IF lToRead = 0 THEN GOTO md5_readFile_close
GOTO md5_readFile_loop
md5_readFile_close:
CALL CloseHandle(hFile)
END IF
END SUB

SUB test()
'implements the Md5 test suite to make sure that the
'implementation is correct
DIM ctx AS MD5_CTX
DIM szText AS ASCIIZ * 300

CALL md5_Init(ctx ) 'call md5_Init each time to calculate a new digest
szText = ""
CALL md5_Update( ctx, varptr(szText), LEN(szText) )
TELL( "Got: " + lcase$(md5_Digest(ctx) ) )
TELL( "Expected: d41d8cd98f00b204e9800998ecf8427e" )

CALL md5_Init( ctx ) 'call md5_Init each time to calculate a new digest
szText = "a"
CALL md5_Update( ctx, VARPTR(szText), LEN(szText) )
TELL( "Got: " + lcase$(md5_Digest(ctx) ) )
TELL( "Expected: 0cc175b9c0f1b6a831c399e269772661" )

CALL md5_Init( ctx ) 'call md5_Init each time to calculate a new digest
szText = "abc"
CALL md5_Update( ctx, VARPTR(szText), LEN(szText) )
TELL( "Got: " + lcase$(md5_Digest(ctx) ) )
TELL( "Expected: 900150983cd24fb0d6963f7d28e17f72" )

CALL md5_Init( ctx ) 'call md5_Init each time to calculate a new digest
szText = "message digest"
CALL md5_Update( ctx, VARPTR(szText), LEN(szText) )
TELL( "Got: " + lcase$(md5_Digest(ctx) ) )
TELL( "Expected: f96b697d7cb7938d525a2f31aaf161d0" )

CALL md5_Init( ctx ) 'call md5_Init each time to calculate a new digest
szText = "abcdefghijklmnopqrstuvwxyz"
CALL md5_Update( ctx, VARPTR(szText), LEN(szText) )
TELL( "Got: " + lcase$(md5_Digest(ctx) ) )
TELL( "Expected: c3fcd3d76192e4007dfb496cca67e13b" )

CALL md5_Init( ctx ) 'call md5_Init each time to calculate a new digest
szText = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
CALL md5_Update( ctx, VARPTR(szText), LEN(szText) )
TELL( "Got: " + lcase$(md5_Digest(ctx) ) )
TELL( "Expected: d174ab98d277d9f5a5611c2c9f419d9f" )

CALL md5_Init( ctx ) 'call md5_Init each time to calculate a new digest
szText = "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
CALL md5_Update( ctx, VARPTR(szText), LEN(szText) )
TELL( "Got: " + lcase$(md5_Digest(ctx) ) )
TELL( "Expected: 57edf4a22be3c955ac49da2e2107b67a" )

END SUB

FUNCTION PBMAIN() AS LONG

CALL Test()
waitkey$
END FUNCTION

[This message has been edited by Florent Heyworth (edited February 12, 2004).]

IP: Logged

All times are EasternTime (US)

next newest topic | next oldest topic

Administrative Options: Close Topic | Archive/Move | Delete Topic
Post New Topic  Post A Reply
Hop to:

Contact Us | PowerBASIC BASIC Compilers

Copyright © 1999-2005 PowerBASIC, Inc. All Rights Reserved.


Ultimate Bulletin Board 5.45c