Path: blob/main/sys/contrib/openzfs/module/icp/algs/skein/skein.c
48775 views
// SPDX-License-Identifier: LicenseRef-OpenZFS-ThirdParty-PublicDomain1/*2* Implementation of the Skein hash function.3* Source code author: Doug Whiting, 2008.4* This algorithm and source code is released to the public domain.5*/6/* Copyright 2013 Doug Whiting. This code is released to the public domain. */78#include <sys/sysmacros.h>9#include <sys/types.h>10#include <sys/skein.h> /* get the Skein API definitions */11#include "skein_impl.h" /* get internal definitions */1213/* 256-bit Skein */14/* init the context for a straight hashing operation */15int16Skein_256_Init(Skein_256_Ctxt_t *ctx, size_t hashBitLen)17{18union {19uint8_t b[SKEIN_256_STATE_BYTES];20uint64_t w[SKEIN_256_STATE_WORDS];21} cfg; /* config block */2223Skein_Assert(hashBitLen > 0, SKEIN_BAD_HASHLEN);24ctx->h.hashBitLen = hashBitLen; /* output hash bit count */2526switch (hashBitLen) { /* use pre-computed values, where available */27#ifndef SKEIN_NO_PRECOMP28case 256:29memcpy(ctx->X, SKEIN_256_IV_256, sizeof (ctx->X));30break;31case 224:32memcpy(ctx->X, SKEIN_256_IV_224, sizeof (ctx->X));33break;34case 160:35memcpy(ctx->X, SKEIN_256_IV_160, sizeof (ctx->X));36break;37case 128:38memcpy(ctx->X, SKEIN_256_IV_128, sizeof (ctx->X));39break;40#endif41default:42/* here if there is no precomputed IV value available */43/*44* build/process the config block, type == CONFIG (could be45* precomputed)46*/47/* set tweaks: T0=0; T1=CFG | FINAL */48Skein_Start_New_Type(ctx, CFG_FINAL);4950/* set the schema, version */51cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);52/* hash result length in bits */53cfg.w[1] = Skein_Swap64(hashBitLen);54cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL);55/* zero pad config block */56memset(&cfg.w[3], 0, sizeof (cfg) - 3 * sizeof (cfg.w[0]));5758/* compute the initial chaining values from config block */59/* zero the chaining variables */60memset(ctx->X, 0, sizeof (ctx->X));61Skein_256_Process_Block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN);62break;63}64/*65* The chaining vars ctx->X are now initialized for the given66* hashBitLen.67* Set up to process the data message portion of the hash (default)68*/69Skein_Start_New_Type(ctx, MSG); /* T0=0, T1= MSG type */7071return (SKEIN_SUCCESS);72}7374/* init the context for a MAC and/or tree hash operation */75/*76* [identical to Skein_256_Init() when keyBytes == 0 &&77* treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL]78*/79int80Skein_256_InitExt(Skein_256_Ctxt_t *ctx, size_t hashBitLen, uint64_t treeInfo,81const uint8_t *key, size_t keyBytes)82{83union {84uint8_t b[SKEIN_256_STATE_BYTES];85uint64_t w[SKEIN_256_STATE_WORDS];86} cfg; /* config block */8788Skein_Assert(hashBitLen > 0, SKEIN_BAD_HASHLEN);89Skein_Assert(keyBytes == 0 || key != NULL, SKEIN_FAIL);9091/* compute the initial chaining values ctx->X[], based on key */92if (keyBytes == 0) { /* is there a key? */93/* no key: use all zeroes as key for config block */94memset(ctx->X, 0, sizeof (ctx->X));95} else { /* here to pre-process a key */9697Skein_assert(sizeof (cfg.b) >= sizeof (ctx->X));98/* do a mini-Init right here */99/* set output hash bit count = state size */100ctx->h.hashBitLen = 8 * sizeof (ctx->X);101/* set tweaks: T0 = 0; T1 = KEY type */102Skein_Start_New_Type(ctx, KEY);103/* zero the initial chaining variables */104memset(ctx->X, 0, sizeof (ctx->X));105/* hash the key */106(void) Skein_256_Update(ctx, key, keyBytes);107/* put result into cfg.b[] */108(void) Skein_256_Final_Pad(ctx, cfg.b);109/* copy over into ctx->X[] */110memcpy(ctx->X, cfg.b, sizeof (cfg.b));111#if SKEIN_NEED_SWAP112{113uint_t i;114/* convert key bytes to context words */115for (i = 0; i < SKEIN_256_STATE_WORDS; i++)116ctx->X[i] = Skein_Swap64(ctx->X[i]);117}118#endif119}120/*121* build/process the config block, type == CONFIG (could be122* precomputed for each key)123*/124ctx->h.hashBitLen = hashBitLen; /* output hash bit count */125Skein_Start_New_Type(ctx, CFG_FINAL);126127memset(&cfg.w, 0, sizeof (cfg.w)); /* pre-pad cfg.w[] with zeroes */128cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);129cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */130/* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */131cfg.w[2] = Skein_Swap64(treeInfo);132133Skein_Show_Key(256, &ctx->h, key, keyBytes);134135/* compute the initial chaining values from config block */136Skein_256_Process_Block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN);137138/* The chaining vars ctx->X are now initialized */139/* Set up to process the data message portion of the hash (default) */140ctx->h.bCnt = 0; /* buffer b[] starts out empty */141Skein_Start_New_Type(ctx, MSG);142143return (SKEIN_SUCCESS);144}145146/* process the input bytes */147int148Skein_256_Update(Skein_256_Ctxt_t *ctx, const uint8_t *msg, size_t msgByteCnt)149{150size_t n;151152/* catch uninitialized context */153Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES, SKEIN_FAIL);154155/* process full blocks, if any */156if (msgByteCnt + ctx->h.bCnt > SKEIN_256_BLOCK_BYTES) {157/* finish up any buffered message data */158if (ctx->h.bCnt) {159/* # bytes free in buffer b[] */160n = SKEIN_256_BLOCK_BYTES - ctx->h.bCnt;161if (n) {162/* check on our logic here */163Skein_assert(n < msgByteCnt);164memcpy(&ctx->b[ctx->h.bCnt], msg, n);165msgByteCnt -= n;166msg += n;167ctx->h.bCnt += n;168}169Skein_assert(ctx->h.bCnt == SKEIN_256_BLOCK_BYTES);170Skein_256_Process_Block(ctx, ctx->b, 1,171SKEIN_256_BLOCK_BYTES);172ctx->h.bCnt = 0;173}174/*175* now process any remaining full blocks, directly from input176* message data177*/178if (msgByteCnt > SKEIN_256_BLOCK_BYTES) {179/* number of full blocks to process */180n = (msgByteCnt - 1) / SKEIN_256_BLOCK_BYTES;181Skein_256_Process_Block(ctx, msg, n,182SKEIN_256_BLOCK_BYTES);183msgByteCnt -= n * SKEIN_256_BLOCK_BYTES;184msg += n * SKEIN_256_BLOCK_BYTES;185}186Skein_assert(ctx->h.bCnt == 0);187}188189/* copy any remaining source message data bytes into b[] */190if (msgByteCnt) {191Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES);192memcpy(&ctx->b[ctx->h.bCnt], msg, msgByteCnt);193ctx->h.bCnt += msgByteCnt;194}195196return (SKEIN_SUCCESS);197}198199/* finalize the hash computation and output the result */200int201Skein_256_Final(Skein_256_Ctxt_t *ctx, uint8_t *hashVal)202{203size_t i, n, byteCnt;204uint64_t X[SKEIN_256_STATE_WORDS];205206/* catch uninitialized context */207Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES, SKEIN_FAIL);208209ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */210/* zero pad b[] if necessary */211if (ctx->h.bCnt < SKEIN_256_BLOCK_BYTES)212memset(&ctx->b[ctx->h.bCnt], 0,213SKEIN_256_BLOCK_BYTES - ctx->h.bCnt);214215/* process the final block */216Skein_256_Process_Block(ctx, ctx->b, 1, ctx->h.bCnt);217218/* now output the result */219/* total number of output bytes */220byteCnt = (ctx->h.hashBitLen + 7) >> 3;221222/* run Threefish in "counter mode" to generate output */223/* zero out b[], so it can hold the counter */224memset(ctx->b, 0, sizeof (ctx->b));225/* keep a local copy of counter mode "key" */226memcpy(X, ctx->X, sizeof (X));227for (i = 0; i * SKEIN_256_BLOCK_BYTES < byteCnt; i++) {228/* build the counter block */229*(uint64_t *)ctx->b = Skein_Swap64((uint64_t)i);230Skein_Start_New_Type(ctx, OUT_FINAL);231/* run "counter mode" */232Skein_256_Process_Block(ctx, ctx->b, 1, sizeof (uint64_t));233/* number of output bytes left to go */234n = byteCnt - i * SKEIN_256_BLOCK_BYTES;235if (n >= SKEIN_256_BLOCK_BYTES)236n = SKEIN_256_BLOCK_BYTES;237Skein_Put64_LSB_First(hashVal + i * SKEIN_256_BLOCK_BYTES,238ctx->X, n); /* "output" the ctr mode bytes */239Skein_Show_Final(256, &ctx->h, n,240hashVal + i * SKEIN_256_BLOCK_BYTES);241/* restore the counter mode key for next time */242memcpy(ctx->X, X, sizeof (X));243}244return (SKEIN_SUCCESS);245}246247/* 512-bit Skein */248249/* init the context for a straight hashing operation */250int251Skein_512_Init(Skein_512_Ctxt_t *ctx, size_t hashBitLen)252{253union {254uint8_t b[SKEIN_512_STATE_BYTES];255uint64_t w[SKEIN_512_STATE_WORDS];256} cfg; /* config block */257258Skein_Assert(hashBitLen > 0, SKEIN_BAD_HASHLEN);259ctx->h.hashBitLen = hashBitLen; /* output hash bit count */260261switch (hashBitLen) { /* use pre-computed values, where available */262#ifndef SKEIN_NO_PRECOMP263case 512:264memcpy(ctx->X, SKEIN_512_IV_512, sizeof (ctx->X));265break;266case 384:267memcpy(ctx->X, SKEIN_512_IV_384, sizeof (ctx->X));268break;269case 256:270memcpy(ctx->X, SKEIN_512_IV_256, sizeof (ctx->X));271break;272case 224:273memcpy(ctx->X, SKEIN_512_IV_224, sizeof (ctx->X));274break;275#endif276default:277/*278* here if there is no precomputed IV value available279* build/process the config block, type == CONFIG (could be280* precomputed)281*/282/* set tweaks: T0=0; T1=CFG | FINAL */283Skein_Start_New_Type(ctx, CFG_FINAL);284285/* set the schema, version */286cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);287/* hash result length in bits */288cfg.w[1] = Skein_Swap64(hashBitLen);289cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL);290/* zero pad config block */291memset(&cfg.w[3], 0, sizeof (cfg) - 3 * sizeof (cfg.w[0]));292293/* compute the initial chaining values from config block */294/* zero the chaining variables */295memset(ctx->X, 0, sizeof (ctx->X));296Skein_512_Process_Block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN);297break;298}299300/*301* The chaining vars ctx->X are now initialized for the given302* hashBitLen. Set up to process the data message portion of the303* hash (default)304*/305Skein_Start_New_Type(ctx, MSG); /* T0=0, T1= MSG type */306307return (SKEIN_SUCCESS);308}309310/* init the context for a MAC and/or tree hash operation */311/*312* [identical to Skein_512_Init() when keyBytes == 0 &&313* treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL]314*/315int316Skein_512_InitExt(Skein_512_Ctxt_t *ctx, size_t hashBitLen, uint64_t treeInfo,317const uint8_t *key, size_t keyBytes)318{319union {320uint8_t b[SKEIN_512_STATE_BYTES];321uint64_t w[SKEIN_512_STATE_WORDS];322} cfg; /* config block */323324Skein_Assert(hashBitLen > 0, SKEIN_BAD_HASHLEN);325Skein_Assert(keyBytes == 0 || key != NULL, SKEIN_FAIL);326327/* compute the initial chaining values ctx->X[], based on key */328if (keyBytes == 0) { /* is there a key? */329/* no key: use all zeroes as key for config block */330memset(ctx->X, 0, sizeof (ctx->X));331} else { /* here to pre-process a key */332333Skein_assert(sizeof (cfg.b) >= sizeof (ctx->X));334/* do a mini-Init right here */335/* set output hash bit count = state size */336ctx->h.hashBitLen = 8 * sizeof (ctx->X);337/* set tweaks: T0 = 0; T1 = KEY type */338Skein_Start_New_Type(ctx, KEY);339/* zero the initial chaining variables */340memset(ctx->X, 0, sizeof (ctx->X));341(void) Skein_512_Update(ctx, key, keyBytes); /* hash the key */342/* put result into cfg.b[] */343(void) Skein_512_Final_Pad(ctx, cfg.b);344/* copy over into ctx->X[] */345memcpy(ctx->X, cfg.b, sizeof (cfg.b));346#if SKEIN_NEED_SWAP347{348uint_t i;349/* convert key bytes to context words */350for (i = 0; i < SKEIN_512_STATE_WORDS; i++)351ctx->X[i] = Skein_Swap64(ctx->X[i]);352}353#endif354}355/*356* build/process the config block, type == CONFIG (could be357* precomputed for each key)358*/359ctx->h.hashBitLen = hashBitLen; /* output hash bit count */360Skein_Start_New_Type(ctx, CFG_FINAL);361362memset(&cfg.w, 0, sizeof (cfg.w)); /* pre-pad cfg.w[] with zeroes */363cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);364cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */365/* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */366cfg.w[2] = Skein_Swap64(treeInfo);367368Skein_Show_Key(512, &ctx->h, key, keyBytes);369370/* compute the initial chaining values from config block */371Skein_512_Process_Block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN);372373/* The chaining vars ctx->X are now initialized */374/* Set up to process the data message portion of the hash (default) */375ctx->h.bCnt = 0; /* buffer b[] starts out empty */376Skein_Start_New_Type(ctx, MSG);377378return (SKEIN_SUCCESS);379}380381/* process the input bytes */382int383Skein_512_Update(Skein_512_Ctxt_t *ctx, const uint8_t *msg, size_t msgByteCnt)384{385size_t n;386387/* catch uninitialized context */388Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES, SKEIN_FAIL);389390/* process full blocks, if any */391if (msgByteCnt + ctx->h.bCnt > SKEIN_512_BLOCK_BYTES) {392/* finish up any buffered message data */393if (ctx->h.bCnt) {394/* # bytes free in buffer b[] */395n = SKEIN_512_BLOCK_BYTES - ctx->h.bCnt;396if (n) {397/* check on our logic here */398Skein_assert(n < msgByteCnt);399memcpy(&ctx->b[ctx->h.bCnt], msg, n);400msgByteCnt -= n;401msg += n;402ctx->h.bCnt += n;403}404Skein_assert(ctx->h.bCnt == SKEIN_512_BLOCK_BYTES);405Skein_512_Process_Block(ctx, ctx->b, 1,406SKEIN_512_BLOCK_BYTES);407ctx->h.bCnt = 0;408}409/*410* now process any remaining full blocks, directly from input411* message data412*/413if (msgByteCnt > SKEIN_512_BLOCK_BYTES) {414/* number of full blocks to process */415n = (msgByteCnt - 1) / SKEIN_512_BLOCK_BYTES;416Skein_512_Process_Block(ctx, msg, n,417SKEIN_512_BLOCK_BYTES);418msgByteCnt -= n * SKEIN_512_BLOCK_BYTES;419msg += n * SKEIN_512_BLOCK_BYTES;420}421Skein_assert(ctx->h.bCnt == 0);422}423424/* copy any remaining source message data bytes into b[] */425if (msgByteCnt) {426Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES);427memcpy(&ctx->b[ctx->h.bCnt], msg, msgByteCnt);428ctx->h.bCnt += msgByteCnt;429}430431return (SKEIN_SUCCESS);432}433434/* finalize the hash computation and output the result */435int436Skein_512_Final(Skein_512_Ctxt_t *ctx, uint8_t *hashVal)437{438size_t i, n, byteCnt;439uint64_t X[SKEIN_512_STATE_WORDS];440441/* catch uninitialized context */442Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES, SKEIN_FAIL);443444ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */445/* zero pad b[] if necessary */446if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES)447memset(&ctx->b[ctx->h.bCnt], 0,448SKEIN_512_BLOCK_BYTES - ctx->h.bCnt);449450/* process the final block */451Skein_512_Process_Block(ctx, ctx->b, 1, ctx->h.bCnt);452453/* now output the result */454/* total number of output bytes */455byteCnt = (ctx->h.hashBitLen + 7) >> 3;456457/* run Threefish in "counter mode" to generate output */458/* zero out b[], so it can hold the counter */459memset(ctx->b, 0, sizeof (ctx->b));460/* keep a local copy of counter mode "key" */461memcpy(X, ctx->X, sizeof (X));462for (i = 0; i * SKEIN_512_BLOCK_BYTES < byteCnt; i++) {463/* build the counter block */464*(uint64_t *)ctx->b = Skein_Swap64((uint64_t)i);465Skein_Start_New_Type(ctx, OUT_FINAL);466/* run "counter mode" */467Skein_512_Process_Block(ctx, ctx->b, 1, sizeof (uint64_t));468/* number of output bytes left to go */469n = byteCnt - i * SKEIN_512_BLOCK_BYTES;470if (n >= SKEIN_512_BLOCK_BYTES)471n = SKEIN_512_BLOCK_BYTES;472Skein_Put64_LSB_First(hashVal + i * SKEIN_512_BLOCK_BYTES,473ctx->X, n); /* "output" the ctr mode bytes */474Skein_Show_Final(512, &ctx->h, n,475hashVal + i * SKEIN_512_BLOCK_BYTES);476/* restore the counter mode key for next time */477memcpy(ctx->X, X, sizeof (X));478}479return (SKEIN_SUCCESS);480}481482/* 1024-bit Skein */483484/* init the context for a straight hashing operation */485int486Skein1024_Init(Skein1024_Ctxt_t *ctx, size_t hashBitLen)487{488union {489uint8_t b[SKEIN1024_STATE_BYTES];490uint64_t w[SKEIN1024_STATE_WORDS];491} cfg; /* config block */492493Skein_Assert(hashBitLen > 0, SKEIN_BAD_HASHLEN);494ctx->h.hashBitLen = hashBitLen; /* output hash bit count */495496switch (hashBitLen) { /* use pre-computed values, where available */497#ifndef SKEIN_NO_PRECOMP498case 512:499memcpy(ctx->X, SKEIN1024_IV_512, sizeof (ctx->X));500break;501case 384:502memcpy(ctx->X, SKEIN1024_IV_384, sizeof (ctx->X));503break;504case 1024:505memcpy(ctx->X, SKEIN1024_IV_1024, sizeof (ctx->X));506break;507#endif508default:509/* here if there is no precomputed IV value available */510/*511* build/process the config block, type == CONFIG (could be512* precomputed)513*/514/* set tweaks: T0=0; T1=CFG | FINAL */515Skein_Start_New_Type(ctx, CFG_FINAL);516517/* set the schema, version */518cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);519/* hash result length in bits */520cfg.w[1] = Skein_Swap64(hashBitLen);521cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL);522/* zero pad config block */523memset(&cfg.w[3], 0, sizeof (cfg) - 3 * sizeof (cfg.w[0]));524525/* compute the initial chaining values from config block */526/* zero the chaining variables */527memset(ctx->X, 0, sizeof (ctx->X));528Skein1024_Process_Block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN);529break;530}531532/*533* The chaining vars ctx->X are now initialized for the given534* hashBitLen. Set up to process the data message portion of the hash535* (default)536*/537Skein_Start_New_Type(ctx, MSG); /* T0=0, T1= MSG type */538539return (SKEIN_SUCCESS);540}541542/* init the context for a MAC and/or tree hash operation */543/*544* [identical to Skein1024_Init() when keyBytes == 0 &&545* treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL]546*/547int548Skein1024_InitExt(Skein1024_Ctxt_t *ctx, size_t hashBitLen, uint64_t treeInfo,549const uint8_t *key, size_t keyBytes)550{551union {552uint8_t b[SKEIN1024_STATE_BYTES];553uint64_t w[SKEIN1024_STATE_WORDS];554} cfg; /* config block */555556Skein_Assert(hashBitLen > 0, SKEIN_BAD_HASHLEN);557Skein_Assert(keyBytes == 0 || key != NULL, SKEIN_FAIL);558559/* compute the initial chaining values ctx->X[], based on key */560if (keyBytes == 0) { /* is there a key? */561/* no key: use all zeroes as key for config block */562memset(ctx->X, 0, sizeof (ctx->X));563} else { /* here to pre-process a key */564Skein_assert(sizeof (cfg.b) >= sizeof (ctx->X));565/* do a mini-Init right here */566/* set output hash bit count = state size */567ctx->h.hashBitLen = 8 * sizeof (ctx->X);568/* set tweaks: T0 = 0; T1 = KEY type */569Skein_Start_New_Type(ctx, KEY);570/* zero the initial chaining variables */571memset(ctx->X, 0, sizeof (ctx->X));572(void) Skein1024_Update(ctx, key, keyBytes); /* hash the key */573/* put result into cfg.b[] */574(void) Skein1024_Final_Pad(ctx, cfg.b);575/* copy over into ctx->X[] */576memcpy(ctx->X, cfg.b, sizeof (cfg.b));577#if SKEIN_NEED_SWAP578{579uint_t i;580/* convert key bytes to context words */581for (i = 0; i < SKEIN1024_STATE_WORDS; i++)582ctx->X[i] = Skein_Swap64(ctx->X[i]);583}584#endif585}586/*587* build/process the config block, type == CONFIG (could be588* precomputed for each key)589*/590ctx->h.hashBitLen = hashBitLen; /* output hash bit count */591Skein_Start_New_Type(ctx, CFG_FINAL);592593memset(&cfg.w, 0, sizeof (cfg.w)); /* pre-pad cfg.w[] with zeroes */594cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);595/* hash result length in bits */596cfg.w[1] = Skein_Swap64(hashBitLen);597/* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */598cfg.w[2] = Skein_Swap64(treeInfo);599600Skein_Show_Key(1024, &ctx->h, key, keyBytes);601602/* compute the initial chaining values from config block */603Skein1024_Process_Block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN);604605/* The chaining vars ctx->X are now initialized */606/* Set up to process the data message portion of the hash (default) */607ctx->h.bCnt = 0; /* buffer b[] starts out empty */608Skein_Start_New_Type(ctx, MSG);609610return (SKEIN_SUCCESS);611}612613/* process the input bytes */614int615Skein1024_Update(Skein1024_Ctxt_t *ctx, const uint8_t *msg, size_t msgByteCnt)616{617size_t n;618619/* catch uninitialized context */620Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES, SKEIN_FAIL);621622/* process full blocks, if any */623if (msgByteCnt + ctx->h.bCnt > SKEIN1024_BLOCK_BYTES) {624/* finish up any buffered message data */625if (ctx->h.bCnt) {626/* # bytes free in buffer b[] */627n = SKEIN1024_BLOCK_BYTES - ctx->h.bCnt;628if (n) {629/* check on our logic here */630Skein_assert(n < msgByteCnt);631memcpy(&ctx->b[ctx->h.bCnt], msg, n);632msgByteCnt -= n;633msg += n;634ctx->h.bCnt += n;635}636Skein_assert(ctx->h.bCnt == SKEIN1024_BLOCK_BYTES);637Skein1024_Process_Block(ctx, ctx->b, 1,638SKEIN1024_BLOCK_BYTES);639ctx->h.bCnt = 0;640}641/*642* now process any remaining full blocks, directly from643* input message data644*/645if (msgByteCnt > SKEIN1024_BLOCK_BYTES) {646/* number of full blocks to process */647n = (msgByteCnt - 1) / SKEIN1024_BLOCK_BYTES;648Skein1024_Process_Block(ctx, msg, n,649SKEIN1024_BLOCK_BYTES);650msgByteCnt -= n * SKEIN1024_BLOCK_BYTES;651msg += n * SKEIN1024_BLOCK_BYTES;652}653Skein_assert(ctx->h.bCnt == 0);654}655656/* copy any remaining source message data bytes into b[] */657if (msgByteCnt) {658Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES);659memcpy(&ctx->b[ctx->h.bCnt], msg, msgByteCnt);660ctx->h.bCnt += msgByteCnt;661}662663return (SKEIN_SUCCESS);664}665666/* finalize the hash computation and output the result */667int668Skein1024_Final(Skein1024_Ctxt_t *ctx, uint8_t *hashVal)669{670size_t i, n, byteCnt;671uint64_t X[SKEIN1024_STATE_WORDS];672673/* catch uninitialized context */674Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES, SKEIN_FAIL);675676ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */677/* zero pad b[] if necessary */678if (ctx->h.bCnt < SKEIN1024_BLOCK_BYTES)679memset(&ctx->b[ctx->h.bCnt], 0,680SKEIN1024_BLOCK_BYTES - ctx->h.bCnt);681682/* process the final block */683Skein1024_Process_Block(ctx, ctx->b, 1, ctx->h.bCnt);684685/* now output the result */686/* total number of output bytes */687byteCnt = (ctx->h.hashBitLen + 7) >> 3;688689/* run Threefish in "counter mode" to generate output */690/* zero out b[], so it can hold the counter */691memset(ctx->b, 0, sizeof (ctx->b));692/* keep a local copy of counter mode "key" */693memcpy(X, ctx->X, sizeof (X));694for (i = 0; i * SKEIN1024_BLOCK_BYTES < byteCnt; i++) {695/* build the counter block */696*(uint64_t *)ctx->b = Skein_Swap64((uint64_t)i);697Skein_Start_New_Type(ctx, OUT_FINAL);698/* run "counter mode" */699Skein1024_Process_Block(ctx, ctx->b, 1, sizeof (uint64_t));700/* number of output bytes left to go */701n = byteCnt - i * SKEIN1024_BLOCK_BYTES;702if (n >= SKEIN1024_BLOCK_BYTES)703n = SKEIN1024_BLOCK_BYTES;704Skein_Put64_LSB_First(hashVal + i * SKEIN1024_BLOCK_BYTES,705ctx->X, n); /* "output" the ctr mode bytes */706Skein_Show_Final(1024, &ctx->h, n,707hashVal + i * SKEIN1024_BLOCK_BYTES);708/* restore the counter mode key for next time */709memcpy(ctx->X, X, sizeof (X));710}711return (SKEIN_SUCCESS);712}713714/* Functions to support MAC/tree hashing */715/* (this code is identical for Optimized and Reference versions) */716717/* finalize the hash computation and output the block, no OUTPUT stage */718int719Skein_256_Final_Pad(Skein_256_Ctxt_t *ctx, uint8_t *hashVal)720{721/* catch uninitialized context */722Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES, SKEIN_FAIL);723724ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */725/* zero pad b[] if necessary */726if (ctx->h.bCnt < SKEIN_256_BLOCK_BYTES)727memset(&ctx->b[ctx->h.bCnt], 0,728SKEIN_256_BLOCK_BYTES - ctx->h.bCnt);729/* process the final block */730Skein_256_Process_Block(ctx, ctx->b, 1, ctx->h.bCnt);731732/* "output" the state bytes */733Skein_Put64_LSB_First(hashVal, ctx->X, SKEIN_256_BLOCK_BYTES);734735return (SKEIN_SUCCESS);736}737738/* finalize the hash computation and output the block, no OUTPUT stage */739int740Skein_512_Final_Pad(Skein_512_Ctxt_t *ctx, uint8_t *hashVal)741{742/* catch uninitialized context */743Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES, SKEIN_FAIL);744745ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */746/* zero pad b[] if necessary */747if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES)748memset(&ctx->b[ctx->h.bCnt], 0,749SKEIN_512_BLOCK_BYTES - ctx->h.bCnt);750/* process the final block */751Skein_512_Process_Block(ctx, ctx->b, 1, ctx->h.bCnt);752753/* "output" the state bytes */754Skein_Put64_LSB_First(hashVal, ctx->X, SKEIN_512_BLOCK_BYTES);755756return (SKEIN_SUCCESS);757}758759/* finalize the hash computation and output the block, no OUTPUT stage */760int761Skein1024_Final_Pad(Skein1024_Ctxt_t *ctx, uint8_t *hashVal)762{763/* catch uninitialized context */764Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES, SKEIN_FAIL);765766/* tag as the final block */767ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL;768/* zero pad b[] if necessary */769if (ctx->h.bCnt < SKEIN1024_BLOCK_BYTES)770memset(&ctx->b[ctx->h.bCnt], 0,771SKEIN1024_BLOCK_BYTES - ctx->h.bCnt);772/* process the final block */773Skein1024_Process_Block(ctx, ctx->b, 1, ctx->h.bCnt);774775/* "output" the state bytes */776Skein_Put64_LSB_First(hashVal, ctx->X, SKEIN1024_BLOCK_BYTES);777778return (SKEIN_SUCCESS);779}780781#if SKEIN_TREE_HASH782/* just do the OUTPUT stage */783int784Skein_256_Output(Skein_256_Ctxt_t *ctx, uint8_t *hashVal)785{786size_t i, n, byteCnt;787uint64_t X[SKEIN_256_STATE_WORDS];788789/* catch uninitialized context */790Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES, SKEIN_FAIL);791792/* now output the result */793/* total number of output bytes */794byteCnt = (ctx->h.hashBitLen + 7) >> 3;795796/* run Threefish in "counter mode" to generate output */797/* zero out b[], so it can hold the counter */798memset(ctx->b, 0, sizeof (ctx->b));799/* keep a local copy of counter mode "key" */800memcpy(X, ctx->X, sizeof (X));801for (i = 0; i * SKEIN_256_BLOCK_BYTES < byteCnt; i++) {802/* build the counter block */803*(uint64_t *)ctx->b = Skein_Swap64((uint64_t)i);804Skein_Start_New_Type(ctx, OUT_FINAL);805/* run "counter mode" */806Skein_256_Process_Block(ctx, ctx->b, 1, sizeof (uint64_t));807/* number of output bytes left to go */808n = byteCnt - i * SKEIN_256_BLOCK_BYTES;809if (n >= SKEIN_256_BLOCK_BYTES)810n = SKEIN_256_BLOCK_BYTES;811Skein_Put64_LSB_First(hashVal + i * SKEIN_256_BLOCK_BYTES,812ctx->X, n); /* "output" the ctr mode bytes */813Skein_Show_Final(256, &ctx->h, n,814hashVal + i * SKEIN_256_BLOCK_BYTES);815/* restore the counter mode key for next time */816memcpy(ctx->X, X, sizeof (X));817}818return (SKEIN_SUCCESS);819}820821/* just do the OUTPUT stage */822int823Skein_512_Output(Skein_512_Ctxt_t *ctx, uint8_t *hashVal)824{825size_t i, n, byteCnt;826uint64_t X[SKEIN_512_STATE_WORDS];827828/* catch uninitialized context */829Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES, SKEIN_FAIL);830831/* now output the result */832/* total number of output bytes */833byteCnt = (ctx->h.hashBitLen + 7) >> 3;834835/* run Threefish in "counter mode" to generate output */836/* zero out b[], so it can hold the counter */837memset(ctx->b, 0, sizeof (ctx->b));838/* keep a local copy of counter mode "key" */839memcpy(X, ctx->X, sizeof (X));840for (i = 0; i * SKEIN_512_BLOCK_BYTES < byteCnt; i++) {841/* build the counter block */842*(uint64_t *)ctx->b = Skein_Swap64((uint64_t)i);843Skein_Start_New_Type(ctx, OUT_FINAL);844/* run "counter mode" */845Skein_512_Process_Block(ctx, ctx->b, 1, sizeof (uint64_t));846/* number of output bytes left to go */847n = byteCnt - i * SKEIN_512_BLOCK_BYTES;848if (n >= SKEIN_512_BLOCK_BYTES)849n = SKEIN_512_BLOCK_BYTES;850Skein_Put64_LSB_First(hashVal + i * SKEIN_512_BLOCK_BYTES,851ctx->X, n); /* "output" the ctr mode bytes */852Skein_Show_Final(256, &ctx->h, n,853hashVal + i * SKEIN_512_BLOCK_BYTES);854/* restore the counter mode key for next time */855memcpy(ctx->X, X, sizeof (X));856}857return (SKEIN_SUCCESS);858}859860/* just do the OUTPUT stage */861int862Skein1024_Output(Skein1024_Ctxt_t *ctx, uint8_t *hashVal)863{864size_t i, n, byteCnt;865uint64_t X[SKEIN1024_STATE_WORDS];866867/* catch uninitialized context */868Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES, SKEIN_FAIL);869870/* now output the result */871/* total number of output bytes */872byteCnt = (ctx->h.hashBitLen + 7) >> 3;873874/* run Threefish in "counter mode" to generate output */875/* zero out b[], so it can hold the counter */876memset(ctx->b, 0, sizeof (ctx->b));877/* keep a local copy of counter mode "key" */878memcpy(X, ctx->X, sizeof (X));879for (i = 0; i * SKEIN1024_BLOCK_BYTES < byteCnt; i++) {880/* build the counter block */881*(uint64_t *)ctx->b = Skein_Swap64((uint64_t)i);882Skein_Start_New_Type(ctx, OUT_FINAL);883/* run "counter mode" */884Skein1024_Process_Block(ctx, ctx->b, 1, sizeof (uint64_t));885/* number of output bytes left to go */886n = byteCnt - i * SKEIN1024_BLOCK_BYTES;887if (n >= SKEIN1024_BLOCK_BYTES)888n = SKEIN1024_BLOCK_BYTES;889Skein_Put64_LSB_First(hashVal + i * SKEIN1024_BLOCK_BYTES,890ctx->X, n); /* "output" the ctr mode bytes */891Skein_Show_Final(256, &ctx->h, n,892hashVal + i * SKEIN1024_BLOCK_BYTES);893/* restore the counter mode key for next time */894memcpy(ctx->X, X, sizeof (X));895}896return (SKEIN_SUCCESS);897}898#endif899900#ifdef _KERNEL901EXPORT_SYMBOL(Skein_512_Init);902EXPORT_SYMBOL(Skein_512_InitExt);903EXPORT_SYMBOL(Skein_512_Update);904EXPORT_SYMBOL(Skein_512_Final);905#endif906907908