1(* ETH Oberon, Copyright 2001 ETH Zuerich Institut fuer Computersysteme, ETH Zentrum, CH-8092 Zuerich. 2Refer to the "General ETH Oberon System Source License" contract available at: http://www.oberon.ethz.ch/ *) 3 4MODULE ethMD5; (** portable *) (* ejz *) 5 IMPORT SYSTEM; 6 7(* todo. Use fixed size integers and sets. *) 8 9(** The MD5 Message-Digest Algorithm (RFC1321) 10 11The algorithm takes as input a message of arbitrary length and produces 12as output a 128-bit "fingerprint" or "message digest" of the input. It is 13conjectured that it is computationally infeasible to produce two messages 14having the same message digest, or to produce any message having a 15given prespecified target message digest. The MD5 algorithm is intended 16for digital signature applications, where a large file must be "compressed" 17in a secure manner before being encrypted with a private (secret) key 18under a public-key cryptosystem such as RSA. *) 19 20 TYPE 21 Context* = POINTER TO ContextDesc; 22 ContextDesc = RECORD 23 buf: ARRAY 4 OF LONGINT; 24 bits: LONGINT; 25 in: ARRAY 64 OF CHAR 26 END; 27 Digest* = ARRAY 16 OF CHAR; 28 29(** Begin an MD5 operation, with a new context. *) 30 PROCEDURE New*(): Context; 31 VAR cont: Context; 32 BEGIN 33 NEW(cont); 34 cont.buf[0] := 00000000067452301H; 35 cont.buf[1] := 0FFFFFFFFEFCDAB89H; 36 cont.buf[2] := 0FFFFFFFF98BADCFEH; 37 cont.buf[3] := 00000000010325476H; 38 cont.bits := 0; 39 RETURN cont 40 END New; 41 42 PROCEDURE ByteReverse(VAR in: ARRAY OF SYSTEM.BYTE; VAR out: ARRAY OF LONGINT; longs: LONGINT); 43 VAR 44 adr: SYSTEM.ADDRESS; 45 t, i: LONGINT; 46 bytes: ARRAY 4 OF CHAR; 47 BEGIN 48 adr := SYSTEM.ADR(in[0]); i := 0; 49 WHILE i < longs DO 50 SYSTEM.MOVE(adr, SYSTEM.ADR(bytes[0]), 4); 51 t := ORD(bytes[3]); 52 t := 256*t + ORD(bytes[2]); 53 t := 256*t + ORD(bytes[1]); 54 t := 256*t + ORD(bytes[0]); 55 out[i] := t; 56 INC(adr, 4); INC(i) 57 END 58 END ByteReverse; 59 60 PROCEDURE F1(x, y, z: LONGINT): LONGINT; 61 BEGIN 62 RETURN SYSTEM.VAL(LONGINT, (SYSTEM.VAL(SET, x)*SYSTEM.VAL(SET, y)) + ((-SYSTEM.VAL(SET, x))*SYSTEM.VAL(SET, z))) 63 END F1; 64 65 PROCEDURE F2(x, y, z: LONGINT): LONGINT; 66 BEGIN 67 RETURN SYSTEM.VAL(LONGINT, (SYSTEM.VAL(SET, x)*SYSTEM.VAL(SET, z)) + (SYSTEM.VAL(SET, y)*(-SYSTEM.VAL(SET, z)))) 68 END F2; 69 70 PROCEDURE F3(x, y, z: LONGINT): LONGINT; 71 BEGIN 72 RETURN SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, x) / SYSTEM.VAL(SET, y) / SYSTEM.VAL(SET, z)) 73 END F3; 74 75 PROCEDURE F4(x, y, z: LONGINT): LONGINT; 76 BEGIN 77 RETURN SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, y) / (SYSTEM.VAL(SET, x)+(-SYSTEM.VAL(SET, z)))) 78 END F4; 79 80 PROCEDURE STEP1(VAR w: LONGINT; x, y, z, data, s: LONGINT); 81 BEGIN 82 w := w+F1(x, y, z)+data; 83 w := SYSTEM.ROT(w, s); 84 INC(w, x) 85 END STEP1; 86 87 PROCEDURE STEP2(VAR w: LONGINT; x, y, z, data, s: LONGINT); 88 BEGIN 89 w := w+F2(x, y, z)+data; 90 w := SYSTEM.ROT(w, s); 91 INC(w, x) 92 END STEP2; 93 94 PROCEDURE STEP3(VAR w: LONGINT; x, y, z, data, s: LONGINT); 95 BEGIN 96 w := w+F3(x, y, z)+data; 97 w := SYSTEM.ROT(w, s); 98 INC(w, x) 99 END STEP3; 100 101 PROCEDURE STEP4(VAR w: LONGINT; x, y, z, data, s: LONGINT); 102 BEGIN 103 w := w+F4(x, y, z)+data; 104 w := SYSTEM.ROT(w, s); 105 INC(w, x) 106 END STEP4; 107 108 PROCEDURE Transform(VAR buf, in: ARRAY OF LONGINT); 109 VAR a, b, c, d: LONGINT; 110 BEGIN 111 a := buf[0]; b := buf[1]; c := buf[2]; d := buf[3]; 112 113 STEP1(a, b, c, d, in[0] + 0FFFFFFFFD76AA478H, 7); 114 STEP1(d, a, b, c, in[1] + 0FFFFFFFFE8C7B756H, 12); 115 STEP1(c, d, a, b, in[2] + 000000000242070DBH, 17); 116 STEP1(b, c, d, a, in[3] + 0FFFFFFFFC1BDCEEEH, 22); 117 STEP1(a, b, c, d, in[4] + 0FFFFFFFFF57C0FAFH, 7); 118 STEP1(d, a, b, c, in[5] + 0000000004787C62AH, 12); 119 STEP1(c, d, a, b, in[6] + 0FFFFFFFFA8304613H, 17); 120 STEP1(b, c, d, a, in[7] + 0FFFFFFFFFD469501H, 22); 121 STEP1(a, b, c, d, in[8] + 000000000698098D8H, 7); 122 STEP1(d, a, b, c, in[9] + 0FFFFFFFF8B44F7AFH, 12); 123 STEP1(c, d, a, b, in[10] + 0FFFFFFFFFFFF5BB1H, 17); 124 STEP1(b, c, d, a, in[11] + 0FFFFFFFF895CD7BEH, 22); 125 STEP1(a, b, c, d, in[12] + 0000000006B901122H, 7); 126 STEP1(d, a, b, c, in[13] + 0FFFFFFFFFD987193H, 12); 127 STEP1(c, d, a, b, in[14] + 0FFFFFFFFA679438EH, 17); 128 STEP1(b, c, d, a, in[15] + 00000000049B40821H, 22); 129 130 STEP2(a, b, c, d, in[1] + 0FFFFFFFFF61E2562H, 5); 131 STEP2(d, a, b, c, in[6] + 0FFFFFFFFC040B340H, 9); 132 STEP2(c, d, a, b, in[11] + 000000000265E5A51H, 14); 133 STEP2(b, c, d, a, in[0] + 0FFFFFFFFE9B6C7AAH, 20); 134 STEP2(a, b, c, d, in[5] + 0FFFFFFFFD62F105DH, 5); 135 STEP2(d, a, b, c, in[10] + 00000000002441453H, 9); 136 STEP2(c, d, a, b, in[15] + 0FFFFFFFFD8A1E681H, 14); 137 STEP2(b, c, d, a, in[4] + 0FFFFFFFFE7D3FBC8H, 20); 138 STEP2(a, b, c, d, in[9] + 00000000021E1CDE6H, 5); 139 STEP2(d, a, b, c, in[14] + 0FFFFFFFFC33707D6H, 9); 140 STEP2(c, d, a, b, in[3] + 0FFFFFFFFF4D50D87H, 14); 141 STEP2(b, c, d, a, in[8] + 000000000455A14EDH, 20); 142 STEP2(a, b, c, d, in[13] + 0FFFFFFFFA9E3E905H, 5); 143 STEP2(d, a, b, c, in[2] + 0FFFFFFFFFCEFA3F8H, 9); 144 STEP2(c, d, a, b, in[7] + 000000000676F02D9H, 14); 145 STEP2(b, c, d, a, in[12] + 0FFFFFFFF8D2A4C8AH, 20); 146 147 STEP3(a, b, c, d, in[5] + 0FFFFFFFFFFFA3942H, 4); 148 STEP3(d, a, b, c, in[8] + 0FFFFFFFF8771F681H, 11); 149 STEP3(c, d, a, b, in[11] + 0000000006D9D6122H, 16); 150 STEP3(b, c, d, a, in[14] + 0FFFFFFFFFDE5380CH, 23); 151 STEP3(a, b, c, d, in[1] + 0FFFFFFFFA4BEEA44H, 4); 152 STEP3(d, a, b, c, in[4] + 0000000004BDECFA9H, 11); 153 STEP3(c, d, a, b, in[7] + 0FFFFFFFFF6BB4B60H, 16); 154 STEP3(b, c, d, a, in[10] + 0FFFFFFFFBEBFBC70H, 23); 155 STEP3(a, b, c, d, in[13] + 000000000289B7EC6H, 4); 156 STEP3(d, a, b, c, in[0] + 0FFFFFFFFEAA127FAH, 11); 157 STEP3(c, d, a, b, in[3] + 0FFFFFFFFD4EF3085H, 16); 158 STEP3(b, c, d, a, in[6] + 00000000004881D05H, 23); 159 STEP3(a, b, c, d, in[9] + 0FFFFFFFFD9D4D039H, 4); 160 STEP3(d, a, b, c, in[12] + 0FFFFFFFFE6DB99E5H, 11); 161 STEP3(c, d, a, b, in[15] + 0000000001FA27CF8H, 16); 162 STEP3(b, c, d, a, in[2] + 0FFFFFFFFC4AC5665H, 23); 163 164 STEP4(a, b, c, d, in[0] + 0FFFFFFFFF4292244H, 6); 165 STEP4(d, a, b, c, in[7] + 000000000432AFF97H, 10); 166 STEP4(c, d, a, b, in[14] + 0FFFFFFFFAB9423A7H, 15); 167 STEP4(b, c, d, a, in[5] + 0FFFFFFFFFC93A039H, 21); 168 STEP4(a, b, c, d, in[12] + 000000000655B59C3H, 6); 169 STEP4(d, a, b, c, in[3] + 0FFFFFFFF8F0CCC92H, 10); 170 STEP4(c, d, a, b, in[10] + 0FFFFFFFFFFEFF47DH, 15); 171 STEP4(b, c, d, a, in[1] + 0FFFFFFFF85845DD1H, 21); 172 STEP4(a, b, c, d, in[8] + 0000000006FA87E4FH, 6); 173 STEP4(d, a, b, c, in[15] + 0FFFFFFFFFE2CE6E0H, 10); 174 STEP4(c, d, a, b, in[6] + 0FFFFFFFFA3014314H, 15); 175 STEP4(b, c, d, a, in[13] + 0000000004E0811A1H, 21); 176 STEP4(a, b, c, d, in[4] + 0FFFFFFFFF7537E82H, 6); 177 STEP4(d, a, b, c, in[11] + 0FFFFFFFFBD3AF235H, 10); 178 STEP4(c, d, a, b, in[2] + 0000000002AD7D2BBH, 15); 179 STEP4(b, c, d, a, in[9] + 0FFFFFFFFEB86D391H, 21); 180 181 INC(buf[0], a); INC(buf[1], b); 182 INC(buf[2], c); INC(buf[3], d) 183 END Transform; 184 185(** Continues an MD5 message-digest operation, processing another 186 message block, and updating the context. *) 187 PROCEDURE Write*(context: Context; ch: CHAR); 188 VAR 189 in: ARRAY 16 OF LONGINT; 190 t, len: LONGINT; 191 BEGIN 192 t := context.bits; len := 1; 193 context.bits := t + 8; 194 t := (t DIV 8) MOD 64; 195 IF t > 0 THEN 196 t := 64-t; 197 IF 1 < t THEN 198 context.in[64-t] := ch; 199 RETURN 200 END; 201 ASSERT(len = 1); 202 context.in[64-t] := ch; 203 ByteReverse(context.in, in, 16); 204 Transform(context.buf, in); 205 DEC(len, t) 206 END; 207 IF len > 0 THEN 208 context.in[0] := ch 209 END 210 END Write; 211 212(** Continues an MD5 message-digest operation, processing another 213 message block, and updating the context. *) 214 PROCEDURE WriteBytes*(context: Context; VAR buf: ARRAY OF CHAR; len: LONGINT); 215 VAR 216 in: ARRAY 16 OF LONGINT; 217 beg, t: LONGINT; 218 BEGIN 219 beg := 0; t := context.bits; 220 context.bits := t + len*8; 221 t := (t DIV 8) MOD 64; 222 IF t > 0 THEN 223 t := 64-t; 224 IF len < t THEN 225 SYSTEM.MOVE(SYSTEM.ADR(buf[beg]), SYSTEM.ADR(context.in[64-t]), len); 226 RETURN 227 END; 228 SYSTEM.MOVE(SYSTEM.ADR(buf[beg]), SYSTEM.ADR(context.in[64-t]), t); 229 ByteReverse(context.in, in, 16); 230 Transform(context.buf, in); 231 INC(beg, t); DEC(len, t) 232 END; 233 WHILE len >= 64 DO 234 SYSTEM.MOVE(SYSTEM.ADR(buf[beg]), SYSTEM.ADR(context.in[0]), 64); 235 ByteReverse(context.in, in, 16); 236 Transform(context.buf, in); 237 INC(beg, 64); DEC(len, 64) 238 END; 239 IF len > 0 THEN 240 SYSTEM.MOVE(SYSTEM.ADR(buf[beg]), SYSTEM.ADR(context.in[0]), len) 241 END 242 END WriteBytes; 243 244(** Ends an MD5 message-digest operation, writing the message digest. *) 245 PROCEDURE Close*(context: Context; VAR digest: Digest); 246 VAR 247 in: ARRAY 16 OF LONGINT; 248 beg, i, count: LONGINT; 249 BEGIN 250 count := (context.bits DIV 8) MOD 64; 251 beg := count; 252 context.in[beg] := CHR(128); INC(beg); 253 count := 64-1-count; 254 IF count < 8 THEN 255 i := 0; 256 WHILE i < count DO 257 context.in[beg+i] := 0X; INC(i) 258 END; 259 ByteReverse(context.in, in, 16); 260 Transform(context.buf, in); 261 i := 0; 262 WHILE i < 56 DO 263 context.in[i] := 0X; INC(i) 264 END 265 ELSE 266 i := 0; 267 WHILE i < (count-8) DO 268 context.in[beg+i] := 0X; INC(i) 269 END 270 END; 271 ByteReverse(context.in, in, 14); 272 in[14] := context.bits; in[15] := 0; 273 Transform(context.buf, in); 274 ByteReverse(context.buf, in, 4); 275 SYSTEM.MOVE(SYSTEM.ADR(in[0]), SYSTEM.ADR(digest[0]), 16) 276 END Close; 277 278 PROCEDURE HexDigit(i: LONGINT): CHAR; 279 BEGIN 280 IF i < 10 THEN 281 RETURN CHR(ORD("0")+i) 282 ELSE 283 RETURN CHR(ORD("a")+i-10) 284 END 285 END HexDigit; 286 287(** Convert the digest into an hexadecimal string. *) 288 PROCEDURE ToString*(digest: Digest; VAR str: ARRAY OF CHAR); 289 VAR i: LONGINT; 290 BEGIN 291 FOR i := 0 TO 15 DO 292 str[2*i] := HexDigit(ORD(digest[i]) DIV 16); 293 str[2*i+1] := HexDigit(ORD(digest[i]) MOD 16) 294 END; 295 str[32] := 0X 296 END ToString; 297 298END ethMD5. 299