1 /***********************************************************************
2 **
3 ** Implementation of the Skein hash function.
4 **
5 ** Source code author: Doug Whiting, 2008.
6 **
7 ** This algorithm and source code is released to the public domain.
8 **
9 ************************************************************************/
10 
11 #include <string.h>      /* get the memcpy/memset functions */
12 #include "skein.h"       /* get the Skein API definitions   */
13 
14 /*****************************************************************/
15 /* External function to process blkCnt (nonzero) full block(s) of data. */
16 void    Skein_256_Process_Block(Skein_256_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd);
17 void    Skein_512_Process_Block(Skein_512_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd);
18 void    Skein1024_Process_Block(Skein1024_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd);
19 
20 /*****************************************************************/
21 /*     Portable (i.e., slow) endianness conversion functions     */
Skein_Swap64(u64b_t w64)22 u64b_t Skein_Swap64(u64b_t w64)
23     {    /* instantiate the function body here */
24     static const u64b_t ONE = 1;              /* use this to check endianness */
25 
26     /* figure out endianness "on-the-fly" */
27     if (1 == ((u08b_t *) & ONE)[0])
28         return w64;                           /* little-endian is fast */
29     else
30         return  (( w64       & 0xFF) << 56) | /*    big-endian is slow */
31                 (((w64 >> 8) & 0xFF) << 48) |
32                 (((w64 >>16) & 0xFF) << 40) |
33                 (((w64 >>24) & 0xFF) << 32) |
34                 (((w64 >>32) & 0xFF) << 24) |
35                 (((w64 >>40) & 0xFF) << 16) |
36                 (((w64 >>48) & 0xFF) <<  8) |
37                 (((w64 >>56) & 0xFF)      ) ;
38     }
39 
Skein_Put64_LSB_First(u08b_t * dst,const u64b_t * src,size_t bCnt)40 void    Skein_Put64_LSB_First(u08b_t *dst,const u64b_t *src,size_t bCnt)
41     { /* this version is fully portable (big-endian or little-endian), but slow */
42     size_t n;
43 
44     for (n=0;n<bCnt;n++)
45         dst[n] = (u08b_t) (src[n>>3] >> (8*(n&7)));
46     }
47 
Skein_Get64_LSB_First(u64b_t * dst,const u08b_t * src,size_t wCnt)48 void    Skein_Get64_LSB_First(u64b_t *dst,const u08b_t *src,size_t wCnt)
49     { /* this version is fully portable (big-endian or little-endian), but slow */
50     size_t n;
51 
52     for (n=0;n<8*wCnt;n+=8)
53         dst[n/8] = (((u64b_t) src[n  ])      ) +
54                    (((u64b_t) src[n+1]) <<  8) +
55                    (((u64b_t) src[n+2]) << 16) +
56                    (((u64b_t) src[n+3]) << 24) +
57                    (((u64b_t) src[n+4]) << 32) +
58                    (((u64b_t) src[n+5]) << 40) +
59                    (((u64b_t) src[n+6]) << 48) +
60                    (((u64b_t) src[n+7]) << 56) ;
61     }
62 
63 /*****************************************************************/
64 /*     256-bit Skein                                             */
65 /*****************************************************************/
66 
67 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
68 /* init the context for a straight hashing operation */
Skein_256_Init(Skein_256_Ctxt_t * ctx,size_t hashBitLen)69 int Skein_256_Init(Skein_256_Ctxt_t *ctx, size_t hashBitLen)
70     {
71     union
72         {
73         u08b_t  b[SKEIN_256_STATE_BYTES];
74         u64b_t  w[SKEIN_256_STATE_WORDS];
75         } cfg;                                  /* config block */
76 
77     Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
78 
79     /* build/process config block for hashing */
80     ctx->h.hashBitLen = hashBitLen;             /* output hash byte count */
81     Skein_Start_New_Type(ctx,CFG_FINAL);        /* set tweaks: T0=0; T1=CFG | FINAL */
82 
83     memset(&cfg.w,0,sizeof(cfg.w));             /* pre-pad cfg.w[] with zeroes */
84     cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);  /* set the schema, version */
85     cfg.w[1] = Skein_Swap64(hashBitLen);        /* hash result length in bits */
86     cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL);
87 
88     /* compute the initial chaining values from config block */
89     memset(ctx->X,0,sizeof(ctx->X));            /* zero the chaining variables */
90     Skein_256_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
91 
92     /* The chaining vars ctx->X are now initialized for the given hashBitLen. */
93     /* Set up to process the data message portion of the hash (default) */
94     Skein_Start_New_Type(ctx,MSG);              /* T0=0, T1= MSG type, h.bCnt=0 */
95 
96     return SKEIN_SUCCESS;
97     }
98 
99 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
100 /* init the context for a MAC and/or tree hash operation */
101 /* [identical to Skein_256_Init() when keyBytes == 0 && treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */
Skein_256_InitExt(Skein_256_Ctxt_t * ctx,size_t hashBitLen,u64b_t treeInfo,const u08b_t * key,size_t keyBytes)102 int Skein_256_InitExt(Skein_256_Ctxt_t *ctx,size_t hashBitLen,u64b_t treeInfo, const u08b_t *key, size_t keyBytes)
103     {
104     uint_t i;
105     union
106         {
107         u08b_t  b[SKEIN_256_STATE_BYTES];
108         u64b_t  w[SKEIN_256_STATE_WORDS];
109         } cfg;                                  /* config block */
110 
111     Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
112     Skein_Assert(keyBytes == 0 || key != NULL,SKEIN_FAIL);
113 
114     /* compute the initial chaining values ctx->X[], based on key */
115     if (keyBytes == 0)                          /* is there a key? */
116         {
117         memset(ctx->X,0,sizeof(ctx->X));        /* no key: use all zeroes as key for config block */
118         }
119     else                                        /* here to pre-process a key */
120         {
121         Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X));
122         /* do a mini-Init right here */
123         ctx->h.hashBitLen=8*sizeof(ctx->X);     /* set output hash bit count = state size */
124         Skein_Start_New_Type(ctx,KEY);          /* set tweaks: T0 = 0; T1 = KEY type */
125         memset(ctx->X,0,sizeof(ctx->X));        /* zero the initial chaining variables */
126         Skein_256_Update(ctx,key,keyBytes);     /* hash the key */
127         Skein_256_Final_Pad(ctx,cfg.b);         /* put result into cfg.b[] */
128         memcpy(ctx->X,cfg.b,sizeof(cfg.b));     /* copy over into ctx->X[] */
129         for (i=0;i<SKEIN_256_STATE_WORDS;i++)   /* convert key bytes to context words */
130             ctx->X[i] = Skein_Swap64(ctx->X[i]);
131         }
132 
133     /* build/process the config block, type == CONFIG (could be precomputed for each key) */
134     ctx->h.hashBitLen = hashBitLen;             /* output hash bit count */
135     Skein_Start_New_Type(ctx,CFG_FINAL);
136 
137     memset(&cfg.w,0,sizeof(cfg.w));             /* pre-pad cfg.w[] with zeroes */
138     cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);
139     cfg.w[1] = Skein_Swap64(hashBitLen);        /* hash result length in bits */
140     cfg.w[2] = Skein_Swap64(treeInfo);          /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */
141 
142     Skein_Show_Key(256,&ctx->h,key,keyBytes);
143 
144     /* compute the initial chaining values from config block */
145     Skein_256_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
146 
147     /* The chaining vars ctx->X are now initialized */
148     /* Set up to process the data message portion of the hash */
149     Skein_Start_New_Type(ctx,MSG);              /* T0=0, T1= MSG type, h.bCnt=0 */
150 
151     return SKEIN_SUCCESS;
152     }
153 
154 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
155 /* process the input bytes */
Skein_256_Update(Skein_256_Ctxt_t * ctx,const u08b_t * msg,size_t msgByteCnt)156 int Skein_256_Update(Skein_256_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt)
157     {
158     size_t n;
159 
160     Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL);     /* catch uninitialized context */
161 
162     /* process full blocks, if any */
163     if (msgByteCnt + ctx->h.bCnt > SKEIN_256_BLOCK_BYTES)
164         {
165         if (ctx->h.bCnt)                              /* finish up any buffered message data */
166             {
167             n = SKEIN_256_BLOCK_BYTES - ctx->h.bCnt;  /* # bytes free in buffer b[] */
168             if (n)
169                 {
170                 Skein_assert(n < msgByteCnt);         /* check on our logic here */
171                 memcpy(&ctx->b[ctx->h.bCnt],msg,n);
172                 msgByteCnt  -= n;
173                 msg         += n;
174                 ctx->h.bCnt += n;
175                 }
176             Skein_assert(ctx->h.bCnt == SKEIN_256_BLOCK_BYTES);
177             Skein_256_Process_Block(ctx,ctx->b,1,SKEIN_256_BLOCK_BYTES);
178             ctx->h.bCnt = 0;
179             }
180         /* now process any remaining full blocks, directly from input message data */
181         if (msgByteCnt > SKEIN_256_BLOCK_BYTES)
182             {
183             n = (msgByteCnt-1) / SKEIN_256_BLOCK_BYTES;   /* number of full blocks to process */
184             Skein_256_Process_Block(ctx,msg,n,SKEIN_256_BLOCK_BYTES);
185             msgByteCnt -= n * SKEIN_256_BLOCK_BYTES;
186             msg        += n * SKEIN_256_BLOCK_BYTES;
187             }
188         Skein_assert(ctx->h.bCnt == 0);
189         }
190 
191     /* copy any remaining source message data bytes into b[] */
192     if (msgByteCnt)
193         {
194         Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES);
195         memcpy(&ctx->b[ctx->h.bCnt],msg,msgByteCnt);
196         ctx->h.bCnt += msgByteCnt;
197         }
198 
199     return SKEIN_SUCCESS;
200     }
201 
202 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
203 /* finalize the hash computation and output the result */
Skein_256_Final(Skein_256_Ctxt_t * ctx,u08b_t * hashVal)204 int Skein_256_Final(Skein_256_Ctxt_t *ctx, u08b_t *hashVal)
205     {
206     size_t i,n,byteCnt;
207     u64b_t X[SKEIN_256_STATE_WORDS];
208     Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
209 
210     ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL;        /* tag as the final block */
211     if (ctx->h.bCnt < SKEIN_256_BLOCK_BYTES)   /* zero pad b[] if necessary */
212         memset(&ctx->b[ctx->h.bCnt],0,SKEIN_256_BLOCK_BYTES - ctx->h.bCnt);
213     Skein_256_Process_Block(ctx,ctx->b,1,ctx->h.bCnt);    /* process the final block */
214 
215     /* now output the result */
216     byteCnt = (ctx->h.hashBitLen + 7) >> 3;    /* total number of output bytes */
217 
218     /* run Threefish in "counter mode" to generate output */
219     memset(ctx->b,0,sizeof(ctx->b));  /* zero out b[], so it can hold the counter */
220     memcpy(X,ctx->X,sizeof(X));       /* keep a local copy of counter mode "key" */
221     for (i=0;i*SKEIN_256_BLOCK_BYTES < byteCnt;i++)
222         {
223         ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
224         Skein_Start_New_Type(ctx,OUT_FINAL);
225         Skein_256_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
226         n = byteCnt - i*SKEIN_256_BLOCK_BYTES;   /* number of output bytes left to go */
227         if (n >= SKEIN_256_BLOCK_BYTES)
228             n  = SKEIN_256_BLOCK_BYTES;
229         Skein_Put64_LSB_First(hashVal+i*SKEIN_256_BLOCK_BYTES,ctx->X,n);   /* "output" the ctr mode bytes */
230         Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN_256_BLOCK_BYTES);
231         memcpy(ctx->X,X,sizeof(X));   /* restore the counter mode key for next time */
232         }
233     return SKEIN_SUCCESS;
234     }
235 
236 #if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF)
Skein_256_API_CodeSize(void)237 size_t Skein_256_API_CodeSize(void)
238     {
239     return ((u08b_t *) Skein_256_API_CodeSize) -
240            ((u08b_t *) Skein_256_Init);
241     }
242 #endif
243 
244 /*****************************************************************/
245 /*     512-bit Skein                                             */
246 /*****************************************************************/
247 
248 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
249 /* init the context for a straight hashing operation */
Skein_512_Init(Skein_512_Ctxt_t * ctx,size_t hashBitLen)250 int Skein_512_Init(Skein_512_Ctxt_t *ctx, size_t hashBitLen)
251     {
252     union
253         {
254         u08b_t  b[SKEIN_512_STATE_BYTES];
255         u64b_t  w[SKEIN_512_STATE_WORDS];
256         } cfg;                                  /* config block */
257 
258     Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
259 
260     /* build/process config block for hashing */
261     ctx->h.hashBitLen = hashBitLen;             /* output hash byte count */
262     Skein_Start_New_Type(ctx,CFG_FINAL);        /* set tweaks: T0=0; T1=CFG | FINAL */
263 
264     memset(&cfg.w,0,sizeof(cfg.w));             /* pre-pad cfg.w[] with zeroes */
265     cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);  /* set the schema, version */
266     cfg.w[1] = Skein_Swap64(hashBitLen);        /* hash result length in bits */
267     cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL);
268 
269     /* compute the initial chaining values from config block */
270     memset(ctx->X,0,sizeof(ctx->X));            /* zero the chaining variables */
271     Skein_512_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
272 
273     /* The chaining vars ctx->X are now initialized for the given hashBitLen. */
274     /* Set up to process the data message portion of the hash (default) */
275     Skein_Start_New_Type(ctx,MSG);              /* T0=0, T1= MSG type, h.bCnt=0 */
276 
277     return SKEIN_SUCCESS;
278     }
279 
280 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
281 /* init the context for a MAC and/or tree hash operation */
282 /* [identical to Skein_512_Init() when keyBytes == 0 && treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */
Skein_512_InitExt(Skein_512_Ctxt_t * ctx,size_t hashBitLen,u64b_t treeInfo,const u08b_t * key,size_t keyBytes)283 int Skein_512_InitExt(Skein_512_Ctxt_t *ctx,size_t hashBitLen,u64b_t treeInfo, const u08b_t *key, size_t keyBytes)
284     {
285     uint_t i;
286     union
287         {
288         u08b_t  b[SKEIN_512_STATE_BYTES];
289         u64b_t  w[SKEIN_512_STATE_WORDS];
290         } cfg;                                  /* config block */
291 
292     Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
293     Skein_Assert(keyBytes == 0 || key != NULL,SKEIN_FAIL);
294 
295     /* compute the initial chaining values ctx->X[], based on key */
296     if (keyBytes == 0)                          /* is there a key? */
297         {
298         memset(ctx->X,0,sizeof(ctx->X));        /* no key: use all zeroes as key for config block */
299         }
300     else                                        /* here to pre-process a key */
301         {
302         Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X));
303         /* do a mini-Init right here */
304         ctx->h.hashBitLen=8*sizeof(ctx->X);     /* set output hash bit count = state size */
305         Skein_Start_New_Type(ctx,KEY);          /* set tweaks: T0 = 0; T1 = KEY type */
306         memset(ctx->X,0,sizeof(ctx->X));        /* zero the initial chaining variables */
307         Skein_512_Update(ctx,key,keyBytes);     /* hash the key */
308         Skein_512_Final_Pad(ctx,cfg.b);         /* put result into cfg.b[] */
309         memcpy(ctx->X,cfg.b,sizeof(cfg.b));     /* copy over into ctx->X[] */
310         for (i=0;i<SKEIN_512_STATE_WORDS;i++)   /* convert key bytes to context words */
311             ctx->X[i] = Skein_Swap64(ctx->X[i]);
312         }
313 
314     /* build/process the config block, type == CONFIG (could be precomputed for each key) */
315     ctx->h.hashBitLen = hashBitLen;             /* output hash bit count */
316     Skein_Start_New_Type(ctx,CFG_FINAL);
317 
318     memset(&cfg.w,0,sizeof(cfg.w));             /* pre-pad cfg.w[] with zeroes */
319     cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);
320     cfg.w[1] = Skein_Swap64(hashBitLen);        /* hash result length in bits */
321     cfg.w[2] = Skein_Swap64(treeInfo);          /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */
322 
323     Skein_Show_Key(512,&ctx->h,key,keyBytes);
324 
325     /* compute the initial chaining values from config block */
326     Skein_512_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
327 
328     /* The chaining vars ctx->X are now initialized */
329     /* Set up to process the data message portion of the hash */
330     Skein_Start_New_Type(ctx,MSG);              /* T0=0, T1= MSG type, h.bCnt=0 */
331 
332     return SKEIN_SUCCESS;
333     }
334 
335 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
336 /* process the input bytes */
Skein_512_Update(Skein_512_Ctxt_t * ctx,const u08b_t * msg,size_t msgByteCnt)337 int Skein_512_Update(Skein_512_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt)
338     {
339     size_t n;
340 
341     Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL);     /* catch uninitialized context */
342 
343     /* process full blocks, if any */
344     if (msgByteCnt + ctx->h.bCnt > SKEIN_512_BLOCK_BYTES)
345         {
346         if (ctx->h.bCnt)                              /* finish up any buffered message data */
347             {
348             n = SKEIN_512_BLOCK_BYTES - ctx->h.bCnt;  /* # bytes free in buffer b[] */
349             if (n)
350                 {
351                 Skein_assert(n < msgByteCnt);         /* check on our logic here */
352                 memcpy(&ctx->b[ctx->h.bCnt],msg,n);
353                 msgByteCnt  -= n;
354                 msg         += n;
355                 ctx->h.bCnt += n;
356                 }
357             Skein_assert(ctx->h.bCnt == SKEIN_512_BLOCK_BYTES);
358             Skein_512_Process_Block(ctx,ctx->b,1,SKEIN_512_BLOCK_BYTES);
359             ctx->h.bCnt = 0;
360             }
361         /* now process any remaining full blocks, directly from input message data */
362         if (msgByteCnt > SKEIN_512_BLOCK_BYTES)
363             {
364             n = (msgByteCnt-1) / SKEIN_512_BLOCK_BYTES;   /* number of full blocks to process */
365             Skein_512_Process_Block(ctx,msg,n,SKEIN_512_BLOCK_BYTES);
366             msgByteCnt -= n * SKEIN_512_BLOCK_BYTES;
367             msg        += n * SKEIN_512_BLOCK_BYTES;
368             }
369         Skein_assert(ctx->h.bCnt == 0);
370         }
371 
372     /* copy any remaining source message data bytes into b[] */
373     if (msgByteCnt)
374         {
375         Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES);
376         memcpy(&ctx->b[ctx->h.bCnt],msg,msgByteCnt);
377         ctx->h.bCnt += msgByteCnt;
378         }
379 
380     return SKEIN_SUCCESS;
381     }
382 
383 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
384 /* finalize the hash computation and output the result */
Skein_512_Final(Skein_512_Ctxt_t * ctx,u08b_t * hashVal)385 int Skein_512_Final(Skein_512_Ctxt_t *ctx, u08b_t *hashVal)
386     {
387     size_t i,n,byteCnt;
388     u64b_t X[SKEIN_512_STATE_WORDS];
389     Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
390 
391     ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL;                 /* tag as the final block */
392     if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES)   /* zero pad b[] if necessary */
393         memset(&ctx->b[ctx->h.bCnt],0,SKEIN_512_BLOCK_BYTES - ctx->h.bCnt);
394 
395     Skein_512_Process_Block(ctx,ctx->b,1,ctx->h.bCnt);  /* process the final block */
396 
397     /* now output the result */
398     byteCnt = (ctx->h.hashBitLen + 7) >> 3;             /* total number of output bytes */
399 
400     /* run Threefish in "counter mode" to generate more output */
401     memset(ctx->b,0,sizeof(ctx->b));  /* zero out b[], so it can hold the counter */
402     memcpy(X,ctx->X,sizeof(X));       /* keep a local copy of counter mode "key" */
403     for (i=0;i*SKEIN_512_BLOCK_BYTES < byteCnt;i++)
404         {
405         ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
406         Skein_Start_New_Type(ctx,OUT_FINAL);
407         Skein_512_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
408         n = byteCnt - i*SKEIN_512_BLOCK_BYTES;   /* number of output bytes left to go */
409         if (n >= SKEIN_512_BLOCK_BYTES)
410             n  = SKEIN_512_BLOCK_BYTES;
411         Skein_Put64_LSB_First(hashVal+i*SKEIN_512_BLOCK_BYTES,ctx->X,n);   /* "output" the ctr mode bytes */
412         Skein_Show_Final(512,&ctx->h,n,hashVal+i*SKEIN_512_BLOCK_BYTES);
413         memcpy(ctx->X,X,sizeof(X));   /* restore the counter mode key for next time */
414         }
415 
416     return SKEIN_SUCCESS;
417     }
418 
419 #if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF)
Skein_512_API_CodeSize(void)420 size_t Skein_512_API_CodeSize(void)
421     {
422     return ((u08b_t *) Skein_512_API_CodeSize) -
423            ((u08b_t *) Skein_512_Init);
424     }
425 #endif
426 
427 /*****************************************************************/
428 /*    1024-bit Skein                                             */
429 /*****************************************************************/
430 
431 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
432 /* init the context for a straight hashing operation */
Skein1024_Init(Skein1024_Ctxt_t * ctx,size_t hashBitLen)433 int Skein1024_Init(Skein1024_Ctxt_t *ctx, size_t hashBitLen)
434     {
435     union
436         {
437         u08b_t  b[SKEIN1024_STATE_BYTES];
438         u64b_t  w[SKEIN1024_STATE_WORDS];
439         } cfg;                                  /* config block */
440 
441     Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
442 
443     /* build/process config block for hashing */
444     ctx->h.hashBitLen = hashBitLen;             /* output hash byte count */
445     Skein_Start_New_Type(ctx,CFG_FINAL);        /* set tweaks: T0=0; T1=CFG | FINAL */
446 
447     memset(&cfg.w,0,sizeof(cfg.w));             /* pre-pad cfg.w[] with zeroes */
448     cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);  /* set the schema, version */
449     cfg.w[1] = Skein_Swap64(hashBitLen);        /* hash result length in bits */
450     cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL);
451 
452     /* compute the initial chaining values from config block */
453     memset(ctx->X,0,sizeof(ctx->X));            /* zero the chaining variables */
454     Skein1024_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
455 
456     /* The chaining vars ctx->X are now initialized for the given hashBitLen. */
457     /* Set up to process the data message portion of the hash (default) */
458     Skein_Start_New_Type(ctx,MSG);              /* T0=0, T1= MSG type, h.bCnt=0 */
459 
460     return SKEIN_SUCCESS;
461     }
462 
463 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
464 /* init the context for a MAC and/or tree hash operation */
465 /* [identical to Skein1024_Init() when keyBytes == 0 && treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */
Skein1024_InitExt(Skein1024_Ctxt_t * ctx,size_t hashBitLen,u64b_t treeInfo,const u08b_t * key,size_t keyBytes)466 int Skein1024_InitExt(Skein1024_Ctxt_t *ctx,size_t hashBitLen,u64b_t treeInfo, const u08b_t *key, size_t keyBytes)
467     {
468     uint_t i;
469     union
470         {
471         u08b_t  b[SKEIN1024_STATE_BYTES];
472         u64b_t  w[SKEIN1024_STATE_WORDS];
473         } cfg;                                  /* config block */
474 
475     Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN);
476     Skein_Assert(keyBytes == 0 || key != NULL,SKEIN_FAIL);
477 
478     /* compute the initial chaining values ctx->X[], based on key */
479     if (keyBytes == 0)                          /* is there a key? */
480         {
481         memset(ctx->X,0,sizeof(ctx->X));        /* no key: use all zeroes as key for config block */
482         }
483     else                                        /* here to pre-process a key */
484         {
485         Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X));
486         /* do a mini-Init right here */
487         ctx->h.hashBitLen=8*sizeof(ctx->X);     /* set output hash bit count = state size */
488         Skein_Start_New_Type(ctx,KEY);          /* set tweaks: T0 = 0; T1 = KEY type */
489         memset(ctx->X,0,sizeof(ctx->X));        /* zero the initial chaining variables */
490         Skein1024_Update(ctx,key,keyBytes);     /* hash the key */
491         Skein1024_Final_Pad(ctx,cfg.b);         /* put result into cfg.b[] */
492         memcpy(ctx->X,cfg.b,sizeof(cfg.b));     /* copy over into ctx->X[] */
493         for (i=0;i<SKEIN1024_STATE_WORDS;i++)   /* convert key bytes to context words */
494             ctx->X[i] = Skein_Swap64(ctx->X[i]);
495         }
496 
497     /* build/process the config block, type == CONFIG (could be precomputed for each key) */
498     ctx->h.hashBitLen = hashBitLen;             /* output hash bit count */
499     Skein_Start_New_Type(ctx,CFG_FINAL);
500 
501     memset(&cfg.w,0,sizeof(cfg.w));             /* pre-pad cfg.w[] with zeroes */
502     cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);
503     cfg.w[1] = Skein_Swap64(hashBitLen);        /* hash result length in bits */
504     cfg.w[2] = Skein_Swap64(treeInfo);          /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */
505 
506     Skein_Show_Key(1024,&ctx->h,key,keyBytes);
507 
508     /* compute the initial chaining values from config block */
509     Skein1024_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN);
510 
511     /* The chaining vars ctx->X are now initialized */
512     /* Set up to process the data message portion of the hash */
513     Skein_Start_New_Type(ctx,MSG);              /* T0=0, T1= MSG type, h.bCnt=0 */
514 
515     return SKEIN_SUCCESS;
516     }
517 
518 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
519 /* process the input bytes */
Skein1024_Update(Skein1024_Ctxt_t * ctx,const u08b_t * msg,size_t msgByteCnt)520 int Skein1024_Update(Skein1024_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt)
521     {
522     size_t n;
523 
524     Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL);     /* catch uninitialized context */
525 
526     /* process full blocks, if any */
527     if (msgByteCnt + ctx->h.bCnt > SKEIN1024_BLOCK_BYTES)
528         {
529         if (ctx->h.bCnt)                              /* finish up any buffered message data */
530             {
531             n = SKEIN1024_BLOCK_BYTES - ctx->h.bCnt;  /* # bytes free in buffer b[] */
532             if (n)
533                 {
534                 Skein_assert(n < msgByteCnt);         /* check on our logic here */
535                 memcpy(&ctx->b[ctx->h.bCnt],msg,n);
536                 msgByteCnt  -= n;
537                 msg         += n;
538                 ctx->h.bCnt += n;
539                 }
540             Skein_assert(ctx->h.bCnt == SKEIN1024_BLOCK_BYTES);
541             Skein1024_Process_Block(ctx,ctx->b,1,SKEIN1024_BLOCK_BYTES);
542             ctx->h.bCnt = 0;
543             }
544         /* now process any remaining full blocks, directly from input message data */
545         if (msgByteCnt > SKEIN1024_BLOCK_BYTES)
546             {
547             n = (msgByteCnt-1) / SKEIN1024_BLOCK_BYTES;   /* number of full blocks to process */
548             Skein1024_Process_Block(ctx,msg,n,SKEIN1024_BLOCK_BYTES);
549             msgByteCnt -= n * SKEIN1024_BLOCK_BYTES;
550             msg        += n * SKEIN1024_BLOCK_BYTES;
551             }
552         Skein_assert(ctx->h.bCnt == 0);
553         }
554 
555     /* copy any remaining source message data bytes into b[] */
556     if (msgByteCnt)
557         {
558         Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES);
559         memcpy(&ctx->b[ctx->h.bCnt],msg,msgByteCnt);
560         ctx->h.bCnt += msgByteCnt;
561         }
562 
563     return SKEIN_SUCCESS;
564     }
565 
566 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
567 /* finalize the hash computation and output the result */
Skein1024_Final(Skein1024_Ctxt_t * ctx,u08b_t * hashVal)568 int Skein1024_Final(Skein1024_Ctxt_t *ctx, u08b_t *hashVal)
569     {
570     size_t i,n,byteCnt;
571     u64b_t X[SKEIN1024_STATE_WORDS];
572     Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
573 
574     ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL;                 /* tag as the final block */
575     if (ctx->h.bCnt < SKEIN1024_BLOCK_BYTES)   /* zero pad b[] if necessary */
576         memset(&ctx->b[ctx->h.bCnt],0,SKEIN1024_BLOCK_BYTES - ctx->h.bCnt);
577 
578     Skein1024_Process_Block(ctx,ctx->b,1,ctx->h.bCnt);  /* process the final block */
579 
580     /* now output the result */
581     byteCnt = (ctx->h.hashBitLen + 7) >> 3;    /* total number of output bytes */
582 
583     /* run Threefish in "counter mode" to generate output */
584     memset(ctx->b,0,sizeof(ctx->b));  /* zero out b[], so it can hold the counter */
585     memcpy(X,ctx->X,sizeof(X));       /* keep a local copy of counter mode "key" */
586     for (i=0;i*SKEIN1024_BLOCK_BYTES < byteCnt;i++)
587         {
588         ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
589         Skein_Start_New_Type(ctx,OUT_FINAL);
590         Skein1024_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
591         n = byteCnt - i*SKEIN1024_BLOCK_BYTES;   /* number of output bytes left to go */
592         if (n >= SKEIN1024_BLOCK_BYTES)
593             n  = SKEIN1024_BLOCK_BYTES;
594         Skein_Put64_LSB_First(hashVal+i*SKEIN1024_BLOCK_BYTES,ctx->X,n);   /* "output" the ctr mode bytes */
595         Skein_Show_Final(1024,&ctx->h,n,hashVal+i*SKEIN1024_BLOCK_BYTES);
596         memcpy(ctx->X,X,sizeof(X));   /* restore the counter mode key for next time */
597         }
598     return SKEIN_SUCCESS;
599     }
600 
601 #if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF)
Skein1024_API_CodeSize(void)602 size_t Skein1024_API_CodeSize(void)
603     {
604     return ((u08b_t *) Skein1024_API_CodeSize) -
605            ((u08b_t *) Skein1024_Init);
606     }
607 #endif
608 
609 /**************** Functions to support MAC/tree hashing ***************/
610 /*   (this code is identical for Optimized and Reference versions)    */
611 
612 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
613 /* finalize the hash computation and output the block, no OUTPUT stage */
Skein_256_Final_Pad(Skein_256_Ctxt_t * ctx,u08b_t * hashVal)614 int Skein_256_Final_Pad(Skein_256_Ctxt_t *ctx, u08b_t *hashVal)
615     {
616     Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
617 
618     ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL;        /* tag as the final block */
619     if (ctx->h.bCnt < SKEIN_256_BLOCK_BYTES)   /* zero pad b[] if necessary */
620         memset(&ctx->b[ctx->h.bCnt],0,SKEIN_256_BLOCK_BYTES - ctx->h.bCnt);
621     Skein_256_Process_Block(ctx,ctx->b,1,ctx->h.bCnt);    /* process the final block */
622 
623     Skein_Put64_LSB_First(hashVal,ctx->X,SKEIN_256_BLOCK_BYTES);   /* "output" the state bytes */
624 
625     return SKEIN_SUCCESS;
626     }
627 
628 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
629 /* finalize the hash computation and output the block, no OUTPUT stage */
Skein_512_Final_Pad(Skein_512_Ctxt_t * ctx,u08b_t * hashVal)630 int Skein_512_Final_Pad(Skein_512_Ctxt_t *ctx, u08b_t *hashVal)
631     {
632     Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
633 
634     ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL;        /* tag as the final block */
635     if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES)   /* zero pad b[] if necessary */
636         memset(&ctx->b[ctx->h.bCnt],0,SKEIN_512_BLOCK_BYTES - ctx->h.bCnt);
637     Skein_512_Process_Block(ctx,ctx->b,1,ctx->h.bCnt);    /* process the final block */
638 
639     Skein_Put64_LSB_First(hashVal,ctx->X,SKEIN_512_BLOCK_BYTES);   /* "output" the state bytes */
640 
641     return SKEIN_SUCCESS;
642     }
643 
644 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
645 /* finalize the hash computation and output the block, no OUTPUT stage */
Skein1024_Final_Pad(Skein1024_Ctxt_t * ctx,u08b_t * hashVal)646 int Skein1024_Final_Pad(Skein1024_Ctxt_t *ctx, u08b_t *hashVal)
647     {
648     Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
649 
650     ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL;        /* tag as the final block */
651     if (ctx->h.bCnt < SKEIN1024_BLOCK_BYTES)   /* zero pad b[] if necessary */
652         memset(&ctx->b[ctx->h.bCnt],0,SKEIN1024_BLOCK_BYTES - ctx->h.bCnt);
653     Skein1024_Process_Block(ctx,ctx->b,1,ctx->h.bCnt);    /* process the final block */
654 
655     Skein_Put64_LSB_First(hashVal,ctx->X,SKEIN1024_BLOCK_BYTES);   /* "output" the state bytes */
656 
657     return SKEIN_SUCCESS;
658     }
659 
660 #if SKEIN_TREE_HASH
661 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
662 /* just do the OUTPUT stage                                       */
Skein_256_Output(Skein_256_Ctxt_t * ctx,u08b_t * hashVal)663 int Skein_256_Output(Skein_256_Ctxt_t *ctx, u08b_t *hashVal)
664     {
665     size_t i,n,byteCnt;
666     u64b_t X[SKEIN_256_STATE_WORDS];
667     Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
668 
669     /* now output the result */
670     byteCnt = (ctx->h.hashBitLen + 7) >> 3;    /* total number of output bytes */
671 
672     /* run Threefish in "counter mode" to generate output */
673     memset(ctx->b,0,sizeof(ctx->b));  /* zero out b[], so it can hold the counter */
674     memcpy(X,ctx->X,sizeof(X));       /* keep a local copy of counter mode "key" */
675     for (i=0;i*SKEIN_256_BLOCK_BYTES < byteCnt;i++)
676         {
677         ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
678         Skein_Start_New_Type(ctx,OUT_FINAL);
679         Skein_256_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
680         n = byteCnt - i*SKEIN_256_BLOCK_BYTES;   /* number of output bytes left to go */
681         if (n >= SKEIN_256_BLOCK_BYTES)
682             n  = SKEIN_256_BLOCK_BYTES;
683         Skein_Put64_LSB_First(hashVal+i*SKEIN_256_BLOCK_BYTES,ctx->X,n);   /* "output" the ctr mode bytes */
684         Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN_256_BLOCK_BYTES);
685         memcpy(ctx->X,X,sizeof(X));   /* restore the counter mode key for next time */
686         }
687     return SKEIN_SUCCESS;
688     }
689 
690 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
691 /* just do the OUTPUT stage                                       */
Skein_512_Output(Skein_512_Ctxt_t * ctx,u08b_t * hashVal)692 int Skein_512_Output(Skein_512_Ctxt_t *ctx, u08b_t *hashVal)
693     {
694     size_t i,n,byteCnt;
695     u64b_t X[SKEIN_512_STATE_WORDS];
696     Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
697 
698     /* now output the result */
699     byteCnt = (ctx->h.hashBitLen + 7) >> 3;    /* total number of output bytes */
700 
701     /* run Threefish in "counter mode" to generate output */
702     memset(ctx->b,0,sizeof(ctx->b));  /* zero out b[], so it can hold the counter */
703     memcpy(X,ctx->X,sizeof(X));       /* keep a local copy of counter mode "key" */
704     for (i=0;i*SKEIN_512_BLOCK_BYTES < byteCnt;i++)
705         {
706         ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
707         Skein_Start_New_Type(ctx,OUT_FINAL);
708         Skein_512_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
709         n = byteCnt - i*SKEIN_512_BLOCK_BYTES;   /* number of output bytes left to go */
710         if (n >= SKEIN_512_BLOCK_BYTES)
711             n  = SKEIN_512_BLOCK_BYTES;
712         Skein_Put64_LSB_First(hashVal+i*SKEIN_512_BLOCK_BYTES,ctx->X,n);   /* "output" the ctr mode bytes */
713         Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN_512_BLOCK_BYTES);
714         memcpy(ctx->X,X,sizeof(X));   /* restore the counter mode key for next time */
715         }
716     return SKEIN_SUCCESS;
717     }
718 
719 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
720 /* just do the OUTPUT stage                                       */
Skein1024_Output(Skein1024_Ctxt_t * ctx,u08b_t * hashVal)721 int Skein1024_Output(Skein1024_Ctxt_t *ctx, u08b_t *hashVal)
722     {
723     size_t i,n,byteCnt;
724     u64b_t X[SKEIN1024_STATE_WORDS];
725     Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL);    /* catch uninitialized context */
726 
727     /* now output the result */
728     byteCnt = (ctx->h.hashBitLen + 7) >> 3;    /* total number of output bytes */
729 
730     /* run Threefish in "counter mode" to generate output */
731     memset(ctx->b,0,sizeof(ctx->b));  /* zero out b[], so it can hold the counter */
732     memcpy(X,ctx->X,sizeof(X));       /* keep a local copy of counter mode "key" */
733     for (i=0;i*SKEIN1024_BLOCK_BYTES < byteCnt;i++)
734         {
735         ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */
736         Skein_Start_New_Type(ctx,OUT_FINAL);
737         Skein1024_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */
738         n = byteCnt - i*SKEIN1024_BLOCK_BYTES;   /* number of output bytes left to go */
739         if (n >= SKEIN1024_BLOCK_BYTES)
740             n  = SKEIN1024_BLOCK_BYTES;
741         Skein_Put64_LSB_First(hashVal+i*SKEIN1024_BLOCK_BYTES,ctx->X,n);   /* "output" the ctr mode bytes */
742         Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN1024_BLOCK_BYTES);
743         memcpy(ctx->X,X,sizeof(X));   /* restore the counter mode key for next time */
744         }
745     return SKEIN_SUCCESS;
746     }
747 #endif
748