/** * @cond internal * @file shake.c * @copyright * Uses public domain code by Mathias Panzenböck \n * Uses CC0 code by David Leon Gil, 2015 \n * Copyright (c) 2015 Cryptography Research, Inc. \n * Released under the MIT License. See LICENSE.txt for license information. * @author Mike Hamburg * @brief SHA-3-n and SHAKE-n instances. * @warning EXPERIMENTAL! The names, parameter orders etc are likely to change. */ #define __STDC_WANT_LIB_EXT1__ 1 /* for memset_s */ #define _BSD_SOURCE 1 /* for endian */ #include #include #include /* to open and read from /dev/urandom */ #include #include #include #include #include /* Subset of Mathias Panzenböck's portable endian code, public domain */ #if defined(__linux__) || defined(__CYGWIN__) # include #elif defined(__OpenBSD__) # include #elif defined(__APPLE__) # include # define htole64(x) OSSwapHostToLittleInt64(x) # define le64toh(x) OSSwapLittleToHostInt64(x) #elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) # include # define le64toh(x) letoh64(x) #elif defined(_WIN16) || defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) # include # include # if BYTE_ORDER == LITTLE_ENDIAN # define htole64(x) (x) # define le64toh(x) (x) # elif BYTE_ORDER == BIG_ENDIAN # define htole64(x) __builtin_bswap64(x) # define le64toh(x) __builtin_bswap64(x) # else # error byte order not supported # endif #else # error platform not supported #endif /* The internal, non-opaque definition of the sponge struct. */ typedef union { uint64_t w[25]; uint8_t b[25*8]; } kdomain_t[1]; typedef struct kparams_s { uint8_t position, flags, rate, startRound, pad, ratePad, maxOut, client; } kparams_t[1]; typedef struct keccak_sponge_s { kdomain_t state; kparams_t params; } keccak_sponge_t[1]; #define INTERNAL_SPONGE_STRUCT 1 #include "shake.h" #include "decaf.h" #define FLAG_ABSORBING 'A' #define FLAG_SQUEEZING 'Z' #define FLAG_RNG_SQU 'R' #define FLAG_DET_SQU 'D' #define FLAG_RNG_ABS 'r' #define FLAG_DET_ABS 'd' #define FLAG_RNG_UNI 'u' #define FLAG_DET_UNI 'g' /** Constants. **/ static const uint8_t pi[24] = { 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 }; #define RC_B(x,n) ((((x##ull)>>n)&1)<<((1<> (64 - s)); } /* Helper macros to unroll the permutation. TODO: opt tradeoffs. */ #define REPEAT5(e) e e e e e #define FOR51(v, e) v = 0; REPEAT5(e; v += 1;) //#if (defined(__OPTIMIZE__) && !defined(__OPTIMIZE_SIZE__)) # define FOR55(v, e) v = 0; REPEAT5(e; v += 5;) # define REPEAT24(e) e e e e e e e e e e e e e e e e e e e e e e e e // #else // # define FOR55(v, e) for (v=0; v<25; v+= 5) { e; } // # define REPEAT24(e) {int _j=0; for (_j=0; _j<24; _j++) { e }} // #endif /*** The Keccak-f[1600] permutation ***/ static void __attribute__((noinline)) keccakf(kdomain_t state, uint8_t startRound) { uint64_t* a = state->w; uint64_t b[5] = {0}, t, u; uint8_t x, y, i; for (i=0; i<25; i++) a[i] = le64toh(a[i]); for (i = startRound; i < 24; i++) { FOR51(x, b[x] = 0; FOR55(y, b[x] ^= a[x + y];)) FOR51(x, FOR55(y, a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); )) // Rho and pi t = a[1]; x = y = 0; REPEAT24(u = a[pi[x]]; y += x+1; a[pi[x]] = rol(t, y % 64); t = u; x++; ) // Chi FOR55(y, FOR51(x, b[x] = a[y + x];) FOR51(x, a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]);) ) // Iota a[0] ^= RC[i]; } for (i=0; i<25; i++) a[i] = htole64(a[i]); } static inline void dokeccak (keccak_sponge_t sponge) { keccakf(sponge->state, sponge->params->startRound); sponge->params->position = 0; } void sha3_update ( struct keccak_sponge_s * __restrict__ sponge, const uint8_t *in, size_t len ) { if (!len) return; assert(sponge->params->position < sponge->params->rate); assert(sponge->params->rate < sizeof(sponge->state)); assert(sponge->params->flags == FLAG_ABSORBING); while (len) { size_t cando = sponge->params->rate - sponge->params->position, i; uint8_t* state = &sponge->state->b[sponge->params->position]; if (cando > len) { for (i = 0; i < len; i += 1) state[i] ^= in[i]; sponge->params->position += len; return; } else { for (i = 0; i < cando; i += 1) state[i] ^= in[i]; dokeccak(sponge); len -= cando; in += cando; } } } void sha3_output ( keccak_sponge_t sponge, uint8_t * __restrict__ out, size_t len ) { assert(sponge->params->position < sponge->params->rate); assert(sponge->params->rate < sizeof(sponge->state)); if (sponge->params->maxOut != 0xFF) { assert(sponge->params->maxOut >= len); sponge->params->maxOut -= len; } switch (sponge->params->flags) { case FLAG_SQUEEZING: break; case FLAG_ABSORBING: { uint8_t* state = sponge->state->b; state[sponge->params->position] ^= sponge->params->pad; state[sponge->params->rate - 1] ^= sponge->params->ratePad; dokeccak(sponge); break; } default: assert(0); } while (len) { size_t cando = sponge->params->rate - sponge->params->position; uint8_t* state = &sponge->state->b[sponge->params->position]; if (cando > len) { memcpy(out, state, len); sponge->params->position += len; return; } else { memcpy(out, state, cando); dokeccak(sponge); len -= cando; out += cando; } } } /** TODO: unify with decaf_bzero? */ void sponge_destroy ( keccak_sponge_t sponge ) { #ifdef __STDC_LIB_EXT1__ memset_s(sponge, sizeof(sponge), 0, sizeof(sponge)); #else volatile uint64_t *destroy = (volatile uint64_t *)sponge; unsigned i; for (i=0; istate, 0, sizeof(sponge->state)); sponge->params[0] = params[0]; } void sponge_hash ( const uint8_t *in, size_t inlen, uint8_t *out, size_t outlen, const struct kparams_s *params ) { keccak_sponge_t sponge; sponge_init(sponge, params); sha3_update(sponge, in, inlen); sha3_output(sponge, out, outlen); sponge_destroy(sponge); } #define DEFSHAKE(n) \ const struct kparams_s SHAKE##n##_params_s = \ { 0, FLAG_ABSORBING, 200-n/4, 0, 0x1f, 0x80, 0xFF, 0 }; #define DEFSHA3(n) \ const struct kparams_s SHA3_##n##_params_s = \ { 0, FLAG_ABSORBING, 200-n/4, 0, 0x06, 0x80, n/8, 0 }; size_t sponge_default_output_bytes ( const keccak_sponge_t s ) { return (s->params->maxOut == 0xFF) ? (200-s->params->rate) : ((200-s->params->rate)/2); } DEFSHAKE(128) DEFSHAKE(256) DEFSHA3(224) DEFSHA3(256) DEFSHA3(384) DEFSHA3(512) /** Get entropy from a CPU, preferably in the form of RDRAND, but possibly instead from RDTSC. */ static void get_cpu_entropy(uint8_t *entropy, size_t len) { # if (defined(__i386__) || defined(__x86_64__)) static char tested = 0, have_rdrand = 0; if (!tested) { u_int32_t a,b,c,d; a=1; __asm__("cpuid" : "+a"(a), "=b"(b), "=c"(c), "=d"(d)); have_rdrand = (c>>30)&1; tested = 1; } if (have_rdrand) { # if defined(__x86_64__) uint64_t out, a=0, *eo = (uint64_t *)entropy; # elif defined(__i386__) uint32_t out, a=0, *eo = (uint64_t *)entropy; #endif len /= sizeof(out); uint32_t tries; for (tries = 100+len; tries && len; len--, eo++) { for (a = 0; tries && !a; tries--) { __asm__ __volatile__ ("rdrand %0\n\tsetc %%al" : "=r"(out), "+a"(a) :: "cc" ); } *eo ^= out; } } else if (len>8) { uint64_t out; __asm__ __volatile__ ("rdtsc" : "=A"(out)); *(uint64_t*) entropy ^= out; } #else (void) entropy; (void) len; #endif } void spongerng_next ( keccak_sponge_t sponge, uint8_t * __restrict__ out, size_t len ) { assert(sponge->params->position < sponge->params->rate); assert(sponge->params->rate < sizeof(sponge->state)); switch(sponge->params->flags) { case FLAG_DET_SQU: case FLAG_RNG_SQU: break; case FLAG_DET_ABS: case FLAG_RNG_ABS: { uint8_t* state = sponge->state->b; state[sponge->params->position] ^= sponge->params->pad; state[sponge->params->rate - 1] ^= sponge->params->ratePad; dokeccak(sponge); sponge->params->flags = (sponge->params->flags == FLAG_DET_ABS) ? FLAG_DET_SQU : FLAG_RNG_SQU; break; } default: assert(0); }; while (len) { size_t cando = sponge->params->rate - sponge->params->position; uint8_t* state = &sponge->state->b[sponge->params->position]; if (cando > len) { memcpy(out, state, len); memset(state, 0, len); sponge->params->position += len; return; } else { memcpy(out, state, cando); memset(state, 0, cando); if (sponge->params->flags == FLAG_RNG_SQU) get_cpu_entropy(sponge->state->b, 32); dokeccak(sponge); len -= cando; out += cando; } } /* Anti-rollback */ if (sponge->params->position < 32) { memset(&sponge->state->b, 0, 32); sponge->params->position = 32; } } void spongerng_stir ( keccak_sponge_t sponge, const uint8_t * __restrict__ in, size_t len ) { assert(sponge->params->position < sponge->params->rate); assert(sponge->params->rate < sizeof(sponge->state)); switch(sponge->params->flags) { case FLAG_RNG_SQU: get_cpu_entropy(sponge->state->b, 32); /* fall through */ case FLAG_DET_SQU: sponge->params->flags = (sponge->params->flags == FLAG_DET_SQU) ? FLAG_DET_ABS : FLAG_RNG_ABS; dokeccak(sponge); break; case FLAG_DET_ABS: case FLAG_RNG_ABS: break; case FLAG_DET_UNI: case FLAG_RNG_UNI: break; default: assert(0); }; while (len) { size_t i; size_t cando = sponge->params->rate - sponge->params->position; uint8_t* state = &sponge->state->b[sponge->params->position]; if (cando > len) { for (i = 0; i < len; i += 1) state[i] ^= in[i]; sponge->params->position += len; return; } else { for (i = 0; i < cando; i += 1) state[i] ^= in[i]; dokeccak(sponge); len -= cando; in += cando; } } } static const struct kparams_s spongerng_params = { 0, FLAG_RNG_UNI, 200-256/4, 0, 0x06, 0x80, 0xFF, 0 }; void spongerng_init_from_buffer ( keccak_sponge_t sponge, const uint8_t * __restrict__ in, size_t len, int deterministic ) { sponge_init(sponge, &spongerng_params); sponge->params->flags = deterministic ? FLAG_DET_ABS : FLAG_RNG_ABS; spongerng_stir(sponge, in, len); } int spongerng_init_from_file ( keccak_sponge_t sponge, const char *file, size_t len, int deterministic ) { sponge_init(sponge, &spongerng_params); sponge->params->flags = deterministic ? FLAG_DET_UNI : FLAG_RNG_UNI; if (!len) return -2; int fd = open(file, O_RDONLY); if (fd < 0) return errno ? errno : -1; uint8_t buffer[128]; while (len) { ssize_t red = read(fd, buffer, (len > sizeof(buffer)) ? sizeof(buffer) : len); if (red <= 0) { close(fd); return errno ? errno : -1; } spongerng_stir(sponge,buffer,red); len -= red; }; close(fd); sponge->params->flags = deterministic ? FLAG_DET_ABS : FLAG_RNG_ABS; return 0; } int spongerng_init_from_dev_urandom ( keccak_sponge_t sponge ) { return spongerng_init_from_file(sponge, "/dev/urandom", 64, 0); } const struct kparams_s STROBE_256 = { 0, 0, 200-256/4, 0, 0, 0, 0, 0 }; const struct kparams_s STROBE_KEYED_256 = { 0, 0, 200-256/4, 12, 0, 0, 0, 0 }; const struct kparams_s STROBE_KEYED_128 = { 0, 0, 200-128/4, 12, 0, 0, 0, 0 }; /* Strobe is different in that its rate is padded by one byte. */ void strobe_init( keccak_sponge_t sponge, const struct kparams_s *params, uint8_t am_client ) { sponge_init(sponge,params); sponge->params->client = !!am_client; } static void strobe_duplex ( keccak_sponge_t sponge, unsigned char *out, const unsigned char *in, size_t len ) { unsigned j; while (len) { assert(sponge->params->rate >= sponge->params->position); size_t cando = sponge->params->rate - sponge->params->position; uint8_t* state = &sponge->state->b[sponge->params->position]; if (cando >= len) { for (j=0; in && jparams->position += len; return; } else { if (in) { for (j=0; jparams->rate < sizeof(sponge->state)); assert(sponge->params->position <= sponge->params->rate); if (sizeof(sponge->state) - sponge->params->rate < len) { /** Tiny case */ unsigned char tmp[len]; strobe_duplex(sponge,tmp,NULL,len); if (sponge->params->position) dokeccak(sponge); strobe_duplex(sponge,tmp,NULL,len); decaf_bzero(tmp,len); } else { if (sponge->params->rate < len + sponge->params->position) { dokeccak(sponge); } memset(sponge->state->b, 0, len); sponge->params->position = len; } } static void strobe_unduplex ( keccak_sponge_t sponge, unsigned char *out, const unsigned char *in, size_t len ) { unsigned j; while (len) { assert(sponge->params->rate >= sponge->params->position); size_t cando = sponge->params->rate - sponge->params->position; uint8_t* state = &sponge->state->b[sponge->params->position]; if (cando >= len) { for (j=0; in && jparams->position += len; return; } else { for (j=0; in && jparams->rate < sizeof(sponge->state)); decaf_bool_t ret = DECAF_SUCCESS; if (!more) { strobe_duplex(sponge,NULL,control,len); sponge->state->b[sponge->params->position] ^= 0x1; sponge->state->b[sponge->params->rate] ^= 0x2; dokeccak(sponge); sponge->params->flags = control[len-1]; } else if (sponge->params->flags && sponge->params->flags != control[len-1]) { ret = DECAF_FAILURE; } sponge->params->flags = control[len-1]; return ret; } decaf_bool_t strobe_encrypt ( keccak_sponge_t sponge, unsigned char *out, const unsigned char *in, size_t len, uint8_t more ) { unsigned char control[] = { CIPHERTEXT | (sponge->params->client ? CLIENT_TO_SERVER : SERVER_TO_CLIENT) }; decaf_bool_t ret = strobe_control_word(sponge, control, sizeof(control), more); strobe_duplex(sponge, out, in, len); if (!sponge->params->pad/*keyed*/) ret = DECAF_FAILURE; return ret; } decaf_bool_t strobe_decrypt ( keccak_sponge_t sponge, unsigned char *out, const unsigned char *in, size_t len, uint8_t more ) { unsigned char control[] = { CIPHERTEXT | (sponge->params->client ? SERVER_TO_CLIENT : CLIENT_TO_SERVER) }; decaf_bool_t ret = strobe_control_word(sponge, control, sizeof(control), more); strobe_unduplex(sponge, out, in, len); if (!sponge->params->pad/*keyed*/) ret = DECAF_FAILURE; return ret; } decaf_bool_t strobe_plaintext ( keccak_sponge_t sponge, const unsigned char *in, size_t len, uint8_t iSent, uint8_t more ) { unsigned char control[] = { PLAINTEXT | ((sponge->params->client == !!iSent) ? CLIENT_TO_SERVER : SERVER_TO_CLIENT) }; decaf_bool_t ret = strobe_control_word(sponge, control, sizeof(control), more); strobe_duplex(sponge, NULL, in, len); return ret; } decaf_bool_t strobe_key ( keccak_sponge_t sponge, const unsigned char *in, size_t len, uint8_t more ) { unsigned char control[] = { KEY }; decaf_bool_t ret = strobe_control_word(sponge, control, sizeof(control), more); strobe_duplex(sponge, NULL, in, len); sponge->params->pad/*=keyed*/ = 1; return ret; } decaf_bool_t strobe_nonce ( keccak_sponge_t sponge, const unsigned char *in, size_t len, uint8_t more ) { unsigned char control[] = { NONCE }; decaf_bool_t ret = strobe_control_word(sponge, control, sizeof(control), more); strobe_duplex(sponge, NULL, in, len); return ret; } decaf_bool_t strobe_ad ( keccak_sponge_t sponge, const unsigned char *in, size_t len, uint8_t more ) { unsigned char control[] = { AD }; decaf_bool_t ret = strobe_control_word(sponge, control, sizeof(control), more); strobe_duplex(sponge, NULL, in, len); return ret; } #define STROBE_FORGET_BYTES 32 decaf_bool_t strobe_produce_auth ( keccak_sponge_t sponge, unsigned char *out, size_t len ) { unsigned char control[] = { (unsigned char)len, (unsigned char)STROBE_FORGET_BYTES, TAGFORGET | (sponge->params->client ? CLIENT_TO_SERVER : SERVER_TO_CLIENT) }; decaf_bool_t ret = strobe_control_word(sponge, control, sizeof(control), 0); strobe_duplex(sponge, out, NULL, len); strobe_forget(sponge, STROBE_FORGET_BYTES); if (!sponge->params->pad/*keyed*/) ret = DECAF_FAILURE; return ret; } decaf_bool_t strobe_prng ( keccak_sponge_t sponge, unsigned char *out, size_t len, uint8_t more ) { /* FIXME: length?? */ unsigned char control[] = { PRNG }; decaf_bool_t ret = strobe_control_word(sponge, control, sizeof(control), more); strobe_duplex(sponge, out, NULL, len); // /** TODO: orly? */ // unsigned char control2[] = { 0, STROBE_FORGET_BYTES, TAGFORGET }; // ret &= strobe_control_word(sponge, control2, sizeof(control2)); // strobe_forget(sponge, STROBE_FORGET_BYTES); if (!sponge->params->pad/*keyed*/) ret = DECAF_FAILURE; return ret; } /* TODO: remove reliance on decaf? */ decaf_bool_t strobe_verify_auth ( keccak_sponge_t sponge, const unsigned char *in, size_t len ) { unsigned char control[] = { (unsigned char)len, (unsigned char)STROBE_FORGET_BYTES, TAGFORGET | (sponge->params->client ? SERVER_TO_CLIENT : CLIENT_TO_SERVER) }; decaf_bool_t ret = strobe_control_word(sponge, control, sizeof(control), 0); unsigned char zero[len]; strobe_unduplex(sponge, zero, in, len); strobe_forget(sponge, STROBE_FORGET_BYTES); /* Check for 0 */ decaf_bool_t chain=0; unsigned i; for (i=0; i>(8*sizeof(decaf_word_t)); if (!sponge->params->pad/*keyed*/) ret = DECAF_FAILURE; return ret; } decaf_bool_t strobe_respec ( keccak_sponge_t sponge, const struct kparams_s *params ) { unsigned char control[] = { params->rate, params->startRound, RESPEC }; decaf_bool_t ret = strobe_control_word(sponge, control, sizeof(control), 0); if (!sponge->params->pad/*keyed*/) ret = DECAF_FAILURE; sponge->params->rate = params->rate; sponge->params->startRound = params->startRound; return ret; } /* TODO: Keyak instances, etc */