/* [identical to Skein_512_Init() when keyBytes == 0 && treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */ int Skein_512_InitExt(Skein_512_Ctxt_t *ctx,size_t hashBitLen,u64b_t treeInfo, const u08b_t *key, size_t keyBytes) { union { u08b_t b[SKEIN_512_STATE_BYTES]; u64b_t w[SKEIN_512_STATE_WORDS]; } cfg; /* config block */ Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN); Skein_Assert(keyBytes == 0 || key != NULL,SKEIN_FAIL); /* compute the initial chaining values ctx->X[], based on key */ if (keyBytes == 0) /* is there a key? */ { memset(ctx->X,0,sizeof(ctx->X)); /* no key: use all zeroes as key for config block */ } else /* here to pre-process a key */ { Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X)); /* do a mini-Init right here */ ctx->h.hashBitLen=8*sizeof(ctx->X); /* set output hash bit count = state size */ Skein_Start_New_Type(ctx,KEY); /* set tweaks: T0 = 0; T1 = KEY type */ memset(ctx->X,0,sizeof(ctx->X)); /* zero the initial chaining variables */ Skein_512_Update(ctx,key,keyBytes); /* hash the key */ Skein_512_Final_Pad(ctx,cfg.b); /* put result into cfg.b[] */ memcpy(ctx->X,cfg.b,sizeof(cfg.b)); /* copy over into ctx->X[] */ #if SKEIN_NEED_SWAP { uint_t i; for (i=0; i<SKEIN_512_STATE_WORDS; i++) /* convert key bytes to context words */ ctx->X[i] = Skein_Swap64(ctx->X[i]); } #endif } /* build/process the config block, type == CONFIG (could be precomputed for each key) */ ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ Skein_Start_New_Type(ctx,CFG_FINAL); memset(&cfg.w,0,sizeof(cfg.w)); /* pre-pad cfg.w[] with zeroes */ cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */ cfg.w[2] = Skein_Swap64(treeInfo); /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */ Skein_Show_Key(512,&ctx->h,key,keyBytes); /* compute the initial chaining values from config block */ Skein_512_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN); /* The chaining vars ctx->X are now initialized */ /* Set up to process the data message portion of the hash (default) */ ctx->h.bCnt = 0; /* buffer b[] starts out empty */ Skein_Start_New_Type(ctx,MSG); return SKEIN_SUCCESS; }
/* finalize the hash computation and output the result */ int Skein_512_Final(Skein_512_Ctxt_t *ctx, u08b_t *hashVal) { size_t i,n,byteCnt; u64b_t X[SKEIN_512_STATE_WORDS]; Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */ if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES) /* zero pad b[] if necessary */ memset(&ctx->b[ctx->h.bCnt],0,SKEIN_512_BLOCK_BYTES - ctx->h.bCnt); Skein_512_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */ /* now output the result */ byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */ /* run Threefish in "counter mode" to generate output */ memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */ memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */ for (i=0; i*SKEIN_512_BLOCK_BYTES < byteCnt; i++) { ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */ Skein_Start_New_Type(ctx,OUT_FINAL); Skein_512_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */ n = byteCnt - i*SKEIN_512_BLOCK_BYTES; /* number of output bytes left to go */ if (n >= SKEIN_512_BLOCK_BYTES) n = SKEIN_512_BLOCK_BYTES; Skein_Put64_LSB_First(hashVal+i*SKEIN_512_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */ Skein_Show_Final(512,&ctx->h,n,hashVal+i*SKEIN_512_BLOCK_BYTES); memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */ } return SKEIN_SUCCESS; }
/* init the context for a straight hashing operation */ int Skein_512_Init(Skein_512_Ctxt_t *ctx, size_t hashBitLen) { union { uint8_t b[SKEIN_512_STATE_BYTES]; uint64_t w[SKEIN_512_STATE_WORDS]; } cfg; /* config block */ Skein_Assert(hashBitLen > 0, SKEIN_BAD_HASHLEN); ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ switch (hashBitLen) { /* use pre-computed values, where available */ #ifndef SKEIN_NO_PRECOMP case 512: bcopy(SKEIN_512_IV_512, ctx->X, sizeof (ctx->X)); break; case 384: bcopy(SKEIN_512_IV_384, ctx->X, sizeof (ctx->X)); break; case 256: bcopy(SKEIN_512_IV_256, ctx->X, sizeof (ctx->X)); break; case 224: bcopy(SKEIN_512_IV_224, ctx->X, sizeof (ctx->X)); break; #endif default: /* * here if there is no precomputed IV value available * build/process the config block, type == CONFIG (could be * precomputed) */ /* set tweaks: T0=0; T1=CFG | FINAL */ Skein_Start_New_Type(ctx, CFG_FINAL); /* set the schema, version */ cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); /* hash result length in bits */ cfg.w[1] = Skein_Swap64(hashBitLen); cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL); /* zero pad config block */ bzero(&cfg.w[3], sizeof (cfg) - 3 * sizeof (cfg.w[0])); /* compute the initial chaining values from config block */ /* zero the chaining variables */ bzero(ctx->X, sizeof (ctx->X)); Skein_512_Process_Block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN); break; } /* * The chaining vars ctx->X are now initialized for the given * hashBitLen. Set up to process the data message portion of the * hash (default) */ Skein_Start_New_Type(ctx, MSG); /* T0=0, T1= MSG type */ return (SKEIN_SUCCESS); }
/* process data to be hashed */ int Skein::Update(const BitSequence *data, DataLength databitlen) { /* only the final Update() call is allowed do partial bytes, else assert an error */ Skein_Assert((skeinState.u.h.T[1] & SKEIN_T1_FLAG_BIT_PAD) == 0 || databitlen == 0, FAIL); Skein_Assert(skeinState.statebits % 256 == 0 && (skeinState.statebits-256) < 1024,FAIL); if ((databitlen & 7) == 0) /* partial bytes? */ { switch ((skeinState.statebits >> 8) & 3) { case 2: return Skein_512_Update(&skeinState.u.ctx_512,data,databitlen >> 3); case 1: return Skein_256_Update(&skeinState.u.ctx_256,data,databitlen >> 3); case 0: return Skein1024_Update(&skeinState.u.ctx1024,data,databitlen >> 3); default: return FAIL; } } else { /* handle partial final byte */
int skeinCtxPrepare(SkeinCtx_t* ctx, SkeinSize_t size) { Skein_Assert(ctx && size, SKEIN_FAIL); memset(ctx ,0, sizeof(SkeinCtx_t)); ctx->skeinSize = size; return SKEIN_SUCCESS; }
int skeinMacInit(SkeinCtx_t* ctx, const uint8_t *key, size_t keyLen, size_t hashBitLen) { int ret = SKEIN_FAIL; u64b_t* X = NULL; size_t Xlen = 0; uint64_t treeInfo = SKEIN_CFG_TREE_INFO_SEQUENTIAL; Skein_Assert(ctx, SKEIN_FAIL); X = ctx->m.s256.X; Xlen = (size_t)(ctx->skeinSize/8); Skein_Assert(hashBitLen, SKEIN_BAD_HASHLEN); switch (ctx->skeinSize) { case Skein256: ret = Skein_256_InitExt(&ctx->m.s256, hashBitLen, treeInfo, (const u08b_t*)key, keyLen); break; case Skein512: ret = Skein_512_InitExt(&ctx->m.s512, hashBitLen, treeInfo, (const u08b_t*)key, keyLen); break; case Skein1024: ret = Skein1024_InitExt(&ctx->m.s1024, hashBitLen, treeInfo, (const u08b_t*)key, keyLen); break; } if (ret == SKEIN_SUCCESS) { /* Save chaining variables for this combination of key, keyLen, hashBitLen */ memcpy(ctx->XSave, X, Xlen); } return ret; }
int Skein_512_Final_Pad(Skein_512_Ctxt_t *ctx, u08b_t *hashVal) { Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */ if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES) /* zero pad b[] if necessary */ memset(&ctx->b[ctx->h.bCnt],0,SKEIN_512_BLOCK_BYTES - ctx->h.bCnt); Skein_512_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */ Skein_Put64_LSB_First(hashVal,ctx->X,SKEIN_512_BLOCK_BYTES); /* "output" the state bytes */ return SKEIN_SUCCESS; }
/* process the input bytes */ int Skein1024_Update(Skein1024_Ctxt_t *ctx, const uint8_t *msg, size_t msgByteCnt) { size_t n; /* catch uninitialized context */ Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES, SKEIN_FAIL); /* process full blocks, if any */ if (msgByteCnt + ctx->h.bCnt > SKEIN1024_BLOCK_BYTES) { /* finish up any buffered message data */ if (ctx->h.bCnt) { /* # bytes free in buffer b[] */ n = SKEIN1024_BLOCK_BYTES - ctx->h.bCnt; if (n) { /* check on our logic here */ Skein_assert(n < msgByteCnt); bcopy(msg, &ctx->b[ctx->h.bCnt], n); msgByteCnt -= n; msg += n; ctx->h.bCnt += n; } Skein_assert(ctx->h.bCnt == SKEIN1024_BLOCK_BYTES); Skein1024_Process_Block(ctx, ctx->b, 1, SKEIN1024_BLOCK_BYTES); ctx->h.bCnt = 0; } /* * now process any remaining full blocks, directly from * input message data */ if (msgByteCnt > SKEIN1024_BLOCK_BYTES) { /* number of full blocks to process */ n = (msgByteCnt - 1) / SKEIN1024_BLOCK_BYTES; Skein1024_Process_Block(ctx, msg, n, SKEIN1024_BLOCK_BYTES); msgByteCnt -= n * SKEIN1024_BLOCK_BYTES; msg += n * SKEIN1024_BLOCK_BYTES; } Skein_assert(ctx->h.bCnt == 0); } /* copy any remaining source message data bytes into b[] */ if (msgByteCnt) { Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES); bcopy(msg, &ctx->b[ctx->h.bCnt], msgByteCnt); ctx->h.bCnt += msgByteCnt; } return (SKEIN_SUCCESS); }
/* init the context for a straight hashing operation */ int Skein_256_Init(Skein_256_Ctxt_t *ctx, size_t hashBitLen) { union { u08b_t b[SKEIN_256_STATE_BYTES]; u64b_t w[SKEIN_256_STATE_WORDS]; } cfg; /* config block */ Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN); ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ switch (hashBitLen) { /* use pre-computed values, where available */ case 256: memcpy(ctx->X,SKEIN_256_IV_256,sizeof(ctx->X)); break; case 224: memcpy(ctx->X,SKEIN_256_IV_224,sizeof(ctx->X)); break; case 160: memcpy(ctx->X,SKEIN_256_IV_160,sizeof(ctx->X)); break; case 128: memcpy(ctx->X,SKEIN_256_IV_128,sizeof(ctx->X)); break; default: /* here if there is no precomputed IV value available */ /* build/process the config block, type == CONFIG (could be precomputed) */ Skein_Start_New_Type(ctx,CFG_FINAL); /* set tweaks: T0=0; T1=CFG | FINAL */ cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); /* set the schema, version */ cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */ cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL); memset(&cfg.w[3],0,sizeof(cfg) - 3*sizeof(cfg.w[0])); /* zero pad config block */ /* compute the initial chaining values from config block */ memset(ctx->X,0,sizeof(ctx->X)); /* zero the chaining variables */ Skein_256_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN); break; } /* The chaining vars ctx->X are now initialized for the given hashBitLen. */ /* Set up to process the data message portion of the hash (default) */ Skein_Start_New_Type(ctx,MSG); /* T0=0, T1= MSG type */ return SKEIN_SUCCESS; }
int skeinFinal(SkeinCtx_t* ctx, uint8_t* hash) { int ret = SKEIN_FAIL; Skein_Assert(ctx, SKEIN_FAIL); switch (ctx->skeinSize) { case Skein256: ret = Skein_256_Final(&ctx->m.s256, (u08b_t*)hash); break; case Skein512: ret = Skein_512_Final(&ctx->m.s512, (u08b_t*)hash); break; case Skein1024: ret = Skein1024_Final(&ctx->m.s1024, (u08b_t*)hash); break; } return ret; }
/* finalize the hash computation and output the block, no OUTPUT stage */ int Skein_256_Final_Pad(Skein_256_Ctxt_t *ctx, uint8_t *hashVal) { /* catch uninitialized context */ Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES, SKEIN_FAIL); ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */ /* zero pad b[] if necessary */ if (ctx->h.bCnt < SKEIN_256_BLOCK_BYTES) bzero(&ctx->b[ctx->h.bCnt], SKEIN_256_BLOCK_BYTES - ctx->h.bCnt); /* process the final block */ Skein_256_Process_Block(ctx, ctx->b, 1, ctx->h.bCnt); /* "output" the state bytes */ Skein_Put64_LSB_First(hashVal, ctx->X, SKEIN_256_BLOCK_BYTES); return (SKEIN_SUCCESS); }
int skeinUpdate(SkeinCtx_t *ctx, const uint8_t *msg, size_t msgByteCnt) { int ret = SKEIN_FAIL; Skein_Assert(ctx, SKEIN_FAIL); switch (ctx->skeinSize) { case Skein256: ret = Skein_256_Update(&ctx->m.s256, (const u08b_t*)msg, msgByteCnt); break; case Skein512: ret = Skein_512_Update(&ctx->m.s512, (const u08b_t*)msg, msgByteCnt); break; case Skein1024: ret = Skein1024_Update(&ctx->m.s1024, (const u08b_t*)msg, msgByteCnt); break; } return ret; }
/* select the context size and init the context */ int Skein::Init(int hashbitlen) { #if SKEIN_256_NIST_MAX_HASH_BITS if (hashbitlen <= SKEIN_256_NIST_MAX_HASHBITS) { Skein_Assert(hashbitlen > 0,BAD_HASHLEN); skeinState.statebits = 64*SKEIN_256_STATE_WORDS; return Skein_256_Init(&skeinState.u.ctx_256,(size_t) hashbitlen); } #endif if (hashbitlen <= SKEIN_512_NIST_MAX_HASHBITS) { skeinState.statebits = 64*SKEIN_512_STATE_WORDS; return Skein_512_Init(&skeinState.u.ctx_512,(size_t) hashbitlen); } else { skeinState.statebits = 64*SKEIN1024_STATE_WORDS; return Skein1024_Init(&skeinState.u.ctx1024,(size_t) hashbitlen); } }
int skeinInit(SkeinCtx_t* ctx, size_t hashBitLen) { int ret = SKEIN_FAIL; size_t Xlen = 0; u64b_t* X = NULL; uint64_t treeInfo = SKEIN_CFG_TREE_INFO_SEQUENTIAL; Skein_Assert(ctx, SKEIN_FAIL); /* * The following two lines rely of the fact that the real Skein contexts are * a union in out context and thus have tha maximum memory available. * The beauty of C :-) . */ X = ctx->m.s256.X; Xlen = (size_t)(ctx->skeinSize/8); /* * If size is the same and hash bit length is zero then reuse * the save chaining variables. */ switch (ctx->skeinSize) { case Skein256: ret = Skein_256_InitExt(&ctx->m.s256, hashBitLen, treeInfo, NULL, 0); break; case Skein512: ret = Skein_512_InitExt(&ctx->m.s512, hashBitLen, treeInfo, NULL, 0); break; case Skein1024: ret = Skein1024_InitExt(&ctx->m.s1024, hashBitLen, treeInfo, NULL, 0); break; } if (ret == SKEIN_SUCCESS) { /* Save chaining variables for this combination of size and hashBitLen */ memcpy(ctx->XSave, X, Xlen); } return ret; }
int skeinUpdateBits(SkeinCtx_t *ctx, const uint8_t *msg, size_t msgBitCnt) { /* * I've used the bit pad implementation from skein_test.c (see NIST CD) * and modified it to use the convenience functions and added some pointer * arithmetic. */ size_t length; uint8_t mask; uint8_t* up; /* only the final Update() call is allowed do partial bytes, else assert an error */ Skein_Assert((ctx->m.h.T[1] & SKEIN_T1_FLAG_BIT_PAD) == 0 || msgBitCnt == 0, SKEIN_FAIL); /* if number of bits is a multiple of bytes - that's easy */ if ((msgBitCnt & 0x7) == 0) { return skeinUpdate(ctx, msg, msgBitCnt >> 3); } skeinUpdate(ctx, msg, (msgBitCnt >> 3) + 1); /* * The next line rely on the fact that the real Skein contexts * are a union in our context. After the addition the pointer points to * Skein's real partial block buffer. * If this layout ever changes we have to adapt this as well. */ up = (uint8_t*)ctx->m.s256.X + ctx->skeinSize / 8; Skein_Set_Bit_Pad_Flag(ctx->m.h); /* set tweak flag for the skeinFinal call */ /* now "pad" the final partial byte the way NIST likes */ length = ctx->m.h.bCnt; /* get the bCnt value (same location for all block sizes) */ Skein_assert(length != 0); /* internal sanity check: there IS a partial byte in the buffer! */ mask = (uint8_t) (1u << (7 - (msgBitCnt & 7))); /* partial byte bit mask */ up[length-1] = (uint8_t)((up[length-1] & (0-mask))|mask); /* apply bit padding on final byte (in the buffer) */ return SKEIN_SUCCESS; }
/* just do the OUTPUT stage */ int Skein1024_Output(Skein1024_Ctxt_t *ctx, uint8_t *hashVal) { size_t i, n, byteCnt; uint64_t X[SKEIN1024_STATE_WORDS]; /* catch uninitialized context */ Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES, SKEIN_FAIL); /* now output the result */ /* total number of output bytes */ byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* run Threefish in "counter mode" to generate output */ /* zero out b[], so it can hold the counter */ bzero(ctx->b, sizeof (ctx->b)); /* keep a local copy of counter mode "key" */ bcopy(ctx->X, X, sizeof (X)); for (i = 0; i * SKEIN1024_BLOCK_BYTES < byteCnt; i++) { /* build the counter block */ uint64_t tmp = Skein_Swap64((uint64_t)i); bcopy(&tmp, ctx->b, sizeof (tmp)); Skein_Start_New_Type(ctx, OUT_FINAL); /* run "counter mode" */ Skein1024_Process_Block(ctx, ctx->b, 1, sizeof (uint64_t)); /* number of output bytes left to go */ n = byteCnt - i * SKEIN1024_BLOCK_BYTES; if (n >= SKEIN1024_BLOCK_BYTES) n = SKEIN1024_BLOCK_BYTES; Skein_Put64_LSB_First(hashVal + i * SKEIN1024_BLOCK_BYTES, ctx->X, n); /* "output" the ctr mode bytes */ Skein_Show_Final(256, &ctx->h, n, hashVal + i * SKEIN1024_BLOCK_BYTES); /* restore the counter mode key for next time */ bcopy(X, ctx->X, sizeof (X)); } return (SKEIN_SUCCESS); }