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