Mercurial > pidgin.yaz
annotate src/cipher.c @ 13925:60f39c405dff
[gaim-migrate @ 16442]
It is currently possible for yourself to not show up in your own
buddy list at signon with Jabber. To reproduce:
1. Sign on and add yourself to your buddy list
2. Sign off and exit Gaim
3. Delete your blist.xml
4. Sign on
The same bug would also appear when signing into your Jabber
account using Gaim for the first time.
Normally this works because the Jabber PRPL fakes showing your status
whenever jabber_presence_send() is called. However, the call to
jabber_presence_send() can happen BEFORE we receive the roster from the
server (it usually does, I think) so the PRPL tries to set the status
for yourself, but your GaimBuddy node doesn't exist yet.
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Thu, 06 Jul 2006 08:24:26 +0000 |
parents | ff94569010f5 |
children | 8bda65b88e49 |
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" | |
13758 | 59 #include "dbus-maybe.h" |
10684 | 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]; | |
11183 | 70 guchar buffer[64]; |
10684 | 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 } | |
11183 | 79 #define MD5_PUT_GUINT32(n,b,i) { \ |
80 (b)[(i) ] = (guchar)((n) ); \ | |
13218
c01aa6ea4947
[gaim-migrate @ 15582]
Richard Laager <rlaager@wiktel.com>
parents:
12389
diff
changeset
|
81 (b)[(i) + 1] = (guchar)((n) >> 8); \ |
11183 | 82 (b)[(i) + 2] = (guchar)((n) >> 16); \ |
83 (b)[(i) + 3] = (guchar)((n) >> 24); \ | |
10684 | 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 | |
11183 | 128 md5_process(struct MD5Context *md5_context, const guchar data[64]) { |
10684 | 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 | |
11183 | 198 |
10684 | 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 | |
11183 | 248 md5_append(GaimCipherContext *context, const guchar *data, size_t len) { |
10684 | 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 | |
11183 | 286 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
|
287 size_t *out_len) |
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
288 { |
10684 | 289 struct MD5Context *md5_context = NULL; |
290 guint32 last, pad; | |
291 guint32 high, low; | |
11183 | 292 guchar message[8]; |
293 guchar padding[64] = { | |
10684 | 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 | |
10687
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
300 g_return_val_if_fail(in_len >= 16, FALSE); |
10684 | 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 | |
10687
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
322 if(out_len) |
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
323 *out_len = 16; |
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
324 |
10684 | 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 /******************************************************************************* | |
11329 | 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) { | |
13218
c01aa6ea4947
[gaim-migrate @ 15582]
Richard Laager <rlaager@wiktel.com>
parents:
12389
diff
changeset
|
476 struct MD4_Context *mctx; |
c01aa6ea4947
[gaim-migrate @ 15582]
Richard Laager <rlaager@wiktel.com>
parents:
12389
diff
changeset
|
477 mctx = g_new0(struct MD4_Context, 1); |
c01aa6ea4947
[gaim-migrate @ 15582]
Richard Laager <rlaager@wiktel.com>
parents:
12389
diff
changeset
|
478 gaim_cipher_context_set_data(context, mctx); |
c01aa6ea4947
[gaim-migrate @ 15582]
Richard Laager <rlaager@wiktel.com>
parents:
12389
diff
changeset
|
479 gaim_cipher_context_reset(context, extra); |
11329 | 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) { | |
13218
c01aa6ea4947
[gaim-migrate @ 15582]
Richard Laager <rlaager@wiktel.com>
parents:
12389
diff
changeset
|
490 struct MD4_Context *mctx; |
11329 | 491 |
13218
c01aa6ea4947
[gaim-migrate @ 15582]
Richard Laager <rlaager@wiktel.com>
parents:
12389
diff
changeset
|
492 mctx = gaim_cipher_context_get_data(context); |
11329 | 493 |
13218
c01aa6ea4947
[gaim-migrate @ 15582]
Richard Laager <rlaager@wiktel.com>
parents:
12389
diff
changeset
|
494 mctx->hash[0] = 0x67452301; |
11329 | 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 | |
13218
c01aa6ea4947
[gaim-migrate @ 15582]
Richard Laager <rlaager@wiktel.com>
parents:
12389
diff
changeset
|
568 gaim_cipher_context_reset(context, NULL); |
11329 | 569 |
13218
c01aa6ea4947
[gaim-migrate @ 15582]
Richard Laager <rlaager@wiktel.com>
parents:
12389
diff
changeset
|
570 md4_context = gaim_cipher_context_get_data(context); |
11329 | 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 | |
11335 | 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 * */ | |
11677 | 709 static guint32 leftkey_swap[16] = |
11335 | 710 { |
711 0x00000000, 0x00000001, 0x00000100, 0x00000101, | |
712 0x00010000, 0x00010001, 0x00010100, 0x00010101, | |
713 0x01000000, 0x01000001, 0x01000100, 0x01000101, | |
714 0x01010000, 0x01010001, 0x01010100, 0x01010101 | |
715 }; | |
716 | |
11677 | 717 static guint32 rightkey_swap[16] = |
11335 | 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 **/ | |
11597 | 815 static void |
11335 | 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 **/ | |
11597 | 900 static void |
13697 | 901 des_set_key (GaimCipherContext *context, const guchar * key) |
11335 | 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 **/ | |
11597 | 921 static int |
11335 | 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 | |
11597 | 947 static gint |
948 des_encrypt(GaimCipherContext *context, const guchar data[], | |
949 size_t len, guchar output[], size_t *outlen) { | |
11335 | 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 | |
13218
c01aa6ea4947
[gaim-migrate @ 15582]
Richard Laager <rlaager@wiktel.com>
parents:
12389
diff
changeset
|
988 des_context = gaim_cipher_context_get_data(context); |
11335 | 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 */ | |
11597 | 1008 des_set_key, /* set key */ |
11335 | 1009 NULL /* get key size */ |
1010 }; | |
1011 | |
1012 | |
11329 | 1013 /******************************************************************************* |
10684 | 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 | |
13218
c01aa6ea4947
[gaim-migrate @ 15582]
Richard Laager <rlaager@wiktel.com>
parents:
12389
diff
changeset
|
1022 gint lenW; |
10684 | 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; | |
11183 | 1086 sha1_ctx->H[4] += E; |
10684 | 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 | |
11183 | 1171 sha1_append(GaimCipherContext *context, const guchar *data, size_t len) { |
10684 | 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 | |
11183 | 1194 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
|
1195 size_t *out_len) |
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
1196 { |
10684 | 1197 struct SHA1Context *sha1_ctx; |
11183 | 1198 guchar pad0x80 = 0x80, pad0x00 = 0x00; |
1199 guchar padlen[8]; | |
10684 | 1200 gint i; |
1201 | |
10687
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
1202 g_return_val_if_fail(in_len >= 20, FALSE); |
10684 | 1203 |
1204 sha1_ctx = gaim_cipher_context_get_data(context); | |
1205 | |
1206 g_return_val_if_fail(sha1_ctx, FALSE); | |
1207 | |
11183 | 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); | |
10684 | 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++) { | |
11183 | 1224 digest[i] = (guchar)(sha1_ctx->H[i / 4] >> 24); |
10684 | 1225 sha1_ctx->H[i / 4] <<= 8; |
1226 } | |
1227 | |
1228 gaim_cipher_context_reset(context, NULL); | |
1229 | |
10687
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
1230 if(out_len) |
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
1231 *out_len = 20; |
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
1232 |
10684 | 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 | |
10687
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
1324 gboolean |
11183 | 1325 gaim_cipher_digest_region(const gchar *name, const guchar *data, |
10687
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
1326 size_t data_len, size_t in_len, |
11183 | 1327 guchar digest[], size_t *out_len) |
10684 | 1328 { |
1329 GaimCipher *cipher; | |
1330 GaimCipherContext *context; | |
10687
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
1331 gboolean ret = FALSE; |
10684 | 1332 |
10687
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
1333 g_return_val_if_fail(name, FALSE); |
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
1334 g_return_val_if_fail(data, FALSE); |
10684 | 1335 |
1336 cipher = gaim_ciphers_find_cipher(name); | |
1337 | |
10687
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
1338 g_return_val_if_fail(cipher, FALSE); |
10684 | 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); | |
10687
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
1344 return FALSE; |
10684 | 1345 } |
1346 | |
1347 context = gaim_cipher_context_new(cipher, NULL); | |
1348 gaim_cipher_context_append(context, data, data_len); | |
10687
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
1349 ret = gaim_cipher_context_digest(context, in_len, digest, out_len); |
11143 | 1350 gaim_cipher_context_destroy(context); |
10687
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
1351 |
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
1352 return ret; |
10684 | 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); | |
13758 | 1384 GAIM_DBUS_REGISTER_POINTER(cipher, GaimCipher); |
10684 | 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); | |
13758 | 1406 |
1407 GAIM_DBUS_UNREGISTER_POINTER(cipher); | |
10684 | 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); | |
11329 | 1445 gaim_ciphers_register_cipher("md4", &MD4Ops); |
11335 | 1446 gaim_ciphers_register_cipher("des", &DESOps); |
10684 | 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 | |
11183 | 1572 gaim_cipher_context_set_iv(GaimCipherContext *context, guchar *iv, size_t len) |
10684 | 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 | |
11183 | 1590 gaim_cipher_context_append(GaimCipherContext *context, const guchar *data, |
10684 | 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 | |
10687
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
1608 gaim_cipher_context_digest(GaimCipherContext *context, size_t in_len, |
11183 | 1609 guchar digest[], size_t *out_len) |
10684 | 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) | |
10687
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
1619 return cipher->ops->digest(context, in_len, digest, out_len); |
10684 | 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 | |
10687
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
1628 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
|
1629 gchar digest_s[], size_t *out_len) |
10684 | 1630 { |
10687
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
1631 /* 8k is a bit excessive, will tweak later. */ |
11183 | 1632 guchar digest[BUF_LEN * 4]; |
10684 | 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 | |
10687
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
1639 if(!gaim_cipher_context_digest(context, sizeof(digest), digest, &dlen)) |
10684 | 1640 return FALSE; |
1641 | |
12388
4e045668b9d0
[gaim-migrate @ 14694]
Richard Laager <rlaager@wiktel.com>
parents:
12382
diff
changeset
|
1642 /* 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
|
1643 if(in_len <= dlen * 2) |
10687
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
1644 return FALSE; |
10684 | 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 | |
10687
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
1651 if(out_len) |
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
1652 *out_len = dlen * 2; |
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
1653 |
10684 | 1654 return TRUE; |
1655 } | |
1656 | |
1657 gint | |
11183 | 1658 gaim_cipher_context_encrypt(GaimCipherContext *context, const guchar data[], |
1659 size_t len, guchar output[], size_t *outlen) | |
10684 | 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 | |
11183 | 1682 gaim_cipher_context_decrypt(GaimCipherContext *context, const guchar data[], |
1683 size_t len, guchar output[], size_t *outlen) | |
10684 | 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 | |
11183 | 1706 gaim_cipher_context_set_salt(GaimCipherContext *context, guchar *salt) { |
10684 | 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 | |
13697 | 1741 gaim_cipher_context_set_key(GaimCipherContext *context, const guchar *key) { |
10684 | 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 } | |
12382
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1788 |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1789 gchar *gaim_cipher_http_digest_calculate_session_key( |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1790 const gchar *algorithm, |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1791 const gchar *username, |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1792 const gchar *realm, |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1793 const gchar *password, |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1794 const gchar *nonce, |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1795 const gchar *client_nonce) |
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 GaimCipher *cipher; |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1798 GaimCipherContext *context; |
12388
4e045668b9d0
[gaim-migrate @ 14694]
Richard Laager <rlaager@wiktel.com>
parents:
12382
diff
changeset
|
1799 gchar hash[33]; /* We only support MD5. */ |
12382
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1800 |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1801 g_return_val_if_fail(username != NULL, NULL); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1802 g_return_val_if_fail(realm != NULL, NULL); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1803 g_return_val_if_fail(password != NULL, NULL); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1804 g_return_val_if_fail(nonce != NULL, NULL); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1805 |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1806 /* Check for a supported algorithm. */ |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1807 g_return_val_if_fail(algorithm == NULL || |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1808 *algorithm == '\0' || |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1809 strcasecmp(algorithm, "MD5") || |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1810 strcasecmp(algorithm, "MD5-sess"), NULL); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1811 |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1812 cipher = gaim_ciphers_find_cipher("md5"); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1813 g_return_val_if_fail(cipher != NULL, NULL); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1814 |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1815 context = gaim_cipher_context_new(cipher, NULL); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1816 |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1817 gaim_cipher_context_append(context, (guchar *)username, strlen(username)); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1818 gaim_cipher_context_append(context, (guchar *)":", 1); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1819 gaim_cipher_context_append(context, (guchar *)realm, strlen(realm)); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1820 gaim_cipher_context_append(context, (guchar *)":", 1); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1821 gaim_cipher_context_append(context, (guchar *)password, strlen(password)); |
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 (algorithm != NULL && !strcasecmp(algorithm, "MD5-sess")) |
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 guchar digest[16]; |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1826 |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1827 if (client_nonce == 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 gaim_cipher_context_destroy(context); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1830 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
|
1831 return NULL; |
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 |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1834 gaim_cipher_context_digest(context, sizeof(digest), digest, NULL); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1835 gaim_cipher_context_destroy(context); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1836 |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1837 context = gaim_cipher_context_new(cipher, NULL); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1838 gaim_cipher_context_append(context, digest, sizeof(digest)); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1839 gaim_cipher_context_append(context, (guchar *)":", 1); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1840 gaim_cipher_context_append(context, (guchar *)nonce, strlen(nonce)); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1841 gaim_cipher_context_append(context, (guchar *)":", 1); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1842 gaim_cipher_context_append(context, (guchar *)client_nonce, strlen(client_nonce)); |
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 |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1845 gaim_cipher_context_digest_to_str(context, sizeof(hash), hash, NULL); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1846 gaim_cipher_context_destroy(context); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1847 |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1848 return g_strdup(hash); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1849 } |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1850 |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1851 gchar *gaim_cipher_http_digest_calculate_response( |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1852 const gchar *algorithm, |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1853 const gchar *method, |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1854 const gchar *digest_uri, |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1855 const gchar *qop, |
12389
e024601d45c7
[gaim-migrate @ 14695]
Richard Laager <rlaager@wiktel.com>
parents:
12388
diff
changeset
|
1856 const gchar *entity, |
12382
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1857 const gchar *nonce, |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1858 const gchar *nonce_count, |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1859 const gchar *client_nonce, |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1860 const gchar *session_key) |
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 GaimCipher *cipher; |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1863 GaimCipherContext *context; |
12388
4e045668b9d0
[gaim-migrate @ 14694]
Richard Laager <rlaager@wiktel.com>
parents:
12382
diff
changeset
|
1864 static gchar hash2[33]; /* We only support MD5. */ |
12382
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1865 |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1866 g_return_val_if_fail(method != NULL, NULL); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1867 g_return_val_if_fail(digest_uri != NULL, NULL); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1868 g_return_val_if_fail(nonce != NULL, NULL); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1869 g_return_val_if_fail(session_key != NULL, NULL); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1870 |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1871 /* Check for a supported algorithm. */ |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1872 g_return_val_if_fail(algorithm == NULL || |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1873 *algorithm == '\0' || |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1874 strcasecmp(algorithm, "MD5") || |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1875 strcasecmp(algorithm, "MD5-sess"), NULL); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1876 |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1877 /* Check for a supported "quality of protection". */ |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1878 g_return_val_if_fail(qop == NULL || |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1879 *qop == '\0' || |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1880 strcasecmp(qop, "auth") || |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1881 strcasecmp(qop, "auth-int"), NULL); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1882 |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1883 cipher = gaim_ciphers_find_cipher("md5"); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1884 g_return_val_if_fail(cipher != NULL, NULL); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1885 |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1886 context = gaim_cipher_context_new(cipher, NULL); |
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 gaim_cipher_context_append(context, (guchar *)method, strlen(method)); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1889 gaim_cipher_context_append(context, (guchar *)":", 1); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1890 gaim_cipher_context_append(context, (guchar *)digest_uri, strlen(digest_uri)); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1891 |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1892 if (qop != NULL && !strcasecmp(qop, "auth-int")) |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1893 { |
12389
e024601d45c7
[gaim-migrate @ 14695]
Richard Laager <rlaager@wiktel.com>
parents:
12388
diff
changeset
|
1894 GaimCipherContext *context2; |
e024601d45c7
[gaim-migrate @ 14695]
Richard Laager <rlaager@wiktel.com>
parents:
12388
diff
changeset
|
1895 gchar entity_hash[33]; |
e024601d45c7
[gaim-migrate @ 14695]
Richard Laager <rlaager@wiktel.com>
parents:
12388
diff
changeset
|
1896 |
e024601d45c7
[gaim-migrate @ 14695]
Richard Laager <rlaager@wiktel.com>
parents:
12388
diff
changeset
|
1897 if (entity == NULL) |
12382
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 gaim_cipher_context_destroy(context); |
12389
e024601d45c7
[gaim-migrate @ 14695]
Richard Laager <rlaager@wiktel.com>
parents:
12388
diff
changeset
|
1900 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
|
1901 return NULL; |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1902 } |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1903 |
12389
e024601d45c7
[gaim-migrate @ 14695]
Richard Laager <rlaager@wiktel.com>
parents:
12388
diff
changeset
|
1904 context2 = gaim_cipher_context_new(cipher, NULL); |
e024601d45c7
[gaim-migrate @ 14695]
Richard Laager <rlaager@wiktel.com>
parents:
12388
diff
changeset
|
1905 gaim_cipher_context_append(context2, (guchar *)entity, strlen(entity)); |
e024601d45c7
[gaim-migrate @ 14695]
Richard Laager <rlaager@wiktel.com>
parents:
12388
diff
changeset
|
1906 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
|
1907 gaim_cipher_context_destroy(context2); |
e024601d45c7
[gaim-migrate @ 14695]
Richard Laager <rlaager@wiktel.com>
parents:
12388
diff
changeset
|
1908 |
12382
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1909 gaim_cipher_context_append(context, (guchar *)":", 1); |
12389
e024601d45c7
[gaim-migrate @ 14695]
Richard Laager <rlaager@wiktel.com>
parents:
12388
diff
changeset
|
1910 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
|
1911 } |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1912 |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1913 gaim_cipher_context_digest_to_str(context, sizeof(hash2), hash2, NULL); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1914 gaim_cipher_context_destroy(context); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1915 |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1916 context = gaim_cipher_context_new(cipher, NULL); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1917 gaim_cipher_context_append(context, (guchar *)session_key, strlen(session_key)); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1918 gaim_cipher_context_append(context, (guchar *)":", 1); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1919 gaim_cipher_context_append(context, (guchar *)nonce, strlen(nonce)); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1920 gaim_cipher_context_append(context, (guchar *)":", 1); |
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 if (qop != NULL && *qop != '\0') |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1923 { |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1924 if (nonce_count == 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 gaim_cipher_context_destroy(context); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1927 gaim_debug_error("cipher", "Required nonce_count missing for digest calculation."); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1928 return NULL; |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1929 } |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1930 |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1931 if (client_nonce == 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 gaim_cipher_context_destroy(context); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1934 gaim_debug_error("cipher", "Required client_nonce missing for digest calculation."); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1935 return NULL; |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1936 } |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1937 |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1938 gaim_cipher_context_append(context, (guchar *)nonce_count, strlen(nonce_count)); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1939 gaim_cipher_context_append(context, (guchar *)":", 1); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1940 gaim_cipher_context_append(context, (guchar *)client_nonce, strlen(client_nonce)); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1941 gaim_cipher_context_append(context, (guchar *)":", 1); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1942 |
13395
ff4e85e04adf
[gaim-migrate @ 15768]
Richard Laager <rlaager@wiktel.com>
parents:
13218
diff
changeset
|
1943 gaim_cipher_context_append(context, (guchar *)qop, strlen(qop)); |
12382
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1944 |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1945 gaim_cipher_context_append(context, (guchar *)":", 1); |
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 |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1948 gaim_cipher_context_append(context, (guchar *)hash2, strlen(hash2)); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1949 gaim_cipher_context_digest_to_str(context, sizeof(hash2), hash2, NULL); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1950 gaim_cipher_context_destroy(context); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1951 |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1952 return g_strdup(hash2); |
cfc808463763
[gaim-migrate @ 14688]
Richard Laager <rlaager@wiktel.com>
parents:
11677
diff
changeset
|
1953 } |