Message Digest (MD5)

Message Digest (MD5) is an algorithm that maps an ASCII character vector of indeterminate length onto a 16-digit hex hash that is hypersensitive to small changes in the message. MD5 is widely used for checking passwords without storing information from which the password could be derived.

An original function ∆md5 by Conrad Hoesle-Kienzlen and BrianOliver has been here rewritten as class MD5, with two methods. Both functions are written for Dyalog APL.

An alternative approach is to use the .NET System.Security.Cryptography framework, as illustrated by this APLX example

(Note that APLX was discontinued in 2016)

Methods

hash ← MD5.Hash msg   ⍝ message digest

ok ← MD5.SelfTest     ⍝ Boolean: results match the test answers

Notes

  1. Although their listings appear very different, MD5 was derived from ∆md5 by a series of substitutions, each followed by SelfTest. Substitutions removed repeating patterns in the code and symbol reassignments, with the notable exception of ABCD.

  2. The encoding functions F G H I correspond closely to the CMN versions on Wikipedia.

  3. The apply operator was the result of refactoring the ∆F ∆G ∆H ∆I functions in the original

  4. The round operator was the result of refactoring the four 'rounds' of ∆md5

  5. ⎕NXLATE is now deprecated and should be replaced by use of ⎕UCS in Dyalog 12

  1. Wikipedia article on MD5 Message Digest

  2. Wikia MD5 code examples

Listing

:Class MD5 ⍝ create a message digest with the MD5-algorithm (RFC1321)

    ⍝ static class: no instances
    ⍝ see also http://en.wikipedia.org/wiki/Md5

    ⍝ Written 07.07.1999 Conrad Hoesle-Kienzlen <chk@hoesle-kienzlen.de>
    ⍝ Revised 17.03.2002 Brian W. Oliver <bwo@aplborealis.com>
    ⍝ Revised 09.04.2008 Stephen Taylor <sjt@dyalog.com>

⍝----------------------------------- public methods
    ∇ r←Hash msg;chunk;bits;rawbits;ABCD;chunks;start
     ⍝ msg: message of arbitrary length
     ⍝ r:   digest, always 16 hex digits (32 characters)
      :Access Public Shared

      ⎕SIGNAL 11/⍨0∊msg∊ASCII                                   ⍝ reject non-ASCII characters

      rawbits←,⍉(8/2)⊤¯1+ASCII⍳msg                              ⍝ convert message to binary
      bits←512{⍵↑⍨⍺×⊃0 ⍺⊤⊃⍴⍵}rawbits,512↑1                      ⍝ pad to multiple of 512 bits
      (¯64↑bits)←,⊖8 8⍴,(64⍴2)⊤⍴rawbits                         ⍝ write length at end

      ABCD←INITIALSTATES
                                                                ⍝ convert to decimal word length,
      chunks←16 cols 2⊥⍉(32 cols bits)[;,24 16 8 0∘.+⍳8]        ⍝ reverse byte-order, encode to decimal

      :For chunk :In ↓chunks

          start←ABCD                                            ⍝ initial state for this chunk

          ABCD←ABCD(chunk round F)Fshifts                       ⍝ round F
          ABCD←ABCD(chunk round G)Gshifts                       ⍝ round G
          ABCD←ABCD(chunk round H)Hshifts                       ⍝ round H
          ABCD←ABCD(chunk round I)Ishifts                       ⍝ round I

          ABCD{MAX|⍺+⍵}←start                                   ⍝ add to initial cycle state

      :EndFor

      r←⊃,/hex¨ABCD

    ∇ ok←SelfTest
      :Access Public Shared
      :If ok←'0cc175b9c0f1b6a831c399e269772661'≡Hash'a'
      :AndIf ok←'d41d8cd98f00b204e9800998ecf8427e'≡Hash''
      :AndIf ok←'7215ee9c7d9dc229d2921a40e899ec5f'≡Hash' '
      :AndIf ok'f96b697d7cb7938d525a2f31aaf161d0'≡Hash'message digest'
          ok←'9e107d9d372bb6826bd81d3542a419d6'≡Hash'The quick brown fox jumps over the lazy dog'
      :EndIf

⍝----------------------------------- vocabulary
    ⎕IO ⎕ML←1 0
    MAX←4294967296                                              ⍝ maximum integer
    ASCII←⎕AV[⍋1+⎕NXLATE 0]                                     ⍝ ASCII character string
    cols←{⍵⍴⍨((⍴⍵)÷⍺),⍺}                                        ⍝ reshape in ⍺ cols
    bin←(32/2)∘⊤                                                ⍝ convert to 32-bit binary
    hex←{'0123456789abcdef'[1+,⌽4 2⍴⌽(8/16)⊤⍵]}                 ⍝ convert to hex
    CONVERSIONTABLE←⌊MAX×|1○⍳64

    INITIALSTATES←1732584193 4023233417 2562383102 271733878    ⍝ initial variable states
⍝  '67452301'h 'efcdab89'h '98badcfe'h '10325476'h (low byte order)

    F←{X Y Z←⍵ ⋄ (X∧Y)∨(~X)∧Z}                                  ⍝ encoding function
    G←{X Y Z←⍵ ⋄ (X∧Z)∨Y∧~Z}                                    ⍝ encoding function
    H←{X Y Z←⍵ ⋄ X≠Y≠Z}                                         ⍝ encoding function
    I←{X Y Z←⍵ ⋄ Y≠X∨~Z}                                        ⍝ encoding function
   ⍝ cf http://en.wikipedia.org/wiki/Md5#Algorithm

      apply←{                                                   ⍝ apply encoding function ⍺⍺
          A B C D k s i←⍵                                       ⍝ with arguments ⍵
          B+2⊥s⌽bin ⍺[k]+CONVERSIONTABLE[i]+A+2⊥⍺⍺ bin¨B C D    ⍝ to message chunk ⍺
      }

    ∇ ABCD←ABCD(chunk round fn)shifts;tgt;rot;shft              ⍝ perform a round on chunk
      :For tgt rot shft :InEach (16⍴1 4 3 2)(1-⍳16)(shifts)     ⍝ using fn and shifts,
          ABCD[tgt]←chunk(fn apply)(rot⌽ABCD),shft              ⍝ modifying ABCD
      :EndFor

    Fshifts←(1 7 1)(2 12 2)(3 17 3)(4 22 4)                     ⍝ shifts for round F
    Fshifts,←(5 7 5)(6 12 6)(7 17 7)(8 22 8)
    Fshifts,←(9 7 9)(10 12 10)(11 17 11)(12 22 12)
    Fshifts,←(13 7 13)(14 12 14)(15 17 15)(16 22 16)

    Gshifts←(2 5 17)(7 9 18)(12 14 19)(1 20 20)                 ⍝ shifts for round G
    Gshifts,←(6 5 21)(11 9 22)(16 14 23)(5 20 24)
    Gshifts,←(10 5 25)(15 9 26)(4 14 27)(9 20 28)
    Gshifts,←(14 5 29)(3 9 30)(8 14 31)(13 20 32)

    Hshifts←(6 4 33)(9 11 34)(12 16 35)(15 23 36)               ⍝ shifts for round H
    Hshifts,←(2 4 37)(5 11 38)(8 16 39)(11 23 40)
    Hshifts,←(14 4 41)(1 11 42)(4 16 43)(7 23 44)
    Hshifts,←(10 4 45)(13 11 46)(16 16 47)(3 23 48)

    Ishifts←(1 6 49)(8 10 50)(15 15 51)(6 21 52)                ⍝ shifts for round I
    Ishifts,←(13 6 53)(4 10 54)(11 15 55)(2 21 56)
    Ishifts,←(9 6 57)(16 10 58)(7 15 59)(14 21 60)
    Ishifts,←(5 6 61)(12 10 62)(3 15 63)(10 21 64)

:EndClass

StephenTaylor

MessageDigestHash (last edited 2017-02-16 19:42:06 by KaiJaeger)