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