` Printed Icetips Article

Icetips Article



Windows API: MD5 algorithm
2004-03-17 -- Dan Gorrell
 
Newsgroups: softvelocity.public.clarion6

Here is a piece of a cyptography library that I'm working on.  It's going to
be a while before I am able to release the whole thing, so I thought I'd
just toss this out there for free.  This procedure takes a string and
computes an RFC compliant MD5 hash.


!  MD5FromString -- part of the DanCrypto Clarion Cryptography Library
!  Copyright 2004 (C) by Daniel J. Gorrell
!  You may use this code freely for personal, commercial, or other purposes so long as
this
!  copyright notice is maintained within the code.  This code may not be redistributed as
!  part of a programming library or template without written consent of the author.

MD5FromString        PROCEDURE(STRING myString)

InputLen             LONG
TargetLen            LONG

ResultA              CSTRING(9)
ResultB              CSTRING(9)
ResultC              CSTRING(9)
ResultD              CSTRING(9)

Extras               LONG
DivTimes             LONG

ABuf                 LONG
BBuf                 LONG
CBuf                 LONG
DBuf                 LONG

AA                   LONG
BB                   LONG
CC                   LONG
DD                   LONG

myTempLong           LONG

myTempBytes          GROUP,OVER(myTempLong)
Byte1                  BYTE
Byte2                  BYTE
Byte3                  BYTE
Byte4                  BYTE
                    END

ProcessingString    &CSTRING

my64BitLength       GROUP
myActualLong          ULONG
myPaddingLong         ULONG
                    END

my64BitChars        STRING(8),OVER(my64BitLength)

myXBytes            STRING(64)
myXLongs            ULONG,DIM(16),OVER(myXBytes)

retval              STRING(32)

  CODE

  !STEP 1 - Append padding bits

    !Get original string size
    InputLen = LEN(myString)

    !Determine the size of the target string
    IF InputLen > 55 THEN
      IF InputLen > 64 THEN
        DivTimes = ABS(InputLen/64)
        Extras = (InputLen - (DivTimes * 64))
        IF Extras > 55 THEN
          TargetLen = InputLen + (120 - Extras)
        ELSE
          TargetLen = InputLen + (56 - Extras)
        END
      ELSE
        TargetLen = InputLen + (120 - InputLen)
      END
    ELSE
      TargetLen = InputLen + (56 - InputLen)
    END

    !Create CString that is TargetLen + 8 Bytes (for length)
    ProcessingString &= NEW(CSTRING(TargetLen + 8))

    !Null out entire string (to add 0-bit padding)
    memset(ADDRESS(ProcessingString),00000000b,SIZE(ProcessingString))

    !Copy original string into CString for processing
    ProcessingString[1:InputLen] = myString[1:InputLen]

    !Add one-bit padding byte to CString
    ProcessingString[InputLen+1] = CHR(128) !128 is base10 for 10000000b


  !STEP 2 - Append 64 bit representation of original message length to end

    my64BitLength.myPaddingLong = 00000000h
    my64BitLength.myActualLong  = (InputLen * 8)
    ProcessingString[TargetLen+1:TargetLen+8] = my64BitChars[1:8]

  !STEP 3 - Initialize MD Buffers

    ABuf =  1732584193
    BBuf =  -271733879
    CBuf = -1732584194
    DBuf =   271733878

  !STEP 4 - Process Message in 16-Word (LONG) Blocks

  LOOP i# = 64 TO SIZE(ProcessingString) BY 64

     !Clear our processing buffer
     memset(ADDRESS(myXBytes),00000000b,64)

     !Load in 16 LONGS / 64 CHARS
     myXBytes[1:64] = ProcessingString[(i#-63):i#]

     LOOP j# = 1 TO 16 BY 1

       myTempLong = 0000h
       myTempLong = BOR(myTempLong, BSHIFT(VAL( |
                        ProcessingString[((i#-63)+(((J#-1)*4)+0))]),0))
       myTempLong = BOR(myTempLong, BSHIFT(VAL( |
                        ProcessingString[((i#-63)+(((J#-1)*4)+1))]),8))
       myTempLong = BOR(myTempLong, BSHIFT(VAL( |
                        ProcessingString[((i#-63)+(((J#-1)*4)+2))]),16))
       myTempLong = BOR(myTempLong, BSHIFT(VAL( |
                        ProcessingString[((i#-63)+(((J#-1)*4)+3))]),24))

       myXLongs[j#] = myTempLong

     END

     AA = ABuf
     BB = BBuf
     CC = CBuf
     DD = DBuf

     SELF.MD5_FF(ABuf, BBuf, CBuf, DBuf, myXLongs[1],  7,   -680876936)
     SELF.MD5_FF(DBuf, ABuf, BBuf, CBuf, myXLongs[2],  12,  -389564586)
     SELF.MD5_FF(CBuf, DBuf, ABuf, BBuf, myXLongs[3],  17,   606105819)
     SELF.MD5_FF(BBuf, CBuf, DBuf, ABuf, myXLongs[4],  22, -1044525330)
     SELF.MD5_FF(ABuf, BBuf, CBuf, DBuf, myXLongs[5],  7,   -176418897)
     SELF.MD5_FF(DBuf, ABuf, BBuf, CBuf, myXLongs[6],  12,  1200080426)
     SELF.MD5_FF(CBuf, DBuf, ABuf, BBuf, myXLongs[7],  17, -1473231341)
     SELF.MD5_FF(BBuf, CBuf, DBuf, ABuf, myXLongs[8],  22,   -45705983)
     SELF.MD5_FF(ABuf, BBuf, CBuf, DBuf, myXLongs[9],  7,   1770035416)
     SELF.MD5_FF(DBuf, ABuf, BBuf, CBuf, myXLongs[10], 12, -1958414417)
     SELF.MD5_FF(CBuf, DBuf, ABuf, BBuf, myXLongs[11], 17,      -42063)
     SELF.MD5_FF(BBuf, CBuf, DBuf, ABuf, myXLongs[12], 22, -1990404162)
     SELF.MD5_FF(ABuf, BBuf, CBuf, DBuf, myXLongs[13], 7,   1804603682)
     SELF.MD5_FF(DBuf, ABuf, BBuf, CBuf, myXLongs[14], 12,   -40341101)
     SELF.MD5_FF(CBuf, DBuf, ABuf, BBuf, myXLongs[15], 17, -1502002290)
     SELF.MD5_FF(BBuf, CBuf, DBuf, ABuf, myXLongs[16], 22,  1236535329)

     SELF.MD5_GG(ABuf, BBuf, CBuf, DBuf, myXLongs[2],  5,   -165796510)
     SELF.MD5_GG(DBuf, ABuf, BBuf, CBuf, myXLongs[7],  9,  -1069501632)
     SELF.MD5_GG(CBuf, DBuf, ABuf, BBuf, myXLongs[12], 14,   643717713)
     SELF.MD5_GG(BBuf, CBuf, DBuf, ABuf, myXLongs[1],  20,  -373897302)
     SELF.MD5_GG(ABuf, BBuf, CBuf, DBuf, myXLongs[6],  5,   -701558691)
     SELF.MD5_GG(DBuf, ABuf, BBuf, CBuf, myXLongs[11], 9,     38016083)
     SELF.MD5_GG(CBuf, DBuf, ABuf, BBuf, myXLongs[16], 14,  -660478335)
     SELF.MD5_GG(BBuf, CBuf, DBuf, ABuf, myXLongs[5],  20,  -405537848)
     SELF.MD5_GG(ABuf, BBuf, CBuf, DBuf, myXLongs[10], 5,    568446438)
     SELF.MD5_GG(DBuf, ABuf, BBuf, CBuf, myXLongs[15], 9,  -1019803690)
     SELF.MD5_GG(CBuf, DBuf, ABuf, BBuf, myXLongs[4],  14,  -187363961)
     SELF.MD5_GG(BBuf, CBuf, DBuf, ABuf, myXLongs[9],  20,  1163531501)
     SELF.MD5_GG(ABuf, BBuf, CBuf, DBuf, myXLongs[14], 5,  -1444681467)
     SELF.MD5_GG(DBuf, ABuf, BBuf, CBuf, myXLongs[3],  9,    -51403784)
     SELF.MD5_GG(CBuf, DBuf, ABuf, BBuf, myXLongs[8],  14,  1735328473)
     SELF.MD5_GG(BBuf, CBuf, DBuf, ABuf, myXLongs[13], 20, -1926607734)

     SELF.MD5_HH(ABuf, BBuf, CBuf, DBuf, myXLongs[6],  4,      -378558)
     SELF.MD5_HH(DBuf, ABuf, BBuf, CBuf, myXLongs[9],  11, -2022574463)
     SELF.MD5_HH(CBuf, DBuf, ABuf, BBuf, myXLongs[12], 16,  1839030562)
     SELF.MD5_HH(BBuf, CBuf, DBuf, ABuf, myXLongs[15], 23,   -35309556)
     SELF.MD5_HH(ABuf, BBuf, CBuf, DBuf, myXLongs[2],  4,  -1530992060)
     SELF.MD5_HH(DBuf, ABuf, BBuf, CBuf, myXLongs[5],  11,  1272893353)
     SELF.MD5_HH(CBuf, DBuf, ABuf, BBuf, myXLongs[8],  16,  -155497632)
     SELF.MD5_HH(BBuf, CBuf, DBuf, ABuf, myXLongs[11], 23, -1094730640)
     SELF.MD5_HH(ABuf, BBuf, CBuf, DBuf, myXLongs[14], 4,    681279174)
     SELF.MD5_HH(DBuf, ABuf, BBuf, CBuf, myXLongs[1],  11,  -358537222)
     SELF.MD5_HH(CBuf, DBuf, ABuf, BBuf, myXLongs[4],  16,  -722521979)
     SELF.MD5_HH(BBuf, CBuf, DBuf, ABuf, myXLongs[7],  23,    76029189)
     SELF.MD5_HH(ABuf, BBuf, CBuf, DBuf, myXLongs[10], 4,   -640364487)
     SELF.MD5_HH(DBuf, ABuf, BBuf, CBuf, myXLongs[13], 11,  -421815835)
     SELF.MD5_HH(CBuf, DBuf, ABuf, BBuf, myXLongs[16], 16,   530742520)
     SELF.MD5_HH(BBuf, CBuf, DBuf, ABuf, myXLongs[3],  23,  -995338651)

     SELF.MD5_II(ABuf, BBuf, CBuf, DBuf, myXLongs[1],  6,   -198630844)
     SELF.MD5_II(DBuf, ABuf, BBuf, CBuf, myXLongs[8],  10,  1126891415)
     SELF.MD5_II(CBuf, DBuf, ABuf, BBuf, myXLongs[15], 15, -1416354905)
     SELF.MD5_II(BBuf, CBuf, DBuf, ABuf, myXLongs[6],  21,   -57434055)
     SELF.MD5_II(ABuf, BBuf, CBuf, DBuf, myXLongs[13], 6,   1700485571)
     SELF.MD5_II(DBuf, ABuf, BBuf, CBuf, myXLongs[4],  10, -1894986606)
     SELF.MD5_II(CBuf, DBuf, ABuf, BBuf, myXLongs[11], 15,    -1051523)
     SELF.MD5_II(BBuf, CBuf, DBuf, ABuf, myXLongs[2],  21, -2054922799)
     SELF.MD5_II(ABuf, BBuf, CBuf, DBuf, myXLongs[9],  6,   1873313359)
     SELF.MD5_II(DBuf, ABuf, BBuf, CBuf, myXLongs[16], 10,   -30611744)
     SELF.MD5_II(CBuf, DBuf, ABuf, BBuf, myXLongs[7],  15, -1560198380)
     SELF.MD5_II(BBuf, CBuf, DBuf, ABuf, myXLongs[14], 21,  1309151649)
     SELF.MD5_II(ABuf, BBuf, CBuf, DBuf, myXLongs[5],  6,   -145523070)
     SELF.MD5_II(DBuf, ABuf, BBuf, CBuf, myXLongs[12], 10, -1120210379)
     SELF.MD5_II(CBuf, DBuf, ABuf, BBuf, myXLongs[3],  15,   718787259)
     SELF.MD5_II(BBuf, CBuf, DBuf, ABuf, myXLongs[10], 21,  -343485551)

     ABuf += AA
     BBuf += BB
     CBuf += CC
     DBuf += DD

  END

  LtoA(ABuf,ResultA,16)
  LtoA(BBuf,ResultB,16)
  LtoA(CBuf,ResultC,16)
  LtoA(DBuf,ResultD,16)

  IF LEN(ResultA) < 8 THEN
    LOOP i# = 1 TO (8 - LEN(ResultA)) BY 1
      ResultA = '0' & ResultA
    END
  END

  IF LEN(ResultB) < 8 THEN
    LOOP i# = 1 TO (8 - LEN(ResultB)) BY 1
      ResultB = '0' & ResultB
    END
  END

  IF LEN(ResultC) < 8 THEN
    LOOP i# = 1 TO (8 - LEN(ResultC)) BY 1
      ResultC = '0' & ResultC
    END
  END

  IF LEN(ResultD) < 8 THEN
    LOOP i# = 1 TO (8 - LEN(ResultD)) BY 1
      ResultD = '0' & ResultD
    END
  END

  retval = ResultA[7:8] & ResultA[5:6] & ResultA[3:4] & ResultA[1:2] & |
           ResultB[7:8] & ResultB[5:6] & ResultB[3:4] & ResultB[1:2] & |
           ResultC[7:8] & ResultC[5:6] & ResultC[3:4] & ResultC[1:2] & |
           ResultD[7:8] & ResultD[5:6] & ResultD[3:4] & ResultD[1:2]

  DISPOSE(ProcessingString)
  ProcessingString &= NULL

  RETURN(retval)




You'll need the following in your map.

    MODULE('runtime library')
      LtoA(LONG,*CSTRING,SIGNED),ULONG,RAW,NAME('_ltoa'),PROC
      memcpy(LONG,LONG,UNSIGNED),NAME('_memcpy')
      memset(LONG,LONG,UNSIGNED),NAME('_memset')
    END

You'll need to rename them to procedures instead of methods, and change the calls in the
main procedure so they don't reference SELF.


DanCrypt.MD5_FF                 PROCEDURE(*LONG mya, LONG myb, LONG myc,
LONG myd, LONG myx, LONG mys, LONG myac)
  CODE
    mya = myb + SELF.MD5_RotateLeft((mya + BOR((BAND(myb,myc)),|
                                    (BAND(BXOR(myb,-1),myd))) + |
                                     myx + myac),mys)
  RETURN


DanCrypt.MD5_GG                 PROCEDURE(*LONG mya, LONG myb, LONG myc, |
                                          LONG myd, LONG myx, LONG mys, |
                                          LONG myac)
  CODE
    mya = myb + SELF.MD5_RotateLeft((mya + BOR((BAND(myb,myd)),|
                                    (BAND(myc,(BXOR(myd,-1))))) + |
                                     myx + myac),mys)
  RETURN


DanCrypt.MD5_HH                 PROCEDURE(*LONG mya, LONG myb, LONG myc, |
                                           LONG myd, LONG myx, LONG mys, |
                                           LONG myac)
  CODE
    mya = myb + SELF.MD5_RotateLeft((mya + BXOR((BXOR(myb,myc)),myd) + |
                                     myx + myac),mys)
  RETURN


DanCrypt.MD5_II                 PROCEDURE(*LONG mya, LONG myb, LONG myc, |
                                          LONG myd, LONG myx, LONG mys, |
                                          LONG myac)
  CODE
    mya = myb + SELF.MD5_RotateLeft((mya + BXOR(myc,(BOR(myb,|
                                          (BXOR(myd,-1))))) + |
                                           myx + myac),mys)
  RETURN


DanCrypt.MD5_RotateLeft  PROCEDURE(LONG lValue, LONG iShiftBits)
retval  LONG
  CODE
    retval = (BOR(BSHIFT(lValue,iShiftBits),|
              BSHIFT(lValue, (-1 * (32 - iShiftBits)))))
  RETURN(retval)



Printed May 5, 2024, 5:59 am
This article has been viewed/printed 35113 times.
Google search has resulted in 280 hits on this article since January 25, 2004.