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