diff options
Diffstat (limited to '')
-rw-r--r-- | Makefile | 31 | ||||
-rw-r--r-- | common.h | 19 | ||||
-rw-r--r-- | digest.c (renamed from libkeccak/digest.c) | 0 | ||||
-rw-r--r-- | libkeccak.7 (renamed from man7/libkeccak.7) | 0 | ||||
-rw-r--r-- | libkeccak/hex.c | 65 | ||||
-rw-r--r-- | libkeccak/hmac.c | 423 | ||||
-rw-r--r-- | libkeccak/state.c | 174 | ||||
-rw-r--r-- | libkeccak_behex_lower.3 (renamed from man3/libkeccak_behex_lower.3) | 0 | ||||
-rw-r--r-- | libkeccak_behex_lower.c | 21 | ||||
-rw-r--r-- | libkeccak_behex_upper.3 (renamed from man3/libkeccak_behex_upper.3) | 0 | ||||
-rw-r--r-- | libkeccak_behex_upper.c | 21 | ||||
-rw-r--r-- | libkeccak_degeneralise_spec.3 (renamed from man3/libkeccak_degeneralise_spec.3) | 0 | ||||
-rw-r--r-- | libkeccak_degeneralise_spec.c (renamed from libkeccak/generalised-spec.c) | 3 | ||||
-rw-r--r-- | libkeccak_digest.3 (renamed from man3/libkeccak_digest.3) | 0 | ||||
-rw-r--r-- | libkeccak_fast_digest.3 (renamed from man3/libkeccak_fast_digest.3) | 0 | ||||
-rw-r--r-- | libkeccak_fast_squeeze.3 (renamed from man3/libkeccak_fast_squeeze.3) | 0 | ||||
-rw-r--r-- | libkeccak_fast_update.3 (renamed from man3/libkeccak_fast_update.3) | 0 | ||||
-rw-r--r-- | libkeccak_generalised_spec_initialise.3 (renamed from man3/libkeccak_generalised_spec_initialise.3) | 0 | ||||
-rw-r--r-- | libkeccak_generalised_sum_fd.3 (renamed from man3/libkeccak_generalised_sum_fd.3) | 0 | ||||
-rw-r--r-- | libkeccak_generalised_sum_fd.c (renamed from libkeccak/files.c) | 2 | ||||
-rw-r--r-- | libkeccak_hmac_copy.3 (renamed from man3/libkeccak_hmac_copy.3) | 0 | ||||
-rw-r--r-- | libkeccak_hmac_copy.c | 38 | ||||
-rw-r--r-- | libkeccak_hmac_create.3 (renamed from man3/libkeccak_hmac_create.3) | 0 | ||||
-rw-r--r-- | libkeccak_hmac_destroy.3 (renamed from man3/libkeccak_hmac_destroy.3) | 0 | ||||
-rw-r--r-- | libkeccak_hmac_digest.3 (renamed from man3/libkeccak_hmac_digest.3) | 0 | ||||
-rw-r--r-- | libkeccak_hmac_digest.c | 80 | ||||
-rw-r--r-- | libkeccak_hmac_duplicate.3 (renamed from man3/libkeccak_hmac_duplicate.3) | 0 | ||||
-rw-r--r-- | libkeccak_hmac_fast_destroy.3 (renamed from man3/libkeccak_hmac_fast_destroy.3) | 0 | ||||
-rw-r--r-- | libkeccak_hmac_fast_digest.3 (renamed from man3/libkeccak_hmac_fast_digest.3) | 0 | ||||
-rw-r--r-- | libkeccak_hmac_fast_digest.c | 78 | ||||
-rw-r--r-- | libkeccak_hmac_fast_free.3 (renamed from man3/libkeccak_hmac_fast_free.3) | 0 | ||||
-rw-r--r-- | libkeccak_hmac_fast_update.3 (renamed from man3/libkeccak_hmac_fast_update.3) | 0 | ||||
-rw-r--r-- | libkeccak_hmac_fast_update.c | 51 | ||||
-rw-r--r-- | libkeccak_hmac_free.3 (renamed from man3/libkeccak_hmac_free.3) | 0 | ||||
-rw-r--r-- | libkeccak_hmac_initialise.3 (renamed from man3/libkeccak_hmac_initialise.3) | 0 | ||||
-rw-r--r-- | libkeccak_hmac_marshal.3 (renamed from man3/libkeccak_hmac_marshal.3) | 0 | ||||
-rw-r--r-- | libkeccak_hmac_marshal_size.3 (renamed from man3/libkeccak_hmac_marshal_size.3) | 0 | ||||
-rw-r--r-- | libkeccak_hmac_reset.3 (renamed from man3/libkeccak_hmac_reset.3) | 0 | ||||
-rw-r--r-- | libkeccak_hmac_set_key.3 (renamed from man3/libkeccak_hmac_set_key.3) | 0 | ||||
-rw-r--r-- | libkeccak_hmac_set_key.c | 46 | ||||
-rw-r--r-- | libkeccak_hmac_unmarshal.3 (renamed from man3/libkeccak_hmac_unmarshal.3) | 0 | ||||
-rw-r--r-- | libkeccak_hmac_unmarshal.c | 50 | ||||
-rw-r--r-- | libkeccak_hmac_unmarshal_skip.3 (renamed from man3/libkeccak_hmac_unmarshal_skip.3) | 0 | ||||
-rw-r--r-- | libkeccak_hmac_update.3 (renamed from man3/libkeccak_hmac_update.3) | 0 | ||||
-rw-r--r-- | libkeccak_hmac_update.c | 52 | ||||
-rw-r--r-- | libkeccak_hmac_wipe.3 (renamed from man3/libkeccak_hmac_wipe.3) | 0 | ||||
-rw-r--r-- | libkeccak_hmac_wipe.c | 22 | ||||
-rw-r--r-- | libkeccak_keccaksum_fd.3 (renamed from man3/libkeccak_keccaksum_fd.3) | 0 | ||||
-rw-r--r-- | libkeccak_rawshakesum_fd.3 (renamed from man3/libkeccak_rawshakesum_fd.3) | 0 | ||||
-rw-r--r-- | libkeccak_sha3sum_fd.3 (renamed from man3/libkeccak_sha3sum_fd.3) | 0 | ||||
-rw-r--r-- | libkeccak_shakesum_fd.3 (renamed from man3/libkeccak_shakesum_fd.3) | 0 | ||||
-rw-r--r-- | libkeccak_simple_squeeze.3 (renamed from man3/libkeccak_simple_squeeze.3) | 0 | ||||
-rw-r--r-- | libkeccak_spec_check.3 (renamed from man3/libkeccak_spec_check.3) | 0 | ||||
-rw-r--r-- | libkeccak_spec_rawshake.3 (renamed from man3/libkeccak_spec_rawshake.3) | 0 | ||||
-rw-r--r-- | libkeccak_spec_sha3.3 (renamed from man3/libkeccak_spec_sha3.3) | 0 | ||||
-rw-r--r-- | libkeccak_spec_shake.3 (renamed from man3/libkeccak_spec_shake.3) | 0 | ||||
-rw-r--r-- | libkeccak_squeeze.3 (renamed from man3/libkeccak_squeeze.3) | 0 | ||||
-rw-r--r-- | libkeccak_state_copy.3 (renamed from man3/libkeccak_state_copy.3) | 0 | ||||
-rw-r--r-- | libkeccak_state_copy.c | 21 | ||||
-rw-r--r-- | libkeccak_state_create.3 (renamed from man3/libkeccak_state_create.3) | 0 | ||||
-rw-r--r-- | libkeccak_state_destroy.3 (renamed from man3/libkeccak_state_destroy.3) | 0 | ||||
-rw-r--r-- | libkeccak_state_duplicate.3 (renamed from man3/libkeccak_state_duplicate.3) | 0 | ||||
-rw-r--r-- | libkeccak_state_fast_destroy.3 (renamed from man3/libkeccak_state_fast_destroy.3) | 0 | ||||
-rw-r--r-- | libkeccak_state_fast_free.3 (renamed from man3/libkeccak_state_fast_free.3) | 0 | ||||
-rw-r--r-- | libkeccak_state_free.3 (renamed from man3/libkeccak_state_free.3) | 0 | ||||
-rw-r--r-- | libkeccak_state_initialise.3 (renamed from man3/libkeccak_state_initialise.3) | 0 | ||||
-rw-r--r-- | libkeccak_state_initialise.c | 33 | ||||
-rw-r--r-- | libkeccak_state_marshal.3 (renamed from man3/libkeccak_state_marshal.3) | 0 | ||||
-rw-r--r-- | libkeccak_state_marshal.c | 33 | ||||
-rw-r--r-- | libkeccak_state_marshal_size.3 (renamed from man3/libkeccak_state_marshal_size.3) | 0 | ||||
-rw-r--r-- | libkeccak_state_reset.3 (renamed from man3/libkeccak_state_reset.3) | 0 | ||||
-rw-r--r-- | libkeccak_state_unmarshal.3 (renamed from man3/libkeccak_state_unmarshal.3) | 0 | ||||
-rw-r--r-- | libkeccak_state_unmarshal.c | 36 | ||||
-rw-r--r-- | libkeccak_state_unmarshal_skip.3 (renamed from man3/libkeccak_state_unmarshal_skip.3) | 0 | ||||
-rw-r--r-- | libkeccak_state_unmarshal_skip.c | 18 | ||||
-rw-r--r-- | libkeccak_state_wipe.3 (renamed from man3/libkeccak_state_wipe.3) | 0 | ||||
-rw-r--r-- | libkeccak_state_wipe.c | 15 | ||||
-rw-r--r-- | libkeccak_state_wipe_message.3 (renamed from man3/libkeccak_state_wipe_message.3) | 0 | ||||
-rw-r--r-- | libkeccak_state_wipe_message.c | 17 | ||||
-rw-r--r-- | libkeccak_state_wipe_sponge.3 (renamed from man3/libkeccak_state_wipe_sponge.3) | 0 | ||||
-rw-r--r-- | libkeccak_state_wipe_sponge.c | 17 | ||||
-rw-r--r-- | libkeccak_unhex.3 (renamed from man3/libkeccak_unhex.3) | 0 | ||||
-rw-r--r-- | libkeccak_unhex.c | 29 | ||||
-rw-r--r-- | libkeccak_update.3 (renamed from man3/libkeccak_update.3) | 0 |
84 files changed, 723 insertions, 672 deletions
@@ -18,12 +18,28 @@ LIB_VERSION = $(LIB_MAJOR).$(LIB_MINOR) OBJ =\ - libkeccak/digest.o\ - libkeccak/files.o\ - libkeccak/generalised-spec.o\ - libkeccak/hex.o\ - libkeccak/state.o\ - libkeccak/hmac.o + digest.o\ + libkeccak_behex_lower.o\ + libkeccak_behex_upper.o\ + libkeccak_degeneralise_spec.o\ + libkeccak_generalised_sum_fd.o\ + libkeccak_hmac_copy.o\ + libkeccak_hmac_digest.o\ + libkeccak_hmac_fast_digest.o\ + libkeccak_hmac_fast_update.o\ + libkeccak_hmac_set_key.o\ + libkeccak_hmac_unmarshal.o\ + libkeccak_hmac_update.o\ + libkeccak_hmac_wipe.o\ + libkeccak_state_copy.o\ + libkeccak_state_initialise.o\ + libkeccak_state_marshal.o\ + libkeccak_state_unmarshal.o\ + libkeccak_state_unmarshal_skip.o\ + libkeccak_state_wipe.o\ + libkeccak_state_wipe_message.o\ + libkeccak_state_wipe_sponge.o\ + libkeccak_unhex.o HDR =\ libkeccak.h\ @@ -154,7 +170,8 @@ uninstall: -rm -f -- "$(DESTDIR)$(PREFIX)/lib/libkeccak.a" -rm -rf -- "$(DESTDIR)$(PREFIX)/include/libkeccak" -rm -f -- "$(DESTDIR)$(PREFIX)/include/libkeccak.h" - -cd -- "$(DESTDIR)$(MANPREFIX)" && rm -f -- $(MAN3) $(MAN7) + -cd -- "$(DESTDIR)$(MANPREFIX)/man3" && rm -f -- $(MAN3) + -cd -- "$(DESTDIR)$(MANPREFIX)/man7" && rm -f -- $(MAN7) -rm -rf -- "$(DESTDIR)$(PREFIX)/share/licenses/libkeccak" clean: @@ -15,3 +15,22 @@ # define __builtin_memcpy(dest, src, n) memcpy(dest, src, n) # define __builtin_memmove(dest, src, n) memmove(dest, src, n) #endif + + +/** + * The outer pad pattern for HMAC + */ +#define HMAC_OUTER_PAD 0x5C + +/** + * The inner pad pattern for HMAC + */ +#define HMAC_INNER_PAD 0x36 + + +static void *(*volatile my_explicit_memset)(void *, int, size_t) = memset; +static __attribute__((__optimize__("-O0"))) void +my_explicit_bzero(void *ptr, size_t size) +{ + (*my_explicit_memset)(ptr, 0, size); +} diff --git a/libkeccak/digest.c b/digest.c index 891b471..891b471 100644 --- a/libkeccak/digest.c +++ b/digest.c diff --git a/man7/libkeccak.7 b/libkeccak.7 index 0a6ef04..0a6ef04 100644 --- a/man7/libkeccak.7 +++ b/libkeccak.7 diff --git a/libkeccak/hex.c b/libkeccak/hex.c deleted file mode 100644 index 7db49a6..0000000 --- a/libkeccak/hex.c +++ /dev/null @@ -1,65 +0,0 @@ -/* See LICENSE file for copyright and license details. */ -#include "../libkeccak.h" - - -/** - * Convert a binary hashsum to lower case hexadecimal representation - * - * @param output Output array, should have an allocation size of at least `2 * n + 1` - * @param hashsum The hashsum to convert - * @param n The size of `hashsum` - */ -void -libkeccak_behex_lower(char *restrict output, const void *restrict hashsum_, size_t n) -{ - const char *restrict hashsum = hashsum_; - output[2 * n] = '\0'; - while (n--) { - output[2 * n + 0] = "0123456789abcdef"[(hashsum[n] >> 4) & 15]; - output[2 * n + 1] = "0123456789abcdef"[(hashsum[n] >> 0) & 15]; - } -} - - -/** - * Convert a binary hashsum to upper case hexadecimal representation - * - * @param output Output array, should have an allocation size of at least `2 * n + 1` - * @param hashsum The hashsum to convert - * @param n The size of `hashsum` - */ -void -libkeccak_behex_upper(char *restrict output, const void *restrict hashsum_, size_t n) -{ - const char *restrict hashsum = hashsum_; - output[2 * n] = '\0'; - while (n--) { - output[2 * n + 0] = "0123456789ABCDEF"[(hashsum[n] >> 4) & 15]; - output[2 * n + 1] = "0123456789ABCDEF"[(hashsum[n] >> 0) & 15]; - } -} - - -/** - * Convert a hexadecimal hashsum (both lower case, upper - * case and mixed is supported) to binary representation - * - * @param output Output array, should have an allocation size of at least `strlen(hashsum) / 2` - * @param hashsum The hashsum to convert - */ -void -libkeccak_unhex(void *restrict output_, const char *restrict hashsum) -{ - char *restrict output = output_; - size_t n = strlen(hashsum) / 2; - char a, b; - while (n--) { - a = hashsum[2 * n + 0]; - b = hashsum[2 * n + 1]; - - a = (char)((a & 15) + (a > '9' ? 9 : 0)); - b = (char)((b & 15) + (b > '9' ? 9 : 0)); - - output[n] = (char)((a << 4) | b); - } -} diff --git a/libkeccak/hmac.c b/libkeccak/hmac.c deleted file mode 100644 index 8b14eba..0000000 --- a/libkeccak/hmac.c +++ /dev/null @@ -1,423 +0,0 @@ -/* See LICENSE file for copyright and license details. */ -#include "../common.h" - - - -/** - * The outer pad pattern - */ -#define OUTER_PAD 0x5C - -/** - * The inner pad pattern - */ -#define INNER_PAD 0x36 - - - -static void *(*volatile my_explicit_memset)(void *, int, size_t) = memset; -static __attribute__((__optimize__("-O0"))) void -my_explicit_bzero(void *ptr, size_t size) -{ - (*my_explicit_memset)(ptr, 0, size); -} - - -/** - * Change the HMAC-hashing key on the state - * - * @param state The state that should be reset - * @param key The new key - * @param key_length The length of key, in bits - * @return Zero on success, -1 on error - */ -int -libkeccak_hmac_set_key(libkeccak_hmac_state_t *restrict state, const void *restrict key, size_t key_length) -{ - size_t i, size, new_key_length, key_bytes; - char *old; - - size = (size_t)(state->sponge.r) > key_length ? (size_t)(state->sponge.r) : key_length; - new_key_length = size; - size = (size + 7) >> 3; - key_bytes = (key_length + 7) >> 3; - - if (size != key_bytes) { - state->key_opad = realloc(old = state->key_opad, 2 * size); - if (!state->key_opad) - return state->key_opad = old, -1; - state->key_ipad = state->key_opad + size / sizeof(char); - } - - memcpy(state->key_opad, key, key_bytes); - if (key_length & 7) - state->key_opad[(key_bytes >> 3) - 1] &= (char)((1 << (key_length & 7)) - 1); - - if ((size_t)(state->sponge.r) > key_length) - __builtin_memset(state->key_opad + key_bytes / sizeof(char), 0, size - key_bytes); - - for (i = 0; i < size; i++) { - state->key_ipad[i] = state->key_opad[i] ^ INNER_PAD; - state->key_opad[i] ^= OUTER_PAD; - } - - state->key_length = new_key_length; - - return 0; -} - - -/** - * Wipe sensitive data wihout freeing any data - * - * @param state The state that should be wipe - */ -void -libkeccak_hmac_wipe(volatile libkeccak_hmac_state_t *restrict state) -{ - volatile char *restrict key_pads; - size_t i, size; - key_pads = state->key_opad; - size = 2 * ((state->key_length + 7) >> 3); - libkeccak_state_wipe(&state->sponge); - for (i = 0; i < size; i++) - key_pads[i] = 0; - state->leftover = 0; - __builtin_memset(state->buffer, 0, state->buffer_size); -} - - -/** - * Make a copy of an HMAC hashing-state - * - * @param dest The slot for the duplicate, must not be initialised (memory leak otherwise) - * @param src The state to duplicate - * @return Zero on success, -1 on error - */ -int -libkeccak_hmac_copy(libkeccak_hmac_state_t *restrict dest, const libkeccak_hmac_state_t *restrict src) -{ - size_t size; - - dest->key_opad = NULL; - dest->key_ipad = NULL; - - if (libkeccak_state_copy(&dest->sponge, &src->sponge) < 0) - return -1; - - dest->key_length = src->key_length; - dest->leftover = src->leftover; - - size = (src->key_length + 7) >> 3; - dest->key_opad = malloc(2 * size); - if (dest->key_opad == NULL) - return libkeccak_state_destroy(&dest->sponge), -1; - dest->key_ipad = dest->key_opad + size / sizeof(char); - - memcpy(dest->key_opad, src->key_opad, size); - memcpy(dest->key_ipad, src->key_ipad, size); - - return 0; -} - - -/** - * Unmarshal a `libkeccak_hmac_state_t` from a buffer - * - * @param state The slot for the unmarshalled state, must not be initialised (memory leak otherwise) - * @param data The input buffer - * @return The number of bytes read from `data`, 0 on error - */ -size_t -libkeccak_hmac_unmarshal(libkeccak_hmac_state_t *restrict state, const void *restrict data_) -{ - const char *restrict data = data_; - size_t parsed, size, i; - - state->key_opad = NULL; - state->key_ipad = NULL; - - parsed = libkeccak_state_unmarshal(&state->sponge, data); - if (parsed == 0) - return 0; - - data += parsed / sizeof(char); - state->key_length = *(const size_t *)data; - data += sizeof(size_t) / sizeof(char); - size = (state->key_length + 7) >> 3; - - state->key_opad = malloc(2 * size); - if (!state->key_opad) { - libkeccak_state_destroy(&state->sponge); - return 0; - } - memcpy(state->key_opad, data, size); - data += size / sizeof(char); - - if (data[0]) { - state->key_ipad = state->key_opad + size / sizeof(char); - memcpy(state->key_ipad, state->key_opad, size); - for (i = 0; i < size / sizeof(char); i++) - state->key_ipad[i] ^= (char)(OUTER_PAD ^ INNER_PAD); - } - - state->leftover = data[1]; - state->buffer = NULL; - state->buffer_size = 0; - - return parsed + sizeof(size_t) + size + 2 * sizeof(char); -} - - -/** - * Absorb more, or the first part, of the message - * without wiping sensitive data when possible - * - * @param state The hashing state - * @param msg The partial message - * @param msglen The length of the partial message, in bytes - * @return Zero on success, -1 on error - */ -int -libkeccak_hmac_fast_update(libkeccak_hmac_state_t *restrict state, const void *restrict msg_, size_t msglen) -{ - const char *restrict msg = msg_; - char *old; - size_t i; - int n, cn; - - if (state->key_ipad) { - if (libkeccak_fast_update(&state->sponge, state->key_ipad, state->key_length >> 3) < 0) - return -1; - if (state->key_length & 7) - state->leftover = state->key_ipad[state->key_length >> 3]; - state->key_ipad = NULL; - } - - if (!msg || !msglen) - return 0; - - if (!(state->key_length & 7)) - return libkeccak_fast_update(&state->sponge, msg, msglen); - - if (msglen != state->buffer_size) { - state->buffer = realloc(old = state->buffer, msglen); - if (!state->buffer) - return state->buffer = old, -1; - state->buffer_size = msglen; - } - - n = (int)(state->key_length & 7); - cn = 8 - n; - for (i = 1; i < msglen; i++) - state->buffer[i] = (char)((msg[i - 1] >> cn) | (msg[i] << n)); - state->buffer[0] = (char)((state->leftover & ((1 << n) - 1)) | (msg[0] << n)); - state->leftover = (char)((unsigned char)msg[msglen - 1] >> cn); - - return libkeccak_fast_update(&state->sponge, state->buffer, msglen); -} - - -/** - * Absorb more, or the first part, of the message - * and wipe sensitive data when possible - * - * @param state The hashing state - * @param msg The partial message - * @param msglen The length of the partial message, in bytes - * @return Zero on success, -1 on error - */ -int -libkeccak_hmac_update(libkeccak_hmac_state_t *restrict state, const void *restrict msg_, size_t msglen) -{ - const char *restrict msg = msg_; - size_t i; - int n, cn, r; - - if (state->key_ipad) { - if (libkeccak_update(&state->sponge, state->key_ipad, state->key_length >> 3) < 0) - return -1; - if (state->key_length & 7) - state->leftover = state->key_ipad[state->key_length >> 3]; - state->key_ipad = NULL; - } - - if (!msg || !msglen) - return 0; - - if (!(state->key_length & 7)) - return libkeccak_update(&state->sponge, msg, msglen); - - if (msglen != state->buffer_size) { - free(state->buffer); - state->buffer = malloc(state->buffer_size = msglen); - if (!state->buffer) - return -1; - } - - n = (int)(state->key_length & 7); - cn = 8 - n; - for (i = 1; i < msglen; i++) - state->buffer[i] = (char)(((unsigned char)msg[i - 1] >> cn) | (msg[i] << n)); - state->buffer[0] = (char)((state->leftover & ((1 << n) - 1)) | (msg[0] << n)); - state->leftover = (char)((unsigned char)msg[msglen - 1] >> cn); - - r = libkeccak_update(&state->sponge, state->buffer, msglen); - my_explicit_bzero(state->buffer, msglen); - return r; -} - - -/** - * Absorb the last part of the message and fetch the hash - * without wiping sensitive data when possible - * - * You may use `&state->sponge` for continued squeezing - * - * @param state The hashing state - * @param msg The rest of the message, may be `NULL`, may be modified - * @param msglen The length of the partial message - * @param bits The number of bits at the end of the message not covered by `msglen` - * @param suffix The suffix concatenate to the message, only '1':s and '0':s, and NUL-termination - * @param hashsum Output parameter for the hashsum, may be `NULL` - * @return Zero on success, -1 on error - */ -int -libkeccak_hmac_fast_digest(libkeccak_hmac_state_t *restrict state, const void *restrict msg_, size_t msglen, - size_t bits, const char *restrict suffix, void *restrict hashsum) -{ - const char *restrict msg = msg_; - size_t hashsize = (size_t)state->sponge.n >> 3; - char *tmp = malloc((size_t)((state->sponge.n + 7) >> 3) * sizeof(char)); - char leftover[2]; - size_t newlen; - - if (!tmp) - return -1; - - if (!(state->key_length & 7)) { - if (libkeccak_fast_digest(&state->sponge, msg, msglen, bits, suffix, tmp) < 0) - goto fail; - goto stage_2; - } - - if (libkeccak_hmac_fast_update(state, msg, msglen) < 0) - goto fail; - leftover[0] = state->leftover; - if (bits) { - leftover[0] |= (char)(msg[msglen] >> (state->key_length & 7)); - leftover[1] = (char)((unsigned char)msg[msglen] << (8 - (state->key_length & 7))); - } - newlen = (state->key_length & 7) + bits; - if (libkeccak_fast_digest(&state->sponge, leftover, newlen >> 3, newlen & 7, suffix, tmp) < 0) - goto fail; - -stage_2: - bits = state->sponge.n & 7; - state->key_ipad = state->key_opad; - if (libkeccak_hmac_fast_update(state, NULL, 0) < 0) - goto fail; - - if (!(state->key_length & 7)) { - if (libkeccak_fast_digest(&state->sponge, tmp, hashsize, bits, suffix, hashsum) < 0) - goto fail; - goto stage_3; - } - - if (libkeccak_hmac_fast_update(state, tmp, hashsize) < 0) - goto fail; - leftover[0] = state->leftover; - if (bits) { - leftover[0] |= (char)(tmp[hashsize] >> (state->key_length & 7)); - leftover[1] = (char)((unsigned char)tmp[hashsize] << (8 - (state->key_length & 7))); - } - newlen = (state->key_length & 7) + bits; - if (libkeccak_fast_digest(&state->sponge, leftover, newlen >> 3, newlen & 7, suffix, tmp) < 0) - goto fail; - -stage_3: - free(tmp); - return 0; -fail: - free(tmp); - return -1; -} - - -/** - * Absorb the last part of the message and fetch the hash - * and wipe sensitive data when possible - * - * You may use `&state->sponge` for continued squeezing - * - * @param state The hashing state - * @param msg The rest of the message, may be `NULL`, may be modified - * @param msglen The length of the partial message - * @param bits The number of bits at the end of the message not covered by `msglen` - * @param suffix The suffix concatenate to the message, only '1':s and '0':s, and NUL-termination - * @param hashsum Output parameter for the hashsum, may be `NULL` - * @return Zero on success, -1 on error - */ -int -libkeccak_hmac_digest(libkeccak_hmac_state_t *restrict state, const void *restrict msg_, size_t msglen, - size_t bits, const char *restrict suffix, void *restrict hashsum) -{ - const char *restrict msg = msg_; - size_t hashsize = (size_t)(state->sponge.n >> 3); - char *tmp = malloc((size_t)((state->sponge.n + 7) >> 3) * sizeof(char)); - char leftover[2]; - size_t newlen; - - if (!tmp) - return -1; - - if (!(state->key_length & 7)) { - if (libkeccak_digest(&state->sponge, msg, msglen, bits, suffix, tmp) < 0) - goto fail; - goto stage_2; - } - - if (libkeccak_hmac_update(state, msg, msglen) < 0) - goto fail; - leftover[0] = state->leftover; - if (bits) { - leftover[0] |= (char)(msg[msglen] >> (state->key_length & 7)); - leftover[1] = (char)((unsigned char)msg[msglen] << (8 - (state->key_length & 7))); - } - newlen = (state->key_length & 7) + bits; - if (libkeccak_digest(&state->sponge, leftover, newlen >> 3, newlen & 7, suffix, tmp) < 0) - goto fail; - -stage_2: - bits = state->sponge.n & 7; - state->key_ipad = state->key_opad; - if (libkeccak_hmac_update(state, NULL, 0) < 0) - goto fail; - - if (!(state->key_length & 7)) { - if (libkeccak_digest(&state->sponge, tmp, hashsize, bits, suffix, hashsum) < 0) - goto fail; - goto stage_3; - } - - if (libkeccak_hmac_update(state, tmp, hashsize) < 0) - goto fail; - leftover[0] = state->leftover; - if (bits) { - leftover[0] |= (char)(tmp[hashsize] >> (state->key_length & 7)); - leftover[1] = (char)((unsigned char)tmp[hashsize] << (8 - (state->key_length & 7))); - } - newlen = (state->key_length & 7) + bits; - if (libkeccak_digest(&state->sponge, leftover, newlen >> 3, newlen & 7, suffix, tmp) < 0) - goto fail; - -stage_3: - my_explicit_bzero(tmp, (size_t)((state->sponge.n + 7) >> 3) * sizeof(char)); - free(tmp); - return 0; -fail: - my_explicit_bzero(tmp, (size_t)((state->sponge.n + 7) >> 3) * sizeof(char)); - free(tmp); - return -1; -} - diff --git a/libkeccak/state.c b/libkeccak/state.c deleted file mode 100644 index 9e0ffb1..0000000 --- a/libkeccak/state.c +++ /dev/null @@ -1,174 +0,0 @@ -/* See LICENSE file for copyright and license details. */ -#include "../common.h" - - -/** - * Initialise a state according to hashing specifications - * - * @param state The state that should be initialised - * @param spec The specifications for the state - * @return Zero on success, -1 on error - */ -int -libkeccak_state_initialise(libkeccak_state_t *restrict state, const libkeccak_spec_t *restrict spec) -{ - long int x; - state->r = spec->bitrate; - state->n = spec->output; - state->c = spec->capacity; - state->b = state->r + state->c; - state->w = x = state->b / 25; - state->l = 0; - if (x & 0xF0L) state->l |= 4, x >>= 4; - if (x & 0x0CL) state->l |= 2, x >>= 2; - if (x & 0x02L) state->l |= 1; - state->nr = 12 + (state->l << 1); - state->wmod = (state->w == 64) ? ~0LL : (int64_t)((1ULL << state->w) - 1); - for (x = 0; x < 25; x++) - state->S[x] = 0; - state->mptr = 0; - state->mlen = (size_t)(state->r * state->b) >> 2; - state->M = malloc(state->mlen * sizeof(char)); - return state->M == NULL ? -1 : 0; -} - - -/** - * Wipe data in the state's message wihout freeing any data - * - * @param state The state that should be wipe - */ -void -libkeccak_state_wipe_message(volatile libkeccak_state_t *restrict state) -{ - volatile char *restrict M = state->M; - size_t i; - for (i = 0; i < state->mptr; i++) - M[i] = 0; -} - -/** - * Wipe data in the state's sponge wihout freeing any data - * - * @param state The state that should be wipe - */ -void -libkeccak_state_wipe_sponge(volatile libkeccak_state_t *restrict state) -{ - volatile int64_t *restrict S = state->S; - size_t i; - for (i = 0; i < 25; i++) - S[i] = 0; -} - -/** - * Wipe sensitive data wihout freeing any data - * - * @param state The state that should be wipe - */ -void -libkeccak_state_wipe(volatile libkeccak_state_t *restrict state) -{ - libkeccak_state_wipe_message(state); - libkeccak_state_wipe_sponge(state); -} - - -/** - * Make a copy of a state - * - * @param dest The slot for the duplicate, must not be initialised (memory leak otherwise) - * @param src The state to duplicate - * @return Zero on success, -1 on error - */ -int -libkeccak_state_copy(libkeccak_state_t *restrict dest, const libkeccak_state_t *restrict src) -{ - memcpy(dest, src, sizeof(libkeccak_state_t)); - dest->M = malloc(src->mlen * sizeof(char)); - if (!dest->M) - return -1; - memcpy(dest->M, src->M, src->mptr * sizeof(char)); - return 0; -} - - -/** - * Marshal a `libkeccak_state_t` into a buffer - * - * @param state The state to marshal - * @param data The output buffer - * @return The number of bytes stored to `data` - */ -size_t -libkeccak_state_marshal(const libkeccak_state_t *restrict state, void *restrict data_) -{ -#define set(type, var) *((type *)data) = state->var, data += sizeof(type) / sizeof(char) - char *restrict data = data_; - set(long int, r); - set(long int, c); - set(long int, n); - set(long int, b); - set(long int, w); - set(int64_t, wmod); - set(long int, l); - set(long int, nr); - memcpy(data, state->S, sizeof(state->S)); - data += sizeof(state->S) / sizeof(char); - set(size_t, mptr); - set(size_t, mlen); - memcpy(data, state->M, state->mptr * sizeof(char)); - data += state->mptr; - return sizeof(libkeccak_state_t) - sizeof(char *) + state->mptr * sizeof(char); -#undef set -} - - -/** - * Unmarshal a `libkeccak_state_t` from a buffer - * - * @param state The slot for the unmarshalled state, must not be initialised (memory leak otherwise) - * @param data The input buffer - * @return The number of bytes read from `data`, 0 on error - */ -size_t -libkeccak_state_unmarshal(libkeccak_state_t *restrict state, const void *restrict data_) -{ -#define get(type, var) state->var = *((const type *)data), data += sizeof(type) / sizeof(char) - const char *restrict data = data_; - get(long int, r); - get(long int, c); - get(long int, n); - get(long int, b); - get(long int, w); - get(int64_t, wmod); - get(long int, l); - get(long int, nr); - memcpy(state->S, data, sizeof(state->S)); - data += sizeof(state->S) / sizeof(char); - get(size_t, mptr); - get(size_t, mlen); - state->M = malloc(state->mptr * sizeof(char)); - if (!state->M) - return 0; - memcpy(state->M, data, state->mptr * sizeof(char)); - data += state->mptr; - return sizeof(libkeccak_state_t) - sizeof(char *) + state->mptr * sizeof(char); -#undef get -} - - -/** - * Gets the number of bytes the `libkeccak_state_t` stored - * at the beginning of `data` occupies - * - * @param data The data buffer - * @return The byte size of the stored state - */ -size_t -libkeccak_state_unmarshal_skip(const void *restrict data_) -{ - const char *restrict data = data_; - data += (7 * sizeof(long int) + 26 * sizeof(int64_t)) / sizeof(char); - return sizeof(libkeccak_state_t) - sizeof(char *) + *(const size_t *)data * sizeof(char); -} diff --git a/man3/libkeccak_behex_lower.3 b/libkeccak_behex_lower.3 index 2078790..2078790 100644 --- a/man3/libkeccak_behex_lower.3 +++ b/libkeccak_behex_lower.3 diff --git a/libkeccak_behex_lower.c b/libkeccak_behex_lower.c new file mode 100644 index 0000000..77e48c1 --- /dev/null +++ b/libkeccak_behex_lower.c @@ -0,0 +1,21 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +/** + * Convert a binary hashsum to lower case hexadecimal representation + * + * @param output Output array, should have an allocation size of at least `2 * n + 1` + * @param hashsum The hashsum to convert + * @param n The size of `hashsum` + */ +void +libkeccak_behex_lower(char *restrict output, const void *restrict hashsum_, size_t n) +{ + const unsigned char *restrict hashsum = hashsum_; + output[2 * n] = '\0'; + while (n--) { + output[2 * n + 0] = "0123456789abcdef"[(hashsum[n] >> 4) & 15]; + output[2 * n + 1] = "0123456789abcdef"[(hashsum[n] >> 0) & 15]; + } +} diff --git a/man3/libkeccak_behex_upper.3 b/libkeccak_behex_upper.3 index b5c67bb..b5c67bb 100644 --- a/man3/libkeccak_behex_upper.3 +++ b/libkeccak_behex_upper.3 diff --git a/libkeccak_behex_upper.c b/libkeccak_behex_upper.c new file mode 100644 index 0000000..73a67a1 --- /dev/null +++ b/libkeccak_behex_upper.c @@ -0,0 +1,21 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +/** + * Convert a binary hashsum to upper case hexadecimal representation + * + * @param output Output array, should have an allocation size of at least `2 * n + 1` + * @param hashsum The hashsum to convert + * @param n The size of `hashsum` + */ +void +libkeccak_behex_upper(char *restrict output, const void *restrict hashsum_, size_t n) +{ + const unsigned char *restrict hashsum = hashsum_; + output[2 * n] = '\0'; + while (n--) { + output[2 * n + 0] = "0123456789ABCDEF"[(hashsum[n] >> 4) & 15]; + output[2 * n + 1] = "0123456789ABCDEF"[(hashsum[n] >> 0) & 15]; + } +} diff --git a/man3/libkeccak_degeneralise_spec.3 b/libkeccak_degeneralise_spec.3 index 7ec2b72..7ec2b72 100644 --- a/man3/libkeccak_degeneralise_spec.3 +++ b/libkeccak_degeneralise_spec.3 diff --git a/libkeccak/generalised-spec.c b/libkeccak_degeneralise_spec.c index 0f78583..13963f8 100644 --- a/libkeccak/generalised-spec.c +++ b/libkeccak_degeneralise_spec.c @@ -1,5 +1,5 @@ /* See LICENSE file for copyright and license details. */ -#include "../common.h" +#include "common.h" #ifdef __GNUC__ @@ -12,7 +12,6 @@ #define deft(v, dv) (have_##v ? v : (dv)) - /** * Convert a `libkeccak_generalised_spec_t` to a `libkeccak_spec_t` * diff --git a/man3/libkeccak_digest.3 b/libkeccak_digest.3 index 5f42796..5f42796 100644 --- a/man3/libkeccak_digest.3 +++ b/libkeccak_digest.3 diff --git a/man3/libkeccak_fast_digest.3 b/libkeccak_fast_digest.3 index 9e9c1f3..9e9c1f3 100644 --- a/man3/libkeccak_fast_digest.3 +++ b/libkeccak_fast_digest.3 diff --git a/man3/libkeccak_fast_squeeze.3 b/libkeccak_fast_squeeze.3 index 393e264..393e264 100644 --- a/man3/libkeccak_fast_squeeze.3 +++ b/libkeccak_fast_squeeze.3 diff --git a/man3/libkeccak_fast_update.3 b/libkeccak_fast_update.3 index 3398984..3398984 100644 --- a/man3/libkeccak_fast_update.3 +++ b/libkeccak_fast_update.3 diff --git a/man3/libkeccak_generalised_spec_initialise.3 b/libkeccak_generalised_spec_initialise.3 index 1a3bccb..1a3bccb 100644 --- a/man3/libkeccak_generalised_spec_initialise.3 +++ b/libkeccak_generalised_spec_initialise.3 diff --git a/man3/libkeccak_generalised_sum_fd.3 b/libkeccak_generalised_sum_fd.3 index bae5bae..bae5bae 100644 --- a/man3/libkeccak_generalised_sum_fd.3 +++ b/libkeccak_generalised_sum_fd.3 diff --git a/libkeccak/files.c b/libkeccak_generalised_sum_fd.c index 14a4290..133ffa9 100644 --- a/libkeccak/files.c +++ b/libkeccak_generalised_sum_fd.c @@ -1,5 +1,5 @@ /* See LICENSE file for copyright and license details. */ -#include "../common.h" +#include "common.h" /** diff --git a/man3/libkeccak_hmac_copy.3 b/libkeccak_hmac_copy.3 index 0f29ae8..0f29ae8 100644 --- a/man3/libkeccak_hmac_copy.3 +++ b/libkeccak_hmac_copy.3 diff --git a/libkeccak_hmac_copy.c b/libkeccak_hmac_copy.c new file mode 100644 index 0000000..49fc1e7 --- /dev/null +++ b/libkeccak_hmac_copy.c @@ -0,0 +1,38 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +/** + * Make a copy of an HMAC hashing-state + * + * @param dest The slot for the duplicate, must not be initialised (memory leak otherwise) + * @param src The state to duplicate + * @return Zero on success, -1 on error + */ +int +libkeccak_hmac_copy(libkeccak_hmac_state_t *restrict dest, const libkeccak_hmac_state_t *restrict src) +{ + size_t size; + + dest->key_opad = NULL; + dest->key_ipad = NULL; + + if (libkeccak_state_copy(&dest->sponge, &src->sponge) < 0) + return -1; + + dest->key_length = src->key_length; + dest->leftover = src->leftover; + + size = (src->key_length + 7) >> 3; + dest->key_opad = malloc(2 * size); + if (dest->key_opad == NULL) { + libkeccak_state_destroy(&dest->sponge); + return -1; + } + dest->key_ipad = dest->key_opad + size / sizeof(char); + + memcpy(dest->key_opad, src->key_opad, size); + memcpy(dest->key_ipad, src->key_ipad, size); + + return 0; +} diff --git a/man3/libkeccak_hmac_create.3 b/libkeccak_hmac_create.3 index 91bb8a1..91bb8a1 100644 --- a/man3/libkeccak_hmac_create.3 +++ b/libkeccak_hmac_create.3 diff --git a/man3/libkeccak_hmac_destroy.3 b/libkeccak_hmac_destroy.3 index 0038eca..0038eca 100644 --- a/man3/libkeccak_hmac_destroy.3 +++ b/libkeccak_hmac_destroy.3 diff --git a/man3/libkeccak_hmac_digest.3 b/libkeccak_hmac_digest.3 index 99e460a..99e460a 100644 --- a/man3/libkeccak_hmac_digest.3 +++ b/libkeccak_hmac_digest.3 diff --git a/libkeccak_hmac_digest.c b/libkeccak_hmac_digest.c new file mode 100644 index 0000000..1cba224 --- /dev/null +++ b/libkeccak_hmac_digest.c @@ -0,0 +1,80 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +/** + * Absorb the last part of the message and fetch the hash + * and wipe sensitive data when possible + * + * You may use `&state->sponge` for continued squeezing + * + * @param state The hashing state + * @param msg The rest of the message, may be `NULL`, may be modified + * @param msglen The length of the partial message + * @param bits The number of bits at the end of the message not covered by `msglen` + * @param suffix The suffix concatenate to the message, only '1':s and '0':s, and NUL-termination + * @param hashsum Output parameter for the hashsum, may be `NULL` + * @return Zero on success, -1 on error + */ +int +libkeccak_hmac_digest(libkeccak_hmac_state_t *restrict state, const void *restrict msg_, size_t msglen, + size_t bits, const char *restrict suffix, void *restrict hashsum) +{ + const char *restrict msg = msg_; + size_t hashsize = (size_t)(state->sponge.n >> 3); + char *tmp = malloc((size_t)((state->sponge.n + 7) >> 3) * sizeof(char)); + char leftover[2]; + size_t newlen; + + if (!tmp) + return -1; + + if (!(state->key_length & 7)) { + if (libkeccak_digest(&state->sponge, msg, msglen, bits, suffix, tmp) < 0) + goto fail; + goto stage_2; + } + + if (libkeccak_hmac_update(state, msg, msglen) < 0) + goto fail; + leftover[0] = state->leftover; + if (bits) { + leftover[0] |= (char)(msg[msglen] >> (state->key_length & 7)); + leftover[1] = (char)((unsigned char)msg[msglen] << (8 - (state->key_length & 7))); + } + newlen = (state->key_length & 7) + bits; + if (libkeccak_digest(&state->sponge, leftover, newlen >> 3, newlen & 7, suffix, tmp) < 0) + goto fail; + +stage_2: + bits = state->sponge.n & 7; + state->key_ipad = state->key_opad; + if (libkeccak_hmac_update(state, NULL, 0) < 0) + goto fail; + + if (!(state->key_length & 7)) { + if (libkeccak_digest(&state->sponge, tmp, hashsize, bits, suffix, hashsum) < 0) + goto fail; + goto stage_3; + } + + if (libkeccak_hmac_update(state, tmp, hashsize) < 0) + goto fail; + leftover[0] = state->leftover; + if (bits) { + leftover[0] |= (char)(tmp[hashsize] >> (state->key_length & 7)); + leftover[1] = (char)((unsigned char)tmp[hashsize] << (8 - (state->key_length & 7))); + } + newlen = (state->key_length & 7) + bits; + if (libkeccak_digest(&state->sponge, leftover, newlen >> 3, newlen & 7, suffix, tmp) < 0) + goto fail; + +stage_3: + my_explicit_bzero(tmp, (size_t)((state->sponge.n + 7) >> 3) * sizeof(char)); + free(tmp); + return 0; +fail: + my_explicit_bzero(tmp, (size_t)((state->sponge.n + 7) >> 3) * sizeof(char)); + free(tmp); + return -1; +} diff --git a/man3/libkeccak_hmac_duplicate.3 b/libkeccak_hmac_duplicate.3 index bb16139..bb16139 100644 --- a/man3/libkeccak_hmac_duplicate.3 +++ b/libkeccak_hmac_duplicate.3 diff --git a/man3/libkeccak_hmac_fast_destroy.3 b/libkeccak_hmac_fast_destroy.3 index 31bf894..31bf894 100644 --- a/man3/libkeccak_hmac_fast_destroy.3 +++ b/libkeccak_hmac_fast_destroy.3 diff --git a/man3/libkeccak_hmac_fast_digest.3 b/libkeccak_hmac_fast_digest.3 index 68fcc69..68fcc69 100644 --- a/man3/libkeccak_hmac_fast_digest.3 +++ b/libkeccak_hmac_fast_digest.3 diff --git a/libkeccak_hmac_fast_digest.c b/libkeccak_hmac_fast_digest.c new file mode 100644 index 0000000..d4bacb8 --- /dev/null +++ b/libkeccak_hmac_fast_digest.c @@ -0,0 +1,78 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +/** + * Absorb the last part of the message and fetch the hash + * without wiping sensitive data when possible + * + * You may use `&state->sponge` for continued squeezing + * + * @param state The hashing state + * @param msg The rest of the message, may be `NULL`, may be modified + * @param msglen The length of the partial message + * @param bits The number of bits at the end of the message not covered by `msglen` + * @param suffix The suffix concatenate to the message, only '1':s and '0':s, and NUL-termination + * @param hashsum Output parameter for the hashsum, may be `NULL` + * @return Zero on success, -1 on error + */ +int +libkeccak_hmac_fast_digest(libkeccak_hmac_state_t *restrict state, const void *restrict msg_, size_t msglen, + size_t bits, const char *restrict suffix, void *restrict hashsum) +{ + const char *restrict msg = msg_; + size_t hashsize = (size_t)state->sponge.n >> 3; + char *tmp = malloc((size_t)((state->sponge.n + 7) >> 3) * sizeof(char)); + char leftover[2]; + size_t newlen; + + if (!tmp) + return -1; + + if (!(state->key_length & 7)) { + if (libkeccak_fast_digest(&state->sponge, msg, msglen, bits, suffix, tmp) < 0) + goto fail; + goto stage_2; + } + + if (libkeccak_hmac_fast_update(state, msg, msglen) < 0) + goto fail; + leftover[0] = state->leftover; + if (bits) { + leftover[0] |= (char)(msg[msglen] >> (state->key_length & 7)); + leftover[1] = (char)((unsigned char)msg[msglen] << (8 - (state->key_length & 7))); + } + newlen = (state->key_length & 7) + bits; + if (libkeccak_fast_digest(&state->sponge, leftover, newlen >> 3, newlen & 7, suffix, tmp) < 0) + goto fail; + +stage_2: + bits = state->sponge.n & 7; + state->key_ipad = state->key_opad; + if (libkeccak_hmac_fast_update(state, NULL, 0) < 0) + goto fail; + + if (!(state->key_length & 7)) { + if (libkeccak_fast_digest(&state->sponge, tmp, hashsize, bits, suffix, hashsum) < 0) + goto fail; + goto stage_3; + } + + if (libkeccak_hmac_fast_update(state, tmp, hashsize) < 0) + goto fail; + leftover[0] = state->leftover; + if (bits) { + leftover[0] |= (char)(tmp[hashsize] >> (state->key_length & 7)); + leftover[1] = (char)((unsigned char)tmp[hashsize] << (8 - (state->key_length & 7))); + } + newlen = (state->key_length & 7) + bits; + if (libkeccak_fast_digest(&state->sponge, leftover, newlen >> 3, newlen & 7, suffix, tmp) < 0) + goto fail; + +stage_3: + free(tmp); + return 0; +fail: + free(tmp); + return -1; +} diff --git a/man3/libkeccak_hmac_fast_free.3 b/libkeccak_hmac_fast_free.3 index f888872..f888872 100644 --- a/man3/libkeccak_hmac_fast_free.3 +++ b/libkeccak_hmac_fast_free.3 diff --git a/man3/libkeccak_hmac_fast_update.3 b/libkeccak_hmac_fast_update.3 index a41b72f..a41b72f 100644 --- a/man3/libkeccak_hmac_fast_update.3 +++ b/libkeccak_hmac_fast_update.3 diff --git a/libkeccak_hmac_fast_update.c b/libkeccak_hmac_fast_update.c new file mode 100644 index 0000000..d4a3fbe --- /dev/null +++ b/libkeccak_hmac_fast_update.c @@ -0,0 +1,51 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +/** + * Absorb more, or the first part, of the message + * without wiping sensitive data when possible + * + * @param state The hashing state + * @param msg The partial message + * @param msglen The length of the partial message, in bytes + * @return Zero on success, -1 on error + */ +int +libkeccak_hmac_fast_update(libkeccak_hmac_state_t *restrict state, const void *restrict msg_, size_t msglen) +{ + const char *restrict msg = msg_; + char *old; + size_t i; + int n, cn; + + if (state->key_ipad) { + if (libkeccak_fast_update(&state->sponge, state->key_ipad, state->key_length >> 3) < 0) + return -1; + if (state->key_length & 7) + state->leftover = state->key_ipad[state->key_length >> 3]; + state->key_ipad = NULL; + } + + if (!msg || !msglen) + return 0; + + if (!(state->key_length & 7)) + return libkeccak_fast_update(&state->sponge, msg, msglen); + + if (msglen != state->buffer_size) { + state->buffer = realloc(old = state->buffer, msglen); + if (!state->buffer) + return state->buffer = old, -1; + state->buffer_size = msglen; + } + + n = (int)(state->key_length & 7); + cn = 8 - n; + for (i = 1; i < msglen; i++) + state->buffer[i] = (char)((msg[i - 1] >> cn) | (msg[i] << n)); + state->buffer[0] = (char)((state->leftover & ((1 << n) - 1)) | (msg[0] << n)); + state->leftover = (char)((unsigned char)msg[msglen - 1] >> cn); + + return libkeccak_fast_update(&state->sponge, state->buffer, msglen); +} diff --git a/man3/libkeccak_hmac_free.3 b/libkeccak_hmac_free.3 index c70f369..c70f369 100644 --- a/man3/libkeccak_hmac_free.3 +++ b/libkeccak_hmac_free.3 diff --git a/man3/libkeccak_hmac_initialise.3 b/libkeccak_hmac_initialise.3 index 17b2b9f..17b2b9f 100644 --- a/man3/libkeccak_hmac_initialise.3 +++ b/libkeccak_hmac_initialise.3 diff --git a/man3/libkeccak_hmac_marshal.3 b/libkeccak_hmac_marshal.3 index 2e31dd7..2e31dd7 100644 --- a/man3/libkeccak_hmac_marshal.3 +++ b/libkeccak_hmac_marshal.3 diff --git a/man3/libkeccak_hmac_marshal_size.3 b/libkeccak_hmac_marshal_size.3 index fe8ec2f..fe8ec2f 100644 --- a/man3/libkeccak_hmac_marshal_size.3 +++ b/libkeccak_hmac_marshal_size.3 diff --git a/man3/libkeccak_hmac_reset.3 b/libkeccak_hmac_reset.3 index 4a9aadf..4a9aadf 100644 --- a/man3/libkeccak_hmac_reset.3 +++ b/libkeccak_hmac_reset.3 diff --git a/man3/libkeccak_hmac_set_key.3 b/libkeccak_hmac_set_key.3 index ea8084e..ea8084e 100644 --- a/man3/libkeccak_hmac_set_key.3 +++ b/libkeccak_hmac_set_key.3 diff --git a/libkeccak_hmac_set_key.c b/libkeccak_hmac_set_key.c new file mode 100644 index 0000000..4f450f8 --- /dev/null +++ b/libkeccak_hmac_set_key.c @@ -0,0 +1,46 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +/** + * Change the HMAC-hashing key on the state + * + * @param state The state that should be reset + * @param key The new key + * @param key_length The length of key, in bits + * @return Zero on success, -1 on error + */ +int +libkeccak_hmac_set_key(libkeccak_hmac_state_t *restrict state, const void *restrict key, size_t key_length) +{ + size_t i, size, new_key_length, key_bytes; + char *old; + + size = (size_t)(state->sponge.r) > key_length ? (size_t)(state->sponge.r) : key_length; + new_key_length = size; + size = (size + 7) >> 3; + key_bytes = (key_length + 7) >> 3; + + if (size != key_bytes) { + state->key_opad = realloc(old = state->key_opad, 2 * size); + if (!state->key_opad) + return state->key_opad = old, -1; + state->key_ipad = state->key_opad + size / sizeof(char); + } + + memcpy(state->key_opad, key, key_bytes); + if (key_length & 7) + state->key_opad[(key_bytes >> 3) - 1] &= (char)((1 << (key_length & 7)) - 1); + + if ((size_t)(state->sponge.r) > key_length) + __builtin_memset(state->key_opad + key_bytes / sizeof(char), 0, size - key_bytes); + + for (i = 0; i < size; i++) { + state->key_ipad[i] = state->key_opad[i] ^ HMAC_INNER_PAD; + state->key_opad[i] ^= HMAC_OUTER_PAD; + } + + state->key_length = new_key_length; + + return 0; +} diff --git a/man3/libkeccak_hmac_unmarshal.3 b/libkeccak_hmac_unmarshal.3 index c3ed187..c3ed187 100644 --- a/man3/libkeccak_hmac_unmarshal.3 +++ b/libkeccak_hmac_unmarshal.3 diff --git a/libkeccak_hmac_unmarshal.c b/libkeccak_hmac_unmarshal.c new file mode 100644 index 0000000..e64cd08 --- /dev/null +++ b/libkeccak_hmac_unmarshal.c @@ -0,0 +1,50 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +/** + * Unmarshal a `libkeccak_hmac_state_t` from a buffer + * + * @param state The slot for the unmarshalled state, must not be initialised (memory leak otherwise) + * @param data The input buffer + * @return The number of bytes read from `data`, 0 on error + */ +size_t +libkeccak_hmac_unmarshal(libkeccak_hmac_state_t *restrict state, const void *restrict data_) +{ + const char *restrict data = data_; + size_t parsed, size, i; + + state->key_opad = NULL; + state->key_ipad = NULL; + + parsed = libkeccak_state_unmarshal(&state->sponge, data); + if (parsed == 0) + return 0; + + data += parsed / sizeof(char); + state->key_length = *(const size_t *)data; + data += sizeof(size_t) / sizeof(char); + size = (state->key_length + 7) >> 3; + + state->key_opad = malloc(2 * size); + if (!state->key_opad) { + libkeccak_state_destroy(&state->sponge); + return 0; + } + memcpy(state->key_opad, data, size); + data += size / sizeof(char); + + if (data[0]) { + state->key_ipad = state->key_opad + size / sizeof(char); + memcpy(state->key_ipad, state->key_opad, size); + for (i = 0; i < size / sizeof(char); i++) + state->key_ipad[i] ^= (char)(HMAC_OUTER_PAD ^ HMAC_INNER_PAD); + } + + state->leftover = data[1]; + state->buffer = NULL; + state->buffer_size = 0; + + return parsed + sizeof(size_t) + size + 2 * sizeof(char); +} diff --git a/man3/libkeccak_hmac_unmarshal_skip.3 b/libkeccak_hmac_unmarshal_skip.3 index 25db1ba..25db1ba 100644 --- a/man3/libkeccak_hmac_unmarshal_skip.3 +++ b/libkeccak_hmac_unmarshal_skip.3 diff --git a/man3/libkeccak_hmac_update.3 b/libkeccak_hmac_update.3 index 13891cb..13891cb 100644 --- a/man3/libkeccak_hmac_update.3 +++ b/libkeccak_hmac_update.3 diff --git a/libkeccak_hmac_update.c b/libkeccak_hmac_update.c new file mode 100644 index 0000000..b2321f2 --- /dev/null +++ b/libkeccak_hmac_update.c @@ -0,0 +1,52 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +/** + * Absorb more, or the first part, of the message + * and wipe sensitive data when possible + * + * @param state The hashing state + * @param msg The partial message + * @param msglen The length of the partial message, in bytes + * @return Zero on success, -1 on error + */ +int +libkeccak_hmac_update(libkeccak_hmac_state_t *restrict state, const void *restrict msg_, size_t msglen) +{ + const char *restrict msg = msg_; + size_t i; + int n, cn, r; + + if (state->key_ipad) { + if (libkeccak_update(&state->sponge, state->key_ipad, state->key_length >> 3) < 0) + return -1; + if (state->key_length & 7) + state->leftover = state->key_ipad[state->key_length >> 3]; + state->key_ipad = NULL; + } + + if (!msg || !msglen) + return 0; + + if (!(state->key_length & 7)) + return libkeccak_update(&state->sponge, msg, msglen); + + if (msglen != state->buffer_size) { + free(state->buffer); + state->buffer = malloc(state->buffer_size = msglen); + if (!state->buffer) + return -1; + } + + n = (int)(state->key_length & 7); + cn = 8 - n; + for (i = 1; i < msglen; i++) + state->buffer[i] = (char)(((unsigned char)msg[i - 1] >> cn) | (msg[i] << n)); + state->buffer[0] = (char)((state->leftover & ((1 << n) - 1)) | (msg[0] << n)); + state->leftover = (char)((unsigned char)msg[msglen - 1] >> cn); + + r = libkeccak_update(&state->sponge, state->buffer, msglen); + my_explicit_bzero(state->buffer, msglen); + return r; +} diff --git a/man3/libkeccak_hmac_wipe.3 b/libkeccak_hmac_wipe.3 index 471a9a8..471a9a8 100644 --- a/man3/libkeccak_hmac_wipe.3 +++ b/libkeccak_hmac_wipe.3 diff --git a/libkeccak_hmac_wipe.c b/libkeccak_hmac_wipe.c new file mode 100644 index 0000000..fd99c48 --- /dev/null +++ b/libkeccak_hmac_wipe.c @@ -0,0 +1,22 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +/** + * Wipe sensitive data wihout freeing any data + * + * @param state The state that should be wipe + */ +void +libkeccak_hmac_wipe(volatile libkeccak_hmac_state_t *restrict state) +{ + volatile char *restrict key_pads; + size_t i, size; + key_pads = state->key_opad; + size = 2 * ((state->key_length + 7) >> 3); + libkeccak_state_wipe(&state->sponge); + for (i = 0; i < size; i++) + key_pads[i] = 0; + state->leftover = 0; + __builtin_memset(state->buffer, 0, state->buffer_size); +} diff --git a/man3/libkeccak_keccaksum_fd.3 b/libkeccak_keccaksum_fd.3 index ccd1f8a..ccd1f8a 100644 --- a/man3/libkeccak_keccaksum_fd.3 +++ b/libkeccak_keccaksum_fd.3 diff --git a/man3/libkeccak_rawshakesum_fd.3 b/libkeccak_rawshakesum_fd.3 index 8fad150..8fad150 100644 --- a/man3/libkeccak_rawshakesum_fd.3 +++ b/libkeccak_rawshakesum_fd.3 diff --git a/man3/libkeccak_sha3sum_fd.3 b/libkeccak_sha3sum_fd.3 index 0d697e6..0d697e6 100644 --- a/man3/libkeccak_sha3sum_fd.3 +++ b/libkeccak_sha3sum_fd.3 diff --git a/man3/libkeccak_shakesum_fd.3 b/libkeccak_shakesum_fd.3 index 441c549..441c549 100644 --- a/man3/libkeccak_shakesum_fd.3 +++ b/libkeccak_shakesum_fd.3 diff --git a/man3/libkeccak_simple_squeeze.3 b/libkeccak_simple_squeeze.3 index 8626f5a..8626f5a 100644 --- a/man3/libkeccak_simple_squeeze.3 +++ b/libkeccak_simple_squeeze.3 diff --git a/man3/libkeccak_spec_check.3 b/libkeccak_spec_check.3 index 7dd19d8..7dd19d8 100644 --- a/man3/libkeccak_spec_check.3 +++ b/libkeccak_spec_check.3 diff --git a/man3/libkeccak_spec_rawshake.3 b/libkeccak_spec_rawshake.3 index f5f16b8..f5f16b8 100644 --- a/man3/libkeccak_spec_rawshake.3 +++ b/libkeccak_spec_rawshake.3 diff --git a/man3/libkeccak_spec_sha3.3 b/libkeccak_spec_sha3.3 index 1320631..1320631 100644 --- a/man3/libkeccak_spec_sha3.3 +++ b/libkeccak_spec_sha3.3 diff --git a/man3/libkeccak_spec_shake.3 b/libkeccak_spec_shake.3 index 4beea49..4beea49 100644 --- a/man3/libkeccak_spec_shake.3 +++ b/libkeccak_spec_shake.3 diff --git a/man3/libkeccak_squeeze.3 b/libkeccak_squeeze.3 index 67430a4..67430a4 100644 --- a/man3/libkeccak_squeeze.3 +++ b/libkeccak_squeeze.3 diff --git a/man3/libkeccak_state_copy.3 b/libkeccak_state_copy.3 index 4bd892c..4bd892c 100644 --- a/man3/libkeccak_state_copy.3 +++ b/libkeccak_state_copy.3 diff --git a/libkeccak_state_copy.c b/libkeccak_state_copy.c new file mode 100644 index 0000000..76672d2 --- /dev/null +++ b/libkeccak_state_copy.c @@ -0,0 +1,21 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +/** + * Make a copy of a state + * + * @param dest The slot for the duplicate, must not be initialised (memory leak otherwise) + * @param src The state to duplicate + * @return Zero on success, -1 on error + */ +int +libkeccak_state_copy(libkeccak_state_t *restrict dest, const libkeccak_state_t *restrict src) +{ + memcpy(dest, src, sizeof(libkeccak_state_t)); + dest->M = malloc(src->mlen * sizeof(char)); + if (!dest->M) + return -1; + memcpy(dest->M, src->M, src->mptr * sizeof(char)); + return 0; +} diff --git a/man3/libkeccak_state_create.3 b/libkeccak_state_create.3 index f27e124..f27e124 100644 --- a/man3/libkeccak_state_create.3 +++ b/libkeccak_state_create.3 diff --git a/man3/libkeccak_state_destroy.3 b/libkeccak_state_destroy.3 index 2df1f49..2df1f49 100644 --- a/man3/libkeccak_state_destroy.3 +++ b/libkeccak_state_destroy.3 diff --git a/man3/libkeccak_state_duplicate.3 b/libkeccak_state_duplicate.3 index dfd0612..dfd0612 100644 --- a/man3/libkeccak_state_duplicate.3 +++ b/libkeccak_state_duplicate.3 diff --git a/man3/libkeccak_state_fast_destroy.3 b/libkeccak_state_fast_destroy.3 index f346611..f346611 100644 --- a/man3/libkeccak_state_fast_destroy.3 +++ b/libkeccak_state_fast_destroy.3 diff --git a/man3/libkeccak_state_fast_free.3 b/libkeccak_state_fast_free.3 index 01d0ed8..01d0ed8 100644 --- a/man3/libkeccak_state_fast_free.3 +++ b/libkeccak_state_fast_free.3 diff --git a/man3/libkeccak_state_free.3 b/libkeccak_state_free.3 index 8761d54..8761d54 100644 --- a/man3/libkeccak_state_free.3 +++ b/libkeccak_state_free.3 diff --git a/man3/libkeccak_state_initialise.3 b/libkeccak_state_initialise.3 index cef4d3d..cef4d3d 100644 --- a/man3/libkeccak_state_initialise.3 +++ b/libkeccak_state_initialise.3 diff --git a/libkeccak_state_initialise.c b/libkeccak_state_initialise.c new file mode 100644 index 0000000..2559f47 --- /dev/null +++ b/libkeccak_state_initialise.c @@ -0,0 +1,33 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +/** + * Initialise a state according to hashing specifications + * + * @param state The state that should be initialised + * @param spec The specifications for the state + * @return Zero on success, -1 on error + */ +int +libkeccak_state_initialise(libkeccak_state_t *restrict state, const libkeccak_spec_t *restrict spec) +{ + long int x; + state->r = spec->bitrate; + state->n = spec->output; + state->c = spec->capacity; + state->b = state->r + state->c; + state->w = x = state->b / 25; + state->l = 0; + if (x & 0xF0L) state->l |= 4, x >>= 4; + if (x & 0x0CL) state->l |= 2, x >>= 2; + if (x & 0x02L) state->l |= 1; + state->nr = 12 + (state->l << 1); + state->wmod = (state->w == 64) ? ~0LL : (int64_t)((1ULL << state->w) - 1); + for (x = 0; x < 25; x++) + state->S[x] = 0; + state->mptr = 0; + state->mlen = (size_t)(state->r * state->b) >> 2; + state->M = malloc(state->mlen * sizeof(char)); + return state->M == NULL ? -1 : 0; +} diff --git a/man3/libkeccak_state_marshal.3 b/libkeccak_state_marshal.3 index ae21d17..ae21d17 100644 --- a/man3/libkeccak_state_marshal.3 +++ b/libkeccak_state_marshal.3 diff --git a/libkeccak_state_marshal.c b/libkeccak_state_marshal.c new file mode 100644 index 0000000..2714a52 --- /dev/null +++ b/libkeccak_state_marshal.c @@ -0,0 +1,33 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +/** + * Marshal a `libkeccak_state_t` into a buffer + * + * @param state The state to marshal + * @param data The output buffer + * @return The number of bytes stored to `data` + */ +size_t +libkeccak_state_marshal(const libkeccak_state_t *restrict state, void *restrict data_) +{ +#define set(type, var) *((type *)data) = state->var, data += sizeof(type) / sizeof(char) + char *restrict data = data_; + set(long int, r); + set(long int, c); + set(long int, n); + set(long int, b); + set(long int, w); + set(int64_t, wmod); + set(long int, l); + set(long int, nr); + memcpy(data, state->S, sizeof(state->S)); + data += sizeof(state->S) / sizeof(char); + set(size_t, mptr); + set(size_t, mlen); + memcpy(data, state->M, state->mptr * sizeof(char)); + data += state->mptr; + return sizeof(libkeccak_state_t) - sizeof(char *) + state->mptr * sizeof(char); +#undef set +} diff --git a/man3/libkeccak_state_marshal_size.3 b/libkeccak_state_marshal_size.3 index 9eca42b..9eca42b 100644 --- a/man3/libkeccak_state_marshal_size.3 +++ b/libkeccak_state_marshal_size.3 diff --git a/man3/libkeccak_state_reset.3 b/libkeccak_state_reset.3 index 566bd6b..566bd6b 100644 --- a/man3/libkeccak_state_reset.3 +++ b/libkeccak_state_reset.3 diff --git a/man3/libkeccak_state_unmarshal.3 b/libkeccak_state_unmarshal.3 index 8643164..8643164 100644 --- a/man3/libkeccak_state_unmarshal.3 +++ b/libkeccak_state_unmarshal.3 diff --git a/libkeccak_state_unmarshal.c b/libkeccak_state_unmarshal.c new file mode 100644 index 0000000..7177bd5 --- /dev/null +++ b/libkeccak_state_unmarshal.c @@ -0,0 +1,36 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +/** + * Unmarshal a `libkeccak_state_t` from a buffer + * + * @param state The slot for the unmarshalled state, must not be initialised (memory leak otherwise) + * @param data The input buffer + * @return The number of bytes read from `data`, 0 on error + */ +size_t +libkeccak_state_unmarshal(libkeccak_state_t *restrict state, const void *restrict data_) +{ +#define get(type, var) state->var = *((const type *)data), data += sizeof(type) / sizeof(char) + const char *restrict data = data_; + get(long int, r); + get(long int, c); + get(long int, n); + get(long int, b); + get(long int, w); + get(int64_t, wmod); + get(long int, l); + get(long int, nr); + memcpy(state->S, data, sizeof(state->S)); + data += sizeof(state->S) / sizeof(char); + get(size_t, mptr); + get(size_t, mlen); + state->M = malloc(state->mptr * sizeof(char)); + if (!state->M) + return 0; + memcpy(state->M, data, state->mptr * sizeof(char)); + data += state->mptr; + return sizeof(libkeccak_state_t) - sizeof(char *) + state->mptr * sizeof(char); +#undef get +} diff --git a/man3/libkeccak_state_unmarshal_skip.3 b/libkeccak_state_unmarshal_skip.3 index 9fb9336..9fb9336 100644 --- a/man3/libkeccak_state_unmarshal_skip.3 +++ b/libkeccak_state_unmarshal_skip.3 diff --git a/libkeccak_state_unmarshal_skip.c b/libkeccak_state_unmarshal_skip.c new file mode 100644 index 0000000..df488bf --- /dev/null +++ b/libkeccak_state_unmarshal_skip.c @@ -0,0 +1,18 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +/** + * Gets the number of bytes the `libkeccak_state_t` stored + * at the beginning of `data` occupies + * + * @param data The data buffer + * @return The byte size of the stored state + */ +size_t +libkeccak_state_unmarshal_skip(const void *restrict data_) +{ + const char *restrict data = data_; + data += (7 * sizeof(long int) + 26 * sizeof(int64_t)) / sizeof(char); + return sizeof(libkeccak_state_t) - sizeof(char *) + *(const size_t *)data * sizeof(char); +} diff --git a/man3/libkeccak_state_wipe.3 b/libkeccak_state_wipe.3 index 1ae2759..1ae2759 100644 --- a/man3/libkeccak_state_wipe.3 +++ b/libkeccak_state_wipe.3 diff --git a/libkeccak_state_wipe.c b/libkeccak_state_wipe.c new file mode 100644 index 0000000..e5c721c --- /dev/null +++ b/libkeccak_state_wipe.c @@ -0,0 +1,15 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +/** + * Wipe sensitive data wihout freeing any data + * + * @param state The state that should be wipe + */ +void +libkeccak_state_wipe(volatile libkeccak_state_t *restrict state) +{ + libkeccak_state_wipe_message(state); + libkeccak_state_wipe_sponge(state); +} diff --git a/man3/libkeccak_state_wipe_message.3 b/libkeccak_state_wipe_message.3 index 7d53afb..7d53afb 100644 --- a/man3/libkeccak_state_wipe_message.3 +++ b/libkeccak_state_wipe_message.3 diff --git a/libkeccak_state_wipe_message.c b/libkeccak_state_wipe_message.c new file mode 100644 index 0000000..d6bc8a0 --- /dev/null +++ b/libkeccak_state_wipe_message.c @@ -0,0 +1,17 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +/** + * Wipe data in the state's message wihout freeing any data + * + * @param state The state that should be wipe + */ +void +libkeccak_state_wipe_message(volatile libkeccak_state_t *restrict state) +{ + volatile char *restrict M = state->M; + size_t i; + for (i = 0; i < state->mptr; i++) + M[i] = 0; +} diff --git a/man3/libkeccak_state_wipe_sponge.3 b/libkeccak_state_wipe_sponge.3 index 31d6c66..31d6c66 100644 --- a/man3/libkeccak_state_wipe_sponge.3 +++ b/libkeccak_state_wipe_sponge.3 diff --git a/libkeccak_state_wipe_sponge.c b/libkeccak_state_wipe_sponge.c new file mode 100644 index 0000000..ad8c29f --- /dev/null +++ b/libkeccak_state_wipe_sponge.c @@ -0,0 +1,17 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +/** + * Wipe data in the state's sponge wihout freeing any data + * + * @param state The state that should be wipe + */ +void +libkeccak_state_wipe_sponge(volatile libkeccak_state_t *restrict state) +{ + volatile int64_t *restrict S = state->S; + size_t i; + for (i = 0; i < 25; i++) + S[i] = 0; +} diff --git a/man3/libkeccak_unhex.3 b/libkeccak_unhex.3 index c7dc9bc..c7dc9bc 100644 --- a/man3/libkeccak_unhex.3 +++ b/libkeccak_unhex.3 diff --git a/libkeccak_unhex.c b/libkeccak_unhex.c new file mode 100644 index 0000000..a12beb1 --- /dev/null +++ b/libkeccak_unhex.c @@ -0,0 +1,29 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +/** + * Convert a hexadecimal hashsum (both lower case, upper + * case and mixed is supported) to binary representation + * + * @param output Output array, should have an allocation size of at least `strlen(hashsum) / 2` + * @param hashsum The hashsum to convert + */ +void +libkeccak_unhex(void *restrict output_, const char *restrict hashsum) +{ + unsigned char *restrict output = output_; + size_t n = strlen(hashsum) / 2; + unsigned char a, b; + while (n--) { + a = (unsigned char)hashsum[2 * n + 0]; + b = (unsigned char)hashsum[2 * n + 1]; + + a = (unsigned char)((a & 15) + (a > '9' ? 9 : 0)); + b = (unsigned char)((b & 15) + (b > '9' ? 9 : 0)); + + a <<= 4; + a |= b; + output[n] = a; + } +} diff --git a/man3/libkeccak_update.3 b/libkeccak_update.3 index 4e9f584..4e9f584 100644 --- a/man3/libkeccak_update.3 +++ b/libkeccak_update.3 |