comparison libgaim/cipher.c @ 14192:60b1bc8dbf37

[gaim-migrate @ 16863] Renamed 'core' to 'libgaim' committer: Tailor Script <tailor@pidgin.im>
author Evan Schoenberg <evan.s@dreskin.net>
date Sat, 19 Aug 2006 01:50:10 +0000
parents
children
comparison
equal deleted inserted replaced
14191:009db0b357b5 14192:60b1bc8dbf37
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 * Original md4 taken from linux kernel
12 * MD4 Message Digest Algorithm (RFC1320).
13 *
14 * Implementation derived from Andrew Tridgell and Steve French's
15 * CIFS MD4 implementation, and the cryptoapi implementation
16 * originally based on the public domain implementation written
17 * by Colin Plumb in 1993.
18 *
19 * Copyright (c) Andrew Tridgell 1997-1998.
20 * Modified by Steve French (sfrench@us.ibm.com) 2002
21 * Copyright (c) Cryptoapi developers.
22 * Copyright (c) 2002 David S. Miller (davem@redhat.com)
23 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
24 *
25 * Original des taken from gpg
26 *
27 * des.c - DES and Triple-DES encryption/decryption Algorithm
28 * Copyright (C) 1998 Free Software Foundation, Inc.
29 *
30 * Please see below for more legal information!
31 *
32 * According to the definition of DES in FIPS PUB 46-2 from December 1993.
33 * For a description of triple encryption, see:
34 * Bruce Schneier: Applied Cryptography. Second Edition.
35 * John Wiley & Sons, 1996. ISBN 0-471-12845-7. Pages 358 ff.
36 *
37 * This file is part of GnuPG.
38 *
39 * This program is free software; you can redistribute it and/or modify
40 * it under the terms of the GNU General Public License as published by
41 * the Free Software Foundation; either version 2 of the License, or
42 * (at your option) any later version.
43 *
44 * This program is distributed in the hope that it will be useful,
45 * but WITHOUT ANY WARRANTY; without even the implied warranty of
46 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
47 * GNU General Public License for more details.
48 *
49 * You should have received a copy of the GNU General Public License
50 * along with this program; if not, write to the Free Software
51 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
52 */
53 #include <glib.h>
54 #include <string.h>
55 #include <stdio.h>
56
57 #include "internal.h"
58 #include "cipher.h"
59 #include "dbus-maybe.h"
60 #include "debug.h"
61 #include "signals.h"
62 #include "value.h"
63
64 /*******************************************************************************
65 * MD5
66 ******************************************************************************/
67 struct MD5Context {
68 guint32 total[2];
69 guint32 state[4];
70 guchar buffer[64];
71 };
72
73 #define MD5_GET_GUINT32(n,b,i) { \
74 (n) = ((guint32)(b) [(i) ] ) \
75 | ((guint32)(b) [(i) + 1] << 8) \
76 | ((guint32)(b) [(i) + 2] << 16) \
77 | ((guint32)(b) [(i) + 3] << 24); \
78 }
79 #define MD5_PUT_GUINT32(n,b,i) { \
80 (b)[(i) ] = (guchar)((n) ); \
81 (b)[(i) + 1] = (guchar)((n) >> 8); \
82 (b)[(i) + 2] = (guchar)((n) >> 16); \
83 (b)[(i) + 3] = (guchar)((n) >> 24); \
84 }
85
86 static void
87 md5_init(GaimCipherContext *context, gpointer extra) {
88 struct MD5Context *md5_context;
89
90 md5_context = g_new0(struct MD5Context, 1);
91
92 gaim_cipher_context_set_data(context, md5_context);
93
94 gaim_cipher_context_reset(context, extra);
95 }
96
97 static void
98 md5_reset(GaimCipherContext *context, gpointer extra) {
99 struct MD5Context *md5_context;
100
101 md5_context = gaim_cipher_context_get_data(context);
102
103 md5_context->total[0] = 0;
104 md5_context->total[1] = 0;
105
106 md5_context->state[0] = 0x67452301;
107 md5_context->state[1] = 0xEFCDAB89;
108 md5_context->state[2] = 0x98BADCFE;
109 md5_context->state[3] = 0x10325476;
110
111 memset(md5_context->buffer, 0, sizeof(md5_context->buffer));
112 }
113
114 static void
115 md5_uninit(GaimCipherContext *context) {
116 struct MD5Context *md5_context;
117
118 gaim_cipher_context_reset(context, NULL);
119
120 md5_context = gaim_cipher_context_get_data(context);
121 memset(md5_context, 0, sizeof(md5_context));
122
123 g_free(md5_context);
124 md5_context = NULL;
125 }
126
127 static void
128 md5_process(struct MD5Context *md5_context, const guchar data[64]) {
129 guint32 X[16], A, B, C, D;
130
131 A = md5_context->state[0];
132 B = md5_context->state[1];
133 C = md5_context->state[2];
134 D = md5_context->state[3];
135
136 MD5_GET_GUINT32(X[ 0], data, 0);
137 MD5_GET_GUINT32(X[ 1], data, 4);
138 MD5_GET_GUINT32(X[ 2], data, 8);
139 MD5_GET_GUINT32(X[ 3], data, 12);
140 MD5_GET_GUINT32(X[ 4], data, 16);
141 MD5_GET_GUINT32(X[ 5], data, 20);
142 MD5_GET_GUINT32(X[ 6], data, 24);
143 MD5_GET_GUINT32(X[ 7], data, 28);
144 MD5_GET_GUINT32(X[ 8], data, 32);
145 MD5_GET_GUINT32(X[ 9], data, 36);
146 MD5_GET_GUINT32(X[10], data, 40);
147 MD5_GET_GUINT32(X[11], data, 44);
148 MD5_GET_GUINT32(X[12], data, 48);
149 MD5_GET_GUINT32(X[13], data, 52);
150 MD5_GET_GUINT32(X[14], data, 56);
151 MD5_GET_GUINT32(X[15], data, 60);
152
153 #define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
154 #define P(a,b,c,d,k,s,t) { \
155 a += F(b,c,d) + X[k] + t; \
156 a = S(a,s) + b; \
157 }
158
159 /* first pass */
160 #define F(x,y,z) (z ^ (x & (y ^ z)))
161 P(A, B, C, D, 0, 7, 0xD76AA478);
162 P(D, A, B, C, 1, 12, 0xE8C7B756);
163 P(C, D, A, B, 2, 17, 0x242070DB);
164 P(B, C, D, A, 3, 22, 0xC1BDCEEE);
165 P(A, B, C, D, 4, 7, 0xF57C0FAF);
166 P(D, A, B, C, 5, 12, 0x4787C62A);
167 P(C, D, A, B, 6, 17, 0xA8304613);
168 P(B, C, D, A, 7, 22, 0xFD469501);
169 P(A, B, C, D, 8, 7, 0x698098D8);
170 P(D, A, B, C, 9, 12, 0x8B44F7AF);
171 P(C, D, A, B, 10, 17, 0xFFFF5BB1);
172 P(B, C, D, A, 11, 22, 0x895CD7BE);
173 P(A, B, C, D, 12, 7, 0x6B901122);
174 P(D, A, B, C, 13, 12, 0xFD987193);
175 P(C, D, A, B, 14, 17, 0xA679438E);
176 P(B, C, D, A, 15, 22, 0x49B40821);
177 #undef F
178
179 /* second pass */
180 #define F(x,y,z) (y ^ (z & (x ^ y)))
181 P(A, B, C, D, 1, 5, 0xF61E2562);
182 P(D, A, B, C, 6, 9, 0xC040B340);
183 P(C, D, A, B, 11, 14, 0x265E5A51);
184 P(B, C, D, A, 0, 20, 0xE9B6C7AA);
185 P(A, B, C, D, 5, 5, 0xD62F105D);
186 P(D, A, B, C, 10, 9, 0x02441453);
187 P(C, D, A, B, 15, 14, 0xD8A1E681);
188 P(B, C, D, A, 4, 20, 0xE7D3FBC8);
189 P(A, B, C, D, 9, 5, 0x21E1CDE6);
190 P(D, A, B, C, 14, 9, 0xC33707D6);
191 P(C, D, A, B, 3, 14, 0xF4D50D87);
192 P(B, C, D, A, 8, 20, 0x455A14ED);
193 P(A, B, C, D, 13, 5, 0xA9E3E905);
194 P(D, A, B, C, 2, 9, 0xFCEFA3F8);
195 P(C, D, A, B, 7, 14, 0x676F02D9);
196 P(B, C, D, A, 12, 20, 0x8D2A4C8A);
197 #undef F
198
199 /* third pass */
200 #define F(x,y,z) (x ^ y ^ z)
201 P(A, B, C, D, 5, 4, 0xFFFA3942);
202 P(D, A, B, C, 8, 11, 0x8771F681);
203 P(C, D, A, B, 11, 16, 0x6D9D6122);
204 P(B, C, D, A, 14, 23, 0xFDE5380C);
205 P(A, B, C, D, 1, 4, 0xA4BEEA44);
206 P(D, A, B, C, 4, 11, 0x4BDECFA9);
207 P(C, D, A, B, 7, 16, 0xF6BB4B60);
208 P(B, C, D, A, 10, 23, 0xBEBFBC70);
209 P(A, B, C, D, 13, 4, 0x289B7EC6);
210 P(D, A, B, C, 0, 11, 0xEAA127FA);
211 P(C, D, A, B, 3, 16, 0xD4EF3085);
212 P(B, C, D, A, 6, 23, 0x04881D05);
213 P(A, B, C, D, 9, 4, 0xD9D4D039);
214 P(D, A, B, C, 12, 11, 0xE6DB99E5);
215 P(C, D, A, B, 15, 16, 0x1FA27CF8);
216 P(B, C, D, A, 2, 23, 0xC4AC5665);
217 #undef F
218
219 /* forth pass */
220 #define F(x,y,z) (y ^ (x | ~z))
221 P(A, B, C, D, 0, 6, 0xF4292244);
222 P(D, A, B, C, 7, 10, 0x432AFF97);
223 P(C, D, A, B, 14, 15, 0xAB9423A7);
224 P(B, C, D, A, 5, 21, 0xFC93A039);
225 P(A, B, C, D, 12, 6, 0x655B59C3);
226 P(D, A, B, C, 3, 10, 0x8F0CCC92);
227 P(C, D, A, B, 10, 15, 0xFFEFF47D);
228 P(B, C, D, A, 1, 21, 0x85845DD1);
229 P(A, B, C, D, 8, 6, 0x6FA87E4F);
230 P(D, A, B, C, 15, 10, 0xFE2CE6E0);
231 P(C, D, A, B, 6, 15, 0xA3014314);
232 P(B, C, D, A, 13, 21, 0x4E0811A1);
233 P(A, B, C, D, 4, 6, 0xF7537E82);
234 P(D, A, B, C, 11, 10, 0xBD3AF235);
235 P(C, D, A, B, 2, 15, 0x2AD7D2BB);
236 P(B, C, D, A, 9, 21, 0xEB86D391);
237 #undef F
238 #undef P
239 #undef S
240
241 md5_context->state[0] += A;
242 md5_context->state[1] += B;
243 md5_context->state[2] += C;
244 md5_context->state[3] += D;
245 }
246
247 static void
248 md5_append(GaimCipherContext *context, const guchar *data, size_t len) {
249 struct MD5Context *md5_context = NULL;
250 guint32 left = 0, fill = 0;
251
252 g_return_if_fail(context != NULL);
253
254 md5_context = gaim_cipher_context_get_data(context);
255 g_return_if_fail(md5_context != NULL);
256
257 left = md5_context->total[0] & 0x3F;
258 fill = 64 - left;
259
260 md5_context->total[0] += len;
261 md5_context->total[0] &= 0xFFFFFFFF;
262
263 if(md5_context->total[0] < len)
264 md5_context->total[1]++;
265
266 if(left && len >= fill) {
267 memcpy((md5_context->buffer + left), data, fill);
268 md5_process(md5_context, md5_context->buffer);
269 len -= fill;
270 data += fill;
271 left = 0;
272 }
273
274 while(len >= 64) {
275 md5_process(md5_context, data);
276 len -= 64;
277 data += 64;
278 }
279
280 if(len) {
281 memcpy((md5_context->buffer + left), data, len);
282 }
283 }
284
285 static gboolean
286 md5_digest(GaimCipherContext *context, size_t in_len, guchar digest[16],
287 size_t *out_len)
288 {
289 struct MD5Context *md5_context = NULL;
290 guint32 last, pad;
291 guint32 high, low;
292 guchar message[8];
293 guchar padding[64] = {
294 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
295 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
296 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
297 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
298 };
299
300 g_return_val_if_fail(in_len >= 16, FALSE);
301
302 md5_context = gaim_cipher_context_get_data(context);
303
304 high = (md5_context->total[0] >> 29)
305 | (md5_context->total[1] << 3);
306 low = (md5_context->total[0] << 3);
307
308 MD5_PUT_GUINT32(low, message, 0);
309 MD5_PUT_GUINT32(high, message, 4);
310
311 last = md5_context->total[0] & 0x3F;
312 pad = (last < 56) ? (56 - last) : (120 - last);
313
314 md5_append(context, padding, pad);
315 md5_append(context, message, 8);
316
317 MD5_PUT_GUINT32(md5_context->state[0], digest, 0);
318 MD5_PUT_GUINT32(md5_context->state[1], digest, 4);
319 MD5_PUT_GUINT32(md5_context->state[2], digest, 8);
320 MD5_PUT_GUINT32(md5_context->state[3], digest, 12);
321
322 if(out_len)
323 *out_len = 16;
324
325 return TRUE;
326 }
327
328 static GaimCipherOps MD5Ops = {
329 NULL, /* Set option */
330 NULL, /* Get option */
331 md5_init, /* init */
332 md5_reset, /* reset */
333 md5_uninit, /* uninit */
334 NULL, /* set iv */
335 md5_append, /* append */
336 md5_digest, /* digest */
337 NULL, /* encrypt */
338 NULL, /* decrypt */
339 NULL, /* set salt */
340 NULL, /* get salt size */
341 NULL, /* set key */
342 NULL /* get key size */
343 };
344
345 /*******************************************************************************
346 * MD4
347 ******************************************************************************/
348 #define MD4_DIGEST_SIZE 16
349 #define MD4_HMAC_BLOCK_SIZE 64
350 #define MD4_BLOCK_WORDS 16
351 #define MD4_HASH_WORDS 4
352
353
354
355 struct MD4_Context {
356 guint32 hash[MD4_HASH_WORDS];
357 guint32 block[MD4_BLOCK_WORDS];
358 guint64 byte_count;
359 };
360
361 static inline guint32 lshift(guint32 x, unsigned int s)
362 {
363 x &= 0xFFFFFFFF;
364 return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s));
365 }
366
367 static inline guint32 F(guint32 x, guint32 y, guint32 z)
368 {
369 return (x & y) | ((~x) & z);
370 }
371
372 static inline guint32 G(guint32 x, guint32 y, guint32 z)
373 {
374 return (x & y) | (x & z) | (y & z);
375 }
376
377 static inline guint32 H(guint32 x, guint32 y, guint32 z)
378 {
379 return x ^ y ^ z;
380 }
381
382 #define ROUND1(a,b,c,d,k,s) (a = lshift(a + F(b,c,d) + k, s))
383 #define ROUND2(a,b,c,d,k,s) (a = lshift(a + G(b,c,d) + k + (guint32)0x5A827999,s))
384 #define ROUND3(a,b,c,d,k,s) (a = lshift(a + H(b,c,d) + k + (guint32)0x6ED9EBA1,s))
385
386 static inline void le32_to_cpu_array(guint32 *buf, unsigned int words)
387 {
388 while (words--) {
389 *buf=GUINT_FROM_LE(*buf);
390 buf++;
391 }
392 }
393
394 static inline void cpu_to_le32_array(guint32 *buf, unsigned int words)
395 {
396 while (words--) {
397 *buf=GUINT_TO_LE(*buf);
398 buf++;
399 }
400 }
401
402 static void md4_transform(guint32 *hash, guint32 const *in)
403 {
404 guint32 a, b, c, d;
405
406 a = hash[0];
407 b = hash[1];
408 c = hash[2];
409 d = hash[3];
410
411 ROUND1(a, b, c, d, in[0], 3);
412 ROUND1(d, a, b, c, in[1], 7);
413 ROUND1(c, d, a, b, in[2], 11);
414 ROUND1(b, c, d, a, in[3], 19);
415 ROUND1(a, b, c, d, in[4], 3);
416 ROUND1(d, a, b, c, in[5], 7);
417 ROUND1(c, d, a, b, in[6], 11);
418 ROUND1(b, c, d, a, in[7], 19);
419 ROUND1(a, b, c, d, in[8], 3);
420 ROUND1(d, a, b, c, in[9], 7);
421 ROUND1(c, d, a, b, in[10], 11);
422 ROUND1(b, c, d, a, in[11], 19);
423 ROUND1(a, b, c, d, in[12], 3);
424 ROUND1(d, a, b, c, in[13], 7);
425 ROUND1(c, d, a, b, in[14], 11);
426 ROUND1(b, c, d, a, in[15], 19);
427
428 ROUND2(a, b, c, d,in[ 0], 3);
429 ROUND2(d, a, b, c, in[4], 5);
430 ROUND2(c, d, a, b, in[8], 9);
431 ROUND2(b, c, d, a, in[12], 13);
432 ROUND2(a, b, c, d, in[1], 3);
433 ROUND2(d, a, b, c, in[5], 5);
434 ROUND2(c, d, a, b, in[9], 9);
435 ROUND2(b, c, d, a, in[13], 13);
436 ROUND2(a, b, c, d, in[2], 3);
437 ROUND2(d, a, b, c, in[6], 5);
438 ROUND2(c, d, a, b, in[10], 9);
439 ROUND2(b, c, d, a, in[14], 13);
440 ROUND2(a, b, c, d, in[3], 3);
441 ROUND2(d, a, b, c, in[7], 5);
442 ROUND2(c, d, a, b, in[11], 9);
443 ROUND2(b, c, d, a, in[15], 13);
444
445 ROUND3(a, b, c, d,in[ 0], 3);
446 ROUND3(d, a, b, c, in[8], 9);
447 ROUND3(c, d, a, b, in[4], 11);
448 ROUND3(b, c, d, a, in[12], 15);
449 ROUND3(a, b, c, d, in[2], 3);
450 ROUND3(d, a, b, c, in[10], 9);
451 ROUND3(c, d, a, b, in[6], 11);
452 ROUND3(b, c, d, a, in[14], 15);
453 ROUND3(a, b, c, d, in[1], 3);
454 ROUND3(d, a, b, c, in[9], 9);
455 ROUND3(c, d, a, b, in[5], 11);
456 ROUND3(b, c, d, a, in[13], 15);
457 ROUND3(a, b, c, d, in[3], 3);
458 ROUND3(d, a, b, c, in[11], 9);
459 ROUND3(c, d, a, b, in[7], 11);
460 ROUND3(b, c, d, a, in[15], 15);
461
462 hash[0] += a;
463 hash[1] += b;
464 hash[2] += c;
465 hash[3] += d;
466 }
467
468 static inline void md4_transform_helper(struct MD4_Context *ctx)
469 {
470 le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(guint32));
471 md4_transform(ctx->hash, ctx->block);
472 }
473
474 static void
475 md4_init(GaimCipherContext *context, gpointer extra) {
476 struct MD4_Context *mctx;
477 mctx = g_new0(struct MD4_Context, 1);
478 gaim_cipher_context_set_data(context, mctx);
479 gaim_cipher_context_reset(context, extra);
480
481 mctx->hash[0] = 0x67452301;
482 mctx->hash[1] = 0xefcdab89;
483 mctx->hash[2] = 0x98badcfe;
484 mctx->hash[3] = 0x10325476;
485 mctx->byte_count = 0;
486 }
487
488 static void
489 md4_reset(GaimCipherContext *context, gpointer extra) {
490 struct MD4_Context *mctx;
491
492 mctx = gaim_cipher_context_get_data(context);
493
494 mctx->hash[0] = 0x67452301;
495 mctx->hash[1] = 0xefcdab89;
496 mctx->hash[2] = 0x98badcfe;
497 mctx->hash[3] = 0x10325476;
498 mctx->byte_count = 0;
499 }
500
501 static void
502 md4_append(GaimCipherContext *context, const guchar *data, size_t len)
503 {
504 struct MD4_Context *mctx = gaim_cipher_context_get_data(context);
505 const guint32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
506
507 mctx->byte_count += len;
508
509 if (avail > len) {
510 memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
511 data, len);
512 return;
513 }
514
515 memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
516 data, avail);
517
518 md4_transform_helper(mctx);
519 data += avail;
520 len -= avail;
521
522 while (len >= sizeof(mctx->block)) {
523 memcpy(mctx->block, data, sizeof(mctx->block));
524 md4_transform_helper(mctx);
525 data += sizeof(mctx->block);
526 len -= sizeof(mctx->block);
527 }
528
529 memcpy(mctx->block, data, len);
530 }
531
532 static gboolean
533 md4_digest(GaimCipherContext *context, size_t in_len, guchar *out,
534 size_t *out_len)
535 {
536 struct MD4_Context *mctx = gaim_cipher_context_get_data(context);
537 const unsigned int offset = mctx->byte_count & 0x3f;
538 char *p = (char *)mctx->block + offset;
539 int padding = 56 - (offset + 1);
540
541
542 if(in_len<16) return FALSE;
543 if(out_len) *out_len = 16;
544 *p++ = 0x80;
545 if (padding < 0) {
546 memset(p, 0x00, padding + sizeof (guint64));
547 md4_transform_helper(mctx);
548 p = (char *)mctx->block;
549 padding = 56;
550 }
551
552 memset(p, 0, padding);
553 mctx->block[14] = mctx->byte_count << 3;
554 mctx->block[15] = mctx->byte_count >> 29;
555 le32_to_cpu_array(mctx->block, (sizeof(mctx->block) -
556 sizeof(guint64)) / sizeof(guint32));
557 md4_transform(mctx->hash, mctx->block);
558 cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(guint32));
559 memcpy(out, mctx->hash, sizeof(mctx->hash));
560 memset(mctx, 0, sizeof(*mctx));
561 return TRUE;
562 }
563
564 static void
565 md4_uninit(GaimCipherContext *context) {
566 struct MD4_Context *md4_context;
567
568 gaim_cipher_context_reset(context, NULL);
569
570 md4_context = gaim_cipher_context_get_data(context);
571 memset(md4_context, 0, sizeof(md4_context));
572
573 g_free(md4_context);
574 md4_context = NULL;
575 }
576
577 static GaimCipherOps MD4Ops = {
578 NULL, /* Set option */
579 NULL, /* Get option */
580 md4_init, /* init */
581 md4_reset, /* reset */
582 md4_uninit, /* uninit */
583 NULL, /* set iv */
584 md4_append, /* append */
585 md4_digest, /* digest */
586 NULL, /* encrypt */
587 NULL, /* decrypt */
588 NULL, /* set salt */
589 NULL, /* get salt size */
590 NULL, /* set key */
591 NULL /* get key size */
592 };
593
594 /******************************************************************************
595 * DES
596 *****************************************************************************/
597
598 typedef struct _des_ctx
599 {
600 guint32 encrypt_subkeys[32];
601 guint32 decrypt_subkeys[32];
602 } des_ctx[1];
603
604 /*
605 * The s-box values are permuted according to the 'primitive function P'
606 */
607 static guint32 sbox1[64] =
608 {
609 0x00808200, 0x00000000, 0x00008000, 0x00808202, 0x00808002, 0x00008202, 0x00000002, 0x00008000,
610 0x00000200, 0x00808200, 0x00808202, 0x00000200, 0x00800202, 0x00808002, 0x00800000, 0x00000002,
611 0x00000202, 0x00800200, 0x00800200, 0x00008200, 0x00008200, 0x00808000, 0x00808000, 0x00800202,
612 0x00008002, 0x00800002, 0x00800002, 0x00008002, 0x00000000, 0x00000202, 0x00008202, 0x00800000,
613 0x00008000, 0x00808202, 0x00000002, 0x00808000, 0x00808200, 0x00800000, 0x00800000, 0x00000200,
614 0x00808002, 0x00008000, 0x00008200, 0x00800002, 0x00000200, 0x00000002, 0x00800202, 0x00008202,
615 0x00808202, 0x00008002, 0x00808000, 0x00800202, 0x00800002, 0x00000202, 0x00008202, 0x00808200,
616 0x00000202, 0x00800200, 0x00800200, 0x00000000, 0x00008002, 0x00008200, 0x00000000, 0x00808002
617 };
618
619 static guint32 sbox2[64] =
620 {
621 0x40084010, 0x40004000, 0x00004000, 0x00084010, 0x00080000, 0x00000010, 0x40080010, 0x40004010,
622 0x40000010, 0x40084010, 0x40084000, 0x40000000, 0x40004000, 0x00080000, 0x00000010, 0x40080010,
623 0x00084000, 0x00080010, 0x40004010, 0x00000000, 0x40000000, 0x00004000, 0x00084010, 0x40080000,
624 0x00080010, 0x40000010, 0x00000000, 0x00084000, 0x00004010, 0x40084000, 0x40080000, 0x00004010,
625 0x00000000, 0x00084010, 0x40080010, 0x00080000, 0x40004010, 0x40080000, 0x40084000, 0x00004000,
626 0x40080000, 0x40004000, 0x00000010, 0x40084010, 0x00084010, 0x00000010, 0x00004000, 0x40000000,
627 0x00004010, 0x40084000, 0x00080000, 0x40000010, 0x00080010, 0x40004010, 0x40000010, 0x00080010,
628 0x00084000, 0x00000000, 0x40004000, 0x00004010, 0x40000000, 0x40080010, 0x40084010, 0x00084000
629 };
630
631 static guint32 sbox3[64] =
632 {
633 0x00000104, 0x04010100, 0x00000000, 0x04010004, 0x04000100, 0x00000000, 0x00010104, 0x04000100,
634 0x00010004, 0x04000004, 0x04000004, 0x00010000, 0x04010104, 0x00010004, 0x04010000, 0x00000104,
635 0x04000000, 0x00000004, 0x04010100, 0x00000100, 0x00010100, 0x04010000, 0x04010004, 0x00010104,
636 0x04000104, 0x00010100, 0x00010000, 0x04000104, 0x00000004, 0x04010104, 0x00000100, 0x04000000,
637 0x04010100, 0x04000000, 0x00010004, 0x00000104, 0x00010000, 0x04010100, 0x04000100, 0x00000000,
638 0x00000100, 0x00010004, 0x04010104, 0x04000100, 0x04000004, 0x00000100, 0x00000000, 0x04010004,
639 0x04000104, 0x00010000, 0x04000000, 0x04010104, 0x00000004, 0x00010104, 0x00010100, 0x04000004,
640 0x04010000, 0x04000104, 0x00000104, 0x04010000, 0x00010104, 0x00000004, 0x04010004, 0x00010100
641 };
642
643 static guint32 sbox4[64] =
644 {
645 0x80401000, 0x80001040, 0x80001040, 0x00000040, 0x00401040, 0x80400040, 0x80400000, 0x80001000,
646 0x00000000, 0x00401000, 0x00401000, 0x80401040, 0x80000040, 0x00000000, 0x00400040, 0x80400000,
647 0x80000000, 0x00001000, 0x00400000, 0x80401000, 0x00000040, 0x00400000, 0x80001000, 0x00001040,
648 0x80400040, 0x80000000, 0x00001040, 0x00400040, 0x00001000, 0x00401040, 0x80401040, 0x80000040,
649 0x00400040, 0x80400000, 0x00401000, 0x80401040, 0x80000040, 0x00000000, 0x00000000, 0x00401000,
650 0x00001040, 0x00400040, 0x80400040, 0x80000000, 0x80401000, 0x80001040, 0x80001040, 0x00000040,
651 0x80401040, 0x80000040, 0x80000000, 0x00001000, 0x80400000, 0x80001000, 0x00401040, 0x80400040,
652 0x80001000, 0x00001040, 0x00400000, 0x80401000, 0x00000040, 0x00400000, 0x00001000, 0x00401040
653 };
654
655 static guint32 sbox5[64] =
656 {
657 0x00000080, 0x01040080, 0x01040000, 0x21000080, 0x00040000, 0x00000080, 0x20000000, 0x01040000,
658 0x20040080, 0x00040000, 0x01000080, 0x20040080, 0x21000080, 0x21040000, 0x00040080, 0x20000000,
659 0x01000000, 0x20040000, 0x20040000, 0x00000000, 0x20000080, 0x21040080, 0x21040080, 0x01000080,
660 0x21040000, 0x20000080, 0x00000000, 0x21000000, 0x01040080, 0x01000000, 0x21000000, 0x00040080,
661 0x00040000, 0x21000080, 0x00000080, 0x01000000, 0x20000000, 0x01040000, 0x21000080, 0x20040080,
662 0x01000080, 0x20000000, 0x21040000, 0x01040080, 0x20040080, 0x00000080, 0x01000000, 0x21040000,
663 0x21040080, 0x00040080, 0x21000000, 0x21040080, 0x01040000, 0x00000000, 0x20040000, 0x21000000,
664 0x00040080, 0x01000080, 0x20000080, 0x00040000, 0x00000000, 0x20040000, 0x01040080, 0x20000080
665 };
666
667 static guint32 sbox6[64] =
668 {
669 0x10000008, 0x10200000, 0x00002000, 0x10202008, 0x10200000, 0x00000008, 0x10202008, 0x00200000,
670 0x10002000, 0x00202008, 0x00200000, 0x10000008, 0x00200008, 0x10002000, 0x10000000, 0x00002008,
671 0x00000000, 0x00200008, 0x10002008, 0x00002000, 0x00202000, 0x10002008, 0x00000008, 0x10200008,
672 0x10200008, 0x00000000, 0x00202008, 0x10202000, 0x00002008, 0x00202000, 0x10202000, 0x10000000,
673 0x10002000, 0x00000008, 0x10200008, 0x00202000, 0x10202008, 0x00200000, 0x00002008, 0x10000008,
674 0x00200000, 0x10002000, 0x10000000, 0x00002008, 0x10000008, 0x10202008, 0x00202000, 0x10200000,
675 0x00202008, 0x10202000, 0x00000000, 0x10200008, 0x00000008, 0x00002000, 0x10200000, 0x00202008,
676 0x00002000, 0x00200008, 0x10002008, 0x00000000, 0x10202000, 0x10000000, 0x00200008, 0x10002008
677 };
678
679 static guint32 sbox7[64] =
680 {
681 0x00100000, 0x02100001, 0x02000401, 0x00000000, 0x00000400, 0x02000401, 0x00100401, 0x02100400,
682 0x02100401, 0x00100000, 0x00000000, 0x02000001, 0x00000001, 0x02000000, 0x02100001, 0x00000401,
683 0x02000400, 0x00100401, 0x00100001, 0x02000400, 0x02000001, 0x02100000, 0x02100400, 0x00100001,
684 0x02100000, 0x00000400, 0x00000401, 0x02100401, 0x00100400, 0x00000001, 0x02000000, 0x00100400,
685 0x02000000, 0x00100400, 0x00100000, 0x02000401, 0x02000401, 0x02100001, 0x02100001, 0x00000001,
686 0x00100001, 0x02000000, 0x02000400, 0x00100000, 0x02100400, 0x00000401, 0x00100401, 0x02100400,
687 0x00000401, 0x02000001, 0x02100401, 0x02100000, 0x00100400, 0x00000000, 0x00000001, 0x02100401,
688 0x00000000, 0x00100401, 0x02100000, 0x00000400, 0x02000001, 0x02000400, 0x00000400, 0x00100001
689 };
690
691 static guint32 sbox8[64] =
692 {
693 0x08000820, 0x00000800, 0x00020000, 0x08020820, 0x08000000, 0x08000820, 0x00000020, 0x08000000,
694 0x00020020, 0x08020000, 0x08020820, 0x00020800, 0x08020800, 0x00020820, 0x00000800, 0x00000020,
695 0x08020000, 0x08000020, 0x08000800, 0x00000820, 0x00020800, 0x00020020, 0x08020020, 0x08020800,
696 0x00000820, 0x00000000, 0x00000000, 0x08020020, 0x08000020, 0x08000800, 0x00020820, 0x00020000,
697 0x00020820, 0x00020000, 0x08020800, 0x00000800, 0x00000020, 0x08020020, 0x00000800, 0x00020820,
698 0x08000800, 0x00000020, 0x08000020, 0x08020000, 0x08020020, 0x08000000, 0x00020000, 0x08000820,
699 0x00000000, 0x08020820, 0x00020020, 0x08000020, 0x08020000, 0x08000800, 0x08000820, 0x00000000,
700 0x08020820, 0x00020800, 0x00020800, 0x00000820, 0x00000820, 0x00020020, 0x08000000, 0x08020800
701 };
702
703
704
705 /*
706 * * These two tables are part of the 'permuted choice 1' function.
707 * * In this implementation several speed improvements are done.
708 * */
709 static guint32 leftkey_swap[16] =
710 {
711 0x00000000, 0x00000001, 0x00000100, 0x00000101,
712 0x00010000, 0x00010001, 0x00010100, 0x00010101,
713 0x01000000, 0x01000001, 0x01000100, 0x01000101,
714 0x01010000, 0x01010001, 0x01010100, 0x01010101
715 };
716
717 static guint32 rightkey_swap[16] =
718 {
719 0x00000000, 0x01000000, 0x00010000, 0x01010000,
720 0x00000100, 0x01000100, 0x00010100, 0x01010100,
721 0x00000001, 0x01000001, 0x00010001, 0x01010001,
722 0x00000101, 0x01000101, 0x00010101, 0x01010101,
723 };
724
725
726
727 /*
728 * Numbers of left shifts per round for encryption subkey schedule
729 * To calculate the decryption key scheduling we just reverse the
730 * ordering of the subkeys so we can omit the table for decryption
731 * subkey schedule.
732 */
733 static guint8 encrypt_rotate_tab[16] =
734 {
735 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
736 };
737
738 /*
739 * Macro to swap bits across two words
740 **/
741 #define DO_PERMUTATION(a, temp, b, offset, mask) \
742 temp = ((a>>offset) ^ b) & mask; \
743 b ^= temp; \
744 a ^= temp<<offset;
745
746
747 /*
748 * This performs the 'initial permutation' for the data to be encrypted or decrypted
749 **/
750 #define INITIAL_PERMUTATION(left, temp, right) \
751 DO_PERMUTATION(left, temp, right, 4, 0x0f0f0f0f) \
752 DO_PERMUTATION(left, temp, right, 16, 0x0000ffff) \
753 DO_PERMUTATION(right, temp, left, 2, 0x33333333) \
754 DO_PERMUTATION(right, temp, left, 8, 0x00ff00ff) \
755 DO_PERMUTATION(left, temp, right, 1, 0x55555555)
756
757
758 /*
759 * The 'inverse initial permutation'
760 **/
761 #define FINAL_PERMUTATION(left, temp, right) \
762 DO_PERMUTATION(left, temp, right, 1, 0x55555555) \
763 DO_PERMUTATION(right, temp, left, 8, 0x00ff00ff) \
764 DO_PERMUTATION(right, temp, left, 2, 0x33333333) \
765 DO_PERMUTATION(left, temp, right, 16, 0x0000ffff) \
766 DO_PERMUTATION(left, temp, right, 4, 0x0f0f0f0f)
767
768
769 /*
770 * A full DES round including 'expansion function', 'sbox substitution'
771 * and 'primitive function P' but without swapping the left and right word.
772 **/
773 #define DES_ROUND(from, to, work, subkey) \
774 work = ((from<<1) | (from>>31)) ^ *subkey++; \
775 to ^= sbox8[ work & 0x3f ]; \
776 to ^= sbox6[ (work>>8) & 0x3f ]; \
777 to ^= sbox4[ (work>>16) & 0x3f ]; \
778 to ^= sbox2[ (work>>24) & 0x3f ]; \
779 work = ((from>>3) | (from<<29)) ^ *subkey++; \
780 to ^= sbox7[ work & 0x3f ]; \
781 to ^= sbox5[ (work>>8) & 0x3f ]; \
782 to ^= sbox3[ (work>>16) & 0x3f ]; \
783 to ^= sbox1[ (work>>24) & 0x3f ];
784
785
786 /*
787 * Macros to convert 8 bytes from/to 32bit words
788 **/
789 #define READ_64BIT_DATA(data, left, right) \
790 left = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; \
791 right = (data[4] << 24) | (data[5] << 16) | (data[6] << 8) | data[7];
792
793 #define WRITE_64BIT_DATA(data, left, right) \
794 data[0] = (left >> 24) &0xff; data[1] = (left >> 16) &0xff; \
795 data[2] = (left >> 8) &0xff; data[3] = left &0xff; \
796 data[4] = (right >> 24) &0xff; data[5] = (right >> 16) &0xff; \
797 data[6] = (right >> 8) &0xff; data[7] = right &0xff;
798
799
800
801
802
803
804 /*
805 * des_key_schedule(): Calculate 16 subkeys pairs (even/odd) for
806 * 16 encryption rounds.
807 * To calculate subkeys for decryption the caller
808 * have to reorder the generated subkeys.
809 *
810 * rawkey: 8 Bytes of key data
811 * subkey: Array of at least 32 guint32s. Will be filled
812 * with calculated subkeys.
813 *
814 **/
815 static void
816 des_key_schedule (const guint8 * rawkey, guint32 * subkey)
817 {
818 guint32 left, right, work;
819 int round;
820
821 READ_64BIT_DATA (rawkey, left, right)
822
823 DO_PERMUTATION (right, work, left, 4, 0x0f0f0f0f)
824 DO_PERMUTATION (right, work, left, 0, 0x10101010)
825
826 left = (leftkey_swap[(left >> 0) & 0xf] << 3) | (leftkey_swap[(left >> 8) & 0xf] << 2)
827 | (leftkey_swap[(left >> 16) & 0xf] << 1) | (leftkey_swap[(left >> 24) & 0xf])
828 | (leftkey_swap[(left >> 5) & 0xf] << 7) | (leftkey_swap[(left >> 13) & 0xf] << 6)
829 | (leftkey_swap[(left >> 21) & 0xf] << 5) | (leftkey_swap[(left >> 29) & 0xf] << 4);
830
831 left &= 0x0fffffff;
832
833 right = (rightkey_swap[(right >> 1) & 0xf] << 3) | (rightkey_swap[(right >> 9) & 0xf] << 2)
834 | (rightkey_swap[(right >> 17) & 0xf] << 1) | (rightkey_swap[(right >> 25) & 0xf])
835 | (rightkey_swap[(right >> 4) & 0xf] << 7) | (rightkey_swap[(right >> 12) & 0xf] << 6)
836 | (rightkey_swap[(right >> 20) & 0xf] << 5) | (rightkey_swap[(right >> 28) & 0xf] << 4);
837
838 right &= 0x0fffffff;
839
840 for (round = 0; round < 16; ++round)
841 {
842 left = ((left << encrypt_rotate_tab[round]) | (left >> (28 - encrypt_rotate_tab[round]))) & 0x0fffffff;
843 right = ((right << encrypt_rotate_tab[round]) | (right >> (28 - encrypt_rotate_tab[round]))) & 0x0fffffff;
844
845 *subkey++ = ((left << 4) & 0x24000000)
846 | ((left << 28) & 0x10000000)
847 | ((left << 14) & 0x08000000)
848 | ((left << 18) & 0x02080000)
849 | ((left << 6) & 0x01000000)
850 | ((left << 9) & 0x00200000)
851 | ((left >> 1) & 0x00100000)
852 | ((left << 10) & 0x00040000)
853 | ((left << 2) & 0x00020000)
854 | ((left >> 10) & 0x00010000)
855 | ((right >> 13) & 0x00002000)
856 | ((right >> 4) & 0x00001000)
857 | ((right << 6) & 0x00000800)
858 | ((right >> 1) & 0x00000400)
859 | ((right >> 14) & 0x00000200)
860 | (right & 0x00000100)
861 | ((right >> 5) & 0x00000020)
862 | ((right >> 10) & 0x00000010)
863 | ((right >> 3) & 0x00000008)
864 | ((right >> 18) & 0x00000004)
865 | ((right >> 26) & 0x00000002)
866 | ((right >> 24) & 0x00000001);
867
868 *subkey++ = ((left << 15) & 0x20000000)
869 | ((left << 17) & 0x10000000)
870 | ((left << 10) & 0x08000000)
871 | ((left << 22) & 0x04000000)
872 | ((left >> 2) & 0x02000000)
873 | ((left << 1) & 0x01000000)
874 | ((left << 16) & 0x00200000)
875 | ((left << 11) & 0x00100000)
876 | ((left << 3) & 0x00080000)
877 | ((left >> 6) & 0x00040000)
878 | ((left << 15) & 0x00020000)
879 | ((left >> 4) & 0x00010000)
880 | ((right >> 2) & 0x00002000)
881 | ((right << 8) & 0x00001000)
882 | ((right >> 14) & 0x00000808)
883 | ((right >> 9) & 0x00000400)
884 | ((right) & 0x00000200)
885 | ((right << 7) & 0x00000100)
886 | ((right >> 7) & 0x00000020)
887 | ((right >> 3) & 0x00000011)
888 | ((right << 2) & 0x00000004)
889 | ((right >> 21) & 0x00000002);
890 }
891 }
892
893
894
895 /*
896 * Fill a DES context with subkeys calculated from a 64bit key.
897 * Does not check parity bits, but simply ignore them.
898 * Does not check for weak keys.
899 **/
900 static void
901 des_set_key (GaimCipherContext *context, const guchar * key)
902 {
903 struct _des_ctx *ctx = gaim_cipher_context_get_data(context);
904 int i;
905
906 des_key_schedule (key, ctx->encrypt_subkeys);
907
908 for(i=0; i<32; i+=2)
909 {
910 ctx->decrypt_subkeys[i] = ctx->encrypt_subkeys[30-i];
911 ctx->decrypt_subkeys[i+1] = ctx->encrypt_subkeys[31-i];
912 }
913 }
914
915
916
917 /*
918 * Electronic Codebook Mode DES encryption/decryption of data according
919 * to 'mode'.
920 **/
921 static int
922 des_ecb_crypt (struct _des_ctx *ctx, const guint8 * from, guint8 * to, int mode)
923 {
924 guint32 left, right, work;
925 guint32 *keys;
926
927 keys = mode ? ctx->decrypt_subkeys : ctx->encrypt_subkeys;
928
929 READ_64BIT_DATA (from, left, right)
930 INITIAL_PERMUTATION (left, work, right)
931
932 DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
933 DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
934 DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
935 DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
936 DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
937 DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
938 DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
939 DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
940
941 FINAL_PERMUTATION (right, work, left)
942 WRITE_64BIT_DATA (to, right, left)
943
944 return 0;
945 }
946
947 static gint
948 des_encrypt(GaimCipherContext *context, const guchar data[],
949 size_t len, guchar output[], size_t *outlen) {
950 int offset = 0;
951 int i = 0;
952 int tmp;
953 guint8 buf[8] = {0,0,0,0,0,0,0,0};
954 while(offset+8<=len) {
955 des_ecb_crypt(gaim_cipher_context_get_data(context),
956 data+offset,
957 output+offset,
958 0);
959 offset+=8;
960 }
961 *outlen = len;
962 if(offset<len) {
963 *outlen += len - offset;
964 tmp = offset;
965 while(tmp<len) {
966 buf[i++] = data[tmp];
967 tmp++;
968 }
969 des_ecb_crypt(gaim_cipher_context_get_data(context),
970 buf,
971 output+offset,
972 0);
973 }
974 return 0;
975 }
976
977 static void
978 des_init(GaimCipherContext *context, gpointer extra) {
979 struct _des_ctx *mctx;
980 mctx = g_new0(struct _des_ctx, 1);
981 gaim_cipher_context_set_data(context, mctx);
982 }
983
984 static void
985 des_uninit(GaimCipherContext *context) {
986 struct _des_ctx *des_context;
987
988 des_context = gaim_cipher_context_get_data(context);
989 memset(des_context, 0, sizeof(des_context));
990
991 g_free(des_context);
992 des_context = NULL;
993 }
994
995 static GaimCipherOps DESOps = {
996 NULL, /* Set option */
997 NULL, /* Get option */
998 des_init, /* init */
999 NULL, /* reset */
1000 des_uninit, /* uninit */
1001 NULL, /* set iv */
1002 NULL, /* append */
1003 NULL, /* digest */
1004 des_encrypt, /* encrypt */
1005 NULL, /* decrypt */
1006 NULL, /* set salt */
1007 NULL, /* get salt size */
1008 des_set_key, /* set key */
1009 NULL /* get key size */
1010 };
1011
1012
1013 /*******************************************************************************
1014 * SHA-1
1015 ******************************************************************************/
1016 #define SHA1_ROTL(X,n) ((((X) << (n)) | ((X) >> (32-(n)))) & 0xFFFFFFFF)
1017
1018 struct SHA1Context {
1019 guint32 H[5];
1020 guint32 W[80];
1021
1022 gint lenW;
1023
1024 guint32 sizeHi;
1025 guint32 sizeLo;
1026 };
1027
1028 static void
1029 sha1_hash_block(struct SHA1Context *sha1_ctx) {
1030 gint i;
1031 guint32 A, B, C, D, E, T;
1032
1033 for(i = 16; i < 80; i++) {
1034 sha1_ctx->W[i] = SHA1_ROTL(sha1_ctx->W[i - 3] ^
1035 sha1_ctx->W[i - 8] ^
1036 sha1_ctx->W[i - 14] ^
1037 sha1_ctx->W[i - 16], 1);
1038 }
1039
1040 A = sha1_ctx->H[0];
1041 B = sha1_ctx->H[1];
1042 C = sha1_ctx->H[2];
1043 D = sha1_ctx->H[3];
1044 E = sha1_ctx->H[4];
1045
1046 for(i = 0; i < 20; i++) {
1047 T = (SHA1_ROTL(A, 5) + (((C ^ D) & B) ^ D) + E + sha1_ctx->W[i] + 0x5A827999) & 0xFFFFFFFF;
1048 E = D;
1049 D = C;
1050 C = SHA1_ROTL(B, 30);
1051 B = A;
1052 A = T;
1053 }
1054
1055 for(i = 20; i < 40; i++) {
1056 T = (SHA1_ROTL(A, 5) + (B ^ C ^ D) + E + sha1_ctx->W[i] + 0x6ED9EBA1) & 0xFFFFFFFF;
1057 E = D;
1058 D = C;
1059 C = SHA1_ROTL(B, 30);
1060 B = A;
1061 A = T;
1062 }
1063
1064 for(i = 40; i < 60; i++) {
1065 T = (SHA1_ROTL(A, 5) + ((B & C) | (D & (B | C))) + E + sha1_ctx->W[i] + 0x8F1BBCDC) & 0xFFFFFFFF;
1066 E = D;
1067 D = C;
1068 C = SHA1_ROTL(B, 30);
1069 B = A;
1070 A = T;
1071 }
1072
1073 for(i = 60; i < 80; i++) {
1074 T = (SHA1_ROTL(A, 5) + (B ^ C ^ D) + E + sha1_ctx->W[i] + 0xCA62C1D6) & 0xFFFFFFFF;
1075 E = D;
1076 D = C;
1077 C = SHA1_ROTL(B, 30);
1078 B = A;
1079 A = T;
1080 }
1081
1082 sha1_ctx->H[0] += A;
1083 sha1_ctx->H[1] += B;
1084 sha1_ctx->H[2] += C;
1085 sha1_ctx->H[3] += D;
1086 sha1_ctx->H[4] += E;
1087 }
1088
1089 static void
1090 sha1_set_opt(GaimCipherContext *context, const gchar *name, void *value) {
1091 struct SHA1Context *ctx;
1092
1093 ctx = gaim_cipher_context_get_data(context);
1094
1095 if(!strcmp(name, "sizeHi")) {
1096 ctx->sizeHi = GPOINTER_TO_INT(value);
1097 } else if(!strcmp(name, "sizeLo")) {
1098 ctx->sizeLo = GPOINTER_TO_INT(value);
1099 } else if(!strcmp(name, "lenW")) {
1100 ctx->lenW = GPOINTER_TO_INT(value);
1101 }
1102 }
1103
1104 static void *
1105 sha1_get_opt(GaimCipherContext *context, const gchar *name) {
1106 struct SHA1Context *ctx;
1107
1108 ctx = gaim_cipher_context_get_data(context);
1109
1110 if(!strcmp(name, "sizeHi")) {
1111 return GINT_TO_POINTER(ctx->sizeHi);
1112 } else if(!strcmp(name, "sizeLo")) {
1113 return GINT_TO_POINTER(ctx->sizeLo);
1114 } else if(!strcmp(name, "lenW")) {
1115 return GINT_TO_POINTER(ctx->lenW);
1116 }
1117
1118 return NULL;
1119 }
1120
1121 static void
1122 sha1_init(GaimCipherContext *context, void *extra) {
1123 struct SHA1Context *sha1_ctx;
1124
1125 sha1_ctx = g_new0(struct SHA1Context, 1);
1126
1127 gaim_cipher_context_set_data(context, sha1_ctx);
1128
1129 gaim_cipher_context_reset(context, extra);
1130 }
1131
1132 static void
1133 sha1_reset(GaimCipherContext *context, void *extra) {
1134 struct SHA1Context *sha1_ctx;
1135 gint i;
1136
1137 sha1_ctx = gaim_cipher_context_get_data(context);
1138
1139 g_return_if_fail(sha1_ctx);
1140
1141 sha1_ctx->lenW = 0;
1142 sha1_ctx->sizeHi = 0;
1143 sha1_ctx->sizeLo = 0;
1144
1145 sha1_ctx->H[0] = 0x67452301;
1146 sha1_ctx->H[1] = 0xEFCDAB89;
1147 sha1_ctx->H[2] = 0x98BADCFE;
1148 sha1_ctx->H[3] = 0x10325476;
1149 sha1_ctx->H[4] = 0xC3D2E1F0;
1150
1151 for(i = 0; i < 80; i++)
1152 sha1_ctx->W[i] = 0;
1153 }
1154
1155 static void
1156 sha1_uninit(GaimCipherContext *context) {
1157 struct SHA1Context *sha1_ctx;
1158
1159 gaim_cipher_context_reset(context, NULL);
1160
1161 sha1_ctx = gaim_cipher_context_get_data(context);
1162
1163 memset(sha1_ctx, 0, sizeof(struct SHA1Context));
1164
1165 g_free(sha1_ctx);
1166 sha1_ctx = NULL;
1167 }
1168
1169
1170 static void
1171 sha1_append(GaimCipherContext *context, const guchar *data, size_t len) {
1172 struct SHA1Context *sha1_ctx;
1173 gint i;
1174
1175 sha1_ctx = gaim_cipher_context_get_data(context);
1176
1177 g_return_if_fail(sha1_ctx);
1178
1179 for(i = 0; i < len; i++) {
1180 sha1_ctx->W[sha1_ctx->lenW / 4] <<= 8;
1181 sha1_ctx->W[sha1_ctx->lenW / 4] |= data[i];
1182
1183 if((++sha1_ctx->lenW) % 64 == 0) {
1184 sha1_hash_block(sha1_ctx);
1185 sha1_ctx->lenW = 0;
1186 }
1187
1188 sha1_ctx->sizeLo += 8;
1189 sha1_ctx->sizeHi += (sha1_ctx->sizeLo < 8);
1190 }
1191 }
1192
1193 static gboolean
1194 sha1_digest(GaimCipherContext *context, size_t in_len, guchar digest[20],
1195 size_t *out_len)
1196 {
1197 struct SHA1Context *sha1_ctx;
1198 guchar pad0x80 = 0x80, pad0x00 = 0x00;
1199 guchar padlen[8];
1200 gint i;
1201
1202 g_return_val_if_fail(in_len >= 20, FALSE);
1203
1204 sha1_ctx = gaim_cipher_context_get_data(context);
1205
1206 g_return_val_if_fail(sha1_ctx, FALSE);
1207
1208 padlen[0] = (guchar)((sha1_ctx->sizeHi >> 24) & 255);
1209 padlen[1] = (guchar)((sha1_ctx->sizeHi >> 16) & 255);
1210 padlen[2] = (guchar)((sha1_ctx->sizeHi >> 8) & 255);
1211 padlen[3] = (guchar)((sha1_ctx->sizeHi >> 0) & 255);
1212 padlen[4] = (guchar)((sha1_ctx->sizeLo >> 24) & 255);
1213 padlen[5] = (guchar)((sha1_ctx->sizeLo >> 16) & 255);
1214 padlen[6] = (guchar)((sha1_ctx->sizeLo >> 8) & 255);
1215 padlen[7] = (guchar)((sha1_ctx->sizeLo >> 0) & 255);
1216
1217 /* pad with a 1, then zeroes, then length */
1218 gaim_cipher_context_append(context, &pad0x80, 1);
1219 while(sha1_ctx->lenW != 56)
1220 gaim_cipher_context_append(context, &pad0x00, 1);
1221 gaim_cipher_context_append(context, padlen, 8);
1222
1223 for(i = 0; i < 20; i++) {
1224 digest[i] = (guchar)(sha1_ctx->H[i / 4] >> 24);
1225 sha1_ctx->H[i / 4] <<= 8;
1226 }
1227
1228 gaim_cipher_context_reset(context, NULL);
1229
1230 if(out_len)
1231 *out_len = 20;
1232
1233 return TRUE;
1234 }
1235
1236 static GaimCipherOps SHA1Ops = {
1237 sha1_set_opt, /* Set Option */
1238 sha1_get_opt, /* Get Option */
1239 sha1_init, /* init */
1240 sha1_reset, /* reset */
1241 sha1_uninit, /* uninit */
1242 NULL, /* set iv */
1243 sha1_append, /* append */
1244 sha1_digest, /* digest */
1245 NULL, /* encrypt */
1246 NULL, /* decrypt */
1247 NULL, /* set salt */
1248 NULL, /* get salt size */
1249 NULL, /* set key */
1250 NULL /* get key size */
1251 };
1252
1253 /*******************************************************************************
1254 * Structs
1255 ******************************************************************************/
1256 struct _GaimCipher {
1257 gchar *name;
1258 GaimCipherOps *ops;
1259 guint ref;
1260 };
1261
1262 struct _GaimCipherContext {
1263 GaimCipher *cipher;
1264 gpointer data;
1265 };
1266
1267 /******************************************************************************
1268 * Globals
1269 *****************************************************************************/
1270 static GList *ciphers = NULL;
1271
1272 /******************************************************************************
1273 * GaimCipher API
1274 *****************************************************************************/
1275 const gchar *
1276 gaim_cipher_get_name(GaimCipher *cipher) {
1277 g_return_val_if_fail(cipher, NULL);
1278
1279 return cipher->name;
1280 }
1281
1282 guint
1283 gaim_cipher_get_capabilities(GaimCipher *cipher) {
1284 GaimCipherOps *ops = NULL;
1285 guint caps = 0;
1286
1287 g_return_val_if_fail(cipher, 0);
1288
1289 ops = cipher->ops;
1290 g_return_val_if_fail(ops, 0);
1291
1292 if(ops->set_option)
1293 caps |= GAIM_CIPHER_CAPS_SET_OPT;
1294 if(ops->get_option)
1295 caps |= GAIM_CIPHER_CAPS_GET_OPT;
1296 if(ops->init)
1297 caps |= GAIM_CIPHER_CAPS_INIT;
1298 if(ops->reset)
1299 caps |= GAIM_CIPHER_CAPS_RESET;
1300 if(ops->uninit)
1301 caps |= GAIM_CIPHER_CAPS_UNINIT;
1302 if(ops->set_iv)
1303 caps |= GAIM_CIPHER_CAPS_SET_IV;
1304 if(ops->append)
1305 caps |= GAIM_CIPHER_CAPS_APPEND;
1306 if(ops->digest)
1307 caps |= GAIM_CIPHER_CAPS_DIGEST;
1308 if(ops->encrypt)
1309 caps |= GAIM_CIPHER_CAPS_ENCRYPT;
1310 if(ops->decrypt)
1311 caps |= GAIM_CIPHER_CAPS_DECRYPT;
1312 if(ops->set_salt)
1313 caps |= GAIM_CIPHER_CAPS_SET_SALT;
1314 if(ops->get_salt_size)
1315 caps |= GAIM_CIPHER_CAPS_GET_SALT_SIZE;
1316 if(ops->set_key)
1317 caps |= GAIM_CIPHER_CAPS_SET_KEY;
1318 if(ops->get_key_size)
1319 caps |= GAIM_CIPHER_CAPS_GET_KEY_SIZE;
1320
1321 return caps;
1322 }
1323
1324 gboolean
1325 gaim_cipher_digest_region(const gchar *name, const guchar *data,
1326 size_t data_len, size_t in_len,
1327 guchar digest[], size_t *out_len)
1328 {
1329 GaimCipher *cipher;
1330 GaimCipherContext *context;
1331 gboolean ret = FALSE;
1332
1333 g_return_val_if_fail(name, FALSE);
1334 g_return_val_if_fail(data, FALSE);
1335
1336 cipher = gaim_ciphers_find_cipher(name);
1337
1338 g_return_val_if_fail(cipher, FALSE);
1339
1340 if(!cipher->ops->append || !cipher->ops->digest) {
1341 gaim_debug_info("cipher", "gaim_cipher_region failed: "
1342 "the %s cipher does not support appending and or "
1343 "digesting.", cipher->name);
1344 return FALSE;
1345 }
1346
1347 context = gaim_cipher_context_new(cipher, NULL);
1348 gaim_cipher_context_append(context, data, data_len);
1349 ret = gaim_cipher_context_digest(context, in_len, digest, out_len);
1350 gaim_cipher_context_destroy(context);
1351
1352 return ret;
1353 }
1354
1355 /******************************************************************************
1356 * GaimCiphers API
1357 *****************************************************************************/
1358 GaimCipher *
1359 gaim_ciphers_find_cipher(const gchar *name) {
1360 GaimCipher *cipher;
1361 GList *l;
1362
1363 g_return_val_if_fail(name, NULL);
1364
1365 for(l = ciphers; l; l = l->next) {
1366 cipher = GAIM_CIPHER(l->data);
1367
1368 if(!g_ascii_strcasecmp(cipher->name, name))
1369 return cipher;
1370 }
1371
1372 return NULL;
1373 }
1374
1375 GaimCipher *
1376 gaim_ciphers_register_cipher(const gchar *name, GaimCipherOps *ops) {
1377 GaimCipher *cipher = NULL;
1378
1379 g_return_val_if_fail(name, NULL);
1380 g_return_val_if_fail(ops, NULL);
1381 g_return_val_if_fail(!gaim_ciphers_find_cipher(name), NULL);
1382
1383 cipher = g_new0(GaimCipher, 1);
1384 GAIM_DBUS_REGISTER_POINTER(cipher, GaimCipher);
1385
1386 cipher->name = g_strdup(name);
1387 cipher->ops = ops;
1388
1389 ciphers = g_list_append(ciphers, cipher);
1390
1391 gaim_signal_emit(gaim_ciphers_get_handle(), "cipher-added", cipher);
1392
1393 return cipher;
1394 }
1395
1396 gboolean
1397 gaim_ciphers_unregister_cipher(GaimCipher *cipher) {
1398 g_return_val_if_fail(cipher, FALSE);
1399 g_return_val_if_fail(cipher->ref == 0, FALSE);
1400
1401 gaim_signal_emit(gaim_ciphers_get_handle(), "cipher-removed", cipher);
1402
1403 ciphers = g_list_remove(ciphers, cipher);
1404
1405 g_free(cipher->name);
1406
1407 GAIM_DBUS_UNREGISTER_POINTER(cipher);
1408 g_free(cipher);
1409
1410 return TRUE;
1411 }
1412
1413 GList *
1414 gaim_ciphers_get_ciphers() {
1415 return ciphers;
1416 }
1417
1418 /******************************************************************************
1419 * GaimCipher Subsystem API
1420 *****************************************************************************/
1421 gpointer
1422 gaim_ciphers_get_handle() {
1423 static gint handle;
1424
1425 return &handle;
1426 }
1427
1428 void
1429 gaim_ciphers_init() {
1430 gpointer handle;
1431
1432 handle = gaim_ciphers_get_handle();
1433
1434 gaim_signal_register(handle, "cipher-added",
1435 gaim_marshal_VOID__POINTER, NULL, 1,
1436 gaim_value_new(GAIM_TYPE_SUBTYPE,
1437 GAIM_SUBTYPE_CIPHER));
1438 gaim_signal_register(handle, "cipher-removed",
1439 gaim_marshal_VOID__POINTER, NULL, 1,
1440 gaim_value_new(GAIM_TYPE_SUBTYPE,
1441 GAIM_SUBTYPE_CIPHER));
1442
1443 gaim_ciphers_register_cipher("md5", &MD5Ops);
1444 gaim_ciphers_register_cipher("sha1", &SHA1Ops);
1445 gaim_ciphers_register_cipher("md4", &MD4Ops);
1446 gaim_ciphers_register_cipher("des", &DESOps);
1447 }
1448
1449 void
1450 gaim_ciphers_uninit() {
1451 GaimCipher *cipher;
1452 GList *l, *ll;
1453
1454 for(l = ciphers; l; l = ll) {
1455 ll = l->next;
1456
1457 cipher = GAIM_CIPHER(l->data);
1458 gaim_ciphers_unregister_cipher(cipher);
1459
1460 ciphers = g_list_remove(ciphers, cipher);
1461 }
1462
1463 g_list_free(ciphers);
1464
1465 gaim_signals_unregister_by_instance(gaim_ciphers_get_handle());
1466 }
1467 /******************************************************************************
1468 * GaimCipherContext API
1469 *****************************************************************************/
1470 void
1471 gaim_cipher_context_set_option(GaimCipherContext *context, const gchar *name,
1472 gpointer value)
1473 {
1474 GaimCipher *cipher = NULL;
1475
1476 g_return_if_fail(context);
1477 g_return_if_fail(name);
1478
1479 cipher = context->cipher;
1480 g_return_if_fail(cipher);
1481
1482 if(cipher->ops && cipher->ops->set_option)
1483 cipher->ops->set_option(context, name, value);
1484 else
1485 gaim_debug_info("cipher", "the %s cipher does not support the "
1486 "set_option operation\n", cipher->name);
1487 }
1488
1489 gpointer
1490 gaim_cipher_context_get_option(GaimCipherContext *context, const gchar *name) {
1491 GaimCipher *cipher = NULL;
1492
1493 g_return_val_if_fail(context, NULL);
1494 g_return_val_if_fail(name, NULL);
1495
1496 cipher = context->cipher;
1497 g_return_val_if_fail(cipher, NULL);
1498
1499 if(cipher->ops && cipher->ops->get_option)
1500 return cipher->ops->get_option(context, name);
1501 else {
1502 gaim_debug_info("cipher", "the %s cipher does not support the "
1503 "get_option operation\n", cipher->name);
1504
1505 return NULL;
1506 }
1507 }
1508
1509 GaimCipherContext *
1510 gaim_cipher_context_new(GaimCipher *cipher, void *extra) {
1511 GaimCipherContext *context = NULL;
1512
1513 g_return_val_if_fail(cipher, NULL);
1514
1515 cipher->ref++;
1516
1517 context = g_new0(GaimCipherContext, 1);
1518 context->cipher = cipher;
1519
1520 if(cipher->ops->init)
1521 cipher->ops->init(context, extra);
1522
1523 return context;
1524 }
1525
1526 GaimCipherContext *
1527 gaim_cipher_context_new_by_name(const gchar *name, void *extra) {
1528 GaimCipher *cipher;
1529
1530 g_return_val_if_fail(name, NULL);
1531
1532 cipher = gaim_ciphers_find_cipher(name);
1533
1534 g_return_val_if_fail(cipher, NULL);
1535
1536 return gaim_cipher_context_new(cipher, extra);
1537 }
1538
1539 void
1540 gaim_cipher_context_reset(GaimCipherContext *context, void *extra) {
1541 GaimCipher *cipher = NULL;
1542
1543 g_return_if_fail(context);
1544
1545 cipher = context->cipher;
1546 g_return_if_fail(cipher);
1547
1548 if(cipher->ops && cipher->ops->reset)
1549 context->cipher->ops->reset(context, extra);
1550 }
1551
1552 void
1553 gaim_cipher_context_destroy(GaimCipherContext *context) {
1554 GaimCipher *cipher = NULL;
1555
1556 g_return_if_fail(context);
1557
1558 cipher = context->cipher;
1559 g_return_if_fail(cipher);
1560
1561 cipher->ref--;
1562
1563 if(cipher->ops && cipher->ops->uninit)
1564 cipher->ops->uninit(context);
1565
1566 memset(context, 0, sizeof(context));
1567 g_free(context);
1568 context = NULL;
1569 }
1570
1571 void
1572 gaim_cipher_context_set_iv(GaimCipherContext *context, guchar *iv, size_t len)
1573 {
1574 GaimCipher *cipher = NULL;
1575
1576 g_return_if_fail(context);
1577 g_return_if_fail(iv);
1578
1579 cipher = context->cipher;
1580 g_return_if_fail(cipher);
1581
1582 if(cipher->ops && cipher->ops->set_iv)
1583 cipher->ops->set_iv(context, iv, len);
1584 else
1585 gaim_debug_info("cipher", "the %s cipher does not support the set"
1586 "initialization vector operation\n", cipher->name);
1587 }
1588
1589 void
1590 gaim_cipher_context_append(GaimCipherContext *context, const guchar *data,
1591 size_t len)
1592 {
1593 GaimCipher *cipher = NULL;
1594
1595 g_return_if_fail(context);
1596
1597 cipher = context->cipher;
1598 g_return_if_fail(cipher);
1599
1600 if(cipher->ops && cipher->ops->append)
1601 cipher->ops->append(context, data, len);
1602 else
1603 gaim_debug_info("cipher", "the %s cipher does not support the append "
1604 "operation\n", cipher->name);
1605 }
1606
1607 gboolean
1608 gaim_cipher_context_digest(GaimCipherContext *context, size_t in_len,
1609 guchar digest[], size_t *out_len)
1610 {
1611 GaimCipher *cipher = NULL;
1612
1613 g_return_val_if_fail(context, FALSE);
1614
1615 cipher = context->cipher;
1616 g_return_val_if_fail(context, FALSE);
1617
1618 if(cipher->ops && cipher->ops->digest)
1619 return cipher->ops->digest(context, in_len, digest, out_len);
1620 else {
1621 gaim_debug_info("cipher", "the %s cipher does not support the digest "
1622 "operation\n", cipher->name);
1623 return FALSE;
1624 }
1625 }
1626
1627 gboolean
1628 gaim_cipher_context_digest_to_str(GaimCipherContext *context, size_t in_len,
1629 gchar digest_s[], size_t *out_len)
1630 {
1631 /* 8k is a bit excessive, will tweak later. */
1632 guchar digest[BUF_LEN * 4];
1633 gint n = 0;
1634 size_t dlen = 0;
1635
1636 g_return_val_if_fail(context, FALSE);
1637 g_return_val_if_fail(digest_s, FALSE);
1638
1639 if(!gaim_cipher_context_digest(context, sizeof(digest), digest, &dlen))
1640 return FALSE;
1641
1642 /* in_len must be greater than dlen * 2 so we have room for the NUL. */
1643 if(in_len <= dlen * 2)
1644 return FALSE;
1645
1646 for(n = 0; n < dlen; n++)
1647 sprintf(digest_s + (n * 2), "%02x", digest[n]);
1648
1649 digest_s[n * 2] = '\0';
1650
1651 if(out_len)
1652 *out_len = dlen * 2;
1653
1654 return TRUE;
1655 }
1656
1657 gint
1658 gaim_cipher_context_encrypt(GaimCipherContext *context, const guchar data[],
1659 size_t len, guchar output[], size_t *outlen)
1660 {
1661 GaimCipher *cipher = NULL;
1662
1663 g_return_val_if_fail(context, -1);
1664
1665 cipher = context->cipher;
1666 g_return_val_if_fail(cipher, -1);
1667
1668 if(cipher->ops && cipher->ops->encrypt)
1669 return cipher->ops->encrypt(context, data, len, output, outlen);
1670 else {
1671 gaim_debug_info("cipher", "the %s cipher does not support the encrypt"
1672 "operation\n", cipher->name);
1673
1674 if(outlen)
1675 *outlen = -1;
1676
1677 return -1;
1678 }
1679 }
1680
1681 gint
1682 gaim_cipher_context_decrypt(GaimCipherContext *context, const guchar data[],
1683 size_t len, guchar output[], size_t *outlen)
1684 {
1685 GaimCipher *cipher = NULL;
1686
1687 g_return_val_if_fail(context, -1);
1688
1689 cipher = context->cipher;
1690 g_return_val_if_fail(cipher, -1);
1691
1692 if(cipher->ops && cipher->ops->decrypt)
1693 return cipher->ops->decrypt(context, data, len, output, outlen);
1694 else {
1695 gaim_debug_info("cipher", "the %s cipher does not support the decrypt"
1696 "operation\n", cipher->name);
1697
1698 if(outlen)
1699 *outlen = -1;
1700
1701 return -1;
1702 }
1703 }
1704
1705 void
1706 gaim_cipher_context_set_salt(GaimCipherContext *context, guchar *salt) {
1707 GaimCipher *cipher = NULL;
1708
1709 g_return_if_fail(context);
1710
1711 cipher = context->cipher;
1712 g_return_if_fail(cipher);
1713
1714 if(cipher->ops && cipher->ops->set_salt)
1715 cipher->ops->set_salt(context, salt);
1716 else
1717 gaim_debug_info("cipher", "the %s cipher does not support the "
1718 "set_salt operation\n", cipher->name);
1719 }
1720
1721 size_t
1722 gaim_cipher_context_get_salt_size(GaimCipherContext *context) {
1723 GaimCipher *cipher = NULL;
1724
1725 g_return_val_if_fail(context, -1);
1726
1727 cipher = context->cipher;
1728 g_return_val_if_fail(cipher, -1);
1729
1730 if(cipher->ops && cipher->ops->get_salt_size)
1731 return cipher->ops->get_salt_size(context);
1732 else {
1733 gaim_debug_info("cipher", "the %s cipher does not support the "
1734 "get_salt_size operation\n", cipher->name);
1735
1736 return -1;
1737 }
1738 }
1739
1740 void
1741 gaim_cipher_context_set_key(GaimCipherContext *context, const guchar *key) {
1742 GaimCipher *cipher = NULL;
1743
1744 g_return_if_fail(context);
1745
1746 cipher = context->cipher;
1747 g_return_if_fail(cipher);
1748
1749 if(cipher->ops && cipher->ops->set_key)
1750 cipher->ops->set_key(context, key);
1751 else
1752 gaim_debug_info("cipher", "the %s cipher does not support the "
1753 "set_key operation\n", cipher->name);
1754 }
1755
1756 size_t
1757 gaim_cipher_context_get_key_size(GaimCipherContext *context) {
1758 GaimCipher *cipher = NULL;
1759
1760 g_return_val_if_fail(context, -1);
1761
1762 cipher = context->cipher;
1763 g_return_val_if_fail(cipher, -1);
1764
1765 if(cipher->ops && cipher->ops->get_key_size)
1766 return cipher->ops->get_key_size(context);
1767 else {
1768 gaim_debug_info("cipher", "the %s cipher does not support the "
1769 "get_key_size operation\n", cipher->name);
1770
1771 return -1;
1772 }
1773 }
1774
1775 void
1776 gaim_cipher_context_set_data(GaimCipherContext *context, gpointer data) {
1777 g_return_if_fail(context);
1778
1779 context->data = data;
1780 }
1781
1782 gpointer
1783 gaim_cipher_context_get_data(GaimCipherContext *context) {
1784 g_return_val_if_fail(context, NULL);
1785
1786 return context->data;
1787 }
1788
1789 gchar *gaim_cipher_http_digest_calculate_session_key(
1790 const gchar *algorithm,
1791 const gchar *username,
1792 const gchar *realm,
1793 const gchar *password,
1794 const gchar *nonce,
1795 const gchar *client_nonce)
1796 {
1797 GaimCipher *cipher;
1798 GaimCipherContext *context;
1799 gchar hash[33]; /* We only support MD5. */
1800
1801 g_return_val_if_fail(username != NULL, NULL);
1802 g_return_val_if_fail(realm != NULL, NULL);
1803 g_return_val_if_fail(password != NULL, NULL);
1804 g_return_val_if_fail(nonce != NULL, NULL);
1805
1806 /* Check for a supported algorithm. */
1807 g_return_val_if_fail(algorithm == NULL ||
1808 *algorithm == '\0' ||
1809 strcasecmp(algorithm, "MD5") ||
1810 strcasecmp(algorithm, "MD5-sess"), NULL);
1811
1812 cipher = gaim_ciphers_find_cipher("md5");
1813 g_return_val_if_fail(cipher != NULL, NULL);
1814
1815 context = gaim_cipher_context_new(cipher, NULL);
1816
1817 gaim_cipher_context_append(context, (guchar *)username, strlen(username));
1818 gaim_cipher_context_append(context, (guchar *)":", 1);
1819 gaim_cipher_context_append(context, (guchar *)realm, strlen(realm));
1820 gaim_cipher_context_append(context, (guchar *)":", 1);
1821 gaim_cipher_context_append(context, (guchar *)password, strlen(password));
1822
1823 if (algorithm != NULL && !strcasecmp(algorithm, "MD5-sess"))
1824 {
1825 guchar digest[16];
1826
1827 if (client_nonce == NULL)
1828 {
1829 gaim_cipher_context_destroy(context);
1830 gaim_debug_error("cipher", "Required client_nonce missing for MD5-sess digest calculation.");
1831 return NULL;
1832 }
1833
1834 gaim_cipher_context_digest(context, sizeof(digest), digest, NULL);
1835 gaim_cipher_context_destroy(context);
1836
1837 context = gaim_cipher_context_new(cipher, NULL);
1838 gaim_cipher_context_append(context, digest, sizeof(digest));
1839 gaim_cipher_context_append(context, (guchar *)":", 1);
1840 gaim_cipher_context_append(context, (guchar *)nonce, strlen(nonce));
1841 gaim_cipher_context_append(context, (guchar *)":", 1);
1842 gaim_cipher_context_append(context, (guchar *)client_nonce, strlen(client_nonce));
1843 }
1844
1845 gaim_cipher_context_digest_to_str(context, sizeof(hash), hash, NULL);
1846 gaim_cipher_context_destroy(context);
1847
1848 return g_strdup(hash);
1849 }
1850
1851 gchar *gaim_cipher_http_digest_calculate_response(
1852 const gchar *algorithm,
1853 const gchar *method,
1854 const gchar *digest_uri,
1855 const gchar *qop,
1856 const gchar *entity,
1857 const gchar *nonce,
1858 const gchar *nonce_count,
1859 const gchar *client_nonce,
1860 const gchar *session_key)
1861 {
1862 GaimCipher *cipher;
1863 GaimCipherContext *context;
1864 static gchar hash2[33]; /* We only support MD5. */
1865
1866 g_return_val_if_fail(method != NULL, NULL);
1867 g_return_val_if_fail(digest_uri != NULL, NULL);
1868 g_return_val_if_fail(nonce != NULL, NULL);
1869 g_return_val_if_fail(session_key != NULL, NULL);
1870
1871 /* Check for a supported algorithm. */
1872 g_return_val_if_fail(algorithm == NULL ||
1873 *algorithm == '\0' ||
1874 strcasecmp(algorithm, "MD5") ||
1875 strcasecmp(algorithm, "MD5-sess"), NULL);
1876
1877 /* Check for a supported "quality of protection". */
1878 g_return_val_if_fail(qop == NULL ||
1879 *qop == '\0' ||
1880 strcasecmp(qop, "auth") ||
1881 strcasecmp(qop, "auth-int"), NULL);
1882
1883 cipher = gaim_ciphers_find_cipher("md5");
1884 g_return_val_if_fail(cipher != NULL, NULL);
1885
1886 context = gaim_cipher_context_new(cipher, NULL);
1887
1888 gaim_cipher_context_append(context, (guchar *)method, strlen(method));
1889 gaim_cipher_context_append(context, (guchar *)":", 1);
1890 gaim_cipher_context_append(context, (guchar *)digest_uri, strlen(digest_uri));
1891
1892 if (qop != NULL && !strcasecmp(qop, "auth-int"))
1893 {
1894 GaimCipherContext *context2;
1895 gchar entity_hash[33];
1896
1897 if (entity == NULL)
1898 {
1899 gaim_cipher_context_destroy(context);
1900 gaim_debug_error("cipher", "Required entity missing for auth-int digest calculation.");
1901 return NULL;
1902 }
1903
1904 context2 = gaim_cipher_context_new(cipher, NULL);
1905 gaim_cipher_context_append(context2, (guchar *)entity, strlen(entity));
1906 gaim_cipher_context_digest_to_str(context2, sizeof(entity_hash), entity_hash, NULL);
1907 gaim_cipher_context_destroy(context2);
1908
1909 gaim_cipher_context_append(context, (guchar *)":", 1);
1910 gaim_cipher_context_append(context, (guchar *)entity_hash, strlen(entity_hash));
1911 }
1912
1913 gaim_cipher_context_digest_to_str(context, sizeof(hash2), hash2, NULL);
1914 gaim_cipher_context_destroy(context);
1915
1916 context = gaim_cipher_context_new(cipher, NULL);
1917 gaim_cipher_context_append(context, (guchar *)session_key, strlen(session_key));
1918 gaim_cipher_context_append(context, (guchar *)":", 1);
1919 gaim_cipher_context_append(context, (guchar *)nonce, strlen(nonce));
1920 gaim_cipher_context_append(context, (guchar *)":", 1);
1921
1922 if (qop != NULL && *qop != '\0')
1923 {
1924 if (nonce_count == NULL)
1925 {
1926 gaim_cipher_context_destroy(context);
1927 gaim_debug_error("cipher", "Required nonce_count missing for digest calculation.");
1928 return NULL;
1929 }
1930
1931 if (client_nonce == NULL)
1932 {
1933 gaim_cipher_context_destroy(context);
1934 gaim_debug_error("cipher", "Required client_nonce missing for digest calculation.");
1935 return NULL;
1936 }
1937
1938 gaim_cipher_context_append(context, (guchar *)nonce_count, strlen(nonce_count));
1939 gaim_cipher_context_append(context, (guchar *)":", 1);
1940 gaim_cipher_context_append(context, (guchar *)client_nonce, strlen(client_nonce));
1941 gaim_cipher_context_append(context, (guchar *)":", 1);
1942
1943 gaim_cipher_context_append(context, (guchar *)qop, strlen(qop));
1944
1945 gaim_cipher_context_append(context, (guchar *)":", 1);
1946 }
1947
1948 gaim_cipher_context_append(context, (guchar *)hash2, strlen(hash2));
1949 gaim_cipher_context_digest_to_str(context, sizeof(hash2), hash2, NULL);
1950 gaim_cipher_context_destroy(context);
1951
1952 return g_strdup(hash2);
1953 }