31215
|
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
|