Thu, 07 Apr 2005 14:55:02 +0000
[gaim-migrate @ 12431]
" The following log snippets should explain it: " --rlaager
(20:24:00) rlaager: Regarding the signal handling
conversation the other day... I've written a patch to stop
calling signal handlers and return as soon as we find one
signal handler that returns TRUE to indicate that it's
handled the signal. Is this the right approach?
(20:24:22) Ethan Blanton (Paco-Paco): the trouble is that it's
documented to behave exactly the way it does
(20:24:31) Ethan Blanton (Paco-Paco): so changing it is
notbackwards compatible
(20:24:31) rlaager: I'm talking for HEAD.
(20:24:41) Ethan Blanton (Paco-Paco): oh, I think that's a
good approach, yes
(20:24:53) rlaager: The way I've described is how I
*expected* it to work, having not read the documentation.
(20:25:09) Ethan Blanton (Paco-Paco): I'm convinced
(20:27:04) Stu Tomlinson (nosnilmot): rlaager: this, I
assume, breaks the generic-ness of signals, by assuming
that any that return values return booleans?
(20:27:26) Ethan Blanton (Paco-Paco): please break it
(20:27:33) Ethan Blanton (Paco-Paco): we already have
out-parameters
(20:27:42) rlaager: nosnilmot: from what I can see, the
return type is handled as a (void *)... so I'm checking that
ret_value != NULL
(20:27:57) rlaager: nosnilmot: that's the correct way to do it,
right?
...
(20:29:01) Ethan Blanton (Paco-Paco): allowing a
meaningful return value is an over-engineering
(20:30:07) rlaager: even after this patch, you should be able
to return meaningful return values
(20:30:15) rlaager: it'll just short-circuit on the first handler
that does
committer: Luke Schierer <lschiere@pidgin.im>
| 10684 | 1 | /* |
| 2 | * gaim | |
| 3 | * | |
| 4 | * Gaim is the legal property of its developers, whose names are too numerous | |
| 5 | * to list here. Please refer to the COPYRIGHT file distributed with this | |
| 6 | * source distribution. | |
| 7 | * | |
| 8 | * Original md5 | |
| 9 | * Copyright (C) 2001-2003 Christophe Devine <c.devine@cr0.net> | |
| 10 | * | |
| 11 | * This program is free software; you can redistribute it and/or modify | |
| 12 | * it under the terms of the GNU General Public License as published by | |
| 13 | * the Free Software Foundation; either version 2 of the License, or | |
| 14 | * (at your option) any later version. | |
| 15 | * | |
| 16 | * This program is distributed in the hope that it will be useful, | |
| 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 19 | * GNU General Public License for more details. | |
| 20 | * | |
| 21 | * You should have received a copy of the GNU General Public License | |
| 22 | * along with this program; if not, write to the Free Software | |
| 23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| 24 | */ | |
| 25 | #include <glib.h> | |
| 26 | #include <string.h> | |
| 27 | #include <stdio.h> | |
| 28 | ||
| 29 | #include "internal.h" | |
| 30 | #include "cipher.h" | |
| 31 | #include "debug.h" | |
| 32 | #include "signals.h" | |
| 33 | #include "value.h" | |
| 34 | ||
| 35 | /******************************************************************************* | |
| 36 | * MD5 | |
| 37 | ******************************************************************************/ | |
| 38 | struct MD5Context { | |
| 39 | guint32 total[2]; | |
| 40 | guint32 state[4]; | |
| 41 | guint8 buffer[64]; | |
| 42 | }; | |
| 43 | ||
| 44 | #define MD5_GET_GUINT32(n,b,i) { \ | |
| 45 | (n) = ((guint32)(b) [(i) ] ) \ | |
| 46 | | ((guint32)(b) [(i) + 1] << 8) \ | |
| 47 | | ((guint32)(b) [(i) + 2] << 16) \ | |
| 48 | | ((guint32)(b) [(i) + 3] << 24); \ | |
| 49 | } | |
| 50 | #define MD5_PUT_GUINT32(n,b,i) { \ | |
| 51 | (b)[(i) ] = (guint8)((n) ); \ | |
| 52 | (b)[(i) + 1] = (guint8)((n) >> 8); \ | |
| 53 | (b)[(i) + 2] = (guint8)((n) >> 16); \ | |
| 54 | (b)[(i) + 3] = (guint8)((n) >> 24); \ | |
| 55 | } | |
| 56 | ||
| 57 | static void | |
| 58 | md5_init(GaimCipherContext *context, gpointer extra) { | |
| 59 | struct MD5Context *md5_context; | |
| 60 | ||
| 61 | md5_context = g_new0(struct MD5Context, 1); | |
| 62 | ||
| 63 | gaim_cipher_context_set_data(context, md5_context); | |
| 64 | ||
| 65 | gaim_cipher_context_reset(context, extra); | |
| 66 | } | |
| 67 | ||
| 68 | static void | |
| 69 | md5_reset(GaimCipherContext *context, gpointer extra) { | |
| 70 | struct MD5Context *md5_context; | |
| 71 | ||
| 72 | md5_context = gaim_cipher_context_get_data(context); | |
| 73 | ||
| 74 | md5_context->total[0] = 0; | |
| 75 | md5_context->total[1] = 0; | |
| 76 | ||
| 77 | md5_context->state[0] = 0x67452301; | |
| 78 | md5_context->state[1] = 0xEFCDAB89; | |
| 79 | md5_context->state[2] = 0x98BADCFE; | |
| 80 | md5_context->state[3] = 0x10325476; | |
| 81 | ||
| 82 | memset(md5_context->buffer, 0, sizeof(md5_context->buffer)); | |
| 83 | } | |
| 84 | ||
| 85 | static void | |
| 86 | md5_uninit(GaimCipherContext *context) { | |
| 87 | struct MD5Context *md5_context; | |
| 88 | ||
| 89 | gaim_cipher_context_reset(context, NULL); | |
| 90 | ||
| 91 | md5_context = gaim_cipher_context_get_data(context); | |
| 92 | memset(md5_context, 0, sizeof(md5_context)); | |
| 93 | ||
| 94 | g_free(md5_context); | |
| 95 | md5_context = NULL; | |
| 96 | } | |
| 97 | ||
| 98 | static void | |
| 99 | md5_process(struct MD5Context *md5_context, const guint8 data[64]) { | |
| 100 | guint32 X[16], A, B, C, D; | |
| 101 | ||
| 102 | A = md5_context->state[0]; | |
| 103 | B = md5_context->state[1]; | |
| 104 | C = md5_context->state[2]; | |
| 105 | D = md5_context->state[3]; | |
| 106 | ||
| 107 | MD5_GET_GUINT32(X[ 0], data, 0); | |
| 108 | MD5_GET_GUINT32(X[ 1], data, 4); | |
| 109 | MD5_GET_GUINT32(X[ 2], data, 8); | |
| 110 | MD5_GET_GUINT32(X[ 3], data, 12); | |
| 111 | MD5_GET_GUINT32(X[ 4], data, 16); | |
| 112 | MD5_GET_GUINT32(X[ 5], data, 20); | |
| 113 | MD5_GET_GUINT32(X[ 6], data, 24); | |
| 114 | MD5_GET_GUINT32(X[ 7], data, 28); | |
| 115 | MD5_GET_GUINT32(X[ 8], data, 32); | |
| 116 | MD5_GET_GUINT32(X[ 9], data, 36); | |
| 117 | MD5_GET_GUINT32(X[10], data, 40); | |
| 118 | MD5_GET_GUINT32(X[11], data, 44); | |
| 119 | MD5_GET_GUINT32(X[12], data, 48); | |
| 120 | MD5_GET_GUINT32(X[13], data, 52); | |
| 121 | MD5_GET_GUINT32(X[14], data, 56); | |
| 122 | MD5_GET_GUINT32(X[15], data, 60); | |
| 123 | ||
| 124 | #define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) | |
| 125 | #define P(a,b,c,d,k,s,t) { \ | |
| 126 | a += F(b,c,d) + X[k] + t; \ | |
| 127 | a = S(a,s) + b; \ | |
| 128 | } | |
| 129 | ||
| 130 | /* first pass */ | |
| 131 | #define F(x,y,z) (z ^ (x & (y ^ z))) | |
| 132 | P(A, B, C, D, 0, 7, 0xD76AA478); | |
| 133 | P(D, A, B, C, 1, 12, 0xE8C7B756); | |
| 134 | P(C, D, A, B, 2, 17, 0x242070DB); | |
| 135 | P(B, C, D, A, 3, 22, 0xC1BDCEEE); | |
| 136 | P(A, B, C, D, 4, 7, 0xF57C0FAF); | |
| 137 | P(D, A, B, C, 5, 12, 0x4787C62A); | |
| 138 | P(C, D, A, B, 6, 17, 0xA8304613); | |
| 139 | P(B, C, D, A, 7, 22, 0xFD469501); | |
| 140 | P(A, B, C, D, 8, 7, 0x698098D8); | |
| 141 | P(D, A, B, C, 9, 12, 0x8B44F7AF); | |
| 142 | P(C, D, A, B, 10, 17, 0xFFFF5BB1); | |
| 143 | P(B, C, D, A, 11, 22, 0x895CD7BE); | |
| 144 | P(A, B, C, D, 12, 7, 0x6B901122); | |
| 145 | P(D, A, B, C, 13, 12, 0xFD987193); | |
| 146 | P(C, D, A, B, 14, 17, 0xA679438E); | |
| 147 | P(B, C, D, A, 15, 22, 0x49B40821); | |
| 148 | #undef F | |
| 149 | ||
| 150 | /* second pass */ | |
| 151 | #define F(x,y,z) (y ^ (z & (x ^ y))) | |
| 152 | P(A, B, C, D, 1, 5, 0xF61E2562); | |
| 153 | P(D, A, B, C, 6, 9, 0xC040B340); | |
| 154 | P(C, D, A, B, 11, 14, 0x265E5A51); | |
| 155 | P(B, C, D, A, 0, 20, 0xE9B6C7AA); | |
| 156 | P(A, B, C, D, 5, 5, 0xD62F105D); | |
| 157 | P(D, A, B, C, 10, 9, 0x02441453); | |
| 158 | P(C, D, A, B, 15, 14, 0xD8A1E681); | |
| 159 | P(B, C, D, A, 4, 20, 0xE7D3FBC8); | |
| 160 | P(A, B, C, D, 9, 5, 0x21E1CDE6); | |
| 161 | P(D, A, B, C, 14, 9, 0xC33707D6); | |
| 162 | P(C, D, A, B, 3, 14, 0xF4D50D87); | |
| 163 | P(B, C, D, A, 8, 20, 0x455A14ED); | |
| 164 | P(A, B, C, D, 13, 5, 0xA9E3E905); | |
| 165 | P(D, A, B, C, 2, 9, 0xFCEFA3F8); | |
| 166 | P(C, D, A, B, 7, 14, 0x676F02D9); | |
| 167 | P(B, C, D, A, 12, 20, 0x8D2A4C8A); | |
| 168 | #undef F | |
| 169 | ||
| 170 | /* third pass */ | |
| 171 | #define F(x,y,z) (x ^ y ^ z) | |
| 172 | P(A, B, C, D, 5, 4, 0xFFFA3942); | |
| 173 | P(D, A, B, C, 8, 11, 0x8771F681); | |
| 174 | P(C, D, A, B, 11, 16, 0x6D9D6122); | |
| 175 | P(B, C, D, A, 14, 23, 0xFDE5380C); | |
| 176 | P(A, B, C, D, 1, 4, 0xA4BEEA44); | |
| 177 | P(D, A, B, C, 4, 11, 0x4BDECFA9); | |
| 178 | P(C, D, A, B, 7, 16, 0xF6BB4B60); | |
| 179 | P(B, C, D, A, 10, 23, 0xBEBFBC70); | |
| 180 | P(A, B, C, D, 13, 4, 0x289B7EC6); | |
| 181 | P(D, A, B, C, 0, 11, 0xEAA127FA); | |
| 182 | P(C, D, A, B, 3, 16, 0xD4EF3085); | |
| 183 | P(B, C, D, A, 6, 23, 0x04881D05); | |
| 184 | P(A, B, C, D, 9, 4, 0xD9D4D039); | |
| 185 | P(D, A, B, C, 12, 11, 0xE6DB99E5); | |
| 186 | P(C, D, A, B, 15, 16, 0x1FA27CF8); | |
| 187 | P(B, C, D, A, 2, 23, 0xC4AC5665); | |
| 188 | #undef F | |
| 189 | ||
| 190 | /* forth pass */ | |
| 191 | #define F(x,y,z) (y ^ (x | ~z)) | |
| 192 | P(A, B, C, D, 0, 6, 0xF4292244); | |
| 193 | P(D, A, B, C, 7, 10, 0x432AFF97); | |
| 194 | P(C, D, A, B, 14, 15, 0xAB9423A7); | |
| 195 | P(B, C, D, A, 5, 21, 0xFC93A039); | |
| 196 | P(A, B, C, D, 12, 6, 0x655B59C3); | |
| 197 | P(D, A, B, C, 3, 10, 0x8F0CCC92); | |
| 198 | P(C, D, A, B, 10, 15, 0xFFEFF47D); | |
| 199 | P(B, C, D, A, 1, 21, 0x85845DD1); | |
| 200 | P(A, B, C, D, 8, 6, 0x6FA87E4F); | |
| 201 | P(D, A, B, C, 15, 10, 0xFE2CE6E0); | |
| 202 | P(C, D, A, B, 6, 15, 0xA3014314); | |
| 203 | P(B, C, D, A, 13, 21, 0x4E0811A1); | |
| 204 | P(A, B, C, D, 4, 6, 0xF7537E82); | |
| 205 | P(D, A, B, C, 11, 10, 0xBD3AF235); | |
| 206 | P(C, D, A, B, 2, 15, 0x2AD7D2BB); | |
| 207 | P(B, C, D, A, 9, 21, 0xEB86D391); | |
| 208 | #undef F | |
| 209 | #undef P | |
| 210 | #undef S | |
| 211 | ||
| 212 | md5_context->state[0] += A; | |
| 213 | md5_context->state[1] += B; | |
| 214 | md5_context->state[2] += C; | |
| 215 | md5_context->state[3] += D; | |
| 216 | } | |
| 217 | ||
| 218 | static void | |
| 219 | md5_append(GaimCipherContext *context, const guint8 *data, size_t len) { | |
| 220 | struct MD5Context *md5_context = NULL; | |
| 221 | guint32 left = 0, fill = 0; | |
| 222 | ||
| 223 | g_return_if_fail(context != NULL); | |
| 224 | ||
| 225 | md5_context = gaim_cipher_context_get_data(context); | |
| 226 | g_return_if_fail(md5_context != NULL); | |
| 227 | ||
| 228 | left = md5_context->total[0] & 0x3F; | |
| 229 | fill = 64 - left; | |
| 230 | ||
| 231 | md5_context->total[0] += len; | |
| 232 | md5_context->total[0] &= 0xFFFFFFFF; | |
| 233 | ||
| 234 | if(md5_context->total[0] < len) | |
| 235 | md5_context->total[1]++; | |
| 236 | ||
| 237 | if(left && len >= fill) { | |
| 238 | memcpy((md5_context->buffer + left), data, fill); | |
| 239 | md5_process(md5_context, md5_context->buffer); | |
| 240 | len -= fill; | |
| 241 | data += fill; | |
| 242 | left = 0; | |
| 243 | } | |
| 244 | ||
| 245 | while(len >= 64) { | |
| 246 | md5_process(md5_context, data); | |
| 247 | len -= 64; | |
| 248 | data += 64; | |
| 249 | } | |
| 250 | ||
| 251 | if(len) { | |
| 252 | memcpy((md5_context->buffer + left), data, len); | |
| 253 | } | |
| 254 | } | |
| 255 | ||
| 256 | static gboolean | |
| 10687 | 257 | md5_digest(GaimCipherContext *context, size_t in_len, guint8 digest[16], |
| 258 | size_t *out_len) | |
| 259 | { | |
| 10684 | 260 | struct MD5Context *md5_context = NULL; |
| 261 | guint32 last, pad; | |
| 262 | guint32 high, low; | |
| 263 | guint8 message[8]; | |
| 264 | guint8 padding[64] = { | |
| 265 | 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 266 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 267 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 268 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | |
| 269 | }; | |
| 270 | ||
| 10687 | 271 | g_return_val_if_fail(in_len >= 16, FALSE); |
| 10684 | 272 | |
| 273 | md5_context = gaim_cipher_context_get_data(context); | |
| 274 | ||
| 275 | high = (md5_context->total[0] >> 29) | |
| 276 | | (md5_context->total[1] << 3); | |
| 277 | low = (md5_context->total[0] << 3); | |
| 278 | ||
| 279 | MD5_PUT_GUINT32(low, message, 0); | |
| 280 | MD5_PUT_GUINT32(high, message, 4); | |
| 281 | ||
| 282 | last = md5_context->total[0] & 0x3F; | |
| 283 | pad = (last < 56) ? (56 - last) : (120 - last); | |
| 284 | ||
| 285 | md5_append(context, padding, pad); | |
| 286 | md5_append(context, message, 8); | |
| 287 | ||
| 288 | MD5_PUT_GUINT32(md5_context->state[0], digest, 0); | |
| 289 | MD5_PUT_GUINT32(md5_context->state[1], digest, 4); | |
| 290 | MD5_PUT_GUINT32(md5_context->state[2], digest, 8); | |
| 291 | MD5_PUT_GUINT32(md5_context->state[3], digest, 12); | |
| 292 | ||
| 10687 | 293 | if(out_len) |
| 294 | *out_len = 16; | |
| 295 | ||
| 10684 | 296 | return TRUE; |
| 297 | } | |
| 298 | ||
| 299 | static GaimCipherOps MD5Ops = { | |
| 300 | NULL, /* Set option */ | |
| 301 | NULL, /* Get option */ | |
| 302 | md5_init, /* init */ | |
| 303 | md5_reset, /* reset */ | |
| 304 | md5_uninit, /* uninit */ | |
| 305 | NULL, /* set iv */ | |
| 306 | md5_append, /* append */ | |
| 307 | md5_digest, /* digest */ | |
| 308 | NULL, /* encrypt */ | |
| 309 | NULL, /* decrypt */ | |
| 310 | NULL, /* set salt */ | |
| 311 | NULL, /* get salt size */ | |
| 312 | NULL, /* set key */ | |
| 313 | NULL /* get key size */ | |
| 314 | }; | |
| 315 | ||
| 316 | /******************************************************************************* | |
| 317 | * SHA-1 | |
| 318 | ******************************************************************************/ | |
| 319 | #define SHA1_ROTL(X,n) ((((X) << (n)) | ((X) >> (32-(n)))) & 0xFFFFFFFF) | |
| 320 | ||
| 321 | struct SHA1Context { | |
| 322 | guint32 H[5]; | |
| 323 | guint32 W[80]; | |
| 324 | ||
| 325 | gint lenW; | |
| 326 | ||
| 327 | guint32 sizeHi; | |
| 328 | guint32 sizeLo; | |
| 329 | }; | |
| 330 | ||
| 331 | static void | |
| 332 | sha1_hash_block(struct SHA1Context *sha1_ctx) { | |
| 333 | gint i; | |
| 334 | guint32 A, B, C, D, E, T; | |
| 335 | ||
| 336 | for(i = 16; i < 80; i++) { | |
| 337 | sha1_ctx->W[i] = SHA1_ROTL(sha1_ctx->W[i - 3] ^ | |
| 338 | sha1_ctx->W[i - 8] ^ | |
| 339 | sha1_ctx->W[i - 14] ^ | |
| 340 | sha1_ctx->W[i - 16], 1); | |
| 341 | } | |
| 342 | ||
| 343 | A = sha1_ctx->H[0]; | |
| 344 | B = sha1_ctx->H[1]; | |
| 345 | C = sha1_ctx->H[2]; | |
| 346 | D = sha1_ctx->H[3]; | |
| 347 | E = sha1_ctx->H[4]; | |
| 348 | ||
| 349 | for(i = 0; i < 20; i++) { | |
| 350 | T = (SHA1_ROTL(A, 5) + (((C ^ D) & B) ^ D) + E + sha1_ctx->W[i] + 0x5A827999) & 0xFFFFFFFF; | |
| 351 | E = D; | |
| 352 | D = C; | |
| 353 | C = SHA1_ROTL(B, 30); | |
| 354 | B = A; | |
| 355 | A = T; | |
| 356 | } | |
| 357 | ||
| 358 | for(i = 20; i < 40; i++) { | |
| 359 | T = (SHA1_ROTL(A, 5) + (B ^ C ^ D) + E + sha1_ctx->W[i] + 0x6ED9EBA1) & 0xFFFFFFFF; | |
| 360 | E = D; | |
| 361 | D = C; | |
| 362 | C = SHA1_ROTL(B, 30); | |
| 363 | B = A; | |
| 364 | A = T; | |
| 365 | } | |
| 366 | ||
| 367 | for(i = 40; i < 60; i++) { | |
| 368 | T = (SHA1_ROTL(A, 5) + ((B & C) | (D & (B | C))) + E + sha1_ctx->W[i] + 0x8F1BBCDC) & 0xFFFFFFFF; | |
| 369 | E = D; | |
| 370 | D = C; | |
| 371 | C = SHA1_ROTL(B, 30); | |
| 372 | B = A; | |
| 373 | A = T; | |
| 374 | } | |
| 375 | ||
| 376 | for(i = 60; i < 80; i++) { | |
| 377 | T = (SHA1_ROTL(A, 5) + (B ^ C ^ D) + E + sha1_ctx->W[i] + 0xCA62C1D6) & 0xFFFFFFFF; | |
| 378 | E = D; | |
| 379 | D = C; | |
| 380 | C = SHA1_ROTL(B, 30); | |
| 381 | B = A; | |
| 382 | A = T; | |
| 383 | } | |
| 384 | ||
| 385 | sha1_ctx->H[0] += A; | |
| 386 | sha1_ctx->H[1] += B; | |
| 387 | sha1_ctx->H[2] += C; | |
| 388 | sha1_ctx->H[3] += D; | |
| 389 | sha1_ctx->H[4] += E; | |
| 390 | } | |
| 391 | ||
| 392 | static void | |
| 393 | sha1_set_opt(GaimCipherContext *context, const gchar *name, void *value) { | |
| 394 | struct SHA1Context *ctx; | |
| 395 | ||
| 396 | ctx = gaim_cipher_context_get_data(context); | |
| 397 | ||
| 398 | if(!strcmp(name, "sizeHi")) { | |
| 399 | ctx->sizeHi = GPOINTER_TO_INT(value); | |
| 400 | } else if(!strcmp(name, "sizeLo")) { | |
| 401 | ctx->sizeLo = GPOINTER_TO_INT(value); | |
| 402 | } else if(!strcmp(name, "lenW")) { | |
| 403 | ctx->lenW = GPOINTER_TO_INT(value); | |
| 404 | } | |
| 405 | } | |
| 406 | ||
| 407 | static void * | |
| 408 | sha1_get_opt(GaimCipherContext *context, const gchar *name) { | |
| 409 | struct SHA1Context *ctx; | |
| 410 | ||
| 411 | ctx = gaim_cipher_context_get_data(context); | |
| 412 | ||
| 413 | if(!strcmp(name, "sizeHi")) { | |
| 414 | return GINT_TO_POINTER(ctx->sizeHi); | |
| 415 | } else if(!strcmp(name, "sizeLo")) { | |
| 416 | return GINT_TO_POINTER(ctx->sizeLo); | |
| 417 | } else if(!strcmp(name, "lenW")) { | |
| 418 | return GINT_TO_POINTER(ctx->lenW); | |
| 419 | } | |
| 420 | ||
| 421 | return NULL; | |
| 422 | } | |
| 423 | ||
| 424 | static void | |
| 425 | sha1_init(GaimCipherContext *context, void *extra) { | |
| 426 | struct SHA1Context *sha1_ctx; | |
| 427 | ||
| 428 | sha1_ctx = g_new0(struct SHA1Context, 1); | |
| 429 | ||
| 430 | gaim_cipher_context_set_data(context, sha1_ctx); | |
| 431 | ||
| 432 | gaim_cipher_context_reset(context, extra); | |
| 433 | } | |
| 434 | ||
| 435 | static void | |
| 436 | sha1_reset(GaimCipherContext *context, void *extra) { | |
| 437 | struct SHA1Context *sha1_ctx; | |
| 438 | gint i; | |
| 439 | ||
| 440 | sha1_ctx = gaim_cipher_context_get_data(context); | |
| 441 | ||
| 442 | g_return_if_fail(sha1_ctx); | |
| 443 | ||
| 444 | sha1_ctx->lenW = 0; | |
| 445 | sha1_ctx->sizeHi = 0; | |
| 446 | sha1_ctx->sizeLo = 0; | |
| 447 | ||
| 448 | sha1_ctx->H[0] = 0x67452301; | |
| 449 | sha1_ctx->H[1] = 0xEFCDAB89; | |
| 450 | sha1_ctx->H[2] = 0x98BADCFE; | |
| 451 | sha1_ctx->H[3] = 0x10325476; | |
| 452 | sha1_ctx->H[4] = 0xC3D2E1F0; | |
| 453 | ||
| 454 | for(i = 0; i < 80; i++) | |
| 455 | sha1_ctx->W[i] = 0; | |
| 456 | } | |
| 457 | ||
| 458 | static void | |
| 459 | sha1_uninit(GaimCipherContext *context) { | |
| 460 | struct SHA1Context *sha1_ctx; | |
| 461 | ||
| 462 | gaim_cipher_context_reset(context, NULL); | |
| 463 | ||
| 464 | sha1_ctx = gaim_cipher_context_get_data(context); | |
| 465 | ||
| 466 | memset(sha1_ctx, 0, sizeof(struct SHA1Context)); | |
| 467 | ||
| 468 | g_free(sha1_ctx); | |
| 469 | sha1_ctx = NULL; | |
| 470 | } | |
| 471 | ||
| 472 | ||
| 473 | static void | |
| 474 | sha1_append(GaimCipherContext *context, const guint8 *data, size_t len) { | |
| 475 | struct SHA1Context *sha1_ctx; | |
| 476 | gint i; | |
| 477 | ||
| 478 | sha1_ctx = gaim_cipher_context_get_data(context); | |
| 479 | ||
| 480 | g_return_if_fail(sha1_ctx); | |
| 481 | ||
| 482 | for(i = 0; i < len; i++) { | |
| 483 | sha1_ctx->W[sha1_ctx->lenW / 4] <<= 8; | |
| 484 | sha1_ctx->W[sha1_ctx->lenW / 4] |= data[i]; | |
| 485 | ||
| 486 | if((++sha1_ctx->lenW) % 64 == 0) { | |
| 487 | sha1_hash_block(sha1_ctx); | |
| 488 | sha1_ctx->lenW = 0; | |
| 489 | } | |
| 490 | ||
| 491 | sha1_ctx->sizeLo += 8; | |
| 492 | sha1_ctx->sizeHi += (sha1_ctx->sizeLo < 8); | |
| 493 | } | |
| 494 | } | |
| 495 | ||
| 496 | static gboolean | |
| 10687 | 497 | sha1_digest(GaimCipherContext *context, size_t in_len, guint8 digest[20], |
| 498 | size_t *out_len) | |
| 499 | { | |
| 10684 | 500 | struct SHA1Context *sha1_ctx; |
| 501 | guint8 pad0x80 = 0x80, pad0x00 = 0x00; | |
| 502 | guint8 padlen[8]; | |
| 503 | gint i; | |
| 504 | ||
| 10687 | 505 | g_return_val_if_fail(in_len >= 20, FALSE); |
| 10684 | 506 | |
| 507 | sha1_ctx = gaim_cipher_context_get_data(context); | |
| 508 | ||
| 509 | g_return_val_if_fail(sha1_ctx, FALSE); | |
| 510 | ||
| 511 | padlen[0] = (guint8)((sha1_ctx->sizeHi >> 24) & 255); | |
| 512 | padlen[1] = (guint8)((sha1_ctx->sizeHi >> 16) & 255); | |
| 513 | padlen[2] = (guint8)((sha1_ctx->sizeHi >> 8) & 255); | |
| 514 | padlen[3] = (guint8)((sha1_ctx->sizeHi >> 0) & 255); | |
| 515 | padlen[4] = (guint8)((sha1_ctx->sizeLo >> 24) & 255); | |
| 516 | padlen[5] = (guint8)((sha1_ctx->sizeLo >> 16) & 255); | |
| 517 | padlen[6] = (guint8)((sha1_ctx->sizeLo >> 8) & 255); | |
| 518 | padlen[7] = (guint8)((sha1_ctx->sizeLo >> 0) & 255); | |
| 519 | ||
| 520 | /* pad with a 1, then zeroes, then length */ | |
| 521 | gaim_cipher_context_append(context, &pad0x80, 1); | |
| 522 | while(sha1_ctx->lenW != 56) | |
| 523 | gaim_cipher_context_append(context, &pad0x00, 1); | |
| 524 | gaim_cipher_context_append(context, padlen, 8); | |
| 525 | ||
| 526 | for(i = 0; i < 20; i++) { | |
| 527 | digest[i] = (guint8)(sha1_ctx->H[i / 4] >> 24); | |
| 528 | sha1_ctx->H[i / 4] <<= 8; | |
| 529 | } | |
| 530 | ||
| 531 | gaim_cipher_context_reset(context, NULL); | |
| 532 | ||
| 10687 | 533 | if(out_len) |
| 534 | *out_len = 20; | |
| 535 | ||
| 10684 | 536 | return TRUE; |
| 537 | } | |
| 538 | ||
| 539 | static GaimCipherOps SHA1Ops = { | |
| 540 | sha1_set_opt, /* Set Option */ | |
| 541 | sha1_get_opt, /* Get Option */ | |
| 542 | sha1_init, /* init */ | |
| 543 | sha1_reset, /* reset */ | |
| 544 | sha1_uninit, /* uninit */ | |
| 545 | NULL, /* set iv */ | |
| 546 | sha1_append, /* append */ | |
| 547 | sha1_digest, /* digest */ | |
| 548 | NULL, /* encrypt */ | |
| 549 | NULL, /* decrypt */ | |
| 550 | NULL, /* set salt */ | |
| 551 | NULL, /* get salt size */ | |
| 552 | NULL, /* set key */ | |
| 553 | NULL /* get key size */ | |
| 554 | }; | |
| 555 | ||
| 556 | /******************************************************************************* | |
| 557 | * Structs | |
| 558 | ******************************************************************************/ | |
| 559 | struct _GaimCipher { | |
| 560 | gchar *name; | |
| 561 | GaimCipherOps *ops; | |
| 562 | guint ref; | |
| 563 | }; | |
| 564 | ||
| 565 | struct _GaimCipherContext { | |
| 566 | GaimCipher *cipher; | |
| 567 | gpointer data; | |
| 568 | }; | |
| 569 | ||
| 570 | /****************************************************************************** | |
| 571 | * Globals | |
| 572 | *****************************************************************************/ | |
| 573 | static GList *ciphers = NULL; | |
| 574 | ||
| 575 | /****************************************************************************** | |
| 576 | * GaimCipher API | |
| 577 | *****************************************************************************/ | |
| 578 | const gchar * | |
| 579 | gaim_cipher_get_name(GaimCipher *cipher) { | |
| 580 | g_return_val_if_fail(cipher, NULL); | |
| 581 | ||
| 582 | return cipher->name; | |
| 583 | } | |
| 584 | ||
| 585 | guint | |
| 586 | gaim_cipher_get_capabilities(GaimCipher *cipher) { | |
| 587 | GaimCipherOps *ops = NULL; | |
| 588 | guint caps = 0; | |
| 589 | ||
| 590 | g_return_val_if_fail(cipher, 0); | |
| 591 | ||
| 592 | ops = cipher->ops; | |
| 593 | g_return_val_if_fail(ops, 0); | |
| 594 | ||
| 595 | if(ops->set_option) | |
| 596 | caps |= GAIM_CIPHER_CAPS_SET_OPT; | |
| 597 | if(ops->get_option) | |
| 598 | caps |= GAIM_CIPHER_CAPS_GET_OPT; | |
| 599 | if(ops->init) | |
| 600 | caps |= GAIM_CIPHER_CAPS_INIT; | |
| 601 | if(ops->reset) | |
| 602 | caps |= GAIM_CIPHER_CAPS_RESET; | |
| 603 | if(ops->uninit) | |
| 604 | caps |= GAIM_CIPHER_CAPS_UNINIT; | |
| 605 | if(ops->set_iv) | |
| 606 | caps |= GAIM_CIPHER_CAPS_SET_IV; | |
| 607 | if(ops->append) | |
| 608 | caps |= GAIM_CIPHER_CAPS_APPEND; | |
| 609 | if(ops->digest) | |
| 610 | caps |= GAIM_CIPHER_CAPS_DIGEST; | |
| 611 | if(ops->encrypt) | |
| 612 | caps |= GAIM_CIPHER_CAPS_ENCRYPT; | |
| 613 | if(ops->decrypt) | |
| 614 | caps |= GAIM_CIPHER_CAPS_DECRYPT; | |
| 615 | if(ops->set_salt) | |
| 616 | caps |= GAIM_CIPHER_CAPS_SET_SALT; | |
| 617 | if(ops->get_salt_size) | |
| 618 | caps |= GAIM_CIPHER_CAPS_GET_SALT_SIZE; | |
| 619 | if(ops->set_key) | |
| 620 | caps |= GAIM_CIPHER_CAPS_SET_KEY; | |
| 621 | if(ops->get_key_size) | |
| 622 | caps |= GAIM_CIPHER_CAPS_GET_KEY_SIZE; | |
| 623 | ||
| 624 | return caps; | |
| 625 | } | |
| 626 | ||
| 10687 | 627 | gboolean |
| 10684 | 628 | gaim_cipher_digest_region(const gchar *name, const guint8 *data, |
| 10687 | 629 | size_t data_len, size_t in_len, |
| 630 | guint8 digest[], size_t *out_len) | |
| 10684 | 631 | { |
| 632 | GaimCipher *cipher; | |
| 633 | GaimCipherContext *context; | |
| 10687 | 634 | gboolean ret = FALSE; |
| 10684 | 635 | |
| 10687 | 636 | g_return_val_if_fail(name, FALSE); |
| 637 | g_return_val_if_fail(data, FALSE); | |
| 10684 | 638 | |
| 639 | cipher = gaim_ciphers_find_cipher(name); | |
| 640 | ||
| 10687 | 641 | g_return_val_if_fail(cipher, FALSE); |
| 10684 | 642 | |
| 643 | if(!cipher->ops->append || !cipher->ops->digest) { | |
| 644 | gaim_debug_info("cipher", "gaim_cipher_region failed: " | |
| 645 | "the %s cipher does not support appending and or " | |
| 646 | "digesting.", cipher->name); | |
| 10687 | 647 | return FALSE; |
| 10684 | 648 | } |
| 649 | ||
| 650 | context = gaim_cipher_context_new(cipher, NULL); | |
| 651 | gaim_cipher_context_append(context, data, data_len); | |
| 10687 | 652 | ret = gaim_cipher_context_digest(context, in_len, digest, out_len); |
| 653 | gaim_cipher_context_destroy(context); | |
| 654 | ||
| 655 | return ret; | |
| 10684 | 656 | } |
| 657 | ||
| 658 | /****************************************************************************** | |
| 659 | * GaimCiphers API | |
| 660 | *****************************************************************************/ | |
| 661 | GaimCipher * | |
| 662 | gaim_ciphers_find_cipher(const gchar *name) { | |
| 663 | GaimCipher *cipher; | |
| 664 | GList *l; | |
| 665 | ||
| 666 | g_return_val_if_fail(name, NULL); | |
| 667 | ||
| 668 | for(l = ciphers; l; l = l->next) { | |
| 669 | cipher = GAIM_CIPHER(l->data); | |
| 670 | ||
| 671 | if(!g_ascii_strcasecmp(cipher->name, name)) | |
| 672 | return cipher; | |
| 673 | } | |
| 674 | ||
| 675 | return NULL; | |
| 676 | } | |
| 677 | ||
| 678 | GaimCipher * | |
| 679 | gaim_ciphers_register_cipher(const gchar *name, GaimCipherOps *ops) { | |
| 680 | GaimCipher *cipher = NULL; | |
| 681 | ||
| 682 | g_return_val_if_fail(name, NULL); | |
| 683 | g_return_val_if_fail(ops, NULL); | |
| 684 | g_return_val_if_fail(!gaim_ciphers_find_cipher(name), NULL); | |
| 685 | ||
| 686 | cipher = g_new0(GaimCipher, 1); | |
| 687 | ||
| 688 | cipher->name = g_strdup(name); | |
| 689 | cipher->ops = ops; | |
| 690 | ||
| 691 | ciphers = g_list_append(ciphers, cipher); | |
| 692 | ||
| 693 | gaim_signal_emit(gaim_ciphers_get_handle(), "cipher-added", cipher); | |
| 694 | ||
| 695 | return cipher; | |
| 696 | } | |
| 697 | ||
| 698 | gboolean | |
| 699 | gaim_ciphers_unregister_cipher(GaimCipher *cipher) { | |
| 700 | g_return_val_if_fail(cipher, FALSE); | |
| 701 | g_return_val_if_fail(cipher->ref == 0, FALSE); | |
| 702 | ||
| 703 | gaim_signal_emit(gaim_ciphers_get_handle(), "cipher-removed", cipher); | |
| 704 | ||
| 705 | ciphers = g_list_remove(ciphers, cipher); | |
| 706 | ||
| 707 | g_free(cipher->name); | |
| 708 | g_free(cipher); | |
| 709 | ||
| 710 | return TRUE; | |
| 711 | } | |
| 712 | ||
| 713 | GList * | |
| 714 | gaim_ciphers_get_ciphers() { | |
| 715 | return ciphers; | |
| 716 | } | |
| 717 | ||
| 718 | /****************************************************************************** | |
| 719 | * GaimCipher Subsystem API | |
| 720 | *****************************************************************************/ | |
| 721 | gpointer | |
| 722 | gaim_ciphers_get_handle() { | |
| 723 | static gint handle; | |
| 724 | ||
| 725 | return &handle; | |
| 726 | } | |
| 727 | ||
| 728 | void | |
| 729 | gaim_ciphers_init() { | |
| 730 | gpointer handle; | |
| 731 | ||
| 732 | handle = gaim_ciphers_get_handle(); | |
| 733 | ||
| 734 | gaim_signal_register(handle, "cipher-added", | |
| 735 | gaim_marshal_VOID__POINTER, NULL, 1, | |
| 736 | gaim_value_new(GAIM_TYPE_SUBTYPE, | |
| 737 | GAIM_SUBTYPE_CIPHER)); | |
| 738 | gaim_signal_register(handle, "cipher-removed", | |
| 739 | gaim_marshal_VOID__POINTER, NULL, 1, | |
| 740 | gaim_value_new(GAIM_TYPE_SUBTYPE, | |
| 741 | GAIM_SUBTYPE_CIPHER)); | |
| 742 | ||
| 743 | gaim_ciphers_register_cipher("md5", &MD5Ops); | |
| 744 | gaim_ciphers_register_cipher("sha1", &SHA1Ops); | |
| 745 | } | |
| 746 | ||
| 747 | void | |
| 748 | gaim_ciphers_uninit() { | |
| 749 | GaimCipher *cipher; | |
| 750 | GList *l, *ll; | |
| 751 | ||
| 752 | for(l = ciphers; l; l = ll) { | |
| 753 | ll = l->next; | |
| 754 | ||
| 755 | cipher = GAIM_CIPHER(l->data); | |
| 756 | gaim_ciphers_unregister_cipher(cipher); | |
| 757 | ||
| 758 | ciphers = g_list_remove(ciphers, cipher); | |
| 759 | } | |
| 760 | ||
| 761 | g_list_free(ciphers); | |
| 762 | ||
| 763 | gaim_signals_unregister_by_instance(gaim_ciphers_get_handle()); | |
| 764 | } | |
| 765 | /****************************************************************************** | |
| 766 | * GaimCipherContext API | |
| 767 | *****************************************************************************/ | |
| 768 | void | |
| 769 | gaim_cipher_context_set_option(GaimCipherContext *context, const gchar *name, | |
| 770 | gpointer value) | |
| 771 | { | |
| 772 | GaimCipher *cipher = NULL; | |
| 773 | ||
| 774 | g_return_if_fail(context); | |
| 775 | g_return_if_fail(name); | |
| 776 | ||
| 777 | cipher = context->cipher; | |
| 778 | g_return_if_fail(cipher); | |
| 779 | ||
| 780 | if(cipher->ops && cipher->ops->set_option) | |
| 781 | cipher->ops->set_option(context, name, value); | |
| 782 | else | |
| 783 | gaim_debug_info("cipher", "the %s cipher does not support the " | |
| 784 | "set_option operation\n", cipher->name); | |
| 785 | } | |
| 786 | ||
| 787 | gpointer | |
| 788 | gaim_cipher_context_get_option(GaimCipherContext *context, const gchar *name) { | |
| 789 | GaimCipher *cipher = NULL; | |
| 790 | ||
| 791 | g_return_val_if_fail(context, NULL); | |
| 792 | g_return_val_if_fail(name, NULL); | |
| 793 | ||
| 794 | cipher = context->cipher; | |
| 795 | g_return_val_if_fail(cipher, NULL); | |
| 796 | ||
| 797 | if(cipher->ops && cipher->ops->get_option) | |
| 798 | return cipher->ops->get_option(context, name); | |
| 799 | else { | |
| 800 | gaim_debug_info("cipher", "the %s cipher does not support the " | |
| 801 | "get_option operation\n", cipher->name); | |
| 802 | ||
| 803 | return NULL; | |
| 804 | } | |
| 805 | } | |
| 806 | ||
| 807 | GaimCipherContext * | |
| 808 | gaim_cipher_context_new(GaimCipher *cipher, void *extra) { | |
| 809 | GaimCipherContext *context = NULL; | |
| 810 | ||
| 811 | g_return_val_if_fail(cipher, NULL); | |
| 812 | ||
| 813 | cipher->ref++; | |
| 814 | ||
| 815 | context = g_new0(GaimCipherContext, 1); | |
| 816 | context->cipher = cipher; | |
| 817 | ||
| 818 | if(cipher->ops->init) | |
| 819 | cipher->ops->init(context, extra); | |
| 820 | ||
| 821 | return context; | |
| 822 | } | |
| 823 | ||
| 824 | GaimCipherContext * | |
| 825 | gaim_cipher_context_new_by_name(const gchar *name, void *extra) { | |
| 826 | GaimCipher *cipher; | |
| 827 | ||
| 828 | g_return_val_if_fail(name, NULL); | |
| 829 | ||
| 830 | cipher = gaim_ciphers_find_cipher(name); | |
| 831 | ||
| 832 | g_return_val_if_fail(cipher, NULL); | |
| 833 | ||
| 834 | return gaim_cipher_context_new(cipher, extra); | |
| 835 | } | |
| 836 | ||
| 837 | void | |
| 838 | gaim_cipher_context_reset(GaimCipherContext *context, void *extra) { | |
| 839 | GaimCipher *cipher = NULL; | |
| 840 | ||
| 841 | g_return_if_fail(context); | |
| 842 | ||
| 843 | cipher = context->cipher; | |
| 844 | g_return_if_fail(cipher); | |
| 845 | ||
| 846 | if(cipher->ops && cipher->ops->reset) | |
| 847 | context->cipher->ops->reset(context, extra); | |
| 848 | } | |
| 849 | ||
| 850 | void | |
| 851 | gaim_cipher_context_destroy(GaimCipherContext *context) { | |
| 852 | GaimCipher *cipher = NULL; | |
| 853 | ||
| 854 | g_return_if_fail(context); | |
| 855 | ||
| 856 | cipher = context->cipher; | |
| 857 | g_return_if_fail(cipher); | |
| 858 | ||
| 859 | cipher->ref--; | |
| 860 | ||
| 861 | if(cipher->ops && cipher->ops->uninit) | |
| 862 | cipher->ops->uninit(context); | |
| 863 | ||
| 864 | memset(context, 0, sizeof(context)); | |
| 865 | g_free(context); | |
| 866 | context = NULL; | |
| 867 | } | |
| 868 | ||
| 869 | void | |
| 870 | gaim_cipher_context_set_iv(GaimCipherContext *context, guint8 *iv, size_t len) | |
| 871 | { | |
| 872 | GaimCipher *cipher = NULL; | |
| 873 | ||
| 874 | g_return_if_fail(context); | |
| 875 | g_return_if_fail(iv); | |
| 876 | ||
| 877 | cipher = context->cipher; | |
| 878 | g_return_if_fail(cipher); | |
| 879 | ||
| 880 | if(cipher->ops && cipher->ops->set_iv) | |
| 881 | cipher->ops->set_iv(context, iv, len); | |
| 882 | else | |
| 883 | gaim_debug_info("cipher", "the %s cipher does not support the set" | |
| 884 | "initialization vector operation\n", cipher->name); | |
| 885 | } | |
| 886 | ||
| 887 | void | |
| 888 | gaim_cipher_context_append(GaimCipherContext *context, const guint8 *data, | |
| 889 | size_t len) | |
| 890 | { | |
| 891 | GaimCipher *cipher = NULL; | |
| 892 | ||
| 893 | g_return_if_fail(context); | |
| 894 | ||
| 895 | cipher = context->cipher; | |
| 896 | g_return_if_fail(cipher); | |
| 897 | ||
| 898 | if(cipher->ops && cipher->ops->append) | |
| 899 | cipher->ops->append(context, data, len); | |
| 900 | else | |
| 901 | gaim_debug_info("cipher", "the %s cipher does not support the append " | |
| 902 | "operation\n", cipher->name); | |
| 903 | } | |
| 904 | ||
| 905 | gboolean | |
| 10687 | 906 | gaim_cipher_context_digest(GaimCipherContext *context, size_t in_len, |
| 907 | guint8 digest[], size_t *out_len) | |
| 10684 | 908 | { |
| 909 | GaimCipher *cipher = NULL; | |
| 910 | ||
| 911 | g_return_val_if_fail(context, FALSE); | |
| 912 | ||
| 913 | cipher = context->cipher; | |
| 914 | g_return_val_if_fail(context, FALSE); | |
| 915 | ||
| 916 | if(cipher->ops && cipher->ops->digest) | |
| 10687 | 917 | return cipher->ops->digest(context, in_len, digest, out_len); |
| 10684 | 918 | else { |
| 919 | gaim_debug_info("cipher", "the %s cipher does not support the digest " | |
| 920 | "operation\n", cipher->name); | |
| 921 | return FALSE; | |
| 922 | } | |
| 923 | } | |
| 924 | ||
| 925 | gboolean | |
| 10687 | 926 | gaim_cipher_context_digest_to_str(GaimCipherContext *context, size_t in_len, |
| 927 | gchar digest_s[], size_t *out_len) | |
| 10684 | 928 | { |
| 10687 | 929 | /* 8k is a bit excessive, will tweak later. */ |
| 10684 | 930 | guint8 digest[BUF_LEN * 4]; |
| 931 | gint n = 0; | |
| 932 | size_t dlen = 0; | |
| 933 | ||
| 934 | g_return_val_if_fail(context, FALSE); | |
| 935 | g_return_val_if_fail(digest_s, FALSE); | |
| 936 | ||
| 10687 | 937 | if(!gaim_cipher_context_digest(context, sizeof(digest), digest, &dlen)) |
| 10684 | 938 | return FALSE; |
| 939 | ||
| 10687 | 940 | if(in_len < dlen * 2) |
| 941 | return FALSE; | |
| 10684 | 942 | |
| 943 | for(n = 0; n < dlen; n++) | |
| 944 | sprintf(digest_s + (n * 2), "%02x", digest[n]); | |
| 945 | ||
| 946 | digest_s[n * 2] = '\0'; | |
| 947 | ||
| 10687 | 948 | if(out_len) |
| 949 | *out_len = dlen * 2; | |
| 950 | ||
| 10684 | 951 | return TRUE; |
| 952 | } | |
| 953 | ||
| 954 | gint | |
| 955 | gaim_cipher_context_encrypt(GaimCipherContext *context, const guint8 data[], | |
| 956 | size_t len, guint8 output[], size_t *outlen) | |
| 957 | { | |
| 958 | GaimCipher *cipher = NULL; | |
| 959 | ||
| 960 | g_return_val_if_fail(context, -1); | |
| 961 | ||
| 962 | cipher = context->cipher; | |
| 963 | g_return_val_if_fail(cipher, -1); | |
| 964 | ||
| 965 | if(cipher->ops && cipher->ops->encrypt) | |
| 966 | return cipher->ops->encrypt(context, data, len, output, outlen); | |
| 967 | else { | |
| 968 | gaim_debug_info("cipher", "the %s cipher does not support the encrypt" | |
| 969 | "operation\n", cipher->name); | |
| 970 | ||
| 971 | if(outlen) | |
| 972 | *outlen = -1; | |
| 973 | ||
| 974 | return -1; | |
| 975 | } | |
| 976 | } | |
| 977 | ||
| 978 | gint | |
| 979 | gaim_cipher_context_decrypt(GaimCipherContext *context, const guint8 data[], | |
| 980 | size_t len, guint8 output[], size_t *outlen) | |
| 981 | { | |
| 982 | GaimCipher *cipher = NULL; | |
| 983 | ||
| 984 | g_return_val_if_fail(context, -1); | |
| 985 | ||
| 986 | cipher = context->cipher; | |
| 987 | g_return_val_if_fail(cipher, -1); | |
| 988 | ||
| 989 | if(cipher->ops && cipher->ops->decrypt) | |
| 990 | return cipher->ops->decrypt(context, data, len, output, outlen); | |
| 991 | else { | |
| 992 | gaim_debug_info("cipher", "the %s cipher does not support the decrypt" | |
| 993 | "operation\n", cipher->name); | |
| 994 | ||
| 995 | if(outlen) | |
| 996 | *outlen = -1; | |
| 997 | ||
| 998 | return -1; | |
| 999 | } | |
| 1000 | } | |
| 1001 | ||
| 1002 | void | |
| 1003 | gaim_cipher_context_set_salt(GaimCipherContext *context, guint8 *salt) { | |
| 1004 | GaimCipher *cipher = NULL; | |
| 1005 | ||
| 1006 | g_return_if_fail(context); | |
| 1007 | ||
| 1008 | cipher = context->cipher; | |
| 1009 | g_return_if_fail(cipher); | |
| 1010 | ||
| 1011 | if(cipher->ops && cipher->ops->set_salt) | |
| 1012 | cipher->ops->set_salt(context, salt); | |
| 1013 | else | |
| 1014 | gaim_debug_info("cipher", "the %s cipher does not support the " | |
| 1015 | "set_salt operation\n", cipher->name); | |
| 1016 | } | |
| 1017 | ||
| 1018 | size_t | |
| 1019 | gaim_cipher_context_get_salt_size(GaimCipherContext *context) { | |
| 1020 | GaimCipher *cipher = NULL; | |
| 1021 | ||
| 1022 | g_return_val_if_fail(context, -1); | |
| 1023 | ||
| 1024 | cipher = context->cipher; | |
| 1025 | g_return_val_if_fail(cipher, -1); | |
| 1026 | ||
| 1027 | if(cipher->ops && cipher->ops->get_salt_size) | |
| 1028 | return cipher->ops->get_salt_size(context); | |
| 1029 | else { | |
| 1030 | gaim_debug_info("cipher", "the %s cipher does not support the " | |
| 1031 | "get_salt_size operation\n", cipher->name); | |
| 1032 | ||
| 1033 | return -1; | |
| 1034 | } | |
| 1035 | } | |
| 1036 | ||
| 1037 | void | |
| 1038 | gaim_cipher_context_set_key(GaimCipherContext *context, guint8 *key) { | |
| 1039 | GaimCipher *cipher = NULL; | |
| 1040 | ||
| 1041 | g_return_if_fail(context); | |
| 1042 | ||
| 1043 | cipher = context->cipher; | |
| 1044 | g_return_if_fail(cipher); | |
| 1045 | ||
| 1046 | if(cipher->ops && cipher->ops->set_key) | |
| 1047 | cipher->ops->set_key(context, key); | |
| 1048 | else | |
| 1049 | gaim_debug_info("cipher", "the %s cipher does not support the " | |
| 1050 | "set_key operation\n", cipher->name); | |
| 1051 | } | |
| 1052 | ||
| 1053 | size_t | |
| 1054 | gaim_cipher_context_get_key_size(GaimCipherContext *context) { | |
| 1055 | GaimCipher *cipher = NULL; | |
| 1056 | ||
| 1057 | g_return_val_if_fail(context, -1); | |
| 1058 | ||
| 1059 | cipher = context->cipher; | |
| 1060 | g_return_val_if_fail(cipher, -1); | |
| 1061 | ||
| 1062 | if(cipher->ops && cipher->ops->get_key_size) | |
| 1063 | return cipher->ops->get_key_size(context); | |
| 1064 | else { | |
| 1065 | gaim_debug_info("cipher", "the %s cipher does not support the " | |
| 1066 | "get_key_size operation\n", cipher->name); | |
| 1067 | ||
| 1068 | return -1; | |
| 1069 | } | |
| 1070 | } | |
| 1071 | ||
| 1072 | void | |
| 1073 | gaim_cipher_context_set_data(GaimCipherContext *context, gpointer data) { | |
| 1074 | g_return_if_fail(context); | |
| 1075 | ||
| 1076 | context->data = data; | |
| 1077 | } | |
| 1078 | ||
| 1079 | gpointer | |
| 1080 | gaim_cipher_context_get_data(GaimCipherContext *context) { | |
| 1081 | g_return_val_if_fail(context, NULL); | |
| 1082 | ||
| 1083 | return context->data; | |
| 1084 | } |