Announcement

Collapse

Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

MD5

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • MD5

    [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.

    Code:
    #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).]

  • #2
    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
    mailto:tngbbs@sinclair.nettngbbs@sinclair.net</A>
    Scott Turchin
    MCSE, MCP+I
    http://www.tngbbs.com
    ----------------------
    True Karate-do is this: that in daily life, one's mind and body be trained and developed in a spirit of humility; and that in critical times, one be devoted utterly to the cause of justice. -Gichin Funakoshi

    Comment


    • #3
      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).]

      Comment


      • #4
        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?

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

        Comment


        • #5

          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:

          Code:
          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 / mailto:gohel@basicguru.comgohel@basicguru.com</A> (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
          http://www.gohel.de - http://www.gohel.net - http://www.pbhq.com

          Comment


          • #6
            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.

            Comment


            • #7
              Here an update for PBCC3.x and PBWIN7.x

              Code:
              #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).]

              Comment


              • #8
                Change from/to...
                Code:
                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
                '... change to ... 
                TYPE MD5_CTX
                     lState(3) AS LONG   'state (ABCD)
                     lCount(1) AS LONG   'number of bits modulo 2^64 (lsp first)
                     bBuf AS STRING * 64 'input buffer
                END TYPE
                The original code for Florent's md5_shiftRight() function uses PB's native "SHIFT RIGHT n-bits", which is a very flexible procedure - ideal for general purposes as per its main intention, but expensive for our specific needs -- here is md5_shiftRight() compiled (44 instructions with numerous recursions):


                We can do all of that with just two FASTPROC'd lines; here are direct replacement functions:
                Code:
                FASTPROC md5_shiftRight(BYVAL lThis AS LONG, BYVAL lBits AS LONG) AS LONG
                 ! mov ecx, lBits
                 ! shr esi, cl
                END FASTPROC = lThis  '// lThis=esi
                
                FASTPROC md5_shiftLeft(BYVAL lThis AS LONG, BYVAL lBits AS LONG) AS LONG
                 ! mov ecx, lBits
                 ! shl esi, cl
                END FASTPROC = lThis  '// lThis=esi

                Also, here's the biggie as it's in the main transform routine so a lot of speed can be gained -- all the inline ROTATEs can be replaced directly for speedup, which results in very much the same improvement as seen above with SHIFTs in regards to reducing many instructions down to just one or two ... for example:
                Code:
                  a = a + ((((b)) AND ((c))) OR ((NOT (b)) AND ((d)))) + (@bBuf[ 0]) +&Hd76aa478
                  ROTATE LEFT a, %S11: a = a + b
                 
                '... change to ... 
                 
                  a = a + ((((b)) AND ((c))) OR ((NOT (b)) AND ((d)))) + (@bBuf[ 0]) +&Hd76aa478
                  !rol a, %S11
                  a = a + b
                Likewise, the md5_transform() function itself can easily be FASTPROC'd for more speed with simple modifications at the prologue/epilogue...
                Code:
                FASTPROC md5_Transform ( BYVAL ctxptr AS LONG, BYVAL ptrbBuf AS LONG )
                   STATIC a AS LONG, b AS LONG, c AS LONG, d AS LONG, ctx AS MD5_CTX PTR, bBuf AS LONG PTR
                   ctx = ctxptr: bBuf = ptrbBuf
                   a = @ctx.lState(0)
                   b = @ctx.lState(1)
                   c = @ctx.lState(2)
                   d = @ctx.lState(3)
                ' ... -snip- ...
                   @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 FASTPROC
                See this HMAC-MD5 demo for an example implementation of the above changes.
                Last edited by Wayne Diamond; 5 Jan 2015, 05:35 AM.
                -

                Comment

                Working...
                X