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 implementation needs to implement the key functionality namely producing a correct message digest for an input string. It is not necessary to mimic all of the calling modes such as adding to a digest one block at a time over subsequent calls. 
 In addition to coding and verifying your implementation, note any challenges your language presented implementing the solution, implementation choices made, or limitations of your solution. 
 Solutions on this page should implement MD5 directly and NOT use built in (MD5) functions, call outs to operating system calls or library routines written in other languages as is common in the original MD5 task.
 The following are acceptable:
 An original implementation from the specification, reference implementation, or pseudo-code
 A translation of a correct implementation from another language
 A library routine in the same language; however, the source must be included here.


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.

RFC 1321
                            hash code <== string 
   0xd41d8cd98f00b204e9800998ecf8427e <== ""  
   0x0cc175b9c0f1b6a831c399e269772661 <== "a"
   0x900150983cd24fb0d6963f7d28e17f72 <== "abc"
   0xf96b697d7cb7938d525a2f31aaf161d0 <== "message digest"
   0xc3fcd3d76192e4007dfb496cca67e13b <== "abcdefghijklmnopqrstuvwxyz"
   0xd174ab98d277d9f5a5611c2c9f419d9f <== "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
   0x57edf4a22be3c955ac49da2e2107b67a <== "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
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.



 Warning
Rosetta Code is not a place you should rely on for examples of code in critical roles, including security.
Also, note that MD5 has been broken and should not be used in applications requiring security. For these consider SHA2 or the upcoming SHA3.

$ include "seed7_05.s7i";
  include "bytedata.s7i";
  include "bin32.s7i";
  include "float.s7i";
  include "math.s7i";
 
# Use binary integer part of the sines of integers (Radians) as constants:
const func array integer: createMd5Table is func
  result
    var array integer: k is 64 times 0;
  local
    var integer: index is 0;
  begin
    for index range 1 to 64 do
      k[index] := trunc(abs(sin(flt(index))) * 2.0 ** 32);
    end for;
  end func;
 
const func string: md5 (in var string: message) is func
  result
    var string: digest is "";
  local
    # Specify the per-round shift amounts
    const array integer: shiftAmount is [] (
        7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22,
        5,  9, 14, 20,  5,  9, 14, 20,  5,  9, 14, 20,  5,  9, 14, 20,
        4, 11, 16, 23,  4, 11, 16, 23,  4, 11, 16, 23,  4, 11, 16, 23,
        6, 10, 15, 21,  6, 10, 15, 21,  6, 10, 15, 21,  6, 10, 15, 21);
    const array integer: k is createMd5Table;
    var integer: length is 0;
    var integer: chunkIndex is 0;
    var integer: index is 0;
    var array bin32: m is 16 times bin32.value;
    var integer: a0 is 16#67452301;   # a
    var integer: b0 is 16#efcdab89;   # b
    var integer: c0 is 16#98badcfe;   # c
    var integer: d0 is 16#10325476;   # d
    var bin32: a is bin32(0);
    var bin32: b is bin32(0);
    var bin32: c is bin32(0);
    var bin32: d is bin32(0);
    var bin32: f is bin32(0);
    var integer: g is 0;
    var bin32: temp is bin32(0);
  begin
    length := length(message);
    # Append the bit '1' to the message.
    message &:= '\16#80;';
    # Append '0' bits, so that the resulting bit length is congruent to 448 (mod 512).
    message &:= "\0;" mult 63 - (length + 8) mod 64;
    # Append length of message (before pre-processing), in bits, as 64-bit little-endian integer.
    message &:= int64AsEightBytesLe(8 * length);
 
    # Process the message in successive 512-bit chunks:
    for chunkIndex range 1 to length(message) step 64 do
      # Break chunk into sixteen 32-bit little-endian words.
      for index range 1 to 16 do
        m[index] := bin32(bytes2Int(message[chunkIndex + 4 * pred(index) len 4], UNSIGNED, LE));
      end for;
 
      a := bin32(a0 mod 16#100000000);
      b := bin32(b0 mod 16#100000000);
      c := bin32(c0 mod 16#100000000);
      d := bin32(d0 mod 16#100000000);
 
      for index range 1 to 64 do
        if index <= 16 then
          f := d >< (b & (c >< d));
          g := index;
        elsif index <= 32 then
          f := c >< (d & (b >< c));
          g := (5 * index - 4) mod 16 + 1;
        elsif index <= 48 then
          f := b >< c >< d;
          g := (3 * index + 2) mod 16 + 1;
        else
          f := c >< (b | (bin32(16#ffffffff) >< d));
          g := (7 * pred(index)) mod 16 + 1;
        end if;
 
        temp := d;
        d := c;
        c := b;
        b := bin32((ord(b) +
             ord(rotLeft(bin32((ord(a) + ord(f) + k[index] + ord(m[g])) mod 16#100000000),
                         shiftAmount[index]))) mod 16#100000000);
        a := temp;
      end for;
 
      # Add this chunk's hash to result so far:
      a0 +:= ord(a);
      b0 +:= ord(b);
      c0 +:= ord(c);
      d0 +:= ord(d);
    end for;
 
    # Produce the final hash value:
    digest := int32AsFourBytesLe(a0) &
              int32AsFourBytesLe(b0) &
              int32AsFourBytesLe(c0) &
              int32AsFourBytesLe(d0);
  end func;
 
const func boolean: checkMd5 (in string: message, in string: hexMd5) is
  return hex(md5(message)) = hexMd5;
 
const proc: main is func
  begin
    if  checkMd5("", "d41d8cd98f00b204e9800998ecf8427e") and
        checkMd5("a", "0cc175b9c0f1b6a831c399e269772661") and
        checkMd5("abc", "900150983cd24fb0d6963f7d28e17f72") and
        checkMd5("message digest", "f96b697d7cb7938d525a2f31aaf161d0") and
        checkMd5("abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b") and
        checkMd5("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "d174ab98d277d9f5a5611c2c9f419d9f") and
        checkMd5("12345678901234567890123456789012345678901234567890123456789012345678901234567890", "57edf4a22be3c955ac49da2e2107b67a") then
      writeln("md5 is computed correct");
    else
      writeln("There is an error in the md5 function");
    end if;
  end func;