MD5/Implementation: Difference between revisions
Content deleted Content added
Added PicoLisp |
Move Modula-3 MD5 implementation here |
||
Line 386: | Line 386: | ||
57edf4a22be3c955ac49da2e2107b67a |
57edf4a22be3c955ac49da2e2107b67a |
||
</lang> |
</lang> |
||
=={{header|Modula-3}}== |
|||
<lang modula3>INTERFACE MD5; |
|||
IMPORT Word; |
|||
TYPE Digest = ARRAY [0..15] OF CHAR; |
|||
TYPE Buffer = ARRAY [0..63] OF CHAR; |
|||
TYPE T = RECORD |
|||
state: ARRAY [0..3] OF Word.T; |
|||
count: ARRAY [0..1] OF Word.T; |
|||
buffer: Buffer; |
|||
END; |
|||
PROCEDURE Init(VAR md5ctx: T); |
|||
PROCEDURE Update(VAR md5ctx: T; input: TEXT); |
|||
PROCEDURE Final(VAR md5ctx: T): Digest; |
|||
PROCEDURE ToText(hash: Digest): TEXT; |
|||
END MD5.</lang> |
|||
<lang modula3>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.</lang> |
|||
Example usage: |
|||
<lang modula3>MODULE Main; |
|||
IMPORT MD5, IO; |
|||
VAR md5ctx: MD5.T; |
|||
BEGIN |
|||
MD5.Init(md5ctx); |
|||
MD5.Update(md5ctx, "The quick brown fox jumped over the lazy dog's back"); |
|||
IO.Put(MD5.ToText(MD5.Final(md5ctx)) & "\n"); |
|||
END Main.</lang> |
|||
Output: |
|||
<pre> |
|||
e38ca1d920c4b8b8d3946b2c72f01680 |
|||
</pre> |
|||
=={{header|PicoLisp}}== |
=={{header|PicoLisp}}== |