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