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.

' version 19-10-2016
' MD5 from the Wikipedia page "MD5"
' compile with: fbc -s console
 
' macro for a rotate left
#Macro ROtate_Left (x, n) ' rotate left
  (x) = (x) Shl (n) + (x) Shr (32 - (n))
#EndMacro
 
Function MD5(test_str As String) As String
 
  Dim As String message = test_str   ' strings are passed as ByRef's
 
  Dim As UByte sx, s(0 To ...) = { 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 }
 
  Dim As UInteger<32> K(0 To ...) = { &Hd76aa478, &He8c7b756, &H242070db, _
  &Hc1bdceee, &Hf57c0faf, &H4787c62a, &Ha8304613, &Hfd469501, &H698098d8, _
  &H8b44f7af, &Hffff5bb1, &H895cd7be, &H6b901122, &Hfd987193, &Ha679438e, _
  &H49b40821, &Hf61e2562, &Hc040b340, &H265e5a51, &He9b6c7aa, &Hd62f105d, _
  &H02441453, &Hd8a1e681, &He7d3fbc8, &H21e1cde6, &Hc33707d6, &Hf4d50d87, _
  &H455a14ed, &Ha9e3e905, &Hfcefa3f8, &H676f02d9, &H8d2a4c8a, &Hfffa3942, _
  &H8771f681, &H6d9d6122, &Hfde5380c, &Ha4beea44, &H4bdecfa9, &Hf6bb4b60, _
  &Hbebfbc70, &H289b7ec6, &Heaa127fa, &Hd4ef3085, &H04881d05, &Hd9d4d039, _
  &He6db99e5, &H1fa27cf8, &Hc4ac5665, &Hf4292244, &H432aff97, &Hab9423a7, _
  &Hfc93a039, &H655b59c3, &H8f0ccc92, &Hffeff47d, &H85845dd1, &H6fa87e4f, _
  &Hfe2ce6e0, &Ha3014314, &H4e0811a1, &Hf7537e82, &Hbd3af235, &H2ad7d2bb, _
                                                              &Heb86d391 }
 
  ' Initialize variables
  Dim As UInteger<32> A, a0 = &H67452301
  Dim As UInteger<32> B, b0 = &Hefcdab89
  Dim As UInteger<32> C, c0 = &H98badcfe
  Dim As UInteger<32> D, d0 = &H10325476
  Dim As UInteger<32> dtemp, F, g, temp
 
  Dim As Long i, j
 
  Dim As ULongInt l = Len(message)
  ' set the first bit after the message to 1
  message = message + Chr(1 Shl 7)
  ' add one char to the length
  Dim As ULong padding = 64 - ((l +1) Mod (512 \ 8)) ' 512 \ 8 = 64 char.
 
  ' check if we have enough room for inserting the length
  If padding < 8 Then padding = padding + 64
 
  message = message + String(padding, Chr(0))   ' adjust length
  Dim As ULong l1 = Len(message)                ' new length
 
  l = l * 8    ' orignal length in bits
  ' create ubyte ptr to point to l ( = length in bits)
  Dim As UByte Ptr ub_ptr = Cast(UByte Ptr, @l)
 
  For i = 0 To 7  'copy length of message to the last 8 bytes
    message[l1 -8 + i] = ub_ptr[i]
  Next
 
  For j = 0 To (l1 -1) \ 64 ' split into block of 64 bytes
 
    A = a0 : B = b0 : C = c0 : D = d0
 
    ' break chunk into 16 32bit uinteger
    Dim As UInteger<32> Ptr M = Cast(UInteger<32> Ptr, @message[j * 64])
 
    For i = 0 To 63
      Select Case As Const i
        Case 0 To 15
          F = (B And C) Or ((Not B) And D)
          g = i
        Case 16 To 31
          F = (B And D) Or (C And (Not D))
          g = (i * 5 +1) Mod 16
        Case 32 To 47
          F = (B Xor C Xor D)
          g = (i * 3 +5) Mod 16
        Case 48 To 63
          F = C Xor (B Or (Not D))
          g = (i * 7) Mod 16
      End Select
      dtemp = D
      D = C
      C = B
      temp = A + F + K(i)+ M[g] : ROtate_left(temp, s(i))
      B = B + temp
      A = dtemp
    Next
 
    a0 += A : b0 += B : c0 += C : d0 += D
 
  Next
 
  Dim As String answer
  ' convert a0, b0, c0 and d0 in hex, then add, low order first
  Dim As String s1 = Hex(a0, 8)
  For i = 7 To 1 Step -2 : answer +=Mid(s1, i, 2) : Next
  s1 = Hex(b0, 8)
  For i = 7 To 1 Step -2 : answer +=Mid(s1, i, 2) : Next
  s1 = Hex(c0, 8)
  For i = 7 To 1 Step -2 : answer +=Mid(s1, i, 2) : Next
  s1 = Hex(d0, 8)
  For i = 7 To 1 Step -2 : answer +=Mid(s1, i, 2) : Next
 
Return LCase(answer)
 
End Function
 
 
' ------=< MAIN >=------
 
Dim As String test, hash, md5_hash
Dim As ULong i
 
For i = 1 To 7
  Read hash, test
  md5_hash = MD5(test)
 
  Print
  Print test
  Print hash
  Print md5_hash;
 
  If hash = md5_hash Then
    Print " PASS"
  Else
    Print " FAIL"
    Beep
  End If
 
Next
 
' testdata
Data "d41d8cd98f00b204e9800998ecf8427e", ""
Data "0cc175b9c0f1b6a831c399e269772661", "a"
Data "900150983cd24fb0d6963f7d28e17f72", "abc"
Data "f96b697d7cb7938d525a2f31aaf161d0", "message digest"
Data "c3fcd3d76192e4007dfb496cca67e13b", "abcdefghijklmnopqrstuvwxyz"
Data "d174ab98d277d9f5a5611c2c9f419d9f" 
Data "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
Data "57edf4a22be3c955ac49da2e2107b67a"
Data "123456789012345678901234567890123456789012345678901234567890" _
                                           + "12345678901234567890"
 
' empty keyboard buffer
While InKey <> "" : Wend
Print : Print "hit any key to end program"
Sleep
End