Mercurial > pidgin
comparison libpurple/ciphers/sha256.c @ 31217:3af51303d45c
Moved sha256 to the sub library
author | Gary Kramlich <grim@reaperworld.com> |
---|---|
date | Mon, 14 Feb 2011 06:20:59 +0000 |
parents | |
children | 2d3c1197f930 |
comparison
equal
deleted
inserted
replaced
31216:1bdc5f464802 | 31217:3af51303d45c |
---|---|
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 SHA256_HMAC_BLOCK_SIZE 64 | |
26 | |
27 static size_t | |
28 sha256_get_block_size(PurpleCipherContext *context) | |
29 { | |
30 /* This does not change (in this case) */ | |
31 return SHA256_HMAC_BLOCK_SIZE; | |
32 } | |
33 | |
34 #if GLIB_CHECK_VERSION(2,16,0) | |
35 | |
36 static void | |
37 sha256_init(PurpleCipherContext *context, void *extra) | |
38 { | |
39 purple_g_checksum_init(context, G_CHECKSUM_SHA256); | |
40 } | |
41 | |
42 static void | |
43 sha256_reset(PurpleCipherContext *context, void *extra) | |
44 { | |
45 purple_g_checksum_reset(context, G_CHECKSUM_SHA256); | |
46 } | |
47 | |
48 static gboolean | |
49 sha256_digest(PurpleCipherContext *context, gsize in_len, guchar digest[20], | |
50 gsize *out_len) | |
51 { | |
52 return purple_g_checksum_digest(context, G_CHECKSUM_SHA256, in_len, | |
53 digest, out_len); | |
54 } | |
55 | |
56 static PurpleCipherOps SHA256Ops = { | |
57 .init = sha256_init, | |
58 .reset = sha256_reset, | |
59 .uninit = purple_g_checksum_uninit, | |
60 .append = purple_g_checksum_append, | |
61 .digest = sha256_digest, | |
62 .get_block_size = sha256_get_block_size, | |
63 }; | |
64 | |
65 #else /* GLIB_CHECK_VERSION(2,16,0) */ | |
66 | |
67 #define SHA256_ROTR(X,n) ((((X) >> (n)) | ((X) << (32-(n)))) & 0xFFFFFFFF) | |
68 | |
69 static const guint32 sha256_K[64] = | |
70 { | |
71 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, | |
72 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, | |
73 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, | |
74 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, | |
75 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, | |
76 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, | |
77 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, | |
78 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 | |
79 }; | |
80 | |
81 struct SHA256Context { | |
82 guint32 H[8]; | |
83 guint32 W[64]; | |
84 | |
85 gint lenW; | |
86 | |
87 guint32 sizeHi; | |
88 guint32 sizeLo; | |
89 }; | |
90 | |
91 static void | |
92 sha256_hash_block(struct SHA256Context *sha256_ctx) { | |
93 gint i; | |
94 guint32 A, B, C, D, E, F, G, H, T1, T2; | |
95 | |
96 for(i = 16; i < 64; i++) { | |
97 sha256_ctx->W[i] = | |
98 (SHA256_ROTR(sha256_ctx->W[i-2], 17) ^ SHA256_ROTR(sha256_ctx->W[i-2], 19) ^ (sha256_ctx->W[i-2] >> 10)) | |
99 + sha256_ctx->W[i-7] | |
100 + (SHA256_ROTR(sha256_ctx->W[i-15], 7) ^ SHA256_ROTR(sha256_ctx->W[i-15], 18) ^ (sha256_ctx->W[i-15] >> 3)) | |
101 + sha256_ctx->W[i-16]; | |
102 } | |
103 | |
104 A = sha256_ctx->H[0]; | |
105 B = sha256_ctx->H[1]; | |
106 C = sha256_ctx->H[2]; | |
107 D = sha256_ctx->H[3]; | |
108 E = sha256_ctx->H[4]; | |
109 F = sha256_ctx->H[5]; | |
110 G = sha256_ctx->H[6]; | |
111 H = sha256_ctx->H[7]; | |
112 | |
113 for(i = 0; i < 64; i++) { | |
114 T1 = H | |
115 + (SHA256_ROTR(E, 6) ^ SHA256_ROTR(E, 11) ^ SHA256_ROTR(E, 25)) | |
116 + ((E & F) ^ ((~E) & G)) | |
117 + sha256_K[i] + sha256_ctx->W[i]; | |
118 T2 = (SHA256_ROTR(A, 2) ^ SHA256_ROTR(A, 13) ^ SHA256_ROTR(A, 22)) | |
119 + ((A & B) ^ (A & C) ^ (B & C)); | |
120 H = G; | |
121 G = F; | |
122 F = E; | |
123 E = D + T1; | |
124 D = C; | |
125 C = B; | |
126 B = A; | |
127 A = T1 + T2; | |
128 } | |
129 | |
130 sha256_ctx->H[0] += A; | |
131 sha256_ctx->H[1] += B; | |
132 sha256_ctx->H[2] += C; | |
133 sha256_ctx->H[3] += D; | |
134 sha256_ctx->H[4] += E; | |
135 sha256_ctx->H[5] += F; | |
136 sha256_ctx->H[6] += G; | |
137 sha256_ctx->H[7] += H; | |
138 } | |
139 | |
140 static void | |
141 sha256_set_opt(PurpleCipherContext *context, const gchar *name, void *value) { | |
142 struct SHA256Context *ctx; | |
143 | |
144 ctx = purple_cipher_context_get_data(context); | |
145 | |
146 if(!strcmp(name, "sizeHi")) { | |
147 ctx->sizeHi = GPOINTER_TO_INT(value); | |
148 } else if(!strcmp(name, "sizeLo")) { | |
149 ctx->sizeLo = GPOINTER_TO_INT(value); | |
150 } else if(!strcmp(name, "lenW")) { | |
151 ctx->lenW = GPOINTER_TO_INT(value); | |
152 } | |
153 } | |
154 | |
155 static void * | |
156 sha256_get_opt(PurpleCipherContext *context, const gchar *name) { | |
157 struct SHA256Context *ctx; | |
158 | |
159 ctx = purple_cipher_context_get_data(context); | |
160 | |
161 if(!strcmp(name, "sizeHi")) { | |
162 return GINT_TO_POINTER(ctx->sizeHi); | |
163 } else if(!strcmp(name, "sizeLo")) { | |
164 return GINT_TO_POINTER(ctx->sizeLo); | |
165 } else if(!strcmp(name, "lenW")) { | |
166 return GINT_TO_POINTER(ctx->lenW); | |
167 } | |
168 | |
169 return NULL; | |
170 } | |
171 | |
172 static void | |
173 sha256_init(PurpleCipherContext *context, void *extra) { | |
174 struct SHA256Context *sha256_ctx; | |
175 | |
176 sha256_ctx = g_new0(struct SHA256Context, 1); | |
177 | |
178 purple_cipher_context_set_data(context, sha256_ctx); | |
179 | |
180 purple_cipher_context_reset(context, extra); | |
181 } | |
182 | |
183 static void | |
184 sha256_reset(PurpleCipherContext *context, void *extra) { | |
185 struct SHA256Context *sha256_ctx; | |
186 gint i; | |
187 | |
188 sha256_ctx = purple_cipher_context_get_data(context); | |
189 | |
190 g_return_if_fail(sha256_ctx); | |
191 | |
192 sha256_ctx->lenW = 0; | |
193 sha256_ctx->sizeHi = 0; | |
194 sha256_ctx->sizeLo = 0; | |
195 | |
196 sha256_ctx->H[0] = 0x6a09e667; | |
197 sha256_ctx->H[1] = 0xbb67ae85; | |
198 sha256_ctx->H[2] = 0x3c6ef372; | |
199 sha256_ctx->H[3] = 0xa54ff53a; | |
200 sha256_ctx->H[4] = 0x510e527f; | |
201 sha256_ctx->H[5] = 0x9b05688c; | |
202 sha256_ctx->H[6] = 0x1f83d9ab; | |
203 sha256_ctx->H[7] = 0x5be0cd19; | |
204 | |
205 for(i = 0; i < 64; i++) | |
206 sha256_ctx->W[i] = 0; | |
207 } | |
208 | |
209 static void | |
210 sha256_uninit(PurpleCipherContext *context) { | |
211 struct SHA256Context *sha256_ctx; | |
212 | |
213 purple_cipher_context_reset(context, NULL); | |
214 | |
215 sha256_ctx = purple_cipher_context_get_data(context); | |
216 | |
217 memset(sha256_ctx, 0, sizeof(struct SHA256Context)); | |
218 | |
219 g_free(sha256_ctx); | |
220 sha256_ctx = NULL; | |
221 } | |
222 | |
223 static void | |
224 sha256_append(PurpleCipherContext *context, const guchar *data, size_t len) { | |
225 struct SHA256Context *sha256_ctx; | |
226 gint i; | |
227 | |
228 sha256_ctx = purple_cipher_context_get_data(context); | |
229 | |
230 g_return_if_fail(sha256_ctx); | |
231 | |
232 for(i = 0; i < len; i++) { | |
233 sha256_ctx->W[sha256_ctx->lenW / 4] <<= 8; | |
234 sha256_ctx->W[sha256_ctx->lenW / 4] |= data[i]; | |
235 | |
236 if((++sha256_ctx->lenW) % 64 == 0) { | |
237 sha256_hash_block(sha256_ctx); | |
238 sha256_ctx->lenW = 0; | |
239 } | |
240 | |
241 sha256_ctx->sizeLo += 8; | |
242 sha256_ctx->sizeHi += (sha256_ctx->sizeLo < 8); | |
243 } | |
244 } | |
245 | |
246 static gboolean | |
247 sha256_digest(PurpleCipherContext *context, size_t in_len, guchar digest[32], | |
248 size_t *out_len) | |
249 { | |
250 struct SHA256Context *sha256_ctx; | |
251 guchar pad0x80 = 0x80, pad0x00 = 0x00; | |
252 guchar padlen[8]; | |
253 gint i; | |
254 | |
255 g_return_val_if_fail(in_len >= 32, FALSE); | |
256 | |
257 sha256_ctx = purple_cipher_context_get_data(context); | |
258 | |
259 g_return_val_if_fail(sha256_ctx, FALSE); | |
260 | |
261 padlen[0] = (guchar)((sha256_ctx->sizeHi >> 24) & 255); | |
262 padlen[1] = (guchar)((sha256_ctx->sizeHi >> 16) & 255); | |
263 padlen[2] = (guchar)((sha256_ctx->sizeHi >> 8) & 255); | |
264 padlen[3] = (guchar)((sha256_ctx->sizeHi >> 0) & 255); | |
265 padlen[4] = (guchar)((sha256_ctx->sizeLo >> 24) & 255); | |
266 padlen[5] = (guchar)((sha256_ctx->sizeLo >> 16) & 255); | |
267 padlen[6] = (guchar)((sha256_ctx->sizeLo >> 8) & 255); | |
268 padlen[7] = (guchar)((sha256_ctx->sizeLo >> 0) & 255); | |
269 | |
270 /* pad with a 1, then zeroes, then length */ | |
271 purple_cipher_context_append(context, &pad0x80, 1); | |
272 while(sha256_ctx->lenW != 56) | |
273 purple_cipher_context_append(context, &pad0x00, 1); | |
274 purple_cipher_context_append(context, padlen, 8); | |
275 | |
276 for(i = 0; i < 32; i++) { | |
277 digest[i] = (guchar)(sha256_ctx->H[i / 4] >> 24); | |
278 sha256_ctx->H[i / 4] <<= 8; | |
279 } | |
280 | |
281 purple_cipher_context_reset(context, NULL); | |
282 | |
283 if(out_len) | |
284 *out_len = 32; | |
285 | |
286 return TRUE; | |
287 } | |
288 | |
289 static PurpleCipherOps SHA256Ops = { | |
290 .set_option = sha256_set_opt, | |
291 .get_option = sha256_get_opt, | |
292 .init = sha256_init, | |
293 .reset = sha256_reset, | |
294 .uninit = sha256_uninit, | |
295 .append = sha256_append, | |
296 .digest = sha256_digest, | |
297 .get_block_size = sha256_get_block_size, | |
298 }; | |
299 | |
300 #endif /* GLIB_CHECK_VERSION(2,16,0) */ | |
301 | |
302 PurpleCipherOps * | |
303 purple_sha256_cipher_get_ops(void) { | |
304 return &SHA256Ops; | |
305 } | |
306 |