1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 /*
24 * RFC 1321 compliant MD5 implementation,
25 * by Christophe Devine <devine(at)cr0.net>
26 * this program is licensed under the GPL.
27 */
28
29 #include "common/md5.h"
30 #include "common/endian.h"
31 #include "common/str.h"
32 #include "common/stream.h"
33
34 namespace Common {
35
36 struct md5_context {
37 uint32 total[2];
38 uint32 state[4];
39 uint8 buffer[64];
40 };
41
42 static void md5_starts(md5_context *ctx);
43 static void md5_update(md5_context *ctx, const uint8 *input, uint32 length);
44 static void md5_finish(md5_context *ctx, uint8 digest[16]);
45
46
47 #define GET_UINT32(n, b, i) (n) = READ_LE_UINT32(b + i)
48 #define PUT_UINT32(n, b, i) WRITE_LE_UINT32(b + i, n)
49
md5_starts(md5_context * ctx)50 void md5_starts(md5_context *ctx) {
51 ctx->total[0] = 0;
52 ctx->total[1] = 0;
53
54 ctx->state[0] = 0x67452301;
55 ctx->state[1] = 0xEFCDAB89;
56 ctx->state[2] = 0x98BADCFE;
57 ctx->state[3] = 0x10325476;
58 }
59
md5_process(md5_context * ctx,const uint8 data[64])60 static void md5_process(md5_context *ctx, const uint8 data[64]) {
61 uint32 X[16], A, B, C, D;
62
63 GET_UINT32(X[0], data, 0);
64 GET_UINT32(X[1], data, 4);
65 GET_UINT32(X[2], data, 8);
66 GET_UINT32(X[3], data, 12);
67 GET_UINT32(X[4], data, 16);
68 GET_UINT32(X[5], data, 20);
69 GET_UINT32(X[6], data, 24);
70 GET_UINT32(X[7], data, 28);
71 GET_UINT32(X[8], data, 32);
72 GET_UINT32(X[9], data, 36);
73 GET_UINT32(X[10], data, 40);
74 GET_UINT32(X[11], data, 44);
75 GET_UINT32(X[12], data, 48);
76 GET_UINT32(X[13], data, 52);
77 GET_UINT32(X[14], data, 56);
78 GET_UINT32(X[15], data, 60);
79
80 #define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
81
82 #define P(a, b, c, d, k, s, t) \
83 { \
84 a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \
85 }
86
87 A = ctx->state[0];
88 B = ctx->state[1];
89 C = ctx->state[2];
90 D = ctx->state[3];
91
92 #define F(x, y, z) (z ^ (x & (y ^ z)))
93
94 P(A, B, C, D, 0, 7, 0xD76AA478);
95 P(D, A, B, C, 1, 12, 0xE8C7B756);
96 P(C, D, A, B, 2, 17, 0x242070DB);
97 P(B, C, D, A, 3, 22, 0xC1BDCEEE);
98 P(A, B, C, D, 4, 7, 0xF57C0FAF);
99 P(D, A, B, C, 5, 12, 0x4787C62A);
100 P(C, D, A, B, 6, 17, 0xA8304613);
101 P(B, C, D, A, 7, 22, 0xFD469501);
102 P(A, B, C, D, 8, 7, 0x698098D8);
103 P(D, A, B, C, 9, 12, 0x8B44F7AF);
104 P(C, D, A, B, 10, 17, 0xFFFF5BB1);
105 P(B, C, D, A, 11, 22, 0x895CD7BE);
106 P(A, B, C, D, 12, 7, 0x6B901122);
107 P(D, A, B, C, 13, 12, 0xFD987193);
108 P(C, D, A, B, 14, 17, 0xA679438E);
109 P(B, C, D, A, 15, 22, 0x49B40821);
110
111 #undef F
112
113 #define F(x, y, z) (y ^ (z & (x ^ y)))
114
115 P(A, B, C, D, 1, 5, 0xF61E2562);
116 P(D, A, B, C, 6, 9, 0xC040B340);
117 P(C, D, A, B, 11, 14, 0x265E5A51);
118 P(B, C, D, A, 0, 20, 0xE9B6C7AA);
119 P(A, B, C, D, 5, 5, 0xD62F105D);
120 P(D, A, B, C, 10, 9, 0x02441453);
121 P(C, D, A, B, 15, 14, 0xD8A1E681);
122 P(B, C, D, A, 4, 20, 0xE7D3FBC8);
123 P(A, B, C, D, 9, 5, 0x21E1CDE6);
124 P(D, A, B, C, 14, 9, 0xC33707D6);
125 P(C, D, A, B, 3, 14, 0xF4D50D87);
126 P(B, C, D, A, 8, 20, 0x455A14ED);
127 P(A, B, C, D, 13, 5, 0xA9E3E905);
128 P(D, A, B, C, 2, 9, 0xFCEFA3F8);
129 P(C, D, A, B, 7, 14, 0x676F02D9);
130 P(B, C, D, A, 12, 20, 0x8D2A4C8A);
131
132 #undef F
133
134 #define F(x, y, z) (x ^ y ^ z)
135
136 P(A, B, C, D, 5, 4, 0xFFFA3942);
137 P(D, A, B, C, 8, 11, 0x8771F681);
138 P(C, D, A, B, 11, 16, 0x6D9D6122);
139 P(B, C, D, A, 14, 23, 0xFDE5380C);
140 P(A, B, C, D, 1, 4, 0xA4BEEA44);
141 P(D, A, B, C, 4, 11, 0x4BDECFA9);
142 P(C, D, A, B, 7, 16, 0xF6BB4B60);
143 P(B, C, D, A, 10, 23, 0xBEBFBC70);
144 P(A, B, C, D, 13, 4, 0x289B7EC6);
145 P(D, A, B, C, 0, 11, 0xEAA127FA);
146 P(C, D, A, B, 3, 16, 0xD4EF3085);
147 P(B, C, D, A, 6, 23, 0x04881D05);
148 P(A, B, C, D, 9, 4, 0xD9D4D039);
149 P(D, A, B, C, 12, 11, 0xE6DB99E5);
150 P(C, D, A, B, 15, 16, 0x1FA27CF8);
151 P(B, C, D, A, 2, 23, 0xC4AC5665);
152
153 #undef F
154
155 #define F(x, y, z) (y ^ (x | ~z))
156
157 P(A, B, C, D, 0, 6, 0xF4292244);
158 P(D, A, B, C, 7, 10, 0x432AFF97);
159 P(C, D, A, B, 14, 15, 0xAB9423A7);
160 P(B, C, D, A, 5, 21, 0xFC93A039);
161 P(A, B, C, D, 12, 6, 0x655B59C3);
162 P(D, A, B, C, 3, 10, 0x8F0CCC92);
163 P(C, D, A, B, 10, 15, 0xFFEFF47D);
164 P(B, C, D, A, 1, 21, 0x85845DD1);
165 P(A, B, C, D, 8, 6, 0x6FA87E4F);
166 P(D, A, B, C, 15, 10, 0xFE2CE6E0);
167 P(C, D, A, B, 6, 15, 0xA3014314);
168 P(B, C, D, A, 13, 21, 0x4E0811A1);
169 P(A, B, C, D, 4, 6, 0xF7537E82);
170 P(D, A, B, C, 11, 10, 0xBD3AF235);
171 P(C, D, A, B, 2, 15, 0x2AD7D2BB);
172 P(B, C, D, A, 9, 21, 0xEB86D391);
173
174 #undef F
175
176 ctx->state[0] += A;
177 ctx->state[1] += B;
178 ctx->state[2] += C;
179 ctx->state[3] += D;
180 }
181
md5_update(md5_context * ctx,const uint8 * input,uint32 length)182 void md5_update(md5_context *ctx, const uint8 *input, uint32 length) {
183 uint32 left, fill;
184
185 if (!length)
186 return;
187
188 left = ctx->total[0] & 0x3F;
189 fill = 64 - left;
190
191 ctx->total[0] += length;
192 ctx->total[0] &= 0xFFFFFFFF;
193
194 if (ctx->total[0] < length)
195 ctx->total[1]++;
196
197 if (left && length >= fill) {
198 memcpy((void *)(ctx->buffer + left), (const void *)input, fill);
199 md5_process(ctx, ctx->buffer);
200 length -= fill;
201 input += fill;
202 left = 0;
203 }
204
205 while (length >= 64) {
206 md5_process(ctx, input);
207 length -= 64;
208 input += 64;
209 }
210
211 if (length) {
212 memcpy((void *)(ctx->buffer + left), (const void *)input, length);
213 }
214 }
215
216 static const uint8 md5_padding[64] = {
217 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
218 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
219 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
220 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
221 };
222
md5_finish(md5_context * ctx,uint8 digest[16])223 void md5_finish(md5_context *ctx, uint8 digest[16]) {
224 uint32 last, padn;
225 uint32 high, low;
226 uint8 msglen[8];
227
228 high = (ctx->total[0] >> 29) | (ctx->total[1] << 3);
229 low = (ctx->total[0] << 3);
230
231 PUT_UINT32(low, msglen, 0);
232 PUT_UINT32(high, msglen, 4);
233
234 last = ctx->total[0] & 0x3F;
235 padn = (last < 56) ? (56 - last) : (120 - last);
236
237 md5_update(ctx, md5_padding, padn);
238 md5_update(ctx, msglen, 8);
239
240 PUT_UINT32(ctx->state[0], digest, 0);
241 PUT_UINT32(ctx->state[1], digest, 4);
242 PUT_UINT32(ctx->state[2], digest, 8);
243 PUT_UINT32(ctx->state[3], digest, 12);
244 }
245
246
computeStreamMD5(ReadStream & stream,uint8 digest[16],uint32 length)247 bool computeStreamMD5(ReadStream &stream, uint8 digest[16], uint32 length) {
248
249 #ifdef DISABLE_MD5
250 memset(digest, 0, 16);
251 #else
252 md5_context ctx;
253 int i;
254 unsigned char buf[1000];
255 bool restricted = (length != 0);
256 uint32 readlen;
257
258 if (!restricted || sizeof(buf) <= length)
259 readlen = sizeof(buf);
260 else
261 readlen = length;
262
263 md5_starts(&ctx);
264
265 while ((i = stream.read(buf, readlen)) > 0) {
266 md5_update(&ctx, buf, i);
267
268 if (restricted) {
269 length -= i;
270 if (length == 0)
271 break;
272
273 if (sizeof(buf) > length)
274 readlen = length;
275 }
276 }
277
278 md5_finish(&ctx, digest);
279 #endif
280 return true;
281 }
282
computeStreamMD5AsString(ReadStream & stream,uint32 length)283 String computeStreamMD5AsString(ReadStream &stream, uint32 length) {
284 String md5;
285 uint8 digest[16];
286 if (computeStreamMD5(stream, digest, length)) {
287 for (int i = 0; i < 16; i++) {
288 md5 += String::format("%02x", (int)digest[i]);
289 }
290 }
291
292 return md5;
293 }
294
295 } // End of namespace Common
296