Linux-libre 4.14.12-gnu
[librecmc/linux-libre.git] / drivers / staging / skein / skein_api.c
1 /*
2  * Copyright (c) 2010 Werner Dittmann
3  *
4  * Permission is hereby granted, free of charge, to any person
5  * obtaining a copy of this software and associated documentation
6  * files (the "Software"), to deal in the Software without
7  * restriction, including without limitation the rights to use,
8  * copy, modify, merge, publish, distribute, sublicense, and/or sell
9  * copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following
11  * conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23  * OTHER DEALINGS IN THE SOFTWARE.
24  */
25
26 #include <linux/string.h>
27 #include "skein_api.h"
28
29 int skein_ctx_prepare(struct skein_ctx *ctx, enum skein_size size)
30 {
31         skein_assert_ret(ctx && size, SKEIN_FAIL);
32
33         memset(ctx, 0, sizeof(struct skein_ctx));
34         ctx->skein_size = size;
35
36         return SKEIN_SUCCESS;
37 }
38
39 int skein_init(struct skein_ctx *ctx, size_t hash_bit_len)
40 {
41         int ret = SKEIN_FAIL;
42         size_t x_len = 0;
43         u64 *x = NULL;
44         u64 tree_info = SKEIN_CFG_TREE_INFO_SEQUENTIAL;
45
46         skein_assert_ret(ctx, SKEIN_FAIL);
47         /*
48          * The following two lines rely of the fact that the real Skein
49          * contexts are a union in out context and thus have tha maximum
50          * memory available.  The beauty of C :-) .
51          */
52         x = ctx->m.s256.x;
53         x_len = ctx->skein_size / 8;
54         /*
55          * If size is the same and hash bit length is zero then reuse
56          * the save chaining variables.
57          */
58         switch (ctx->skein_size) {
59         case SKEIN_256:
60                 ret = skein_256_init_ext(&ctx->m.s256, hash_bit_len,
61                                          tree_info, NULL, 0);
62                 break;
63         case SKEIN_512:
64                 ret = skein_512_init_ext(&ctx->m.s512, hash_bit_len,
65                                          tree_info, NULL, 0);
66                 break;
67         case SKEIN_1024:
68                 ret = skein_1024_init_ext(&ctx->m.s1024, hash_bit_len,
69                                           tree_info, NULL, 0);
70                 break;
71         }
72
73         if (ret == SKEIN_SUCCESS) {
74                 /*
75                  * Save chaining variables for this combination of size and
76                  * hash_bit_len
77                  */
78                 memcpy(ctx->x_save, x, x_len);
79         }
80         return ret;
81 }
82
83 int skein_mac_init(struct skein_ctx *ctx, const u8 *key, size_t key_len,
84                    size_t hash_bit_len)
85 {
86         int ret = SKEIN_FAIL;
87         u64 *x = NULL;
88         size_t x_len = 0;
89         u64 tree_info = SKEIN_CFG_TREE_INFO_SEQUENTIAL;
90
91         skein_assert_ret(ctx, SKEIN_FAIL);
92
93         x = ctx->m.s256.x;
94         x_len = ctx->skein_size / 8;
95
96         skein_assert_ret(hash_bit_len, SKEIN_BAD_HASHLEN);
97
98         switch (ctx->skein_size) {
99         case SKEIN_256:
100                 ret = skein_256_init_ext(&ctx->m.s256, hash_bit_len,
101                                          tree_info, key, key_len);
102
103                 break;
104         case SKEIN_512:
105                 ret = skein_512_init_ext(&ctx->m.s512, hash_bit_len,
106                                          tree_info, key, key_len);
107                 break;
108         case SKEIN_1024:
109                 ret = skein_1024_init_ext(&ctx->m.s1024, hash_bit_len,
110                                           tree_info, key, key_len);
111
112                 break;
113         }
114         if (ret == SKEIN_SUCCESS) {
115                 /*
116                  * Save chaining variables for this combination of key,
117                  * key_len, hash_bit_len
118                  */
119                 memcpy(ctx->x_save, x, x_len);
120         }
121         return ret;
122 }
123
124 void skein_reset(struct skein_ctx *ctx)
125 {
126         size_t x_len = 0;
127         u64 *x;
128
129         /*
130          * The following two lines rely of the fact that the real Skein
131          * contexts are a union in out context and thus have tha maximum
132          * memory available.  The beautiy of C :-) .
133          */
134         x = ctx->m.s256.x;
135         x_len = ctx->skein_size / 8;
136         /* Restore the chaing variable, reset byte counter */
137         memcpy(x, ctx->x_save, x_len);
138
139         /* Setup context to process the message */
140         skein_start_new_type(&ctx->m, MSG);
141 }
142
143 int skein_update(struct skein_ctx *ctx, const u8 *msg,
144                  size_t msg_byte_cnt)
145 {
146         int ret = SKEIN_FAIL;
147
148         skein_assert_ret(ctx, SKEIN_FAIL);
149
150         switch (ctx->skein_size) {
151         case SKEIN_256:
152                 ret = skein_256_update(&ctx->m.s256, msg, msg_byte_cnt);
153                 break;
154         case SKEIN_512:
155                 ret = skein_512_update(&ctx->m.s512, msg, msg_byte_cnt);
156                 break;
157         case SKEIN_1024:
158                 ret = skein_1024_update(&ctx->m.s1024, msg, msg_byte_cnt);
159                 break;
160         }
161         return ret;
162 }
163
164 int skein_update_bits(struct skein_ctx *ctx, const u8 *msg,
165                       size_t msg_bit_cnt)
166 {
167         /*
168          * I've used the bit pad implementation from skein_test.c (see NIST CD)
169          * and modified it to use the convenience functions and added some
170          * pointer arithmetic.
171          */
172         size_t length;
173         u8 mask;
174         u8 *up;
175
176         /*
177          * only the final Update() call is allowed do partial bytes, else
178          * assert an error
179          */
180         skein_assert_ret((ctx->m.h.T[1] & SKEIN_T1_FLAG_BIT_PAD) == 0 ||
181                          msg_bit_cnt == 0, SKEIN_FAIL);
182
183         /* if number of bits is a multiple of bytes - that's easy */
184         if ((msg_bit_cnt & 0x7) == 0)
185                 return skein_update(ctx, msg, msg_bit_cnt >> 3);
186
187         skein_update(ctx, msg, (msg_bit_cnt >> 3) + 1);
188
189         /*
190          * The next line rely on the fact that the real Skein contexts
191          * are a union in our context. After the addition the pointer points to
192          * Skein's real partial block buffer.
193          * If this layout ever changes we have to adapt this as well.
194          */
195         up = (u8 *)ctx->m.s256.x + ctx->skein_size / 8;
196
197         /* set tweak flag for the skein_final call */
198         skein_set_bit_pad_flag(ctx->m.h);
199
200         /* now "pad" the final partial byte the way NIST likes */
201         /* get the b_cnt value (same location for all block sizes) */
202         length = ctx->m.h.b_cnt;
203         /* internal sanity check: there IS a partial byte in the buffer! */
204         skein_assert(length != 0);
205         /* partial byte bit mask */
206         mask = (u8)(1u << (7 - (msg_bit_cnt & 7)));
207         /* apply bit padding on final byte (in the buffer) */
208         up[length - 1]  = (up[length - 1] & (0 - mask)) | mask;
209
210         return SKEIN_SUCCESS;
211 }
212
213 int skein_final(struct skein_ctx *ctx, u8 *hash)
214 {
215         int ret = SKEIN_FAIL;
216
217         skein_assert_ret(ctx, SKEIN_FAIL);
218
219         switch (ctx->skein_size) {
220         case SKEIN_256:
221                 ret = skein_256_final(&ctx->m.s256, hash);
222                 break;
223         case SKEIN_512:
224                 ret = skein_512_final(&ctx->m.s512, hash);
225                 break;
226         case SKEIN_1024:
227                 ret = skein_1024_final(&ctx->m.s1024, hash);
228                 break;
229         }
230         return ret;
231 }