zeroize keys
[gnutls:gnutls.git] / lib / accelerated / x86 / sha-x86.c
1 /*
2  * Copyright (C) 2011-2012 Free Software Foundation, Inc.
3  *
4  * Author: Nikos Mavrogiannopoulos
5  *
6  * This file is part of GnuTLS.
7  *
8  * The GnuTLS is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>
20  *
21  */
22
23 #include <gnutls_errors.h>
24 #include <gnutls_int.h>
25 #include <gnutls/crypto.h>
26 #include <gnutls_errors.h>
27 #include <aes-x86.h>
28 #include <nettle/sha.h>
29 #include <nettle/macros.h>
30 #include <nettle/nettle-meta.h>
31 #include <sha-x86.h>
32 #include <x86.h>
33
34 void sha1_block_data_order(void *c, const void *p, size_t len);
35 void sha256_block_data_order(void *c, const void *p, size_t len);
36 void sha512_block_data_order(void *c, const void *p, size_t len);
37
38 typedef void (*update_func) (void *, unsigned, const uint8_t *);
39 typedef void (*digest_func) (void *, unsigned, uint8_t *);
40 typedef void (*set_key_func) (void *, unsigned, const uint8_t *);
41 typedef void (*init_func) (void *);
42
43 struct x86_hash_ctx {
44         union {
45                 struct sha1_ctx sha1;
46                 struct sha224_ctx sha224;
47                 struct sha256_ctx sha256;
48 #ifdef ENABLE_SHA512
49                 struct sha384_ctx sha384;
50                 struct sha512_ctx sha512;
51 #endif
52         } ctx;
53         void *ctx_ptr;
54         gnutls_digest_algorithm_t algo;
55         size_t length;
56         update_func update;
57         digest_func digest;
58         init_func init;
59 };
60
61 static int
62 wrap_x86_hash_update(void *_ctx, const void *text, size_t textsize)
63 {
64         struct x86_hash_ctx *ctx = _ctx;
65
66         ctx->update(ctx->ctx_ptr, textsize, text);
67
68         return GNUTLS_E_SUCCESS;
69 }
70
71 static void wrap_x86_hash_deinit(void *hd)
72 {
73         gnutls_free(hd);
74 }
75
76 void x86_sha1_update(struct sha1_ctx *ctx, size_t length,
77                      const uint8_t * data)
78 {
79         struct {
80                 uint32_t h0, h1, h2, h3, h4;
81                 uint32_t Nl, Nh;
82                 uint32_t data[16];
83                 unsigned int num;
84         } octx;
85         size_t res;
86         unsigned t2, i;
87
88         if ((res = ctx->index)) {
89                 res = SHA1_DATA_SIZE - res;
90                 if (length < res)
91                         res = length;
92                 sha1_update(ctx, res, data);
93                 data += res;
94                 length -= res;
95         }
96
97         octx.h0 = ctx->state[0];
98         octx.h1 = ctx->state[1];
99         octx.h2 = ctx->state[2];
100         octx.h3 = ctx->state[3];
101         octx.h4 = ctx->state[4];
102
103         memcpy(octx.data, ctx->block, SHA1_DATA_SIZE);
104         octx.num = ctx->index;
105
106         res = length % SHA1_DATA_SIZE;
107         length -= res;
108
109         if (length > 0) {
110
111                 t2 = length / SHA1_DATA_SIZE;
112
113                 sha1_block_data_order(&octx, data, t2);
114
115                 for (i=0;i<t2;i++)
116                         MD_INCR(ctx);
117                 data += length;
118         }
119
120         ctx->state[0] = octx.h0;
121         ctx->state[1] = octx.h1;
122         ctx->state[2] = octx.h2;
123         ctx->state[3] = octx.h3;
124         ctx->state[4] = octx.h4;
125
126         memcpy(ctx->block, octx.data, octx.num);
127         ctx->index = octx.num;
128
129         if (res > 0) {
130                 sha1_update(ctx, res, data);
131         }
132
133 }
134
135 void x86_sha256_update(struct sha256_ctx *ctx, size_t length,
136                      const uint8_t * data)
137 {
138         struct {
139                 uint32_t h[8];
140                 uint32_t Nl, Nh;
141                 uint32_t data[16];
142                 unsigned int num;
143                 unsigned md_len;
144         } octx;
145         size_t res;
146         unsigned t2, i;
147
148         if ((res = ctx->index)) {
149                 res = SHA256_DATA_SIZE - res;
150                 if (length < res)
151                         res = length;
152                 sha256_update(ctx, res, data);
153                 data += res;
154                 length -= res;
155         }
156
157         memcpy(octx.h, ctx->state, sizeof(octx.h));
158         memcpy(octx.data, ctx->block, SHA256_DATA_SIZE);
159         octx.num = ctx->index;
160
161         res = length % SHA256_DATA_SIZE;
162         length -= res;
163
164         if (length > 0) {
165                 t2 = length / SHA1_DATA_SIZE;
166                 sha256_block_data_order(&octx, data, t2);
167                 
168                 for (i=0;i<t2;i++)
169                         MD_INCR(ctx);
170                 data += length;
171         }
172
173         memcpy(ctx->state, octx.h, sizeof(octx.h));
174
175         memcpy(ctx->block, octx.data, octx.num);
176         ctx->index = octx.num;
177
178         if (res > 0) {
179                 sha256_update(ctx, res, data);
180         }
181 }
182
183 #ifdef ENABLE_SHA512
184 void x86_sha512_update(struct sha512_ctx *ctx, size_t length,
185                      const uint8_t * data)
186 {
187         struct {
188                 uint64_t h[8];
189                 uint64_t Nl, Nh;
190                 union {
191                         uint64_t d[16];
192                         uint8_t p[16*8];
193                 } u;
194                 unsigned int num;
195                 unsigned md_len;
196         } octx;
197         size_t res;
198         unsigned t2, i;
199
200         if ((res = ctx->index)) {
201                 res = SHA512_DATA_SIZE - res;
202                 if (length < res)
203                         res = length;
204                 sha512_update(ctx, res, data);
205                 data += res;
206                 length -= res;
207         }
208
209         memcpy(octx.h, ctx->state, sizeof(octx.h));
210         memcpy(octx.u.p, ctx->block, SHA512_DATA_SIZE);
211         octx.num = ctx->index;
212
213         res = length % SHA512_DATA_SIZE;
214         length -= res;
215
216         if (length > 0) {
217                 t2 = length / SHA512_DATA_SIZE;
218                 sha512_block_data_order(&octx, data, t2);
219                 
220                 for (i=0;i<t2;i++)
221                         MD_INCR(ctx);
222                 data += length;
223         }
224
225         memcpy(ctx->state, octx.h, sizeof(octx.h));
226
227         memcpy(ctx->block, octx.u.p, octx.num);
228         ctx->index = octx.num;
229
230         if (res > 0) {
231                 sha512_update(ctx, res, data);
232         }
233 }
234 #endif
235
236 static int _ctx_init(gnutls_digest_algorithm_t algo,
237                      struct x86_hash_ctx *ctx)
238 {
239         switch (algo) {
240         case GNUTLS_DIG_SHA1:
241                 sha1_init(&ctx->ctx.sha1);
242                 ctx->update = (update_func) x86_sha1_update;
243                 ctx->digest = (digest_func) sha1_digest;
244                 ctx->init = (init_func) sha1_init;
245                 ctx->ctx_ptr = &ctx->ctx.sha1;
246                 ctx->length = SHA1_DIGEST_SIZE;
247                 break;
248         case GNUTLS_DIG_SHA224:
249                 sha224_init(&ctx->ctx.sha224);
250                 ctx->update = (update_func) x86_sha256_update;
251                 ctx->digest = (digest_func) sha256_digest;
252                 ctx->init = (init_func) sha224_init;
253                 ctx->ctx_ptr = &ctx->ctx.sha224;
254                 ctx->length = SHA224_DIGEST_SIZE;
255                 break;
256         case GNUTLS_DIG_SHA256:
257                 sha256_init(&ctx->ctx.sha256);
258                 ctx->update = (update_func) x86_sha256_update;
259                 ctx->digest = (digest_func) sha256_digest;
260                 ctx->init = (init_func) sha256_init;
261                 ctx->ctx_ptr = &ctx->ctx.sha256;
262                 ctx->length = SHA256_DIGEST_SIZE;
263                 break;
264 #ifdef ENABLE_SHA512
265         case GNUTLS_DIG_SHA384:
266                 sha384_init(&ctx->ctx.sha384);
267                 ctx->update = (update_func) x86_sha512_update;
268                 ctx->digest = (digest_func) sha512_digest;
269                 ctx->init = (init_func) sha384_init;
270                 ctx->ctx_ptr = &ctx->ctx.sha384;
271                 ctx->length = SHA384_DIGEST_SIZE;
272                 break;
273         case GNUTLS_DIG_SHA512:
274                 sha512_init(&ctx->ctx.sha512);
275                 ctx->update = (update_func) x86_sha512_update;
276                 ctx->digest = (digest_func) sha512_digest;
277                 ctx->init = (init_func) sha512_init;
278                 ctx->ctx_ptr = &ctx->ctx.sha512;
279                 ctx->length = SHA512_DIGEST_SIZE;
280                 break;
281 #endif
282         default:
283                 gnutls_assert();
284                 return GNUTLS_E_INVALID_REQUEST;
285         }
286
287         return 0;
288 }
289
290
291 static int wrap_x86_hash_init(gnutls_digest_algorithm_t algo, void **_ctx)
292 {
293         struct x86_hash_ctx *ctx;
294         int ret;
295
296         ctx = gnutls_malloc(sizeof(struct x86_hash_ctx));
297         if (ctx == NULL) {
298                 gnutls_assert();
299                 return GNUTLS_E_MEMORY_ERROR;
300         }
301
302         ctx->algo = algo;
303
304         if ((ret = _ctx_init(algo, ctx)) < 0) {
305                 gnutls_assert();
306                 return ret;
307         }
308
309         *_ctx = ctx;
310
311         return 0;
312 }
313
314 static int
315 wrap_x86_hash_output(void *src_ctx, void *digest, size_t digestsize)
316 {
317         struct x86_hash_ctx *ctx;
318         ctx = src_ctx;
319
320         if (digestsize < ctx->length)
321                 return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
322
323         ctx->digest(ctx->ctx_ptr, digestsize, digest);
324
325         return 0;
326 }
327
328 static int wrap_x86_hash_fast(gnutls_digest_algorithm_t algo,
329                                  const void *text, size_t text_size,
330                                  void *digest)
331 {
332         struct x86_hash_ctx ctx;
333         int ret;
334
335         ret = _ctx_init(algo, &ctx);
336         if (ret < 0)
337                 return gnutls_assert_val(ret);
338
339         ctx.update(&ctx, text_size, text);
340         ctx.digest(&ctx, ctx.length, digest);
341
342         return 0;
343 }
344
345 const struct nettle_hash x86_sha1 =
346 NN_HASH(sha1, x86_sha1_update, sha1_digest, SHA1);
347 const struct nettle_hash x86_sha224 =
348 NN_HASH(sha224, x86_sha256_update, sha224_digest, SHA224);
349 const struct nettle_hash x86_sha256 =
350 NN_HASH(sha256, x86_sha256_update, sha256_digest, SHA256);
351
352 #ifdef ENABLE_SHA512
353 const struct nettle_hash x86_sha384 =
354 NN_HASH(sha384, x86_sha512_update, sha384_digest, SHA384);
355 const struct nettle_hash x86_sha512 =
356 NN_HASH(sha512, x86_sha512_update, sha512_digest, SHA512);
357 #endif
358
359 const gnutls_crypto_digest_st sha_x86_ssse3 = {
360         .init = wrap_x86_hash_init,
361         .hash = wrap_x86_hash_update,
362         .output = wrap_x86_hash_output,
363         .deinit = wrap_x86_hash_deinit,
364         .fast = wrap_x86_hash_fast,
365 };