How to resolve the algorithm MD5/Implementation step by step in the Icon and Unicon programming language
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