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 
27 #define SKEIN_ERR_CHECK 1
28 #include <cryptcommon/skeinApi.h>
29 #include <string.h>
30 #include <stdio.h>
31 
skeinCtxPrepare(SkeinCtx_t * ctx,SkeinSize_t size)32 int skeinCtxPrepare(SkeinCtx_t* ctx, SkeinSize_t size)
33 {
34     Skein_Assert(ctx && size, SKEIN_FAIL);
35 
36     memset(ctx ,0, sizeof(SkeinCtx_t));
37     ctx->skeinSize = size;
38 
39     return SKEIN_SUCCESS;
40 }
41 
skeinInit(SkeinCtx_t * ctx,size_t hashBitLen)42 int skeinInit(SkeinCtx_t* ctx, size_t hashBitLen)
43 {
44     int ret = SKEIN_FAIL;
45     size_t Xlen = 0;
46     u64b_t*  X = NULL;
47     uint64_t treeInfo = SKEIN_CFG_TREE_INFO_SEQUENTIAL;
48 
49     Skein_Assert(ctx, SKEIN_FAIL);
50     /*
51      * The following two lines rely of the fact that the real Skein contexts are
52      * a union in out context and thus have tha maximum memory available.
53      * The beauty of C :-) .
54      */
55     X = ctx->m.s256.X;
56     Xlen = (size_t)(ctx->skeinSize/8);
57     /*
58      * If size is the same and hash bit length is zero then reuse
59      * the save chaining variables.
60      */
61     switch (ctx->skeinSize) {
62     case Skein256:
63         ret = Skein_256_InitExt(&ctx->m.s256, hashBitLen,
64                                 treeInfo, NULL, 0);
65         break;
66     case Skein512:
67         ret = Skein_512_InitExt(&ctx->m.s512, hashBitLen,
68                                 treeInfo, NULL, 0);
69         break;
70     case Skein1024:
71         ret = Skein1024_InitExt(&ctx->m.s1024, hashBitLen,
72                                 treeInfo, NULL, 0);
73         break;
74     }
75 
76     if (ret == SKEIN_SUCCESS) {
77         /* Save chaining variables for this combination of size and hashBitLen */
78         memcpy(ctx->XSave, X, Xlen);
79     }
80     return ret;
81 }
82 
skeinMacInit(SkeinCtx_t * ctx,const uint8_t * key,size_t keyLen,size_t hashBitLen)83 int skeinMacInit(SkeinCtx_t* ctx, const uint8_t *key, size_t keyLen,
84                  size_t hashBitLen)
85 {
86     int ret = SKEIN_FAIL;
87     u64b_t*  X = NULL;
88     size_t Xlen = 0;
89     uint64_t treeInfo = SKEIN_CFG_TREE_INFO_SEQUENTIAL;
90 
91     Skein_Assert(ctx, SKEIN_FAIL);
92 
93     X = ctx->m.s256.X;
94     Xlen = (size_t)(ctx->skeinSize/8);
95 
96     Skein_Assert(hashBitLen, SKEIN_BAD_HASHLEN);
97 
98     switch (ctx->skeinSize) {
99     case Skein256:
100         ret = Skein_256_InitExt(&ctx->m.s256, hashBitLen,
101                                 treeInfo,
102                                 (const u08b_t*)key, keyLen);
103 
104         break;
105     case Skein512:
106         ret = Skein_512_InitExt(&ctx->m.s512, hashBitLen,
107                                 treeInfo,
108                                 (const u08b_t*)key, keyLen);
109         break;
110     case Skein1024:
111         ret = Skein1024_InitExt(&ctx->m.s1024, hashBitLen,
112                                 treeInfo,
113                                 (const u08b_t*)key, keyLen);
114 
115         break;
116     }
117     if (ret == SKEIN_SUCCESS) {
118         /* Save chaining variables for this combination of key, keyLen, hashBitLen */
119         memcpy(ctx->XSave, X, Xlen);
120     }
121     return ret;
122 }
123 
skeinReset(SkeinCtx_t * ctx)124 void skeinReset(SkeinCtx_t* ctx)
125 {
126     size_t Xlen = 0;
127     u64b_t*  X = NULL;
128 
129     /*
130      * The following two lines rely of the fact that the real Skein contexts are
131      * a union in out context and thus have tha maximum memory available.
132      * The beautiy of C :-) .
133      */
134     X = ctx->m.s256.X;
135     Xlen = (size_t)(ctx->skeinSize/8);
136     /*
137      * If size is the same and hash bit length is zero then reuse
138      * the save chaining variables.
139      */
140     /* Restore the chaing variable, reset byte counter */
141     memcpy(X, ctx->XSave, Xlen);
142 
143     /* Setup context to process the message */
144     Skein_Start_New_Type(&ctx->m, MSG);
145 }
146 
skeinUpdate(SkeinCtx_t * ctx,const uint8_t * msg,size_t msgByteCnt)147 int skeinUpdate(SkeinCtx_t *ctx, const uint8_t *msg,
148                 size_t msgByteCnt)
149 {
150     int ret = SKEIN_FAIL;
151     Skein_Assert(ctx, SKEIN_FAIL);
152 
153     switch (ctx->skeinSize) {
154     case Skein256:
155         ret = Skein_256_Update(&ctx->m.s256, (const u08b_t*)msg, msgByteCnt);
156         break;
157     case Skein512:
158         ret = Skein_512_Update(&ctx->m.s512, (const u08b_t*)msg, msgByteCnt);
159         break;
160     case Skein1024:
161         ret = Skein1024_Update(&ctx->m.s1024, (const u08b_t*)msg, msgByteCnt);
162         break;
163     }
164     return ret;
165 
166 }
167 
skeinUpdateBits(SkeinCtx_t * ctx,const uint8_t * msg,size_t msgBitCnt)168 int skeinUpdateBits(SkeinCtx_t *ctx, const uint8_t *msg,
169                     size_t msgBitCnt)
170 {
171     /*
172      * I've used the bit pad implementation from skein_test.c (see NIST CD)
173      * and modified it to use the convenience functions and added some pointer
174      * arithmetic.
175      */
176     size_t length;
177     uint8_t mask;
178     uint8_t* up;
179 
180     /* only the final Update() call is allowed do partial bytes, else assert an error */
181     Skein_Assert((ctx->m.h.T[1] & SKEIN_T1_FLAG_BIT_PAD) == 0 || msgBitCnt == 0, SKEIN_FAIL);
182 
183     /* if number of bits is a multiple of bytes - that's easy */
184     if ((msgBitCnt & 0x7) == 0) {
185         return skeinUpdate(ctx, msg, msgBitCnt >> 3);
186     }
187     skeinUpdate(ctx, msg, (msgBitCnt >> 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 = (uint8_t*)ctx->m.s256.X + ctx->skeinSize / 8;
196 
197     Skein_Set_Bit_Pad_Flag(ctx->m.h);                       /* set tweak flag for the skeinFinal call */
198 
199     /* now "pad" the final partial byte the way NIST likes */
200     length = ctx->m.h.bCnt;                                 /* get the bCnt value (same location for all block sizes) */
201     Skein_assert(length != 0);                              /* internal sanity check: there IS a partial byte in the buffer! */
202     mask = (uint8_t) (1u << (7 - (msgBitCnt & 7)));         /* partial byte bit mask */
203     up[length-1]  = (uint8_t)((up[length-1] & (0-mask))|mask);   /* apply bit padding on final byte (in the buffer) */
204 
205     return SKEIN_SUCCESS;
206 }
207 
skeinFinal(SkeinCtx_t * ctx,uint8_t * hash)208 int skeinFinal(SkeinCtx_t* ctx, uint8_t* hash)
209 {
210     int ret = SKEIN_FAIL;
211     Skein_Assert(ctx, SKEIN_FAIL);
212 
213     switch (ctx->skeinSize) {
214     case Skein256:
215         ret = Skein_256_Final(&ctx->m.s256, (u08b_t*)hash);
216         break;
217     case Skein512:
218         ret = Skein_512_Final(&ctx->m.s512, (u08b_t*)hash);
219         break;
220     case Skein1024:
221         ret = Skein1024_Final(&ctx->m.s1024, (u08b_t*)hash);
222         break;
223     }
224     return ret;
225 }
226