Utilize the optimized SHA functions in Padlock HMAC.
[gnutls:gnutls.git] / lib / accelerated / x86 / sha-padlock.c
1 /*
2  * Copyright (C) 2011-2012 Free Software Foundation, Inc.
3  * Portions Copyright (C) 2001 Niels Moeller
4  *
5  * Author: Nikos Mavrogiannopoulos
6  *
7  * This file is part of GNUTLS.
8  *
9  * The GNUTLS library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1 of
12  * the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>
21  *
22  */
23
24 #include <gnutls_int.h>
25 #include <gnutls_hash_int.h>
26 #include <gnutls_errors.h>
27 #include <nettle/sha.h>
28 #include <nettle/hmac.h>
29 #include <nettle/macros.h>
30 #include <aes-padlock.h>
31 #include <assert.h>
32 #include <sha-padlock.h>
33 #include <x86.h>
34
35 #ifdef HAVE_LIBNETTLE
36
37 typedef void (*update_func) (void *, unsigned, const uint8_t *);
38 typedef void (*digest_func) (void *, unsigned, uint8_t *);
39 typedef void (*set_key_func) (void *, unsigned, const uint8_t *);
40 typedef void (*init_func) (void *);
41
42 struct padlock_hash_ctx {
43         union {
44                 struct sha1_ctx sha1;
45                 struct sha224_ctx sha224;
46                 struct sha256_ctx sha256;
47                 struct sha384_ctx sha384;
48                 struct sha512_ctx sha512;
49         } ctx;
50         void *ctx_ptr;
51         gnutls_digest_algorithm_t algo;
52         size_t length;
53         update_func update;
54         digest_func digest;
55         init_func init;
56 };
57
58 static int
59 wrap_padlock_hash_update(void *_ctx, const void *text, size_t textsize)
60 {
61         struct padlock_hash_ctx *ctx = _ctx;
62
63         ctx->update(ctx->ctx_ptr, textsize, text);
64
65         return GNUTLS_E_SUCCESS;
66 }
67
68 static void wrap_padlock_hash_deinit(void *hd)
69 {
70         gnutls_free(hd);
71 }
72
73 #define SHA1_COMPRESS(ctx, data) (padlock_sha1_blocks((void*)(ctx)->state, data, 1))
74 #define SHA256_COMPRESS(ctx, data) (padlock_sha256_blocks((void*)(ctx)->state, data, 1))
75 #define SHA512_COMPRESS(ctx, data) (padlock_sha512_blocks((void*)(ctx)->state, data, 1))
76
77 void
78 padlock_sha1_update(struct sha1_ctx *ctx,
79                     unsigned length, const uint8_t * data)
80 {
81         MD_UPDATE(ctx, length, data, SHA1_COMPRESS, MD_INCR(ctx));
82 }
83
84 void
85 padlock_sha256_update(struct sha256_ctx *ctx,
86                       unsigned length, const uint8_t * data)
87 {
88         MD_UPDATE(ctx, length, data, SHA256_COMPRESS, MD_INCR(ctx));
89 }
90
91 void
92 padlock_sha512_update(struct sha512_ctx *ctx,
93                       unsigned length, const uint8_t * data)
94 {
95         MD_UPDATE(ctx, length, data, SHA512_COMPRESS, MD_INCR(ctx));
96 }
97
98 static void
99 _nettle_write_be32(unsigned length, uint8_t * dst, uint32_t * src)
100 {
101         unsigned i;
102         unsigned words;
103         unsigned leftover;
104
105         words = length / 4;
106         leftover = length % 4;
107
108         for (i = 0; i < words; i++, dst += 4)
109                 WRITE_UINT32(dst, src[i]);
110
111         if (leftover) {
112                 uint32_t word;
113                 unsigned j = leftover;
114
115                 word = src[i];
116
117                 switch (leftover) {
118                 default:
119                         abort();
120                 case 3:
121                         dst[--j] = (word >> 8) & 0xff;
122                         /* Fall through */
123                 case 2:
124                         dst[--j] = (word >> 16) & 0xff;
125                         /* Fall through */
126                 case 1:
127                         dst[--j] = (word >> 24) & 0xff;
128                 }
129         }
130 }
131
132 static void
133 padlock_sha1_digest(struct sha1_ctx *ctx,
134                     unsigned length, uint8_t * digest)
135 {
136         uint32_t high, low;
137
138         assert(length <= SHA1_DIGEST_SIZE);
139
140         MD_PAD(ctx, 8, SHA1_COMPRESS);
141
142         /* There are 512 = 2^9 bits in one block */
143         high = (ctx->count_high << 9) | (ctx->count_low >> 23);
144         low = (ctx->count_low << 9) | (ctx->index << 3);
145
146         /* append the 64 bit count */
147         WRITE_UINT32(ctx->block + (SHA1_DATA_SIZE - 8), high);
148         WRITE_UINT32(ctx->block + (SHA1_DATA_SIZE - 4), low);
149         SHA1_COMPRESS(ctx, ctx->block);
150
151         _nettle_write_be32(length, digest, ctx->state);
152 }
153
154 static void
155 padlock_sha256_digest(struct sha256_ctx *ctx,
156                       unsigned length, uint8_t * digest)
157 {
158         uint32_t high, low;
159
160         assert(length <= SHA256_DIGEST_SIZE);
161
162         MD_PAD(ctx, 8, SHA256_COMPRESS);
163
164         /* There are 512 = 2^9 bits in one block */
165         high = (ctx->count_high << 9) | (ctx->count_low >> 23);
166         low = (ctx->count_low << 9) | (ctx->index << 3);
167
168         /* This is slightly inefficient, as the numbers are converted to
169            big-endian format, and will be converted back by the compression
170            function. It's probably not worth the effort to fix this. */
171         WRITE_UINT32(ctx->block + (SHA256_DATA_SIZE - 8), high);
172         WRITE_UINT32(ctx->block + (SHA256_DATA_SIZE - 4), low);
173         SHA256_COMPRESS(ctx, ctx->block);
174
175         _nettle_write_be32(length, digest, ctx->state);
176 }
177
178 static void
179 padlock_sha512_digest(struct sha512_ctx *ctx,
180                       unsigned length, uint8_t * digest)
181 {
182         uint64_t high, low;
183
184         unsigned i;
185         unsigned words;
186         unsigned leftover;
187
188         assert(length <= SHA512_DIGEST_SIZE);
189
190         MD_PAD(ctx, 16, SHA512_COMPRESS);
191
192         /* There are 1024 = 2^10 bits in one block */
193         high = (ctx->count_high << 10) | (ctx->count_low >> 54);
194         low = (ctx->count_low << 10) | (ctx->index << 3);
195
196         /* This is slightly inefficient, as the numbers are converted to
197            big-endian format, and will be converted back by the compression
198            function. It's probably not worth the effort to fix this. */
199         WRITE_UINT64(ctx->block + (SHA512_DATA_SIZE - 16), high);
200         WRITE_UINT64(ctx->block + (SHA512_DATA_SIZE - 8), low);
201         SHA512_COMPRESS(ctx, ctx->block);
202
203         words = length / 8;
204         leftover = length % 8;
205
206         for (i = 0; i < words; i++, digest += 8)
207                 WRITE_UINT64(digest, ctx->state[i]);
208
209         if (leftover) {
210                 /* Truncate to the right size */
211                 uint64_t word = ctx->state[i] >> (8 * (8 - leftover));
212
213                 do {
214                         digest[--leftover] = word & 0xff;
215                         word >>= 8;
216                 } while (leftover);
217         }
218 }
219
220
221 static int _ctx_init(gnutls_digest_algorithm_t algo,
222                      struct padlock_hash_ctx *ctx)
223 {
224         switch (algo) {
225         case GNUTLS_DIG_SHA1:
226                 sha1_init(&ctx->ctx.sha1);
227                 ctx->update = (update_func) padlock_sha1_update;
228                 ctx->digest = (digest_func) padlock_sha1_digest;
229                 ctx->init = (init_func) sha1_init;
230                 ctx->ctx_ptr = &ctx->ctx.sha1;
231                 ctx->length = SHA1_DIGEST_SIZE;
232                 break;
233         case GNUTLS_DIG_SHA224:
234                 sha224_init(&ctx->ctx.sha224);
235                 ctx->update = (update_func) padlock_sha256_update;
236                 ctx->digest = (digest_func) padlock_sha256_digest;
237                 ctx->init = (init_func) sha224_init;
238                 ctx->ctx_ptr = &ctx->ctx.sha224;
239                 ctx->length = SHA224_DIGEST_SIZE;
240                 break;
241         case GNUTLS_DIG_SHA256:
242                 sha256_init(&ctx->ctx.sha256);
243                 ctx->update = (update_func) padlock_sha256_update;
244                 ctx->digest = (digest_func) padlock_sha256_digest;
245                 ctx->init = (init_func) sha256_init;
246                 ctx->ctx_ptr = &ctx->ctx.sha256;
247                 ctx->length = SHA256_DIGEST_SIZE;
248                 break;
249         case GNUTLS_DIG_SHA384:
250                 sha384_init(&ctx->ctx.sha384);
251                 ctx->update = (update_func) padlock_sha512_update;
252                 ctx->digest = (digest_func) padlock_sha512_digest;
253                 ctx->init = (init_func) sha384_init;
254                 ctx->ctx_ptr = &ctx->ctx.sha384;
255                 ctx->length = SHA384_DIGEST_SIZE;
256                 break;
257         case GNUTLS_DIG_SHA512:
258                 sha512_init(&ctx->ctx.sha512);
259                 ctx->update = (update_func) padlock_sha512_update;
260                 ctx->digest = (digest_func) padlock_sha512_digest;
261                 ctx->init = (init_func) sha512_init;
262                 ctx->ctx_ptr = &ctx->ctx.sha512;
263                 ctx->length = SHA512_DIGEST_SIZE;
264                 break;
265         default:
266                 gnutls_assert();
267                 return GNUTLS_E_INVALID_REQUEST;
268         }
269
270         return 0;
271 }
272
273
274 static int
275 wrap_padlock_hash_init(gnutls_digest_algorithm_t algo, void **_ctx)
276 {
277         struct padlock_hash_ctx *ctx;
278         int ret;
279
280         ctx = gnutls_malloc(sizeof(struct padlock_hash_ctx));
281         if (ctx == NULL) {
282                 gnutls_assert();
283                 return GNUTLS_E_MEMORY_ERROR;
284         }
285
286         ctx->algo = algo;
287
288         if ((ret = _ctx_init(algo, ctx)) < 0) {
289                 gnutls_assert();
290                 return ret;
291         }
292
293         *_ctx = ctx;
294
295         return 0;
296 }
297
298 static int
299 wrap_padlock_hash_output(void *src_ctx, void *digest, size_t digestsize)
300 {
301         struct padlock_hash_ctx *ctx;
302         ctx = src_ctx;
303
304         if (digestsize < ctx->length)
305                 return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
306
307         ctx->digest(ctx->ctx_ptr, digestsize, digest);
308
309         ctx->init(ctx->ctx_ptr);
310
311         return 0;
312 }
313
314 int wrap_padlock_hash_fast(gnutls_digest_algorithm_t algo,
315                            const void *text, size_t text_size,
316                            void *digest)
317 {
318         if (algo == GNUTLS_DIG_SHA1) {
319                 uint32_t iv[5] = {
320                         0x67452301UL,
321                         0xEFCDAB89UL,
322                         0x98BADCFEUL,
323                         0x10325476UL,
324                         0xC3D2E1F0UL,
325                 };
326                 padlock_sha1_oneshot(iv, text, text_size);
327                 _nettle_write_be32(20, digest, iv);
328         } else if (algo == GNUTLS_DIG_SHA256) {
329                 uint32_t iv[8] = {
330                         0x6a09e667UL, 0xbb67ae85UL, 0x3c6ef372UL,
331                             0xa54ff53aUL,
332                         0x510e527fUL, 0x9b05688cUL, 0x1f83d9abUL,
333                             0x5be0cd19UL,
334                 };
335                 padlock_sha256_oneshot(iv, text, text_size);
336                 _nettle_write_be32(32, digest, iv);
337         } else {
338                 struct padlock_hash_ctx ctx;
339                 int ret;
340
341                 ret = _ctx_init(algo, &ctx);
342                 if (ret < 0)
343                         return gnutls_assert_val(ret);
344                 ctx.algo = algo;
345
346                 wrap_padlock_hash_update(&ctx, text, text_size);
347
348                 wrap_padlock_hash_output(&ctx, digest, ctx.length);
349                 wrap_padlock_hash_deinit(&ctx);
350         }
351
352         return 0;
353 }
354
355 const struct nettle_hash padlock_sha1 = NN_HASH(sha1, padlock_sha1_update, padlock_sha1_digest, SHA1);
356 const struct nettle_hash padlock_sha224 = NN_HASH(sha224, padlock_sha256_update, padlock_sha256_digest, SHA224);
357 const struct nettle_hash padlock_sha256 = NN_HASH(sha256, padlock_sha256_update, padlock_sha256_digest, SHA256);
358 const struct nettle_hash padlock_sha384 = NN_HASH(sha384, padlock_sha512_update, padlock_sha512_digest, SHA384);
359 const struct nettle_hash padlock_sha512 = NN_HASH(sha512, padlock_sha512_update, padlock_sha512_digest, SHA512);
360
361 const gnutls_crypto_digest_st sha_padlock_struct = {
362         .init = NULL,
363         .hash = NULL,
364         .output = NULL,
365         .deinit = NULL,
366         .fast = wrap_padlock_hash_fast
367 };
368
369 const gnutls_crypto_digest_st sha_padlock_nano_struct = {
370         .init = wrap_padlock_hash_init,
371         .hash = wrap_padlock_hash_update,
372         .output = wrap_padlock_hash_output,
373         .deinit = wrap_padlock_hash_deinit,
374         .fast = wrap_padlock_hash_fast,
375 };
376
377 #endif                          /* HAVE_LIBNETTLE */