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