245 lines
8.3 KiB
Plaintext
245 lines
8.3 KiB
Plaintext
MODULE MD5;
|
|
|
|
IMPORT Word, Text, Fmt;
|
|
|
|
CONST S11 = 7; S12 = 12; S13 = 17; S14 = 22;
|
|
S21 = 5; S22 = 9; S23 = 14; S24 = 20;
|
|
S31 = 4; S32 = 11; S33 = 16; S34 = 23;
|
|
S41 = 6; S42 = 10; S43 = 15; S44 = 21;
|
|
pad1 = "\200\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000";
|
|
pad2 = "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000";
|
|
pad3 = "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000";
|
|
pad4 = "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000";
|
|
padding = pad1 & pad2 & pad3 & pad4;
|
|
|
|
PROCEDURE Init(VAR md5ctx: T) =
|
|
BEGIN
|
|
<*ASSERT Word.Size = 32*>
|
|
md5ctx.count[0] := 0;
|
|
md5ctx.count[1] := 0;
|
|
|
|
md5ctx.state[0] := 16_67452301;
|
|
md5ctx.state[1] := 16_efcdab89;
|
|
md5ctx.state[2] := 16_98badcfe;
|
|
md5ctx.state[3] := 16_10325476;
|
|
END Init;
|
|
|
|
PROCEDURE Transform(VAR state: ARRAY [0..3] OF Word.T;
|
|
VAR input: Buffer) =
|
|
VAR a, b, c, d: INTEGER;
|
|
x: ARRAY [0..15] OF INTEGER;
|
|
|
|
PROCEDURE Decode(VAR x: ARRAY [0..15] OF INTEGER;
|
|
VAR input: Buffer) =
|
|
BEGIN
|
|
FOR i := 0 TO 15 DO
|
|
x[i] := Word.Insert(x[i], ORD(input[4*i+0]), 0, 8);
|
|
x[i] := Word.Insert(x[i], ORD(input[4*i+1]), 8, 8);
|
|
x[i] := Word.Insert(x[i], ORD(input[4*i+2]), 16, 8);
|
|
x[i] := Word.Insert(x[i], ORD(input[4*i+3]), 24, 8);
|
|
END;
|
|
END Decode;
|
|
|
|
PROCEDURE FF(VAR a: INTEGER; b, c, d, x, s, ac: INTEGER) =
|
|
PROCEDURE F(x, y, z: INTEGER): INTEGER =
|
|
BEGIN
|
|
RETURN Word.Or(Word.And(x, y), Word.And(Word.Not(x), z));
|
|
END F;
|
|
BEGIN
|
|
a := b + Word.Rotate(a + F(b, c, d) + x + ac, s);
|
|
END FF;
|
|
|
|
PROCEDURE GG(VAR a: INTEGER; b, c, d, x, s, ac: INTEGER) =
|
|
PROCEDURE G(x, y, z: INTEGER): INTEGER =
|
|
BEGIN
|
|
RETURN Word.Or(Word.And(x, z), Word.And(y, Word.Not(z)));
|
|
END G;
|
|
BEGIN
|
|
a := b + Word.Rotate(a + G(b, c, d) + x + ac, s);
|
|
END GG;
|
|
|
|
PROCEDURE HH(VAR a: INTEGER; b, c, d, x, s, ac: INTEGER) =
|
|
PROCEDURE H(x, y, z: INTEGER): INTEGER =
|
|
BEGIN
|
|
RETURN Word.Xor(x, Word.Xor(y,z));
|
|
END H;
|
|
BEGIN
|
|
a := b + Word.Rotate(a + H(b, c, d) + x + ac, s);
|
|
END HH;
|
|
|
|
PROCEDURE II(VAR a: INTEGER; b, c, d, x, s, ac: INTEGER) =
|
|
PROCEDURE I(x, y, z: INTEGER): INTEGER =
|
|
BEGIN
|
|
RETURN Word.Xor(y, Word.Or(x, Word.Not(z)))
|
|
END I;
|
|
BEGIN
|
|
a := b + Word.Rotate(a + I(b, c, d) + x + ac, s)
|
|
END II;
|
|
|
|
BEGIN
|
|
Decode(x, input);
|
|
|
|
a := state[0];
|
|
b := state[1];
|
|
c := state[2];
|
|
d := state[3];
|
|
|
|
(* Round 1 *)
|
|
FF(a, b, c, d, x[ 0], S11, 16_d76aa478); (* 1 *)
|
|
FF(d, a, b, c, x[ 1], S12, 16_e8c7b756); (* 2 *)
|
|
FF(c, d, a, b, x[ 2], S13, 16_242070db); (* 3 *)
|
|
FF(b, c, d, a, x[ 3], S14, 16_c1bdceee); (* 4 *)
|
|
FF(a, b, c, d, x[ 4], S11, 16_f57c0faf); (* 5 *)
|
|
FF(d, a, b, c, x[ 5], S12, 16_4787c62a); (* 6 *)
|
|
FF(c, d, a, b, x[ 6], S13, 16_a8304613); (* 7 *)
|
|
FF(b, c, d, a, x[ 7], S14, 16_fd469501); (* 8 *)
|
|
FF(a, b, c, d, x[ 8], S11, 16_698098d8); (* 9 *)
|
|
FF(d, a, b, c, x[ 9], S12, 16_8b44f7af); (* 10 *)
|
|
FF(c, d, a, b, x[10], S13, 16_ffff5bb1); (* 11 *)
|
|
FF(b, c, d, a, x[11], S14, 16_895cd7be); (* 12 *)
|
|
FF(a, b, c, d, x[12], S11, 16_6b901122); (* 13 *)
|
|
FF(d, a, b, c, x[13], S12, 16_fd987193); (* 14 *)
|
|
FF(c, d, a, b, x[14], S13, 16_a679438e); (* 15 *)
|
|
FF(b, c, d, a, x[15], S14, 16_49b40821); (* 16 *)
|
|
|
|
(* Round 2 *)
|
|
GG(a, b, c, d, x[ 1], S21, 16_f61e2562); (* 17 *)
|
|
GG(d, a, b, c, x[ 6], S22, 16_c040b340); (* 18 *)
|
|
GG(c, d, a, b, x[11], S23, 16_265e5a51); (* 19 *)
|
|
GG(b, c, d, a, x[ 0], S24, 16_e9b6c7aa); (* 20 *)
|
|
GG(a, b, c, d, x[ 5], S21, 16_d62f105d); (* 21 *)
|
|
GG(d, a, b, c, x[10], S22, 16_02441453); (* 22 *)
|
|
GG(c, d, a, b, x[15], S23, 16_d8a1e681); (* 23 *)
|
|
GG(b, c, d, a, x[ 4], S24, 16_e7d3fbc8); (* 24 *)
|
|
GG(a, b, c, d, x[ 9], S21, 16_21e1cde6); (* 25 *)
|
|
GG(d, a, b, c, x[14], S22, 16_c33707d6); (* 26 *)
|
|
GG(c, d, a, b, x[ 3], S23, 16_f4d50d87); (* 27 *)
|
|
GG(b, c, d, a, x[ 8], S24, 16_455a14ed); (* 28 *)
|
|
GG(a, b, c, d, x[13], S21, 16_a9e3e905); (* 29 *)
|
|
GG(d, a, b, c, x[ 2], S22, 16_fcefa3f8); (* 30 *)
|
|
GG(c, d, a, b, x[ 7], S23, 16_676f02d9); (* 31 *)
|
|
GG(b, c, d, a, x[12], S24, 16_8d2a4c8a); (* 32 *)
|
|
|
|
(* Round 3 *)
|
|
HH(a, b, c, d, x[ 5], S31, 16_fffa3942); (* 33 *)
|
|
HH(d, a, b, c, x[ 8], S32, 16_8771f681); (* 34 *)
|
|
HH(c, d, a, b, x[11], S33, 16_6d9d6122); (* 35 *)
|
|
HH(b, c, d, a, x[14], S34, 16_fde5380c); (* 36 *)
|
|
HH(a, b, c, d, x[ 1], S31, 16_a4beea44); (* 37 *)
|
|
HH(d, a, b, c, x[ 4], S32, 16_4bdecfa9); (* 38 *)
|
|
HH(c, d, a, b, x[ 7], S33, 16_f6bb4b60); (* 39 *)
|
|
HH(b, c, d, a, x[10], S34, 16_bebfbc70); (* 40 *)
|
|
HH(a, b, c, d, x[13], S31, 16_289b7ec6); (* 41 *)
|
|
HH(d, a, b, c, x[ 0], S32, 16_eaa127fa); (* 42 *)
|
|
HH(c, d, a, b, x[ 3], S33, 16_d4ef3085); (* 43 *)
|
|
HH(b, c, d, a, x[ 6], S34, 16_04881d05); (* 44 *)
|
|
HH(a, b, c, d, x[ 9], S31, 16_d9d4d039); (* 45 *)
|
|
HH(d, a, b, c, x[12], S32, 16_e6db99e5); (* 46 *)
|
|
HH(c, d, a, b, x[15], S33, 16_1fa27cf8); (* 47 *)
|
|
HH(b, c, d, a, x[ 2], S34, 16_c4ac5665); (* 48 *)
|
|
|
|
(* Round 4 *)
|
|
II(a, b, c, d, x[ 0], S41, 16_f4292244); (* 49 *)
|
|
II(d, a, b, c, x[ 7], S42, 16_432aff97); (* 50 *)
|
|
II(c, d, a, b, x[14], S43, 16_ab9423a7); (* 51 *)
|
|
II(b, c, d, a, x[ 5], S44, 16_fc93a039); (* 52 *)
|
|
II(a, b, c, d, x[12], S41, 16_655b59c3); (* 53 *)
|
|
II(d, a, b, c, x[ 3], S42, 16_8f0ccc92); (* 54 *)
|
|
II(c, d, a, b, x[10], S43, 16_ffeff47d); (* 55 *)
|
|
II(b, c, d, a, x[ 1], S44, 16_85845dd1); (* 56 *)
|
|
II(a, b, c, d, x[ 8], S41, 16_6fa87e4f); (* 57 *)
|
|
II(d, a, b, c, x[15], S42, 16_fe2ce6e0); (* 58 *)
|
|
II(c, d, a, b, x[ 6], S43, 16_a3014314); (* 59 *)
|
|
II(b, c, d, a, x[13], S44, 16_4e0811a1); (* 60 *)
|
|
II(a, b, c, d, x[ 4], S41, 16_f7537e82); (* 61 *)
|
|
II(d, a, b, c, x[11], S42, 16_bd3af235); (* 62 *)
|
|
II(c, d, a, b, x[ 2], S43, 16_2ad7d2bb); (* 63 *)
|
|
II(b, c, d, a, x[ 9], S44, 16_eb86d391); (* 64 *)
|
|
|
|
state[0] := Word.Plus(state[0], a);
|
|
state[1] := Word.Plus(state[1], b);
|
|
state[2] := Word.Plus(state[2], c);
|
|
state[3] := Word.Plus(state[3], d);
|
|
END Transform;
|
|
|
|
PROCEDURE Update(VAR md5ctx: T; input: TEXT) =
|
|
VAR index, i, j, partLen: Word.T;
|
|
locbuff: Buffer;
|
|
|
|
BEGIN
|
|
index := Word.And(Word.Shift(md5ctx.count[0], -3), 16_3F);
|
|
md5ctx.count[0] :=
|
|
Word.Plus(md5ctx.count[0], Word.Shift(Text.Length(input), 3));
|
|
|
|
IF md5ctx.count[0] < Text.Length(input) THEN
|
|
INC(md5ctx.count[1]);
|
|
END;
|
|
md5ctx.count[1] := md5ctx.count[1] + Word.Shift(Text.Length(input), -29);
|
|
partLen := 64 - index;
|
|
IF Text.Length(input) >= partLen THEN
|
|
FOR i := index TO 63 DO
|
|
md5ctx.buffer[i] := Text.GetChar(input, i-index);
|
|
END;
|
|
Transform(md5ctx.state, md5ctx.buffer);
|
|
i := partLen;
|
|
WHILE (i + 63) < Text.Length(input) DO
|
|
FOR j := 0 TO 63 DO
|
|
locbuff[j] := Text.GetChar(input, i+j);
|
|
END;
|
|
Transform(md5ctx.state, locbuff);
|
|
INC(i, 64);
|
|
END;
|
|
index := 0;
|
|
ELSE
|
|
i := 0;
|
|
END;
|
|
|
|
j := 0;
|
|
WHILE i+j < Text.Length(input) DO
|
|
md5ctx.buffer[j+index] := Text.GetChar(input, i+j);
|
|
INC(j);
|
|
END;
|
|
END Update;
|
|
|
|
PROCEDURE Final(VAR md5ctx: T): Digest=
|
|
VAR bits: ARRAY [0..7] OF CHAR;
|
|
index, padLen: INTEGER;
|
|
digest: Digest;
|
|
|
|
PROCEDURE Encode(VAR output: ARRAY OF CHAR;
|
|
VAR input: ARRAY OF Word.T;
|
|
count: INTEGER) =
|
|
BEGIN
|
|
FOR i := 0 TO count DO
|
|
output[i*4+0] := VAL(Word.Extract(input[i], 0, 8), CHAR);
|
|
output[i*4+1] := VAL(Word.Extract(input[i], 8, 8), CHAR);
|
|
output[i*4+2] := VAL(Word.Extract(input[i], 16, 8), CHAR);
|
|
output[i*4+3] := VAL(Word.Extract(input[i], 24, 8), CHAR)
|
|
END;
|
|
END Encode;
|
|
BEGIN
|
|
Encode(bits, md5ctx.count, 1);
|
|
index := Word.And(Word.Shift(md5ctx.count[0], -3), 16_3F);
|
|
IF index < 56 THEN
|
|
padLen := 56 - index;
|
|
ELSE
|
|
padLen := 120 - index;
|
|
END;
|
|
Update(md5ctx, Text.Sub(padding, 0, padLen));
|
|
Update(md5ctx, Text.FromChars(bits));
|
|
Encode(digest, md5ctx.state, 3);
|
|
RETURN digest;
|
|
END Final;
|
|
|
|
PROCEDURE ToText(hash: Digest): TEXT =
|
|
VAR buf: TEXT := "";
|
|
BEGIN
|
|
FOR i := 0 TO 15 DO
|
|
buf := buf & Fmt.Pad(Fmt.Int(ORD(hash[i]), 16), 2, '0');
|
|
END;
|
|
RETURN buf;
|
|
END ToText;
|
|
|
|
BEGIN
|
|
END MD5.
|