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

Class: MD5

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

    PBWin/PBCC Class: MD5

    Hi,

    This is the encapsulation of the MD5 algorithm in an easy to use class.

    Updated with memory copy and memory fill powerbasic functions

    Cheers
    Code:
    #compile exe "md5.exe"
    #dim all
    ' =====================================================
    #Include "win32api.inc"
    ' =====================================================
    %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
    
    
    class MD5
    
     instance lState() as Long          'state (ABCD)
     instance lCount() as Long          'number of bits modulo 2^64 (lsp first)
     instance Buf      as Asciiz * 64   'input buffer
    
     class method create()
    
         Redim lState(4)  as instance Long
         Redim lCount(1)  as instance Long
    
         me.init()
    
     end method
    
     class method shiftRight(BYVAL lThis AS LONG, BYVAL lBits AS LONG) AS LONG
    
       SHIFT RIGHT lThis, lBits
    
       method = lThis
    
     end method
    
     class method shiftLeft(BYVAL lThis AS LONG, BYVAL lBits AS LONG) AS LONG
    
       SHIFT LEFT lThis, lBits
    
       method = lThis
    
     end method
    
     class method init()
       'MD5 initialization. Begins an MD5 operation, writing a new context
    
       lCount(0) = 0
       lCount(1) = 0
    
       ' Load magic initialization constants.
       lState(0) = &H67452301
       lState(1) = &HEFCDAB89
       lState(2) = &H98BADCFE
       lState(3) = &H10325476
    
     end method
    
     class method Transform (ByVal bBuf as Long Ptr)
       LOCAL a AS LONG
       LOCAL b AS LONG
       LOCAL c AS LONG
       LOCAL d AS LONG
    
       a = lState(0)
       b = lState(1)
       c = lState(2)
       d = 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
    
      lState(0) = lState(0) + a
      lState(1) = lState(1) + b
      lState(2) = lState(2) + c
      lState(3) = lState(3) + d
    
     end method
    
     ' Update context TO reflect the concatenation of another buffer full
     ' of bytes.
     class method Update(BYVAL bBuf AS BYTE PTR, BYVAL dwLen AS DWORD )
        Local t AS DWORD
        Local p AS BYTE PTR
    
        ' Update bitcount
        t = lCount(0)
    
        lCount(0) = t + me.shiftLeft( dwLen, 3 )
        IF lCount(0) < t THEN
           INCR lCount(1) 'carry from low to high
        END IF
    
        lCount(1) = lCount(1) + me.shiftRight( dwLen, 29 )
    
        t = ( me.shiftRight( t, 3) AND &H3F ) 'Bytes already IN shsInfo->DATA
    
        'handle any leading odd-sized chunks
        IF ISTRUE(t) THEN
           p = VARPTR(buf)
           p = p + t
           t = 64 - t
           IF dwLen < t THEN
              'CALL MoveMemory( BYVAL p, BYVAL bBuf, dwLen )
              memory copy bBuf, p, dwlen
              exit method
           END IF
           'CALL MoveMemory( BYVAL p, BYVAL bBuf, t )
           MEMORY COPY bBuf, p, t
    
           me.Transform(VARPTR(buf))
    
           bBuf  = bBuf + t
           dwLen = dwLen - t
        END IF
    
        'Process DATA IN 64-BYTE chunks
        DO WHILE (dwLen >= 64)
           'CALL MoveMemory( BYVAL VARPTR(Buf), BYVAL bBuf, 64)
           memory copy bBuf, VarPtr(buf), 64
           CALL me.Transform(VARPTR(Buf) )
           bBuf = bBuf + 64
           dwLen = dwLen - 64
        LOOP
    
        'handle any remaining bytes of data
        'CALL MoveMemory( BYVAL VARPTR(buf), BYVAL bBuf, dwLen )
        memory copy bBuf, VarPtr(buf), dwLen
     end method
    
    ' Final wrapup - pad TO 64-BYTE boundary WITH the BIT pattern
    ' 1 0* (64-BIT count of bits processed, MSB-first)
     class method Final( BYVAL bDigest AS BYTE PTR)
        LOCAL dwCount AS DWORD
        LOCAL p       AS BYTE PTR
        LOCAL bBuffer AS BYTE PTR
    
        bBuffer = VARPTR(Buf)
        'Compute number of bytes MOD 64
        dwCount = (me.shiftRight(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(Buf)
        p = p + dwCount
        @p = &H80
        INCR p
    
        ' Bytes of padding needed TO make 64 bytes
        dwCount = 64 - 1 - dwCount
    
        ' Pad out TO 56 MOD 64
        if dwCount < 8 THEN
           'two lots of padding: pad the first block to 64 bytes
           'CALL FillMemory( p, dwCount, 0 )
           memory fill p, dwCount, DWORD 0
    
           CALL me.Transform(VARPTR(Buf) )
           'CALL FillMemory( byval VARPTR(Buf), 56, 0 )
           memory fill varPtr(Buf), dwCount, DWORD 0
        ELSE
           'pad block to 56 bytes
           'CALL FillMemory( byval p, (dwCount - 8), 0)
           memory fill p, dwCount - 8, DWORD 0
        END IF
    
        'append length IN bits and transform
        'CALL MoveMemory( BYVAL VARPTR(@bBuffer[14 * SIZEOF(dwCount)]), BYVAL VARPTR(lCount(0)), SIZEOF(dwCount))
        memory copy VarPtr(lCount(0)), VARPTR(@bBuffer[14 * SIZEOF(dwCount)]), sizeOf(dwCount)
        'CALL MoveMemory( BYVAL VARPTR(@bBuffer[15 * SIZEOF(dwCount)]), BYVAL VARPTR(lCount(1)), SIZEOF(dwCount))
        memory copy VarPtr(lCount(1)), VARPTR(@bBuffer[15 * SIZEOF(dwCount)]), sizeOf(dwCount)
    
        CALL me.Transform(VARPTR(Buf) )
        'CALL MoveMemory( BYVAL bDigest, BYVAL VARPTR(lState(0)), 16)
        memory copy varPtr(lState(0)), bDigest, 16
        'Zeroise sensitive information
        ' CALL FillMemory( byval varptr(ctx), SIZEOF(ctx), 0)
    
     end method
    
     class method digest() 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 me.Final( bDigest)
    
       IF bDigest <> %NULL THEN
          FOR i = 0 TO 15
            sHex = sHex + HEX$(@bDigest[i],2)
          NEXT
       END IF
       method = sHex
    
     end method
    
     interface iMD5
       inherit iDispatch
    
       method readFile(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 Dword
       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:
           Do
            lResult = ReadFile( hFile, BYVAL lpBuffer, lBufLen, lLen , BYVAL %NULL )
            IF lResult = 0 THEN
                Exit Do
            End if
            me.Update(lpBuffer, lLen)
    
            lToRead = lToRead - lLen
    
           Loop until lResult = 0 or lToRead = 0
           Call CloseHandle(hFile)
       END IF
     end method
    
     method Calc(ByVal sText as String) as String
    
         Local szText As ASCIIZ * 512
    
         szText = sText
    
         me.init()
    
         me.update(VarPtr(szText), len(szText))
    
         method = me.digest()
    
     end method
    
    
     end interface
    end class
    ' =====================================================
    function pbmain() as long
    
      local oMD5 as iMD5
    
      oMD5 = class "MD5"
    
      print oMD5.calc("hello")
    
      print oMD5.calc("hello")
    
    end function
    Last edited by Steven Pringels 3; 30 Jan 2013, 08:55 AM.
    So here we are, this is the end.
    But all that dies, is born again.
    - From The Ashes (In This Moment)

    #2
    Just a note... I think it's a pitty that this MD5 algorithm is so sluggish. Maybe some ASM guru could optimize it for speed ?
    So here we are, this is the end.
    But all that dies, is born again.
    - From The Ashes (In This Moment)

    Comment


      #3
      The class does not work correctly with long buffers.

      Originally I wanted to do a speed measurement. And have found the error with an archive greater 53MB.

      This source code is not a class, but it works:
      PowerBASIC and related source code. Please do not post questions or discussions, just source code.

      Comment


        #4
        I'm through. Now walk huge files. 4.3 GB on my computer in 55 seconds.

        Code:
        [B][COLOR="YellowGreen"]' md5hash.inc[/COLOR][/B]
        $C_MD5_HASH_CLSID = GUID$("{95DC23B8-52C1-4FAB-A967-F8975EBF7EF4}")
        $C_MD5_HASH_IID   = GUID$("{215B285E-A941-42D8-A1AC-3C73DEA03363}")
        
        
        [COLOR="YellowGreen"]' Constants FOR md5_Transform routine.[/COLOR]
        %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          [COLOR="YellowGreen"]'state (ABCD)[/COLOR]
             lCount(2)     AS DWORD         [COLOR="YellowGreen"]'number of bits modulo 2^64 (lsp first)[/COLOR]
             bBuf          AS STRING * 64   [COLOR="YellowGreen"]'input buffer[/COLOR]
        END TYPE
        
        
        CLASS cMD5hash $C_MD5_HASH_CLSID COMMON
        INSTANCE m_ctx      AS MD5_CTX
        INSTANCE p_ctx      AS MD5_CTX PTR
        INSTANCE l_buf      AS LONG PTR
        INSTANCE b_buf      AS BYTE PTR
        INSTANCE b_Digest   AS BYTE PTR
        INSTANCE a_Digest() AS BYTE
        
        
            CLASS METHOD CREATE()
                DIM a_Digest(1 TO 16) AS INSTANCE BYTE
                b_Digest = VARPTR(a_Digest(1))
            END METHOD
        
        
            CLASS METHOD DESTROY()
            END METHOD
        
        
            CLASS METHOD md5_Init()
                [COLOR="YellowGreen"]'MD5 initialization. Begins an MD5 operation, writing a new context[/COLOR]
        
                RESET a_Digest()
                RESET m_ctx
                p_ctx = VARPTR(m_ctx)
                b_buf = VARPTR(@p_ctx.bBuf)
                l_buf = VARPTR(@p_ctx.bBuf)
        
                @p_ctx.lCount(0) = 0
                @p_ctx.lCount(1) = 0
        
                [COLOR="YellowGreen"]' Load magic initialization constants.[/COLOR]
                @p_ctx.lState(0) = &H67452301
                @p_ctx.lState(1) = &HEFCDAB89
                @p_ctx.lState(2) = &H98BADCFE
                @p_ctx.lState(3) = &H10325476
        
            END METHOD
        
        
            CLASS METHOD md5_Transform()
            LOCAL a,b,c,d AS LONG
        
                  a = @p_ctx.lState(0)
                  b = @p_ctx.lState(1)
                  c = @p_ctx.lState(2)
                  d = @p_ctx.lState(3)
        
        
                  [COLOR="YellowGreen"]'ROUND 1[/COLOR]
                  a = a + ((((b)) AND ((c))) OR ((NOT (b)) AND ((d)))) + (@l_buf[ 0]) +&Hd76aa478
                  ROTATE LEFT a, %S11: a = a + b
                  d = d + ((((a)) AND ((b))) OR ((NOT (a)) AND ((c)))) + (@l_buf[ 1]) +&He8c7b756
                  ROTATE LEFT d, %S12: d = d + a
                  c = c + ((((d)) AND ((a))) OR ((NOT (d)) AND ((b)))) + (@l_buf[ 2]) +&H242070db
                  ROTATE LEFT c, %S13: c = c + d
                  b = b + ((((c)) AND ((d))) OR ((NOT (c)) AND ((a)))) + (@l_buf[ 3]) +&Hc1bdceee
                  ROTATE LEFT b, %S14: b = b + c
                  '
                  a = a + ((((b)) AND ((c))) OR ((NOT (b)) AND ((d)))) + (@l_buf[ 4]) +&Hf57c0faf
                  ROTATE LEFT a, %S11: a = a + b
                  d = d + ((((a)) AND ((b))) OR ((NOT (a)) AND ((c)))) + (@l_buf[ 5]) +&H4787c62a
                  ROTATE LEFT d, %S12: d = d + a
                  c = c + ((((d)) AND ((a))) OR ((NOT (d)) AND ((b)))) + (@l_buf[ 6]) +&Ha8304613
                  ROTATE LEFT c, %S13: c = c + d
                  b = b + ((((c)) AND ((d))) OR ((NOT (c)) AND ((a)))) + (@l_buf[ 7]) +&Hfd469501
                  ROTATE LEFT b, %S14: b = b + c
                  '
                  a = a + ((((b)) AND ((c))) OR ((NOT (b)) AND ((d)))) + (@l_buf[ 8]) +&H698098d8
                  ROTATE LEFT a, %S11: a = a + b
                  d = d + ((((a)) AND ((b))) OR ((NOT (a)) AND ((c)))) + (@l_buf[ 9]) +&H8b44f7af
                  ROTATE LEFT d, %S12: d = d + a
                  c = c + ((((d)) AND ((a))) OR ((NOT (d)) AND ((b)))) + (@l_buf[10]) +&Hffff5bb1
                  ROTATE LEFT c, %S13: c = c + d
                  b = b + ((((c)) AND ((d))) OR ((NOT (c)) AND ((a)))) + (@l_buf[11]) +&H895cd7be
                  ROTATE LEFT b, %S14: b = b + c
                  '
                  a = a + ((((b)) AND ((c))) OR ((NOT (b)) AND ((d)))) + (@l_buf[12]) +&H6b901122
                  ROTATE LEFT a, %S11: a = a + b
                  d = d + ((((a)) AND ((b))) OR ((NOT (a)) AND ((c)))) + (@l_buf[13]) +&Hfd987193
                  ROTATE LEFT d, %S12: d = d + a
                  c = c + ((((d)) AND ((a))) OR ((NOT (d)) AND ((b)))) + (@l_buf[14]) +&Ha679438e
                  ROTATE LEFT c, %S13: c = c + d
                  b = b + ((((c)) AND ((d))) OR ((NOT (c)) AND ((a)))) + (@l_buf[15]) +&H49b40821
                  ROTATE LEFT b, %S14: b = b + c
        
        
                  [COLOR="YellowGreen"]'ROUND 2[/COLOR]
                  a = a + ((((b)) AND ((d))) OR (((c)) AND (NOT (d)))) + (@l_buf[ 1]) +&Hf61e2562
                  ROTATE LEFT a, %S21: a = a + b
                  d = d + ((((a)) AND ((c))) OR (((b)) AND (NOT (c)))) + (@l_buf[ 6]) +&Hc040b340
                  ROTATE LEFT d, %S22: d = d + a
                  c = c + ((((d)) AND ((b))) OR (((a)) AND (NOT (b)))) + (@l_buf[11]) +&H265e5a51
                  ROTATE LEFT c, %S23: c = c + d
                  b = b + ((((c)) AND ((a))) OR (((d)) AND (NOT (a)))) + (@l_buf[ 0]) +&He9b6c7aa
                  ROTATE LEFT b, %S24: b = b + c
                  '
                  a = a + ((((b)) AND ((d))) OR (((c)) AND (NOT (d)))) + (@l_buf[ 5]) +&Hd62f105d
                  ROTATE LEFT a, %S21: a = a + b
                  d = d + ((((a)) AND ((c))) OR (((b)) AND (NOT (c)))) + (@l_buf[10]) +&H2441453
                  ROTATE LEFT d, %S22: d = d + a
                  c = c + ((((d)) AND ((b))) OR (((a)) AND (NOT (b)))) + (@l_buf[15]) +&Hd8a1e681
                  ROTATE LEFT c, %S23: c = c + d
                  b = b + ((((c)) AND ((a))) OR (((d)) AND (NOT (a)))) + (@l_buf[ 4]) +&He7d3fbc8
                  ROTATE LEFT b, %S24: b = b + c
                  '
                  a = a + ((((b)) AND ((d))) OR (((c)) AND (NOT (d)))) + (@l_buf[ 9]) +&H21e1cde6
                  ROTATE LEFT a, %S21: a = a + b
                  d = d + ((((a)) AND ((c))) OR (((b)) AND (NOT (c)))) + (@l_buf[14]) +&Hc33707d6
                  ROTATE LEFT d, %S22: d = d + a
                  c = c + ((((d)) AND ((b))) OR (((a)) AND (NOT (b)))) + (@l_buf[ 3]) +&Hf4d50d87
                  ROTATE LEFT c, %S23: c = c + d
                  b = b + ((((c)) AND ((a))) OR (((d)) AND (NOT (a)))) + (@l_buf[ 8]) +&H455a14ed
                  ROTATE LEFT b, %S24: b = b + c
                  '
                  a = a + ((((b)) AND ((d))) OR (((c)) AND (NOT (d)))) + (@l_buf[13]) +&Ha9e3e905
                  ROTATE LEFT a, %S21: a = a + b
                  d = d + ((((a)) AND ((c))) OR (((b)) AND (NOT (c)))) + (@l_buf[ 2]) +&Hfcefa3f8
                  ROTATE LEFT d, %S22: d = d + a
                  c = c + ((((d)) AND ((b))) OR (((a)) AND (NOT (b)))) + (@l_buf[ 7]) +&H676f02d9
                  ROTATE LEFT c, %S23: c = c + d
                  b = b + ((((c)) AND ((a))) OR (((d)) AND (NOT (a)))) + (@l_buf[12]) +&H8d2a4c8a
                  ROTATE LEFT b, %S24: b = b + c
        
        
                  [COLOR="YellowGreen"]'ROUND 3[/COLOR]
                  a = a + (((b)) XOR ((c)) XOR ((d))) + (@l_buf[ 5]) +&Hfffa3942
                  ROTATE LEFT a, %S31: a = a + b
                  d = d + (((a)) XOR ((b)) XOR ((c))) + (@l_buf[ 8]) +&H8771f681
                  ROTATE LEFT d, %S32: d = d + a
                  c = c + (((d)) XOR ((a)) XOR ((b))) + (@l_buf[11]) +&H6d9d6122
                  ROTATE LEFT c, %S33: c = c + d
                  b = b + (((c)) XOR ((d)) XOR ((a))) + (@l_buf[14]) +&Hfde5380c
                  ROTATE LEFT b, %S34: b = b + c
                  '
                  a = a + (((b)) XOR ((c)) XOR ((d))) + (@l_buf[ 1]) +&Ha4beea44
                  ROTATE LEFT a, %S31: a = a + b
                  d = d + (((a)) XOR ((b)) XOR ((c))) + (@l_buf[ 4]) +&H4bdecfa9
                  ROTATE LEFT d, %S32: d = d + a
                  c = c + (((d)) XOR ((a)) XOR ((b))) + (@l_buf[ 7]) +&Hf6bb4b60
                  ROTATE LEFT c, %S33: c = c + d
                  b = b + (((c)) XOR ((d)) XOR ((a))) + (@l_buf[10]) +&Hbebfbc70
                  ROTATE LEFT b, %S34: b = b + c
                  '
                  a = a + (((b)) XOR ((c)) XOR ((d))) + (@l_buf[13]) +&H289b7ec6
                  ROTATE LEFT a, %S31: a = a + b
                  d = d + (((a)) XOR ((b)) XOR ((c))) + (@l_buf[ 0]) +&Heaa127fa
                  ROTATE LEFT d, %S32: d = d + a
                  c = c + (((d)) XOR ((a)) XOR ((b))) + (@l_buf[ 3]) +&Hd4ef3085
                  ROTATE LEFT c, %S33: c = c + d
                  b = b + (((c)) XOR ((d)) XOR ((a))) + (@l_buf[ 6]) +&H4881d05
                  ROTATE LEFT b, %S34: b = b + c
                  '
                  a = a + (((b)) XOR ((c)) XOR ((d))) + (@l_buf[ 9]) +&Hd9d4d039
                  ROTATE LEFT a, %S31: a = a + b
                  d = d + (((a)) XOR ((b)) XOR ((c))) + (@l_buf[12]) +&He6db99e5
                  ROTATE LEFT d, %S32: d = d + a
                  c = c + (((d)) XOR ((a)) XOR ((b))) + (@l_buf[15]) +&H1fa27cf8
                  ROTATE LEFT c, %S33: c = c + d
                  b = b + (((c)) XOR ((d)) XOR ((a))) + (@l_buf[ 2]) +&Hc4ac5665
                  ROTATE LEFT b, %S34: b = b + c
        
        
                  [COLOR="YellowGreen"]'ROUND 4[/COLOR]
                  a = a + (((c)) XOR (((b)) OR (NOT (d)))) + (@l_buf[ 0]) +&Hf4292244
                  ROTATE LEFT a, %S41: a = a + b
                  d = d + (((b)) XOR (((a)) OR (NOT (c)))) + (@l_buf[ 7]) +&H432aff97
                  ROTATE LEFT d, %S42: d = d + a
                  c = c + (((a)) XOR (((d)) OR (NOT (b)))) + (@l_buf[14]) +&Hab9423a7
                  ROTATE LEFT c, %S43: c = c + d
                  b = b + (((d)) XOR (((c)) OR (NOT (a)))) + (@l_buf[ 5]) +&Hfc93a039
                  ROTATE LEFT b, %S44: b = b + c
                  '
                  a = a + (((c)) XOR (((b)) OR (NOT (d)))) + (@l_buf[12]) +&H655b59c3
                  ROTATE LEFT a, %S41: a = a + b
                  d = d + (((b)) XOR (((a)) OR (NOT (c)))) + (@l_buf[ 3]) +&H8f0ccc92
                  ROTATE LEFT d, %S42: d = d + a
                  c = c + (((a)) XOR (((d)) OR (NOT (b)))) + (@l_buf[10]) +&Hffeff47d
                  ROTATE LEFT c, %S43: c = c + d
                  b = b + (((d)) XOR (((c)) OR (NOT (a)))) + (@l_buf[ 1]) +&H85845dd1
                  ROTATE LEFT b, %S44: b = b + c
                  '
                  a = a + (((c)) XOR (((b)) OR (NOT (d)))) + (@l_buf[ 8]) +&H6fa87e4f
                  ROTATE LEFT a, %S41: a = a + b
                  d = d + (((b)) XOR (((a)) OR (NOT (c)))) + (@l_buf[15]) +&Hfe2ce6e0
                  ROTATE LEFT d, %S42: d = d + a
                  c = c + (((a)) XOR (((d)) OR (NOT (b)))) + (@l_buf[ 6]) +&Ha3014314
                  ROTATE LEFT c, %S43: c = c + d
                  b = b + (((d)) XOR (((c)) OR (NOT (a)))) + (@l_buf[13]) +&H4e0811a1
                  ROTATE LEFT b, %S44: b = b + c
                  '
                  a = a + (((c)) XOR (((b)) OR (NOT (d)))) + (@l_buf[ 4]) +&Hf7537e82
                  ROTATE LEFT a, %S41: a = a + b
                  d = d + (((b)) XOR (((a)) OR (NOT (c)))) + (@l_buf[11]) +&Hbd3af235
                  ROTATE LEFT d, %S42: d = d + a
                  c = c + (((a)) XOR (((d)) OR (NOT (b)))) + (@l_buf[ 2]) +&H2ad7d2bb
                  ROTATE LEFT c, %S43: c = c + d
                  b = b + (((d)) XOR (((c)) OR (NOT (a)))) + (@l_buf[ 9]) +&Heb86d391
                  ROTATE LEFT b, %S44: b = b + c
        
                  @p_ctx.lState(0) = @p_ctx.lState(0) + a
                  @p_ctx.lState(1) = @p_ctx.lState(1) + b
                  @p_ctx.lState(2) = @p_ctx.lState(2) + c
                  @p_ctx.lState(3) = @p_ctx.lState(3) + d
        
            END METHOD
        
        
            [COLOR="YellowGreen"]' PB really should have BUILT-IN function for shift instead of SHIFT LEFT|RIGHT semantics....[/COLOR]
            CLASS METHOD md5_shiftRight(BYVAL lThis AS LONG, BYVAL lBits AS LONG) AS LONG
        
                SHIFT RIGHT lThis, lBits
                METHOD = lThis
        
            END METHOD
        
        
            CLASS METHOD md5_shiftLeft(BYVAL lThis AS LONG, BYVAL lBits AS LONG) AS LONG
        
                SHIFT LEFT lThis, lBits
                METHOD = lThis
        
            END METHOD
        
        
            [COLOR="YellowGreen"]' Update context TO reflect the concatenation of another buffer full
            ' of bytes.[/COLOR]
            CLASS METHOD md5_Update( BYVAL bData AS BYTE PTR, BYVAL dataLen AS DWORD )
            LOCAL t AS DWORD
        
                [COLOR="YellowGreen"]' Update bitcount[/COLOR]
                t = @p_ctx.lCount(0)
                @p_ctx.lCount(0) = t + me.md5_shiftLeft( dataLen, 3 )
                IF @p_ctx.lCount(0) < t THEN
                   INCR @p_ctx.lCount(1) 'carry from low to high
                END IF
        
                @p_ctx.lCount(1) = @p_ctx.lCount(1) + me.md5_shiftRight( dataLen, 29 )
        
                t = ( me.md5_shiftRight( t, 3) AND &H3F ) 'Bytes already IN shsInfo->DATA
        
                [COLOR="YellowGreen"]'handle any leading odd-sized chunks[/COLOR]
                IF ISTRUE(t) THEN
                   LOCAL p AS BYTE PTR
        
                   p = b_buf
                   p = p + t
                   t = 64 - t
                   IF dataLen < t THEN
                      MEMORY COPY bData, p, dataLen
                      EXIT METHOD
                   END IF
                   MEMORY COPY bData, p, t
                   CALL me.md5_Transform()
                   bData = bData + t
                   dataLen = dataLen - t
                END IF
        
                [COLOR="YellowGreen"]'Process DATA IN 64-BYTE chunks[/COLOR]
                DO WHILE (dataLen >= 64)
                   MEMORY COPY bData, b_buf, 64
                   CALL me.md5_Transform()
                   bData = bData + 64
                   dataLen = dataLen - 64
                LOOP
        
                [COLOR="YellowGreen"]'handle any remaining bytes of data[/COLOR]
                MEMORY COPY bData, b_buf, dataLen
            END METHOD
        
        
            [COLOR="YellowGreen"]' Final wrapup - pad TO 64-BYTE boundary WITH the BIT pattern
            ' 1 0* (64-BIT count of bits processed, MSB-first)[/COLOR]
            CLASS METHOD md5_Final()
            LOCAL lCount  AS DWORD
            LOCAL p       AS BYTE PTR
        
                [COLOR="YellowGreen"]'Compute number of bytes MOD 64[/COLOR]
                lCount = (me.md5_shiftRight( @p_ctx.lCount(0), 3) AND &H3F )
        
                [COLOR="YellowGreen"]'set the first char of padding to &H80.  This is safe since there is
                'always AT least one BYTE free[/COLOR]
                p = b_buf
                p = p + lCount
                @p = &H80
                INCR p
        
                [COLOR="YellowGreen"]' Bytes of padding needed TO make 64 bytes[/COLOR]
                lCount = 64 - 1 - lCount
        
                [COLOR="YellowGreen"]' Pad out TO 56 MOD 64[/COLOR]
                IF lCount < 8 THEN
                   'two lots of padding: pad the first block to 64 bytes
                   MEMORY FILL p, lCount, BYTE 0
                   CALL me.md5_Transform()
                   MEMORY FILL b_buf, 56, BYTE 0
                ELSE
                   [COLOR="YellowGreen"]'pad block to 56 bytes[/COLOR]
                   MEMORY FILL p, (lCount - 8), BYTE 0
                END IF
        
                [COLOR="YellowGreen"]'append length IN bits and transform[/COLOR]
                MEMORY COPY VARPTR(@p_ctx.lCount(0)), VARPTR(@b_buf[14 * SIZEOF(lCount)]), SIZEOF(lCount)
                MEMORY COPY VARPTR(@p_ctx.lCount(1)), VARPTR(@b_buf[15 * SIZEOF(lCount)]), SIZEOF(lCount)
        
                CALL me.md5_Transform()
                MEMORY COPY VARPTR(@p_ctx.lState(0)), b_Digest, 16
        
                [COLOR="YellowGreen"]'Zeroise sensitive information
                'memory fill p_ctx, SIZEOF(@p_ctx), byte 0[/COLOR]
                RESET m_ctx
            END METHOD
        
        
            CLASS METHOD md5_Digest() AS STRING
            [COLOR="YellowGreen"]'returns the MD5 digest as a hex string[/COLOR]
            LOCAL sHex AS STRING
            LOCAL i    AS LONG
        
                CALL me.md5_Final()
        
                IF ( b_Digest <> 0 ) THEN
                    FOR i = 0 TO 15
                        sHex = sHex + HEX$(@b_Digest[i],2)
                    NEXT i
                END IF
        
                METHOD = sHex
            END METHOD
        
        
            CLASS METHOD md5_File( pFile AS WSTRINGZ ) AS LONG
            ON ERROR GOTO FN_ERR
            LOCAL lRet     AS LONG
            LOCAL m_file   AS LONG
            LOCAL m_arrptr AS BYTE PTR
            LOCAL m_arrlen AS DWORD
            LOCAL m_bytes  AS QUAD
            LOCAL m_open   AS LONG
        
                IF NOT ISFILE(pFile) THEN METHOD = %ERR_FILENOTFOUND: EXIT METHOD
        
                DIM m_arr(0) AS BYTE
        
                m_file = FREEFILE
                OPEN pFile FOR BINARY ACCESS READ AS #m_file: m_open = 1
        
                m_bytes  = LOF(#m_file)
                m_arrlen = 1024*1024*1
        
                IF ( m_bytes >= m_arrlen ) THEN
        
                    REDIM m_arr(1 TO m_arrlen)
                    m_arrptr = VARPTR(m_arr(1))
        
                    WHILE ( m_bytes >= m_arrlen )
        
                        GET #m_file,,m_arr()
                        CALL me.md5_Update (m_arrptr, m_arrlen)
                        m_bytes = m_bytes - m_arrlen
        
                    WEND
        
                    RESET m_arr()
        
                END IF
        
                IF ( m_bytes > 0 ) THEN
        
                    REDIM m_arr(1 TO m_bytes)
                    m_arrptr = VARPTR(m_arr(1))
        
                    GET #m_file,,m_arr()
                    CALL me.md5_Update (m_arrptr, CDWD(m_bytes))
                    m_bytes = 0
        
                    RESET m_arr()
        
                END IF
        
            FN_EXIT:
                IF ( m_open = 1 ) THEN
                    CLOSE #m_file
                    m_open = 0
                END IF
                RESET m_arr()
                REDIM m_arr(0)
                METHOD = lRet
                EXIT METHOD
        
            FN_ERR:
                lRet = ERR
                RESUME FN_EXIT
            END METHOD
        
        
        [COLOR="YellowGreen"]' =====================================================================================[/COLOR]
                       INTERFACE iMD5hash $C_MD5_HASH_IID : INHERIT IUNKNOWN
        [COLOR="YellowGreen"]' =====================================================================================[/COLOR]
        
        
                METHOD calc_buffer (BYVAL dataPtr AS LONG, BYVAL dataLen AS LONG) AS WSTRING
                DIM bytePtr AS BYTE PTR
                    bytePtr = dataPtr
                    CALL me.md5_Init()
                    CALL me.md5_Update( bytePtr, dataLen )
                    METHOD = LCASE$(me.md5_Digest())
                END METHOD
        
        
                METHOD calc_file (pFile AS WSTRINGZ) AS WSTRING
                    CALL me.md5_Init()
                    CALL me.md5_File(pFile)
                    METHOD = LCASE$(me.md5_Digest())
                END METHOD
        
        
            END INTERFACE
        
        END CLASS
        Code:
        [B][COLOR="YellowGreen"]' md5hash.bas (Test program)[/COLOR][/B]
        #COMPILER PBWIN 10
        #COMPILE EXE "MD5hash.exe"
        #DIM ALL
        #DEBUG ERROR OFF
        
        
        %UNICODE = 1
        
        
        #INCLUDE "MD5hash.inc"
        
        
        FUNCTION PBMAIN () AS LONG
        ON ERROR GOTO FN_ERR
        LOCAL fn     AS WSTRINGZ * %MAX_PATH
        LOCAL hTxt   AS LONG
        LOCAL o      AS iMD5hash
        LOCAL md5    AS STRING
        LOCAL tx1    AS STRING
        LOCAL tx2    AS WSTRING
        LOCAL Result AS LONG
        LOCAL f      AS LONG
        LOCAL b      AS QUAD
        LOCAL time   AS SINGLE
        
            o = CLASS "cMD5hash"
        
            fn = TRIM$(COMMAND$,ANY $$DQ+$$SPC)
            IF fn = "" THEN DISPLAY OPENFILE 0, , , "", "", CHR$("All files (*.*)", 0 , "*.*", 0), "", "", %OFN_EXPLORER OR %OFN_FILEMUSTEXIST OR %OFN_ENABLESIZING TO fn
            IF fn = "" THEN EXIT FUNCTION
            
        
            TXT.WINDOW("MD5hash - " + fn, 150, 100) TO hTxt
        
        
            DIM a(1 TO 5) AS BYTE
            ARRAY ASSIGN a() = ASC("H"), ASC("a"), ASC("l"), ASC("l"), ASC("o")
            md5 = o.calc_buffer (VARPTR(a(1)),5)
            TXT.PRINT "Hello-Array:   ", md5
            TXT.PRINT "Expected:      ", "d1bf93299de1b68e6d382c893bf1215f"
            TXT.PRINT ""
        
            tx1 = "Hallo"
            md5 = o.calc_buffer (STRPTR(tx1),LEN(tx1))
            TXT.PRINT "Hallo-String:  ", md5
            TXT.PRINT "Expected:      ", "d1bf93299de1b68e6d382c893bf1215f"
            TXT.PRINT ""
        
            tx2 = "Hallo"
            md5 = o.calc_buffer (STRPTR(tx2),LEN(tx2)*2)
            TXT.PRINT "Hallo-Unicode: ", md5
            TXT.PRINT "Expected:      ", "3412427c2723f07b463e3e236feb29d3"
            TXT.PRINT ""
            TXT.PRINT ""
        
        
            time = TIMER
            f = FREEFILE
            OPEN fn FOR BINARY ACCESS READ AS #f
                b = LOF(#f)
                IF ( b < 1024*1024*1000 ) THEN
                    REDIM a(1 TO b)
                    GET #f,,a()
                END IF
            CLOSE #f
            IF ( b < 1024*1024*1000 ) THEN
                md5 = o.calc_buffer (VARPTR(a(1)),b)
                TXT.PRINT PATHNAME$(NAMEX,fn) + " ( " + FORMAT$(b,"#,") + " Bytes )"
                TXT.PRINT "calc_buffer()  ",md5,FORMAT$(TIMER-time,"##.###") + "s"
            END IF
        
        
            time = TIMER
            md5 = o.calc_file (fn)
            TXT.PRINT "calc_file()    ",md5,FORMAT$(TIMER-time,"##.###") + "s"
        
        
        FN_EXIT:
            TXT.PRINT ""
            TXT.PRINT ""
            TXT.PRINT "Press any key..."
            TXT.WAITKEY$
            EXIT FUNCTION
        FN_ERR:
            TXT.PRINT ERROR$
            TXT.WAITKEY$
        END FUNCTION

        Comment


          #5
          Hello.
          See there is way to use .Net System.Security.Cryptography.MD5.
          Any PBasic example please. Tks

          Below a example C#:


          Code:
           [TABLE="border: 0, cellpadding: 0, cellspacing: 0"]
          [TR]
          [TD]string hash = CreateMD5Hash("[URL="http://www.csharpexamples.com/"]http://www.csharpexamples.com[/URL]");
          			Console.WriteLine(hash);
          			//Output:
          			//E426A83F137FA324C3412B92193EED1F[/TD]
           		[/TR]
          [/TABLE]
          [TABLE="border: 0, cellpadding: 0, cellspacing: 0"]
          [TR]
          [TD]1
          			2
          			3
          			4
          			5
          			6
          			7
          			8
          			9
          			10
          			11
          			12
          			13
          			14
          			15[/TD]
           			[TD]public string CreateMD5Hash(string input)
          			{
          			    // Step 1, calculate MD5 hash from input
          			    MD5 md5 = System.Security.Cryptography.MD5.Create();
          			    byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
          			    byte[] hashBytes = md5.ComputeHash(inputBytes);
          
          			    // Step 2, convert byte array to hex string
          			    StringBuilder sb = new StringBuilder();
          			    for (int i = 0; i < hashBytes.Length; i++)
          			    {
          			        sb.Append(hashBytes[i].ToString("X2"));
          			    }
          			    return sb.ToString();[/TD]
           		[/TR]
          [/TABLE]

          Comment

          Working...
          X
          😀
          🥰
          🤢
          😎
          😡
          👍
          👎