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