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