comparison src/cipher.c @ 10684:72a5babfa8b4

[gaim-migrate @ 12231] the cipher api that grim has been working on for ages is finally done!! big congrats and thanks to him!! lots of modified files in this commit. it builds here. moved the md5 files to src/protocols/oscar so that it continues to depend on nothing in gaim. everything else uses the new centralized cipher api. I'm not sure if src/md5.* needs to be removed or not, so I left it there. someone let me know or do it directly. someone check if these need to be added to potfiles.in and let there be much rejoicing! committer: Tailor Script <tailor@pidgin.im>
author Luke Schierer <lschiere@pidgin.im>
date Fri, 11 Mar 2005 13:05:31 +0000
parents
children b256ce6b85b8
comparison
equal deleted inserted replaced
10683:e11f3e1599d4 10684:72a5babfa8b4
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 }