Mercurial > pidgin
comparison libpurple/ciphers/sha1.c @ 31215:521febcb717a
Broke sha1 out
author | Gary Kramlich <grim@reaperworld.com> |
---|---|
date | Mon, 14 Feb 2011 06:05:29 +0000 |
parents | |
children | 2d3c1197f930 |
comparison
equal
deleted
inserted
replaced
31214:04ead332691f | 31215:521febcb717a |
---|---|
1 /* | |
2 * purple | |
3 * | |
4 * Purple is the legal property of its developers, whose names are too numerous | |
5 * to list here. Please refer to the COPYRIGHT file distributed with this | |
6 * source distribution. | |
7 * | |
8 * This program is free software; you can redistribute it and/or modify | |
9 * it under the terms of the GNU General Public License as published by | |
10 * the Free Software Foundation; either version 2 of the License, or | |
11 * (at your option) any later version. | |
12 * | |
13 * This program is distributed in the hope that it will be useful, | |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 * GNU General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU General Public License | |
19 * along with this program; if not, write to the Free Software | |
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA | |
21 */ | |
22 #include <cipher.h> | |
23 #include <string.h> | |
24 | |
25 #define SHA1_HMAC_BLOCK_SIZE 64 | |
26 | |
27 static size_t | |
28 sha1_get_block_size(PurpleCipherContext *context) | |
29 { | |
30 /* This does not change (in this case) */ | |
31 return SHA1_HMAC_BLOCK_SIZE; | |
32 } | |
33 | |
34 #if GLIB_CHECK_VERSION(2,16,0) | |
35 | |
36 static void | |
37 sha1_init(PurpleCipherContext *context, void *extra) | |
38 { | |
39 purple_g_checksum_init(context, G_CHECKSUM_SHA1); | |
40 } | |
41 | |
42 static void | |
43 sha1_reset(PurpleCipherContext *context, void *extra) | |
44 { | |
45 purple_g_checksum_reset(context, G_CHECKSUM_SHA1); | |
46 } | |
47 | |
48 static gboolean | |
49 sha1_digest(PurpleCipherContext *context, gsize in_len, guchar digest[20], | |
50 gsize *out_len) | |
51 { | |
52 return purple_g_checksum_digest(context, G_CHECKSUM_SHA1, in_len, | |
53 digest, out_len); | |
54 } | |
55 | |
56 static PurpleCipherOps SHA1Ops = { | |
57 .init = sha1_init, | |
58 .reset = sha1_reset, | |
59 .uninit = purple_g_checksum_uninit, | |
60 .append = purple_g_checksum_append, | |
61 .digest = sha1_digest, | |
62 .get_block_size = sha1_get_block_size, | |
63 }; | |
64 | |
65 #else /* GLIB_CHECK_VERSION(2,16,0) */ | |
66 | |
67 #define SHA1_HMAC_BLOCK_SIZE 64 | |
68 #define SHA1_ROTL(X,n) ((((X) << (n)) | ((X) >> (32-(n)))) & 0xFFFFFFFF) | |
69 | |
70 struct SHA1Context { | |
71 guint32 H[5]; | |
72 guint32 W[80]; | |
73 | |
74 gint lenW; | |
75 | |
76 guint32 sizeHi; | |
77 guint32 sizeLo; | |
78 }; | |
79 | |
80 static void | |
81 sha1_hash_block(struct SHA1Context *sha1_ctx) { | |
82 gint i; | |
83 guint32 A, B, C, D, E, T; | |
84 | |
85 for(i = 16; i < 80; i++) { | |
86 sha1_ctx->W[i] = SHA1_ROTL(sha1_ctx->W[i - 3] ^ | |
87 sha1_ctx->W[i - 8] ^ | |
88 sha1_ctx->W[i - 14] ^ | |
89 sha1_ctx->W[i - 16], 1); | |
90 } | |
91 | |
92 A = sha1_ctx->H[0]; | |
93 B = sha1_ctx->H[1]; | |
94 C = sha1_ctx->H[2]; | |
95 D = sha1_ctx->H[3]; | |
96 E = sha1_ctx->H[4]; | |
97 | |
98 for(i = 0; i < 20; i++) { | |
99 T = (SHA1_ROTL(A, 5) + (((C ^ D) & B) ^ D) + E + sha1_ctx->W[i] + 0x5A827999) & 0xFFFFFFFF; | |
100 E = D; | |
101 D = C; | |
102 C = SHA1_ROTL(B, 30); | |
103 B = A; | |
104 A = T; | |
105 } | |
106 | |
107 for(i = 20; i < 40; i++) { | |
108 T = (SHA1_ROTL(A, 5) + (B ^ C ^ D) + E + sha1_ctx->W[i] + 0x6ED9EBA1) & 0xFFFFFFFF; | |
109 E = D; | |
110 D = C; | |
111 C = SHA1_ROTL(B, 30); | |
112 B = A; | |
113 A = T; | |
114 } | |
115 | |
116 for(i = 40; i < 60; i++) { | |
117 T = (SHA1_ROTL(A, 5) + ((B & C) | (D & (B | C))) + E + sha1_ctx->W[i] + 0x8F1BBCDC) & 0xFFFFFFFF | |
118 E = D; | |
119 D = C; | |
120 C = SHA1_ROTL(B, 30); | |
121 B = A; | |
122 A = T; | |
123 } | |
124 | |
125 for(i = 60; i < 80; i++) { | |
126 T = (SHA1_ROTL(A, 5) + (B ^ C ^ D) + E + sha1_ctx->W[i] + 0xCA62C1D6) & 0xFFFFFFFF; | |
127 E = D; | |
128 D = C; | |
129 C = SHA1_ROTL(B, 30); | |
130 B = A; | |
131 A = T; | |
132 } | |
133 | |
134 sha1_ctx->H[0] += A; | |
135 sha1_ctx->H[1] += B; | |
136 sha1_ctx->H[2] += C; | |
137 sha1_ctx->H[3] += D; | |
138 sha1_ctx->H[4] += E; | |
139 } | |
140 | |
141 static void | |
142 sha1_set_opt(PurpleCipherContext *context, const gchar *name, void *value) { | |
143 struct SHA1Context *ctx; | |
144 | |
145 ctx = purple_cipher_context_get_data(context); | |
146 | |
147 if(purple_strequal(name, "sizeHi")) { | |
148 ctx->sizeHi = GPOINTER_TO_INT(value); | |
149 } else if(purple_strequal(name, "sizeLo")) { | |
150 ctx->sizeLo = GPOINTER_TO_INT(value); | |
151 } else if(purple_strequal(name, "lenW")) { | |
152 ctx->lenW = GPOINTER_TO_INT(value); | |
153 } | |
154 } | |
155 | |
156 static void * | |
157 sha1_get_opt(PurpleCipherContext *context, const gchar *name) { | |
158 struct SHA1Context *ctx; | |
159 | |
160 ctx = purple_cipher_context_get_data(context); | |
161 | |
162 if(purple_strequal(name, "sizeHi")) { | |
163 return GINT_TO_POINTER(ctx->sizeHi); | |
164 } else if(purple_strequal(name, "sizeLo")) { | |
165 return GINT_TO_POINTER(ctx->sizeLo); | |
166 } else if(purple_strequal(name, "lenW")) { | |
167 return GINT_TO_POINTER(ctx->lenW); | |
168 } | |
169 | |
170 return NULL; | |
171 } | |
172 | |
173 static void | |
174 sha1_init(PurpleCipherContext *context, void *extra) { | |
175 struct SHA1Context *sha1_ctx; | |
176 | |
177 sha1_ctx = g_new0(struct SHA1Context, 1); | |
178 | |
179 purple_cipher_context_set_data(context, sha1_ctx); | |
180 | |
181 purple_cipher_context_reset(context, extra); | |
182 } | |
183 | |
184 static void | |
185 sha1_reset(PurpleCipherContext *context, void *extra) { | |
186 struct SHA1Context *sha1_ctx; | |
187 gint i; | |
188 | |
189 sha1_ctx = purple_cipher_context_get_data(context); | |
190 | |
191 g_return_if_fail(sha1_ctx); | |
192 | |
193 sha1_ctx->lenW = 0; | |
194 sha1_ctx->sizeHi = 0; | |
195 sha1_ctx->sizeLo = 0; | |
196 | |
197 sha1_ctx->H[0] = 0x67452301; | |
198 sha1_ctx->H[1] = 0xEFCDAB89; | |
199 sha1_ctx->H[2] = 0x98BADCFE; | |
200 sha1_ctx->H[3] = 0x10325476; | |
201 sha1_ctx->H[4] = 0xC3D2E1F0; | |
202 | |
203 for(i = 0; i < 80; i++) | |
204 sha1_ctx->W[i] = 0; | |
205 } | |
206 | |
207 static void | |
208 sha1_uninit(PurpleCipherContext *context) { | |
209 struct SHA1Context *sha1_ctx; | |
210 | |
211 purple_cipher_context_reset(context, NULL); | |
212 | |
213 sha1_ctx = purple_cipher_context_get_data(context); | |
214 | |
215 memset(sha1_ctx, 0, sizeof(struct SHA1Context)); | |
216 | |
217 g_free(sha1_ctx); | |
218 sha1_ctx = NULL; | |
219 } | |
220 | |
221 static void | |
222 sha1_append(PurpleCipherContext *context, const guchar *data, size_t len) { | |
223 struct SHA1Context *sha1_ctx; | |
224 gint i; | |
225 | |
226 sha1_ctx = purple_cipher_context_get_data(context); | |
227 | |
228 g_return_if_fail(sha1_ctx); | |
229 | |
230 for(i = 0; i < len; i++) { | |
231 sha1_ctx->W[sha1_ctx->lenW / 4] <<= 8; | |
232 sha1_ctx->W[sha1_ctx->lenW / 4] |= data[i]; | |
233 | |
234 if((++sha1_ctx->lenW) % 64 == 0) { | |
235 sha1_hash_block(sha1_ctx); | |
236 sha1_ctx->lenW = 0; | |
237 } | |
238 | |
239 sha1_ctx->sizeLo += 8; | |
240 sha1_ctx->sizeHi += (sha1_ctx->sizeLo < 8); | |
241 } | |
242 } | |
243 | |
244 static gboolean | |
245 sha1_digest(PurpleCipherContext *context, size_t in_len, guchar digest[20], | |
246 size_t *out_len) | |
247 { | |
248 struct SHA1Context *sha1_ctx; | |
249 guchar pad0x80 = 0x80, pad0x00 = 0x00; | |
250 guchar padlen[8]; | |
251 gint i; | |
252 | |
253 g_return_val_if_fail(in_len >= 20, FALSE); | |
254 | |
255 sha1_ctx = purple_cipher_context_get_data(context); | |
256 | |
257 g_return_val_if_fail(sha1_ctx, FALSE); | |
258 | |
259 padlen[0] = (guchar)((sha1_ctx->sizeHi >> 24) & 255); | |
260 padlen[1] = (guchar)((sha1_ctx->sizeHi >> 16) & 255); | |
261 padlen[2] = (guchar)((sha1_ctx->sizeHi >> 8) & 255); | |
262 padlen[3] = (guchar)((sha1_ctx->sizeHi >> 0) & 255); | |
263 padlen[4] = (guchar)((sha1_ctx->sizeLo >> 24) & 255); | |
264 padlen[5] = (guchar)((sha1_ctx->sizeLo >> 16) & 255); | |
265 padlen[6] = (guchar)((sha1_ctx->sizeLo >> 8) & 255); | |
266 padlen[7] = (guchar)((sha1_ctx->sizeLo >> 0) & 255); | |
267 | |
268 /* pad with a 1, then zeroes, then length */ | |
269 purple_cipher_context_append(context, &pad0x80, 1); | |
270 while(sha1_ctx->lenW != 56) | |
271 purple_cipher_context_append(context, &pad0x00, 1); | |
272 purple_cipher_context_append(context, padlen, 8); | |
273 | |
274 for(i = 0; i < 20; i++) { | |
275 digest[i] = (guchar)(sha1_ctx->H[i / 4] >> 24); | |
276 sha1_ctx->H[i / 4] <<= 8; | |
277 } | |
278 | |
279 purple_cipher_context_reset(context, NULL); | |
280 | |
281 if(out_len) | |
282 *out_len = 20; | |
283 | |
284 return TRUE; | |
285 } | |
286 | |
287 static PurpleCipherOps SHA1Ops = { | |
288 .set_option = sha1_set_opt, | |
289 .get_option = sha1_get_opt, | |
290 .init = sha1_init, | |
291 .reset = sha1_reset, | |
292 .uninit = sha1_uninit, | |
293 .append = sha1_append, | |
294 .digest = sha1_digest, | |
295 .get_block_size = sha1_get_block_size, | |
296 }; | |
297 | |
298 #endif /* GLIB_CHECK_VERSION(2,16,0) */ | |
299 | |
300 PurpleCipherOps * | |
301 purple_sha1_cipher_get_ops(void) { | |
302 return &SHA1Ops; | |
303 } | |
304 |