# Based on wikipedia article pseudocode # # s specifies the per-round shift amounts # []INT s = (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); []BITS k = (16rd76aa478, 16re8c7b756, 16r242070db, 16rc1bdceee, 16rf57c0faf, 16r4787c62a, 16ra8304613, 16rfd469501, 16r698098d8, 16r8b44f7af, 16rffff5bb1, 16r895cd7be, 16r6b901122, 16rfd987193, 16ra679438e, 16r49b40821, 16rf61e2562, 16rc040b340, 16r265e5a51, 16re9b6c7aa, 16rd62f105d, 16r02441453, 16rd8a1e681, 16re7d3fbc8, 16r21e1cde6, 16rc33707d6, 16rf4d50d87, 16r455a14ed, 16ra9e3e905, 16rfcefa3f8, 16r676f02d9, 16r8d2a4c8a, 16rfffa3942, 16r8771f681, 16r6d9d6122, 16rfde5380c, 16ra4beea44, 16r4bdecfa9, 16rf6bb4b60, 16rbebfbc70, 16r289b7ec6, 16reaa127fa, 16rd4ef3085, 16r04881d05, 16rd9d4d039, 16re6db99e5, 16r1fa27cf8, 16rc4ac5665, 16rf4292244, 16r432aff97, 16rab9423a7, 16rfc93a039, 16r655b59c3, 16r8f0ccc92, 16rffeff47d, 16r85845dd1, 16r6fa87e4f, 16rfe2ce6e0, 16ra3014314, 16r4e0811a1, 16rf7537e82, 16rbd3af235, 16r2ad7d2bb, 16reb86d391); OP + = (BITS a, b) BITS: BEGIN BITS c = BIN (ABS (a AND 16rffff) + ABS (b AND 16rffff)); BITS d = BIN (ABS (a SHR 16) + ABS (b SHR 16) + ABS (c SHR 16)); (c AND 16rffff) OR (d SHL 16) END; #[0:63]LONG INT k; FOR i FROM 0 TO 63 DO k[i] := ENTIER (ABS (sin(i+1)) * LONG INT(2)**32) OD;# PROC md5 = (STRING intext) STRING: BEGIN # Initialize variables: # BITS a0 := 16r67452301, a1 := 16refcdab89, a2 := 16r98badcfe, a3 := 16r10325476; STRING text := intext; # Pre-processing: adding a single 1 bit # text +:= REPR 128; # Pre-processing: padding with zeros append "0" bit until message length in bits ≡ 448 (mod 512) # WHILE ELEMS text MOD 64 ≠ 56 DO text +:= REPR 0 OD; # append original length in bits mod (2 pow 64) to message # text +:= dec2asc (ELEMS intext * 8); # MD5 rounds # # Process the message in successive 512-bit chunks: # WHILE text ≠ "" DO # for each 512-bit (64 byte) chunk of message # []CHAR chunk = text[1:64]; text := text[65:]; # break chunk into sixteen 32-bit words M[j], 0 <= j <= 15 # [0:15]BITS m; FOR j FROM 0 TO 15 DO m[j] := BIN (ABS chunk[j*4+1]) OR BIN (ABS chunk[j*4+2]) SHL 8 OR BIN (ABS chunk[j*4+3]) SHL 16 OR BIN (ABS chunk[j*4+4]) SHL 24 OD; INT g; BITS a, b, c, d, f, dtemp; # Initialize hash value for this chunk # a := a0; b := a1; c := a2; d := a3; FOR i FROM 0 TO 63 DO IF 0 <= i AND i <= 15 THEN f := (b AND c) OR ((NOT b) AND d); g := i ELIF 16 <= i AND i <= 31 THEN f := (d AND b) OR ((NOT d) AND c); g := (5×i + 1) MOD 16 ELIF 32 <= i AND i <= 47 THEN f := b XOR c XOR d; g := (3×i + 5) MOD 16 ELIF 48 <= i AND i <= 63 THEN f := c XOR (b OR (NOT d)); g := (7×i) MOD 16 FI; dtemp := d; d := c; c := b; b := b + leftrotate ((a + f + k[1+i] + m[g]), s[1+i]); a := dtemp OD; # Add this chunk's hash to result so far # a0 := a0 + a; a1 := a1 + b; a2 := a2 + c; a3 := a3 + d OD; revhex (a0) + revhex (a1) + revhex (a2) + revhex (a3) END; PROC leftrotate = (BITS x, INT c) BITS: (x SHL c) OR (x SHR (32-c)); # dec2asc: dec to 8 byte asc # PROC dec2asc = (INT nn)STRING: BEGIN STRING h := ""; INT n := nn; FOR i TO 8 DO h +:= REPR (n MOD 256); n ÷:= 256 OD; h END; PROC revhex = (BITS x) STRING : BEGIN # Convert to lowercase hexadecimal STRING # PROC hexdig = (BITS x) CHAR: (REPR (ABS(x) <= 9 | ABS(x) + ABS("0") | ABS(x) - 10 + ABS("a"))); hexdig (x SHR 4 AND 16rf) + hexdig (x AND 16rf) + hexdig (x SHR 12 AND 16rf) + hexdig (x SHR 8 AND 16rf) + hexdig (x SHR 20 AND 16rf) + hexdig (x SHR 16 AND 16rf) + hexdig (x SHR 28 AND 16rf) + hexdig (x SHR 24 AND 16rf) END; STRING testmsg = "The quick brown fox jumps over the lazy dog"; STRING checksum = "9e107d9d372bb6826bd81d3542a419d6"; print ((testmsg, new line)); print ((checksum, new line)); STRING test = md5 (testmsg); IF test = checksum THEN print (("passed", new line)); print ((test, new line)) ELSE print (("failed")) FI