10684
|
1 /*
|
|
2 * gaim
|
|
3 *
|
|
4 * Gaim 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
24 */
|
|
25 #include <glib.h>
|
|
26 #include <string.h>
|
|
27 #include <stdio.h>
|
|
28
|
|
29 #include "internal.h"
|
|
30 #include "cipher.h"
|
|
31 #include "debug.h"
|
|
32 #include "signals.h"
|
|
33 #include "value.h"
|
|
34
|
|
35 /*******************************************************************************
|
|
36 * MD5
|
|
37 ******************************************************************************/
|
|
38 struct MD5Context {
|
|
39 guint32 total[2];
|
|
40 guint32 state[4];
|
|
41 guint8 buffer[64];
|
|
42 };
|
|
43
|
|
44 #define MD5_GET_GUINT32(n,b,i) { \
|
|
45 (n) = ((guint32)(b) [(i) ] ) \
|
|
46 | ((guint32)(b) [(i) + 1] << 8) \
|
|
47 | ((guint32)(b) [(i) + 2] << 16) \
|
|
48 | ((guint32)(b) [(i) + 3] << 24); \
|
|
49 }
|
|
50 #define MD5_PUT_GUINT32(n,b,i) { \
|
|
51 (b)[(i) ] = (guint8)((n) ); \
|
|
52 (b)[(i) + 1] = (guint8)((n) >> 8); \
|
|
53 (b)[(i) + 2] = (guint8)((n) >> 16); \
|
|
54 (b)[(i) + 3] = (guint8)((n) >> 24); \
|
|
55 }
|
|
56
|
|
57 static void
|
|
58 md5_init(GaimCipherContext *context, gpointer extra) {
|
|
59 struct MD5Context *md5_context;
|
|
60
|
|
61 md5_context = g_new0(struct MD5Context, 1);
|
|
62
|
|
63 gaim_cipher_context_set_data(context, md5_context);
|
|
64
|
|
65 gaim_cipher_context_reset(context, extra);
|
|
66 }
|
|
67
|
|
68 static void
|
|
69 md5_reset(GaimCipherContext *context, gpointer extra) {
|
|
70 struct MD5Context *md5_context;
|
|
71
|
|
72 md5_context = gaim_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
|
|
86 md5_uninit(GaimCipherContext *context) {
|
|
87 struct MD5Context *md5_context;
|
|
88
|
|
89 gaim_cipher_context_reset(context, NULL);
|
|
90
|
|
91 md5_context = gaim_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
|
|
99 md5_process(struct MD5Context *md5_context, const guint8 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
|
|
219 md5_append(GaimCipherContext *context, const guint8 *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 = gaim_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
|
|
257 md5_digest(GaimCipherContext *context, size_t *len, guint8 digest[16]) {
|
|
258 struct MD5Context *md5_context = NULL;
|
|
259 guint32 last, pad;
|
|
260 guint32 high, low;
|
|
261 guint8 message[8];
|
|
262 guint8 padding[64] = {
|
|
263 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
264 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
265 0, 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 };
|
|
268
|
|
269 g_return_val_if_fail(len, FALSE);
|
|
270 g_return_val_if_fail(*len >= 16, FALSE);
|
|
271
|
|
272 md5_context = gaim_cipher_context_get_data(context);
|
|
273
|
|
274 high = (md5_context->total[0] >> 29)
|
|
275 | (md5_context->total[1] << 3);
|
|
276 low = (md5_context->total[0] << 3);
|
|
277
|
|
278 MD5_PUT_GUINT32(low, message, 0);
|
|
279 MD5_PUT_GUINT32(high, message, 4);
|
|
280
|
|
281 last = md5_context->total[0] & 0x3F;
|
|
282 pad = (last < 56) ? (56 - last) : (120 - last);
|
|
283
|
|
284 md5_append(context, padding, pad);
|
|
285 md5_append(context, message, 8);
|
|
286
|
|
287 MD5_PUT_GUINT32(md5_context->state[0], digest, 0);
|
|
288 MD5_PUT_GUINT32(md5_context->state[1], digest, 4);
|
|
289 MD5_PUT_GUINT32(md5_context->state[2], digest, 8);
|
|
290 MD5_PUT_GUINT32(md5_context->state[3], digest, 12);
|
|
291
|
|
292 return TRUE;
|
|
293 }
|
|
294
|
|
295 static GaimCipherOps MD5Ops = {
|
|
296 NULL, /* Set option */
|
|
297 NULL, /* Get option */
|
|
298 md5_init, /* init */
|
|
299 md5_reset, /* reset */
|
|
300 md5_uninit, /* uninit */
|
|
301 NULL, /* set iv */
|
|
302 md5_append, /* append */
|
|
303 md5_digest, /* digest */
|
|
304 NULL, /* encrypt */
|
|
305 NULL, /* decrypt */
|
|
306 NULL, /* set salt */
|
|
307 NULL, /* get salt size */
|
|
308 NULL, /* set key */
|
|
309 NULL /* get key size */
|
|
310 };
|
|
311
|
|
312 /*******************************************************************************
|
|
313 * SHA-1
|
|
314 ******************************************************************************/
|
|
315 #define SHA1_ROTL(X,n) ((((X) << (n)) | ((X) >> (32-(n)))) & 0xFFFFFFFF)
|
|
316
|
|
317 struct SHA1Context {
|
|
318 guint32 H[5];
|
|
319 guint32 W[80];
|
|
320
|
|
321 gint lenW;
|
|
322
|
|
323 guint32 sizeHi;
|
|
324 guint32 sizeLo;
|
|
325 };
|
|
326
|
|
327 static void
|
|
328 sha1_hash_block(struct SHA1Context *sha1_ctx) {
|
|
329 gint i;
|
|
330 guint32 A, B, C, D, E, T;
|
|
331
|
|
332 for(i = 16; i < 80; i++) {
|
|
333 sha1_ctx->W[i] = SHA1_ROTL(sha1_ctx->W[i - 3] ^
|
|
334 sha1_ctx->W[i - 8] ^
|
|
335 sha1_ctx->W[i - 14] ^
|
|
336 sha1_ctx->W[i - 16], 1);
|
|
337 }
|
|
338
|
|
339 A = sha1_ctx->H[0];
|
|
340 B = sha1_ctx->H[1];
|
|
341 C = sha1_ctx->H[2];
|
|
342 D = sha1_ctx->H[3];
|
|
343 E = sha1_ctx->H[4];
|
|
344
|
|
345 for(i = 0; i < 20; i++) {
|
|
346 T = (SHA1_ROTL(A, 5) + (((C ^ D) & B) ^ D) + E + sha1_ctx->W[i] + 0x5A827999) & 0xFFFFFFFF;
|
|
347 E = D;
|
|
348 D = C;
|
|
349 C = SHA1_ROTL(B, 30);
|
|
350 B = A;
|
|
351 A = T;
|
|
352 }
|
|
353
|
|
354 for(i = 20; i < 40; i++) {
|
|
355 T = (SHA1_ROTL(A, 5) + (B ^ C ^ D) + E + sha1_ctx->W[i] + 0x6ED9EBA1) & 0xFFFFFFFF;
|
|
356 E = D;
|
|
357 D = C;
|
|
358 C = SHA1_ROTL(B, 30);
|
|
359 B = A;
|
|
360 A = T;
|
|
361 }
|
|
362
|
|
363 for(i = 40; i < 60; i++) {
|
|
364 T = (SHA1_ROTL(A, 5) + ((B & C) | (D & (B | C))) + E + sha1_ctx->W[i] + 0x8F1BBCDC) & 0xFFFFFFFF;
|
|
365 E = D;
|
|
366 D = C;
|
|
367 C = SHA1_ROTL(B, 30);
|
|
368 B = A;
|
|
369 A = T;
|
|
370 }
|
|
371
|
|
372 for(i = 60; i < 80; i++) {
|
|
373 T = (SHA1_ROTL(A, 5) + (B ^ C ^ D) + E + sha1_ctx->W[i] + 0xCA62C1D6) & 0xFFFFFFFF;
|
|
374 E = D;
|
|
375 D = C;
|
|
376 C = SHA1_ROTL(B, 30);
|
|
377 B = A;
|
|
378 A = T;
|
|
379 }
|
|
380
|
|
381 sha1_ctx->H[0] += A;
|
|
382 sha1_ctx->H[1] += B;
|
|
383 sha1_ctx->H[2] += C;
|
|
384 sha1_ctx->H[3] += D;
|
|
385 sha1_ctx->H[4] += E;
|
|
386 }
|
|
387
|
|
388 static void
|
|
389 sha1_set_opt(GaimCipherContext *context, const gchar *name, void *value) {
|
|
390 struct SHA1Context *ctx;
|
|
391
|
|
392 ctx = gaim_cipher_context_get_data(context);
|
|
393
|
|
394 if(!strcmp(name, "sizeHi")) {
|
|
395 ctx->sizeHi = GPOINTER_TO_INT(value);
|
|
396 } else if(!strcmp(name, "sizeLo")) {
|
|
397 ctx->sizeLo = GPOINTER_TO_INT(value);
|
|
398 } else if(!strcmp(name, "lenW")) {
|
|
399 ctx->lenW = GPOINTER_TO_INT(value);
|
|
400 }
|
|
401 }
|
|
402
|
|
403 static void *
|
|
404 sha1_get_opt(GaimCipherContext *context, const gchar *name) {
|
|
405 struct SHA1Context *ctx;
|
|
406
|
|
407 ctx = gaim_cipher_context_get_data(context);
|
|
408
|
|
409 if(!strcmp(name, "sizeHi")) {
|
|
410 return GINT_TO_POINTER(ctx->sizeHi);
|
|
411 } else if(!strcmp(name, "sizeLo")) {
|
|
412 return GINT_TO_POINTER(ctx->sizeLo);
|
|
413 } else if(!strcmp(name, "lenW")) {
|
|
414 return GINT_TO_POINTER(ctx->lenW);
|
|
415 }
|
|
416
|
|
417 return NULL;
|
|
418 }
|
|
419
|
|
420 static void
|
|
421 sha1_init(GaimCipherContext *context, void *extra) {
|
|
422 struct SHA1Context *sha1_ctx;
|
|
423
|
|
424 sha1_ctx = g_new0(struct SHA1Context, 1);
|
|
425
|
|
426 gaim_cipher_context_set_data(context, sha1_ctx);
|
|
427
|
|
428 gaim_cipher_context_reset(context, extra);
|
|
429 }
|
|
430
|
|
431 static void
|
|
432 sha1_reset(GaimCipherContext *context, void *extra) {
|
|
433 struct SHA1Context *sha1_ctx;
|
|
434 gint i;
|
|
435
|
|
436 sha1_ctx = gaim_cipher_context_get_data(context);
|
|
437
|
|
438 g_return_if_fail(sha1_ctx);
|
|
439
|
|
440 sha1_ctx->lenW = 0;
|
|
441 sha1_ctx->sizeHi = 0;
|
|
442 sha1_ctx->sizeLo = 0;
|
|
443
|
|
444 sha1_ctx->H[0] = 0x67452301;
|
|
445 sha1_ctx->H[1] = 0xEFCDAB89;
|
|
446 sha1_ctx->H[2] = 0x98BADCFE;
|
|
447 sha1_ctx->H[3] = 0x10325476;
|
|
448 sha1_ctx->H[4] = 0xC3D2E1F0;
|
|
449
|
|
450 for(i = 0; i < 80; i++)
|
|
451 sha1_ctx->W[i] = 0;
|
|
452 }
|
|
453
|
|
454 static void
|
|
455 sha1_uninit(GaimCipherContext *context) {
|
|
456 struct SHA1Context *sha1_ctx;
|
|
457
|
|
458 gaim_cipher_context_reset(context, NULL);
|
|
459
|
|
460 sha1_ctx = gaim_cipher_context_get_data(context);
|
|
461
|
|
462 memset(sha1_ctx, 0, sizeof(struct SHA1Context));
|
|
463
|
|
464 g_free(sha1_ctx);
|
|
465 sha1_ctx = NULL;
|
|
466 }
|
|
467
|
|
468
|
|
469 static void
|
|
470 sha1_append(GaimCipherContext *context, const guint8 *data, size_t len) {
|
|
471 struct SHA1Context *sha1_ctx;
|
|
472 gint i;
|
|
473
|
|
474 sha1_ctx = gaim_cipher_context_get_data(context);
|
|
475
|
|
476 g_return_if_fail(sha1_ctx);
|
|
477
|
|
478 for(i = 0; i < len; i++) {
|
|
479 sha1_ctx->W[sha1_ctx->lenW / 4] <<= 8;
|
|
480 sha1_ctx->W[sha1_ctx->lenW / 4] |= data[i];
|
|
481
|
|
482 if((++sha1_ctx->lenW) % 64 == 0) {
|
|
483 sha1_hash_block(sha1_ctx);
|
|
484 sha1_ctx->lenW = 0;
|
|
485 }
|
|
486
|
|
487 sha1_ctx->sizeLo += 8;
|
|
488 sha1_ctx->sizeHi += (sha1_ctx->sizeLo < 8);
|
|
489 }
|
|
490 }
|
|
491
|
|
492 static gboolean
|
|
493 sha1_digest(GaimCipherContext *context, size_t *len, guint8 digest[20]) {
|
|
494 struct SHA1Context *sha1_ctx;
|
|
495 guint8 pad0x80 = 0x80, pad0x00 = 0x00;
|
|
496 guint8 padlen[8];
|
|
497 gint i;
|
|
498
|
|
499 g_return_val_if_fail(len, FALSE);
|
|
500 g_return_val_if_fail(*len <= 20, FALSE);
|
|
501
|
|
502 sha1_ctx = gaim_cipher_context_get_data(context);
|
|
503
|
|
504 g_return_val_if_fail(sha1_ctx, FALSE);
|
|
505
|
|
506 padlen[0] = (guint8)((sha1_ctx->sizeHi >> 24) & 255);
|
|
507 padlen[1] = (guint8)((sha1_ctx->sizeHi >> 16) & 255);
|
|
508 padlen[2] = (guint8)((sha1_ctx->sizeHi >> 8) & 255);
|
|
509 padlen[3] = (guint8)((sha1_ctx->sizeHi >> 0) & 255);
|
|
510 padlen[4] = (guint8)((sha1_ctx->sizeLo >> 24) & 255);
|
|
511 padlen[5] = (guint8)((sha1_ctx->sizeLo >> 16) & 255);
|
|
512 padlen[6] = (guint8)((sha1_ctx->sizeLo >> 8) & 255);
|
|
513 padlen[7] = (guint8)((sha1_ctx->sizeLo >> 0) & 255);
|
|
514
|
|
515 /* pad with a 1, then zeroes, then length */
|
|
516 gaim_cipher_context_append(context, &pad0x80, 1);
|
|
517 while(sha1_ctx->lenW != 56)
|
|
518 gaim_cipher_context_append(context, &pad0x00, 1);
|
|
519 gaim_cipher_context_append(context, padlen, 8);
|
|
520
|
|
521 for(i = 0; i < 20; i++) {
|
|
522 digest[i] = (guint8)(sha1_ctx->H[i / 4] >> 24);
|
|
523 sha1_ctx->H[i / 4] <<= 8;
|
|
524 }
|
|
525
|
|
526 gaim_cipher_context_reset(context, NULL);
|
|
527
|
|
528 return TRUE;
|
|
529 }
|
|
530
|
|
531 static GaimCipherOps SHA1Ops = {
|
|
532 sha1_set_opt, /* Set Option */
|
|
533 sha1_get_opt, /* Get Option */
|
|
534 sha1_init, /* init */
|
|
535 sha1_reset, /* reset */
|
|
536 sha1_uninit, /* uninit */
|
|
537 NULL, /* set iv */
|
|
538 sha1_append, /* append */
|
|
539 sha1_digest, /* digest */
|
|
540 NULL, /* encrypt */
|
|
541 NULL, /* decrypt */
|
|
542 NULL, /* set salt */
|
|
543 NULL, /* get salt size */
|
|
544 NULL, /* set key */
|
|
545 NULL /* get key size */
|
|
546 };
|
|
547
|
|
548 /*******************************************************************************
|
|
549 * Structs
|
|
550 ******************************************************************************/
|
|
551 struct _GaimCipher {
|
|
552 gchar *name;
|
|
553 GaimCipherOps *ops;
|
|
554 guint ref;
|
|
555 };
|
|
556
|
|
557 struct _GaimCipherContext {
|
|
558 GaimCipher *cipher;
|
|
559 gpointer data;
|
|
560 };
|
|
561
|
|
562 /******************************************************************************
|
|
563 * Globals
|
|
564 *****************************************************************************/
|
|
565 static GList *ciphers = NULL;
|
|
566
|
|
567 /******************************************************************************
|
|
568 * GaimCipher API
|
|
569 *****************************************************************************/
|
|
570 const gchar *
|
|
571 gaim_cipher_get_name(GaimCipher *cipher) {
|
|
572 g_return_val_if_fail(cipher, NULL);
|
|
573
|
|
574 return cipher->name;
|
|
575 }
|
|
576
|
|
577 guint
|
|
578 gaim_cipher_get_capabilities(GaimCipher *cipher) {
|
|
579 GaimCipherOps *ops = NULL;
|
|
580 guint caps = 0;
|
|
581
|
|
582 g_return_val_if_fail(cipher, 0);
|
|
583
|
|
584 ops = cipher->ops;
|
|
585 g_return_val_if_fail(ops, 0);
|
|
586
|
|
587 if(ops->set_option)
|
|
588 caps |= GAIM_CIPHER_CAPS_SET_OPT;
|
|
589 if(ops->get_option)
|
|
590 caps |= GAIM_CIPHER_CAPS_GET_OPT;
|
|
591 if(ops->init)
|
|
592 caps |= GAIM_CIPHER_CAPS_INIT;
|
|
593 if(ops->reset)
|
|
594 caps |= GAIM_CIPHER_CAPS_RESET;
|
|
595 if(ops->uninit)
|
|
596 caps |= GAIM_CIPHER_CAPS_UNINIT;
|
|
597 if(ops->set_iv)
|
|
598 caps |= GAIM_CIPHER_CAPS_SET_IV;
|
|
599 if(ops->append)
|
|
600 caps |= GAIM_CIPHER_CAPS_APPEND;
|
|
601 if(ops->digest)
|
|
602 caps |= GAIM_CIPHER_CAPS_DIGEST;
|
|
603 if(ops->encrypt)
|
|
604 caps |= GAIM_CIPHER_CAPS_ENCRYPT;
|
|
605 if(ops->decrypt)
|
|
606 caps |= GAIM_CIPHER_CAPS_DECRYPT;
|
|
607 if(ops->set_salt)
|
|
608 caps |= GAIM_CIPHER_CAPS_SET_SALT;
|
|
609 if(ops->get_salt_size)
|
|
610 caps |= GAIM_CIPHER_CAPS_GET_SALT_SIZE;
|
|
611 if(ops->set_key)
|
|
612 caps |= GAIM_CIPHER_CAPS_SET_KEY;
|
|
613 if(ops->get_key_size)
|
|
614 caps |= GAIM_CIPHER_CAPS_GET_KEY_SIZE;
|
|
615
|
|
616 return caps;
|
|
617 }
|
|
618
|
|
619 void
|
|
620 gaim_cipher_digest_region(const gchar *name, const guint8 *data,
|
|
621 size_t data_len, guint8 digest[], size_t *digest_len)
|
|
622 {
|
|
623 GaimCipher *cipher;
|
|
624 GaimCipherContext *context;
|
|
625
|
|
626 g_return_if_fail(name);
|
|
627 g_return_if_fail(data);
|
|
628
|
|
629 cipher = gaim_ciphers_find_cipher(name);
|
|
630
|
|
631 g_return_if_fail(cipher);
|
|
632
|
|
633 if(!cipher->ops->append || !cipher->ops->digest) {
|
|
634 gaim_debug_info("cipher", "gaim_cipher_region failed: "
|
|
635 "the %s cipher does not support appending and or "
|
|
636 "digesting.", cipher->name);
|
|
637 return;
|
|
638 }
|
|
639
|
|
640 context = gaim_cipher_context_new(cipher, NULL);
|
|
641 gaim_cipher_context_append(context, data, data_len);
|
|
642 gaim_cipher_context_digest(context, digest_len, digest);
|
|
643 gaim_cipher_context_destroy(context);
|
|
644 }
|
|
645
|
|
646 /******************************************************************************
|
|
647 * GaimCiphers API
|
|
648 *****************************************************************************/
|
|
649 GaimCipher *
|
|
650 gaim_ciphers_find_cipher(const gchar *name) {
|
|
651 GaimCipher *cipher;
|
|
652 GList *l;
|
|
653
|
|
654 g_return_val_if_fail(name, NULL);
|
|
655
|
|
656 for(l = ciphers; l; l = l->next) {
|
|
657 cipher = GAIM_CIPHER(l->data);
|
|
658
|
|
659 if(!g_ascii_strcasecmp(cipher->name, name))
|
|
660 return cipher;
|
|
661 }
|
|
662
|
|
663 return NULL;
|
|
664 }
|
|
665
|
|
666 GaimCipher *
|
|
667 gaim_ciphers_register_cipher(const gchar *name, GaimCipherOps *ops) {
|
|
668 GaimCipher *cipher = NULL;
|
|
669
|
|
670 g_return_val_if_fail(name, NULL);
|
|
671 g_return_val_if_fail(ops, NULL);
|
|
672 g_return_val_if_fail(!gaim_ciphers_find_cipher(name), NULL);
|
|
673
|
|
674 cipher = g_new0(GaimCipher, 1);
|
|
675
|
|
676 cipher->name = g_strdup(name);
|
|
677 cipher->ops = ops;
|
|
678
|
|
679 ciphers = g_list_append(ciphers, cipher);
|
|
680
|
|
681 gaim_signal_emit(gaim_ciphers_get_handle(), "cipher-added", cipher);
|
|
682
|
|
683 return cipher;
|
|
684 }
|
|
685
|
|
686 gboolean
|
|
687 gaim_ciphers_unregister_cipher(GaimCipher *cipher) {
|
|
688 g_return_val_if_fail(cipher, FALSE);
|
|
689 g_return_val_if_fail(cipher->ref == 0, FALSE);
|
|
690
|
|
691 gaim_signal_emit(gaim_ciphers_get_handle(), "cipher-removed", cipher);
|
|
692
|
|
693 ciphers = g_list_remove(ciphers, cipher);
|
|
694
|
|
695 g_free(cipher->name);
|
|
696 g_free(cipher);
|
|
697
|
|
698 return TRUE;
|
|
699 }
|
|
700
|
|
701 GList *
|
|
702 gaim_ciphers_get_ciphers() {
|
|
703 return ciphers;
|
|
704 }
|
|
705
|
|
706 /******************************************************************************
|
|
707 * GaimCipher Subsystem API
|
|
708 *****************************************************************************/
|
|
709 gpointer
|
|
710 gaim_ciphers_get_handle() {
|
|
711 static gint handle;
|
|
712
|
|
713 return &handle;
|
|
714 }
|
|
715
|
|
716 void
|
|
717 gaim_ciphers_init() {
|
|
718 gpointer handle;
|
|
719
|
|
720 handle = gaim_ciphers_get_handle();
|
|
721
|
|
722 gaim_signal_register(handle, "cipher-added",
|
|
723 gaim_marshal_VOID__POINTER, NULL, 1,
|
|
724 gaim_value_new(GAIM_TYPE_SUBTYPE,
|
|
725 GAIM_SUBTYPE_CIPHER));
|
|
726 gaim_signal_register(handle, "cipher-removed",
|
|
727 gaim_marshal_VOID__POINTER, NULL, 1,
|
|
728 gaim_value_new(GAIM_TYPE_SUBTYPE,
|
|
729 GAIM_SUBTYPE_CIPHER));
|
|
730
|
|
731 gaim_ciphers_register_cipher("md5", &MD5Ops);
|
|
732 gaim_ciphers_register_cipher("sha1", &SHA1Ops);
|
|
733 }
|
|
734
|
|
735 void
|
|
736 gaim_ciphers_uninit() {
|
|
737 GaimCipher *cipher;
|
|
738 GList *l, *ll;
|
|
739
|
|
740 for(l = ciphers; l; l = ll) {
|
|
741 ll = l->next;
|
|
742
|
|
743 cipher = GAIM_CIPHER(l->data);
|
|
744 gaim_ciphers_unregister_cipher(cipher);
|
|
745
|
|
746 ciphers = g_list_remove(ciphers, cipher);
|
|
747 }
|
|
748
|
|
749 g_list_free(ciphers);
|
|
750
|
|
751 gaim_signals_unregister_by_instance(gaim_ciphers_get_handle());
|
|
752 }
|
|
753 /******************************************************************************
|
|
754 * GaimCipherContext API
|
|
755 *****************************************************************************/
|
|
756 void
|
|
757 gaim_cipher_context_set_option(GaimCipherContext *context, const gchar *name,
|
|
758 gpointer value)
|
|
759 {
|
|
760 GaimCipher *cipher = NULL;
|
|
761
|
|
762 g_return_if_fail(context);
|
|
763 g_return_if_fail(name);
|
|
764
|
|
765 cipher = context->cipher;
|
|
766 g_return_if_fail(cipher);
|
|
767
|
|
768 if(cipher->ops && cipher->ops->set_option)
|
|
769 cipher->ops->set_option(context, name, value);
|
|
770 else
|
|
771 gaim_debug_info("cipher", "the %s cipher does not support the "
|
|
772 "set_option operation\n", cipher->name);
|
|
773 }
|
|
774
|
|
775 gpointer
|
|
776 gaim_cipher_context_get_option(GaimCipherContext *context, const gchar *name) {
|
|
777 GaimCipher *cipher = NULL;
|
|
778
|
|
779 g_return_val_if_fail(context, NULL);
|
|
780 g_return_val_if_fail(name, NULL);
|
|
781
|
|
782 cipher = context->cipher;
|
|
783 g_return_val_if_fail(cipher, NULL);
|
|
784
|
|
785 if(cipher->ops && cipher->ops->get_option)
|
|
786 return cipher->ops->get_option(context, name);
|
|
787 else {
|
|
788 gaim_debug_info("cipher", "the %s cipher does not support the "
|
|
789 "get_option operation\n", cipher->name);
|
|
790
|
|
791 return NULL;
|
|
792 }
|
|
793 }
|
|
794
|
|
795 GaimCipherContext *
|
|
796 gaim_cipher_context_new(GaimCipher *cipher, void *extra) {
|
|
797 GaimCipherContext *context = NULL;
|
|
798
|
|
799 g_return_val_if_fail(cipher, NULL);
|
|
800
|
|
801 cipher->ref++;
|
|
802
|
|
803 context = g_new0(GaimCipherContext, 1);
|
|
804 context->cipher = cipher;
|
|
805
|
|
806 if(cipher->ops->init)
|
|
807 cipher->ops->init(context, extra);
|
|
808
|
|
809 return context;
|
|
810 }
|
|
811
|
|
812 GaimCipherContext *
|
|
813 gaim_cipher_context_new_by_name(const gchar *name, void *extra) {
|
|
814 GaimCipher *cipher;
|
|
815
|
|
816 g_return_val_if_fail(name, NULL);
|
|
817
|
|
818 cipher = gaim_ciphers_find_cipher(name);
|
|
819
|
|
820 g_return_val_if_fail(cipher, NULL);
|
|
821
|
|
822 return gaim_cipher_context_new(cipher, extra);
|
|
823 }
|
|
824
|
|
825 void
|
|
826 gaim_cipher_context_reset(GaimCipherContext *context, void *extra) {
|
|
827 GaimCipher *cipher = NULL;
|
|
828
|
|
829 g_return_if_fail(context);
|
|
830
|
|
831 cipher = context->cipher;
|
|
832 g_return_if_fail(cipher);
|
|
833
|
|
834 if(cipher->ops && cipher->ops->reset)
|
|
835 context->cipher->ops->reset(context, extra);
|
|
836 }
|
|
837
|
|
838 void
|
|
839 gaim_cipher_context_destroy(GaimCipherContext *context) {
|
|
840 GaimCipher *cipher = NULL;
|
|
841
|
|
842 g_return_if_fail(context);
|
|
843
|
|
844 cipher = context->cipher;
|
|
845 g_return_if_fail(cipher);
|
|
846
|
|
847 cipher->ref--;
|
|
848
|
|
849 if(cipher->ops && cipher->ops->uninit)
|
|
850 cipher->ops->uninit(context);
|
|
851
|
|
852 memset(context, 0, sizeof(context));
|
|
853 g_free(context);
|
|
854 context = NULL;
|
|
855 }
|
|
856
|
|
857 void
|
|
858 gaim_cipher_context_set_iv(GaimCipherContext *context, guint8 *iv, size_t len)
|
|
859 {
|
|
860 GaimCipher *cipher = NULL;
|
|
861
|
|
862 g_return_if_fail(context);
|
|
863 g_return_if_fail(iv);
|
|
864
|
|
865 cipher = context->cipher;
|
|
866 g_return_if_fail(cipher);
|
|
867
|
|
868 if(cipher->ops && cipher->ops->set_iv)
|
|
869 cipher->ops->set_iv(context, iv, len);
|
|
870 else
|
|
871 gaim_debug_info("cipher", "the %s cipher does not support the set"
|
|
872 "initialization vector operation\n", cipher->name);
|
|
873 }
|
|
874
|
|
875 void
|
|
876 gaim_cipher_context_append(GaimCipherContext *context, const guint8 *data,
|
|
877 size_t len)
|
|
878 {
|
|
879 GaimCipher *cipher = NULL;
|
|
880
|
|
881 g_return_if_fail(context);
|
|
882
|
|
883 cipher = context->cipher;
|
|
884 g_return_if_fail(cipher);
|
|
885
|
|
886 if(cipher->ops && cipher->ops->append)
|
|
887 cipher->ops->append(context, data, len);
|
|
888 else
|
|
889 gaim_debug_info("cipher", "the %s cipher does not support the append "
|
|
890 "operation\n", cipher->name);
|
|
891 }
|
|
892
|
|
893 gboolean
|
|
894 gaim_cipher_context_digest(GaimCipherContext *context, size_t *len,
|
|
895 guint8 digest[])
|
|
896 {
|
|
897 GaimCipher *cipher = NULL;
|
|
898
|
|
899 g_return_val_if_fail(context, FALSE);
|
|
900
|
|
901 cipher = context->cipher;
|
|
902 g_return_val_if_fail(context, FALSE);
|
|
903
|
|
904 if(cipher->ops && cipher->ops->digest)
|
|
905 return cipher->ops->digest(context, len, digest);
|
|
906 else {
|
|
907 gaim_debug_info("cipher", "the %s cipher does not support the digest "
|
|
908 "operation\n", cipher->name);
|
|
909 return FALSE;
|
|
910 }
|
|
911 }
|
|
912
|
|
913 gboolean
|
|
914 gaim_cipher_context_digest_to_str(GaimCipherContext *context, size_t *len,
|
|
915 gchar digest_s[])
|
|
916 {
|
|
917 /* 16k is a bit excessive, will tweak later. */
|
|
918 guint8 digest[BUF_LEN * 4];
|
|
919 gint n = 0;
|
|
920 size_t dlen = 0;
|
|
921
|
|
922 g_return_val_if_fail(context, FALSE);
|
|
923 g_return_val_if_fail(digest_s, FALSE);
|
|
924
|
|
925 if(!gaim_cipher_context_digest(context, &dlen, digest))
|
|
926 return FALSE;
|
|
927
|
|
928 dlen *= 2;
|
|
929
|
|
930 if(len)
|
|
931 *len = dlen;
|
|
932
|
|
933 for(n = 0; n < dlen; n++)
|
|
934 sprintf(digest_s + (n * 2), "%02x", digest[n]);
|
|
935
|
|
936 digest_s[n * 2] = '\0';
|
|
937
|
|
938 return TRUE;
|
|
939 }
|
|
940
|
|
941 gint
|
|
942 gaim_cipher_context_encrypt(GaimCipherContext *context, const guint8 data[],
|
|
943 size_t len, guint8 output[], size_t *outlen)
|
|
944 {
|
|
945 GaimCipher *cipher = NULL;
|
|
946
|
|
947 g_return_val_if_fail(context, -1);
|
|
948
|
|
949 cipher = context->cipher;
|
|
950 g_return_val_if_fail(cipher, -1);
|
|
951
|
|
952 if(cipher->ops && cipher->ops->encrypt)
|
|
953 return cipher->ops->encrypt(context, data, len, output, outlen);
|
|
954 else {
|
|
955 gaim_debug_info("cipher", "the %s cipher does not support the encrypt"
|
|
956 "operation\n", cipher->name);
|
|
957
|
|
958 if(outlen)
|
|
959 *outlen = -1;
|
|
960
|
|
961 return -1;
|
|
962 }
|
|
963 }
|
|
964
|
|
965 gint
|
|
966 gaim_cipher_context_decrypt(GaimCipherContext *context, const guint8 data[],
|
|
967 size_t len, guint8 output[], size_t *outlen)
|
|
968 {
|
|
969 GaimCipher *cipher = NULL;
|
|
970
|
|
971 g_return_val_if_fail(context, -1);
|
|
972
|
|
973 cipher = context->cipher;
|
|
974 g_return_val_if_fail(cipher, -1);
|
|
975
|
|
976 if(cipher->ops && cipher->ops->decrypt)
|
|
977 return cipher->ops->decrypt(context, data, len, output, outlen);
|
|
978 else {
|
|
979 gaim_debug_info("cipher", "the %s cipher does not support the decrypt"
|
|
980 "operation\n", cipher->name);
|
|
981
|
|
982 if(outlen)
|
|
983 *outlen = -1;
|
|
984
|
|
985 return -1;
|
|
986 }
|
|
987 }
|
|
988
|
|
989 void
|
|
990 gaim_cipher_context_set_salt(GaimCipherContext *context, guint8 *salt) {
|
|
991 GaimCipher *cipher = NULL;
|
|
992
|
|
993 g_return_if_fail(context);
|
|
994
|
|
995 cipher = context->cipher;
|
|
996 g_return_if_fail(cipher);
|
|
997
|
|
998 if(cipher->ops && cipher->ops->set_salt)
|
|
999 cipher->ops->set_salt(context, salt);
|
|
1000 else
|
|
1001 gaim_debug_info("cipher", "the %s cipher does not support the "
|
|
1002 "set_salt operation\n", cipher->name);
|
|
1003 }
|
|
1004
|
|
1005 size_t
|
|
1006 gaim_cipher_context_get_salt_size(GaimCipherContext *context) {
|
|
1007 GaimCipher *cipher = NULL;
|
|
1008
|
|
1009 g_return_val_if_fail(context, -1);
|
|
1010
|
|
1011 cipher = context->cipher;
|
|
1012 g_return_val_if_fail(cipher, -1);
|
|
1013
|
|
1014 if(cipher->ops && cipher->ops->get_salt_size)
|
|
1015 return cipher->ops->get_salt_size(context);
|
|
1016 else {
|
|
1017 gaim_debug_info("cipher", "the %s cipher does not support the "
|
|
1018 "get_salt_size operation\n", cipher->name);
|
|
1019
|
|
1020 return -1;
|
|
1021 }
|
|
1022 }
|
|
1023
|
|
1024 void
|
|
1025 gaim_cipher_context_set_key(GaimCipherContext *context, guint8 *key) {
|
|
1026 GaimCipher *cipher = NULL;
|
|
1027
|
|
1028 g_return_if_fail(context);
|
|
1029
|
|
1030 cipher = context->cipher;
|
|
1031 g_return_if_fail(cipher);
|
|
1032
|
|
1033 if(cipher->ops && cipher->ops->set_key)
|
|
1034 cipher->ops->set_key(context, key);
|
|
1035 else
|
|
1036 gaim_debug_info("cipher", "the %s cipher does not support the "
|
|
1037 "set_key operation\n", cipher->name);
|
|
1038 }
|
|
1039
|
|
1040 size_t
|
|
1041 gaim_cipher_context_get_key_size(GaimCipherContext *context) {
|
|
1042 GaimCipher *cipher = NULL;
|
|
1043
|
|
1044 g_return_val_if_fail(context, -1);
|
|
1045
|
|
1046 cipher = context->cipher;
|
|
1047 g_return_val_if_fail(cipher, -1);
|
|
1048
|
|
1049 if(cipher->ops && cipher->ops->get_key_size)
|
|
1050 return cipher->ops->get_key_size(context);
|
|
1051 else {
|
|
1052 gaim_debug_info("cipher", "the %s cipher does not support the "
|
|
1053 "get_key_size operation\n", cipher->name);
|
|
1054
|
|
1055 return -1;
|
|
1056 }
|
|
1057 }
|
|
1058
|
|
1059 void
|
|
1060 gaim_cipher_context_set_data(GaimCipherContext *context, gpointer data) {
|
|
1061 g_return_if_fail(context);
|
|
1062
|
|
1063 context->data = data;
|
|
1064 }
|
|
1065
|
|
1066 gpointer
|
|
1067 gaim_cipher_context_get_data(GaimCipherContext *context) {
|
|
1068 g_return_val_if_fail(context, NULL);
|
|
1069
|
|
1070 return context->data;
|
|
1071 }
|