1 /*
2  * purple
3  *
4  * Purple is the legal property of its developers, whose names are too numerous
5  * to list here.  Please refer to the COPYRIGHT file distributed with this
6  * source distribution.
7  *
8  * Original md5
9  * Copyright (C) 2001-2003  Christophe Devine <c.devine@cr0.net>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
24  */
25 #include <cipher.h>
26 
27 #if !GLIB_CHECK_VERSION(2,16,0)
28 
29 #define MD5_HMAC_BLOCK_SIZE 64
30 
31 struct MD5Context {
32 	guint32 total[2];
33 	guint32 state[4];
34 	guchar buffer[64];
35 };
36 
37 #define MD5_GET_GUINT32(n,b,i) {            \
38 	(n) = ((guint32)(b) [(i)    ]      )    \
39 	| ((guint32)(b) [(i) + 1] <<  8)    \
40 	| ((guint32)(b) [(i) + 2] << 16)    \
41 	| ((guint32)(b) [(i) + 3] << 24);   \
42 }
43 #define MD5_PUT_GUINT32(n,b,i) {            \
44 	(b)[(i)    ] = (guchar)((n)      );     \
45 	(b)[(i) + 1] = (guchar)((n) >>  8);     \
46 	(b)[(i) + 2] = (guchar)((n) >> 16);     \
47 	(b)[(i) + 3] = (guchar)((n) >> 24);     \
48 }
49 
50 static size_t
md5_get_block_size(PurpleCipherContext * context)51 md5_get_block_size(PurpleCipherContext *context)
52 {
53 	/* This does not change (in this case) */
54 	return MD5_HMAC_BLOCK_SIZE;
55 }
56 
57 static void
md5_init(PurpleCipherContext * context,gpointer extra)58 md5_init(PurpleCipherContext *context, gpointer extra) {
59 	struct MD5Context *md5_context;
60 
61 	md5_context = g_new0(struct MD5Context, 1);
62 
63 	purple_cipher_context_set_data(context, md5_context);
64 
65 	purple_cipher_context_reset(context, extra);
66 }
67 
68 static void
md5_reset(PurpleCipherContext * context,gpointer extra)69 md5_reset(PurpleCipherContext *context, gpointer extra) {
70 	struct MD5Context *md5_context;
71 
72 	md5_context = purple_cipher_context_get_data(context);
73 
74 	md5_context->total[0] = 0;
75 	md5_context->total[1] = 0;
76 
77 	md5_context->state[0] = 0x67452301;
78 	md5_context->state[1] = 0xEFCDAB89;
79 	md5_context->state[2] = 0x98BADCFE;
80 	md5_context->state[3] = 0x10325476;
81 
82 	memset(md5_context->buffer, 0, sizeof(md5_context->buffer));
83 }
84 
85 static void
md5_uninit(PurpleCipherContext * context)86 md5_uninit(PurpleCipherContext *context) {
87 	struct MD5Context *md5_context;
88 
89 	purple_cipher_context_reset(context, NULL);
90 
91 	md5_context = purple_cipher_context_get_data(context);
92 	memset(md5_context, 0, sizeof(*md5_context));
93 
94 	g_free(md5_context);
95 	md5_context = NULL;
96 }
97 
98 static void
md5_process(struct MD5Context * md5_context,const guchar data[64])99 md5_process(struct MD5Context *md5_context, const guchar data[64]) {
100 	guint32 X[16], A, B, C, D;
101 
102 	A = md5_context->state[0];
103 	B = md5_context->state[1];
104 	C = md5_context->state[2];
105 	D = md5_context->state[3];
106 
107 	MD5_GET_GUINT32(X[ 0], data,  0);
108 	MD5_GET_GUINT32(X[ 1], data,  4);
109 	MD5_GET_GUINT32(X[ 2], data,  8);
110 	MD5_GET_GUINT32(X[ 3], data, 12);
111 	MD5_GET_GUINT32(X[ 4], data, 16);
112 	MD5_GET_GUINT32(X[ 5], data, 20);
113 	MD5_GET_GUINT32(X[ 6], data, 24);
114 	MD5_GET_GUINT32(X[ 7], data, 28);
115 	MD5_GET_GUINT32(X[ 8], data, 32);
116 	MD5_GET_GUINT32(X[ 9], data, 36);
117 	MD5_GET_GUINT32(X[10], data, 40);
118 	MD5_GET_GUINT32(X[11], data, 44);
119 	MD5_GET_GUINT32(X[12], data, 48);
120 	MD5_GET_GUINT32(X[13], data, 52);
121 	MD5_GET_GUINT32(X[14], data, 56);
122 	MD5_GET_GUINT32(X[15], data, 60);
123 
124 #define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
125 #define P(a,b,c,d,k,s,t) {      \
126 	a += F(b,c,d) + X[k] + t;   \
127 	a = S(a,s) + b;             \
128 }
129 
130 	/* first pass */
131 #define F(x,y,z) (z ^ (x & (y ^ z)))
132 	P(A, B, C, D,  0,  7, 0xD76AA478);
133 	P(D, A, B, C,  1, 12, 0xE8C7B756);
134 	P(C, D, A, B,  2, 17, 0x242070DB);
135 	P(B, C, D, A,  3, 22, 0xC1BDCEEE);
136 	P(A, B, C, D,  4,  7, 0xF57C0FAF);
137 	P(D, A, B, C,  5, 12, 0x4787C62A);
138 	P(C, D, A, B,  6, 17, 0xA8304613);
139 	P(B, C, D, A,  7, 22, 0xFD469501);
140 	P(A, B, C, D,  8,  7, 0x698098D8);
141 	P(D, A, B, C,  9, 12, 0x8B44F7AF);
142 	P(C, D, A, B, 10, 17, 0xFFFF5BB1);
143 	P(B, C, D, A, 11, 22, 0x895CD7BE);
144 	P(A, B, C, D, 12,  7, 0x6B901122);
145 	P(D, A, B, C, 13, 12, 0xFD987193);
146 	P(C, D, A, B, 14, 17, 0xA679438E);
147 	P(B, C, D, A, 15, 22, 0x49B40821);
148 #undef F
149 
150 	/* second pass */
151 #define F(x,y,z) (y ^ (z & (x ^ y)))
152 	P(A, B, C, D,  1,  5, 0xF61E2562);
153 	P(D, A, B, C,  6,  9, 0xC040B340);
154 	P(C, D, A, B, 11, 14, 0x265E5A51);
155 	P(B, C, D, A,  0, 20, 0xE9B6C7AA);
156 	P(A, B, C, D,  5,  5, 0xD62F105D);
157 	P(D, A, B, C, 10,  9, 0x02441453);
158 	P(C, D, A, B, 15, 14, 0xD8A1E681);
159 	P(B, C, D, A,  4, 20, 0xE7D3FBC8);
160 	P(A, B, C, D,  9,  5, 0x21E1CDE6);
161 	P(D, A, B, C, 14,  9, 0xC33707D6);
162 	P(C, D, A, B,  3, 14, 0xF4D50D87);
163 	P(B, C, D, A,  8, 20, 0x455A14ED);
164 	P(A, B, C, D, 13,  5, 0xA9E3E905);
165 	P(D, A, B, C,  2,  9, 0xFCEFA3F8);
166 	P(C, D, A, B,  7, 14, 0x676F02D9);
167 	P(B, C, D, A, 12, 20, 0x8D2A4C8A);
168 #undef F
169 
170 	/* third pass */
171 #define F(x,y,z) (x ^ y ^ z)
172 	P(A, B, C, D,  5,  4, 0xFFFA3942);
173 	P(D, A, B, C,  8, 11, 0x8771F681);
174 	P(C, D, A, B, 11, 16, 0x6D9D6122);
175 	P(B, C, D, A, 14, 23, 0xFDE5380C);
176 	P(A, B, C, D,  1,  4, 0xA4BEEA44);
177 	P(D, A, B, C,  4, 11, 0x4BDECFA9);
178 	P(C, D, A, B,  7, 16, 0xF6BB4B60);
179 	P(B, C, D, A, 10, 23, 0xBEBFBC70);
180 	P(A, B, C, D, 13,  4, 0x289B7EC6);
181 	P(D, A, B, C,  0, 11, 0xEAA127FA);
182 	P(C, D, A, B,  3, 16, 0xD4EF3085);
183 	P(B, C, D, A,  6, 23, 0x04881D05);
184 	P(A, B, C, D,  9,  4, 0xD9D4D039);
185 	P(D, A, B, C, 12, 11, 0xE6DB99E5);
186 	P(C, D, A, B, 15, 16, 0x1FA27CF8);
187 	P(B, C, D, A,  2, 23, 0xC4AC5665);
188 #undef F
189 
190 	/* forth pass */
191 #define F(x,y,z) (y ^ (x | ~z))
192 	P(A, B, C, D,  0,  6, 0xF4292244);
193 	P(D, A, B, C,  7, 10, 0x432AFF97);
194 	P(C, D, A, B, 14, 15, 0xAB9423A7);
195 	P(B, C, D, A,  5, 21, 0xFC93A039);
196 	P(A, B, C, D, 12,  6, 0x655B59C3);
197 	P(D, A, B, C,  3, 10, 0x8F0CCC92);
198 	P(C, D, A, B, 10, 15, 0xFFEFF47D);
199 	P(B, C, D, A,  1, 21, 0x85845DD1);
200 	P(A, B, C, D,  8,  6, 0x6FA87E4F);
201 	P(D, A, B, C, 15, 10, 0xFE2CE6E0);
202 	P(C, D, A, B,  6, 15, 0xA3014314);
203 	P(B, C, D, A, 13, 21, 0x4E0811A1);
204 	P(A, B, C, D,  4,  6, 0xF7537E82);
205 	P(D, A, B, C, 11, 10, 0xBD3AF235);
206 	P(C, D, A, B,  2, 15, 0x2AD7D2BB);
207 	P(B, C, D, A,  9, 21, 0xEB86D391);
208 #undef F
209 #undef P
210 #undef S
211 
212 	md5_context->state[0] += A;
213 	md5_context->state[1] += B;
214 	md5_context->state[2] += C;
215 	md5_context->state[3] += D;
216 	}
217 
218 static void
md5_append(PurpleCipherContext * context,const guchar * data,size_t len)219 md5_append(PurpleCipherContext *context, const guchar *data, size_t len) {
220 	struct MD5Context *md5_context = NULL;
221 	guint32 left = 0, fill = 0;
222 
223 	g_return_if_fail(context != NULL);
224 
225 	md5_context = purple_cipher_context_get_data(context);
226 	g_return_if_fail(md5_context != NULL);
227 
228 	left = md5_context->total[0] & 0x3F;
229 	fill = 64 - left;
230 
231 	md5_context->total[0] += len;
232 	md5_context->total[0] &= 0xFFFFFFFF;
233 
234 	if(md5_context->total[0] < len)
235 		md5_context->total[1]++;
236 
237 	if(left && len >= fill) {
238 		memcpy((md5_context->buffer + left), data, fill);
239 		md5_process(md5_context, md5_context->buffer);
240 		len -= fill;
241 		data += fill;
242 		left = 0;
243 	}
244 
245 	while(len >= 64) {
246 		md5_process(md5_context, data);
247 		len -= 64;
248 		data += 64;
249 	}
250 
251 	if(len) {
252 		memcpy((md5_context->buffer + left), data, len);
253 	}
254 }
255 
256 	static gboolean
md5_digest(PurpleCipherContext * context,size_t in_len,guchar digest[16],size_t * out_len)257 md5_digest(PurpleCipherContext *context, size_t in_len, guchar digest[16],
258 		size_t *out_len)
259 {
260 	struct MD5Context *md5_context = NULL;
261 	guint32 last, pad;
262 	guint32 high, low;
263 	guchar message[8];
264 	guchar padding[64] = {
265 		0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
266 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
267 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
268 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
269 	};
270 
271 	g_return_val_if_fail(in_len >= 16, FALSE);
272 
273 	md5_context = purple_cipher_context_get_data(context);
274 
275 	high = (md5_context->total[0] >> 29)
276 		| (md5_context->total[1] << 3);
277 	low = (md5_context->total[0] << 3);
278 
279 	MD5_PUT_GUINT32(low, message, 0);
280 	MD5_PUT_GUINT32(high, message, 4);
281 
282 	last = md5_context->total[0] & 0x3F;
283 	pad = (last < 56) ? (56 - last) : (120 - last);
284 
285 	md5_append(context, padding, pad);
286 	md5_append(context, message, 8);
287 
288 	MD5_PUT_GUINT32(md5_context->state[0], digest, 0);
289 	MD5_PUT_GUINT32(md5_context->state[1], digest, 4);
290 	MD5_PUT_GUINT32(md5_context->state[2], digest, 8);
291 	MD5_PUT_GUINT32(md5_context->state[3], digest, 12);
292 
293 	if(out_len)
294 		*out_len = 16;
295 
296 	return TRUE;
297 }
298 
299 static PurpleCipherOps MD5Ops = {
300 	NULL,			/* Set Option		*/
301 	NULL,			/* Get Option		*/
302 	md5_init,		/* init				*/
303 	md5_reset,		/* reset			*/
304 	md5_uninit,	/* uninit			*/
305 	NULL,			/* set iv			*/
306 	md5_append,	/* append			*/
307 	md5_digest,		/* digest			*/
308 	NULL,			/* encrypt			*/
309 	NULL,			/* decrypt			*/
310 	NULL,			/* set salt			*/
311 	NULL,			/* get salt size	*/
312 	NULL,			/* set key			*/
313 	NULL,			/* get key size		*/
314 	NULL,			/* set batch mode */
315 	NULL,			/* get batch mode */
316 	md5_get_block_size,	/* get block size */
317 	NULL			/* set key with len */
318 };
319 
320 PurpleCipherOps *
purple_md5_cipher_get_ops(void)321 purple_md5_cipher_get_ops(void) {
322 	return &MD5Ops;
323 }
324 
325 #endif /* !GLIB_CHECK_VERSION(2,16,0) */
326 
327