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