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
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.
The encoding functions F G H I correspond closely to the CMN versions on Wikipedia.
The apply operator was the result of refactoring the ∆F ∆G ∆H ∆I functions in the original
The round operator was the result of refactoring the four 'rounds' of ∆md5
⎕NXLATE is now deprecated and should be replaced by use of ⎕UCS in Dyalog 12
External links
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