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