How to resolve the algorithm MD5/Implementation step by step in the Icon and Unicon programming language

Published on 12 May 2024 09:40 PM

How to resolve the algorithm MD5/Implementation step by step in the Icon and Unicon programming language

Table of Contents

Problem Statement

The purpose of this task to code and validate an implementation of the MD5 Message Digest Algorithm by coding the algorithm directly (not using a call to a built-in or external hashing library). For details of the algorithm refer to MD5 on Wikipedia or the MD5 definition in IETF RFC (1321).

The solutions shown here will provide practical illustrations of bit manipulation, unsigned integers, working with little-endian data. Additionally, the task requires an attention to details such as boundary conditions since being out by even 1 bit will produce dramatically different results. Subtle implementation bugs can result in some hashes being correct while others are wrong. Not only is it critical to get the individual sub functions working correctly, even small errors in padding, endianness, or data layout will result in failure. In addition, intermediate outputs to aid in developing an implementation can be found here. The MD5 Message-Digest Algorithm was developed by RSA Data Security, Inc. in 1991.

Let's start with the solution:

Step by Step solution about How to resolve the algorithm MD5/Implementation step by step in the Icon and Unicon programming language

Source code in the icon programming language

procedure main()  # validate against the RFC test strings and more
   testMD5("The quick brown fox jumps over the lazy dog", 16r9e107d9d372bb6826bd81d3542a419d6)
   testMD5("The quick brown fox jumps over the lazy dog.", 16re4d909c290d0fb1ca068ffaddf22cbd0)
   testMD5("", 16rd41d8cd98f00b204e9800998ecf8427e)    #R = MD5 test suite from RFC
   testMD5("a", 16r0cc175b9c0f1b6a831c399e269772661)   #R
   testMD5("abc", 16r900150983cd24fb0d6963f7d28e17f72) #R
   testMD5("message digest", 16rf96b697d7cb7938d525a2f31aaf161d0) #R 
   testMD5("abcdefghijklmnopqrstuvwxyz", 16rc3fcd3d76192e4007dfb496cca67e13b) #R 
   testMD5("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 16rd174ab98d277d9f5a5611c2c9f419d9f) #R        
   testMD5("12345678901234567890123456789012345678901234567890123456789012345678901234567890", 16r57edf4a22be3c955ac49da2e2107b67a) #R
end

procedure testMD5(s,rh)  # compute the MD5 hash and compare it to reference value
   write("Message(length=",*s,") = ",image(s))
   write("Digest = ",hexstring(h := MD5(s)),if h = rh then " matches reference hash" else (" does not match reference hash = " || hexstring(rh)),"\n")
end

link hexcvt # for testMD5

$define B32                     4   #  32 bits
$define B64                     8   #  64 bits in bytes
$define B512                   64   # 512 bits in bytes
$define M32          16r100000000   # 2^32 
$define M64  16r10000000000000000   # 2^64

procedure MD5(s)                                    #: return MD5 hash of message s
local w,a,b,c,d,i,t,m
local mlength,message,hash
static rs,ks,istate,maxpad,g

initial {
   every (rs := []) |||:= 
      (t := [ 7, 12, 17, 22] | [ 5,  9, 14, 20] | [ 4, 11, 16, 23] | [ 6, 10, 15, 21]) ||| t ||| t ||| t
   every put(ks := [],integer(M32 * abs(sin(i := 1 to 64))))
   istate := [ 16r67452301, 16rEFCDAB89, 16r98BADCFE, 16r10325476 ]  # "Magic" IV
   maxpad := left(char(16r80),B512+B64,char(16r00)) # maximum possible padding
   g := []
   every i := 0 to 63 do                            # precompute offsets
      case round := i/16 of {
         0 : put(g,i + 1)
         1 : put(g,(5*i+1) % 16 + 1)
	 2 : put(g,(3*i+5) % 16 + 1)
         3 : put(g,(7*i) % 16 + 1) 
         }
   if not (*rs = *ks = 64) then runerr(500,"MD5 setup error") 
   }
                                                    # 1. Construct prefix
   t := (*s*8)%M64                                  # original message length
   s ||:= maxpad                                    # append maximum padding 
   s[0-:*s%B512] := ""                              # trim to final length 
   s[0-:B64] := reverse(unsigned2string(t,B64) )    # as little endian length
   
   message := []                                    # 2. Subdivide message
   s ? while put(message,move(B512))                #  into 512 bit blocks

                                                    # 3. Transform message ...
   state := copy(istate)                            # Initialize hashes 
   every m := !message do {                         # For each message block
      w := []
      m ? while put(w,unsigned(reverse(move(B32)))) # break into little-endian words 

      a := state[1]                                 # pick up hashes
      b := state[2]
      c := state[3]
      d := state[4]

      every i := 1 to 64 do  {                      # Process 4 rounds of hashes	
         case round := (i-1)/16 of {
	    0 : a +:= ixor(d, iand(b,ixor(c,d)))          # 0..15  - alternate F
            1 : a +:= ixor(c,iand(d,ixor(b,c)))           # 16..31 - alternate G	
            2 : a +:= ixor(b,ixor(c,d))                   # 32..47 - H
            3 : a +:= ixor(c,ior(b,ixor(d,16rffffffff)))  # 48..64 - alternate I
	    }                                       # Core of FF, GG, HH, II
         a +:= ks[i] + w[g[i]]                      # and the rest
         a %:= M32
         a := ior( ishift(a,rs[i]), ishift(a,-(32-rs[i]))) # 32bit rotate
         a +:= b    
         a :=: b :=: c :=: d                        # rotate variables
	 }
 
      state[1] +:= a                                # Add back new hashes 
      state[2] +:= b
      state[3] +:= c
      state[4] +:= d
      every !state %:= M32                          # mod 2^32
   }
   every (hash := "") ||:= reverse(unsigned2string(!state,4)) # little-endian digest
   return unsigned(hash)
end

procedure unsigned2string(i,w)                      # uint to string pad to w bytes
local s
   if i < 0 then runerr(500,i)
   s := ""
   while (0 < i) | (*s < \w) do {
      s ||:= char(i % 256)
      i /:= 256
      }
   return reverse(s)
end   

link unsigned                                       # string to unsigned integer


  

You may also check:How to resolve the algorithm Abundant, deficient and perfect number classifications step by step in the R programming language
You may also check:How to resolve the algorithm Globally replace text in several files step by step in the AutoHotkey programming language
You may also check:How to resolve the algorithm Look-and-say sequence step by step in the VBA programming language
You may also check:How to resolve the algorithm Miller–Rabin primality test step by step in the Lua programming language
You may also check:How to resolve the algorithm Ordered words step by step in the Frink programming language