Mercurial > pidgin.yaz
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 } |