diff options
-rw-r--r-- | src/benchmark.c | 4 | ||||
-rw-r--r-- | src/libkeccak/digest.c | 117 | ||||
-rw-r--r-- | src/libkeccak/digest.h | 32 | ||||
-rw-r--r-- | src/libkeccak/state.c | 36 | ||||
-rw-r--r-- | src/libkeccak/state.h | 19 |
5 files changed, 193 insertions, 15 deletions
diff --git a/src/benchmark.c b/src/benchmark.c index e126d44..17b2e4b 100644 --- a/src/benchmark.c +++ b/src/benchmark.c @@ -108,12 +108,12 @@ int main(void) /* Updates. */ #if UPDATE_RUNS > 0 for (i = 0; i < UPDATE_RUNS; i++) - if (libkeccak_update(&state, message, MESSAGE_LEN) < 0) + if (libkeccak_fast_update(&state, message, MESSAGE_LEN) < 0) return perror("libkeccak_update"), 1; #endif /* Digest. */ - if (libkeccak_digest(&state, NULL, 0, 0, NULL, hashsum) < 0) + if (libkeccak_fast_digest(&state, NULL, 0, 0, NULL, hashsum) < 0) return perror("libkeccak_digest"), 1; #ifndef IGNORE_BEHEXING libkeccak_behex_lower(hexsum, hashsum, OUTPUT / 8); diff --git a/src/libkeccak/digest.c b/src/libkeccak/digest.c index e001a35..61d0c58 100644 --- a/src/libkeccak/digest.c +++ b/src/libkeccak/digest.c @@ -18,6 +18,8 @@ */ #include "digest.h" +#include "state.h" + /** @@ -362,6 +364,43 @@ void libkeccak_squeezing_phase(register libkeccak_state_t* restrict state, long /** * Absorb more of the message to the Keccak sponge + * without wiping sensitive data when possible + * + * @param state The hashing state + * @param msg The partial message + * @param msglen The length of the partial message + * @return Zero on success, -1 on error + */ +int libkeccak_fast_update(libkeccak_state_t* restrict state, const char* restrict msg, size_t msglen) +{ + size_t len; + auto char* restrict new; + + if (__builtin_expect(state->mptr + msglen > state->mlen, 0)) + { + state->mlen += msglen; + new = realloc(state->M, state->mlen * sizeof(char)); + if (new == NULL) + return state->mlen -= msglen, -1; + state->M = new; + } + + __builtin_memcpy(state->M + state->mptr, msg, msglen * sizeof(char)); + state->mptr += msglen; + len = state->mptr; + len -= state->mptr % (size_t)((state->r * state->b) >> 3); + state->mptr -= len; + + libkeccak_absorption_phase(state, len); + __builtin_memmove(state->M, state->M + len, state->mptr * sizeof(char)); + + return 0; +} + + +/** + * Absorb more of the message to the Keccak sponge + * and wipe sensitive data when possible * * @param state The hashing state * @param msg The partial message @@ -376,9 +415,11 @@ int libkeccak_update(libkeccak_state_t* restrict state, const char* restrict msg if (__builtin_expect(state->mptr + msglen > state->mlen, 0)) { state->mlen += msglen; - new = realloc(state->M, state->mlen * sizeof(char)); /* FIXME insecure */ + new = malloc(state->mlen * sizeof(char)); if (new == NULL) return state->mlen -= msglen, -1; + libkeccak_state_wipe_message(state); + free(state->M); state->M = new; } @@ -397,6 +438,76 @@ int libkeccak_update(libkeccak_state_t* restrict state, const char* restrict msg /** * Absorb the last part of the message and squeeze the Keccak sponge + * without wiping sensitive data when possible + * + * @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 paramter for the hashsum, may be `NULL` + * @return Zero on success, -1 on error + */ +int libkeccak_fast_digest(libkeccak_state_t* restrict state, const char* restrict msg, size_t msglen, + size_t bits, const char* restrict suffix, char* restrict hashsum) +{ + auto char* restrict new; + register long rr = state->r >> 3; + auto size_t suffix_len = suffix ? __builtin_strlen(suffix) : 0; + register size_t ext; + register long i; + + if (msg == NULL) + msglen = bits = 0; + else + msglen += bits >> 3, bits &= 7; + + ext = msglen + ((bits + suffix_len + 7) >> 3) + (size_t)rr; + if (__builtin_expect(state->mptr + ext > state->mlen, 0)) + { + state->mlen += ext; + new = realloc(state->M, state->mlen * sizeof(char)); + if (new == NULL) + return state->mlen -= ext, -1; + state->M = new; + } + + if (msglen) + __builtin_memcpy(state->M + state->mptr, msg, msglen * sizeof(char)); + state->mptr += msglen; + + if (bits) + state->M[state->mptr] = msg[msglen] & (char)((1 << bits) - 1); + if (__builtin_expect(!!suffix_len, 1)) + { + if (bits == 0) + state->M[state->mptr] = 0; + while (suffix_len--) + { + state->M[state->mptr] |= (char)((*suffix++ & 1) << bits++); + if (bits == 8) + bits = 0, state->M[++(state->mptr)] = 0; + } + } + if (bits) + state->mptr++; + + libkeccak_pad10star1(state, bits); + libkeccak_absorption_phase(state, state->mptr); + + if (hashsum != NULL) + libkeccak_squeezing_phase(state, rr, (state->n + 7) >> 3, state->w >> 3, hashsum); + else + for (i = (state->n - 1) / state->r; i--;) + libkeccak_f(state); + + return 0; +} + + +/** + * Absorb the last part of the message and squeeze the Keccak sponge + * and wipe sensitive data when possible * * @param state The hashing state * @param msg The rest of the message, may be `NULL`, may be modified @@ -424,9 +535,11 @@ int libkeccak_digest(libkeccak_state_t* restrict state, const char* restrict msg if (__builtin_expect(state->mptr + ext > state->mlen, 0)) { state->mlen += ext; - new = realloc(state->M, state->mlen * sizeof(char)); /* FIXME insecure */ + new = malloc(state->mlen * sizeof(char)); if (new == NULL) return state->mlen -= ext, -1; + libkeccak_state_wipe_message(state); + free(state->M); state->M = new; } diff --git a/src/libkeccak/digest.h b/src/libkeccak/digest.h index 4d4fe8e..b84370c 100644 --- a/src/libkeccak/digest.h +++ b/src/libkeccak/digest.h @@ -25,6 +25,20 @@ /** * Absorb more of the message to the Keccak sponge + * without wiping sensitive data when possible + * + * @param state The hashing state + * @param msg The partial message + * @param msglen The length of the partial message + * @return Zero on success, -1 on error + */ +__attribute__((nonnull)) +int libkeccak_fast_update(libkeccak_state_t* restrict state, const char* restrict msg, size_t msglen); + + +/** + * Absorb more of the message to the Keccak sponge + * and wipe sensitive data when possible * * @param state The hashing state * @param msg The partial message @@ -37,6 +51,24 @@ int libkeccak_update(libkeccak_state_t* restrict state, const char* restrict msg /** * Absorb the last part of the message and squeeze the Keccak sponge + * without wiping sensitive data when possible + * + * @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 paramter for the hashsum, may be `NULL` + * @return Zero on success, -1 on error + */ +__attribute__((nonnull(1))) +int libkeccak_fast_digest(libkeccak_state_t* restrict state, const char* restrict msg, size_t msglen, + size_t bits, const char* restrict suffix, char* restrict hashsum); + + +/** + * Absorb the last part of the message and squeeze the Keccak sponge + * and wipe sensitive data when possible * * @param state The hashing state * @param msg The rest of the message, may be `NULL`, may be modified diff --git a/src/libkeccak/state.c b/src/libkeccak/state.c index da545d9..22a7d0c 100644 --- a/src/libkeccak/state.c +++ b/src/libkeccak/state.c @@ -53,24 +53,42 @@ int libkeccak_state_initialise(libkeccak_state_t* restrict state, const libkecca /** - * Wipe sensitive data wihout freeing any data, this is intended - * be called from `libkeccak_state_destroy` + * Wipe data in the state's message wihout freeing any data * * @param state The state that should be wipe */ -void libkeccak_state_wipe(volatile libkeccak_state_t* restrict state) +void libkeccak_state_wipe_message(volatile libkeccak_state_t* restrict state) { - volatile int_fast64_t* restrict S; - volatile char* restrict M; + volatile char* restrict M = state->M; size_t i; - S = state->S; - M = state->M; - for (i = 0; i < 25; i++) - S[i] = 0; 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 int_fast64_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 diff --git a/src/libkeccak/state.h b/src/libkeccak/state.h index 8acb56b..74db7f9 100644 --- a/src/libkeccak/state.h +++ b/src/libkeccak/state.h @@ -141,12 +141,27 @@ void libkeccak_state_fast_destroy(libkeccak_state_t* restrict state) /** - * Wipe sensitive data wihout freeing any data, this is intended - * be called from `libkeccak_state_destroy` + * Wipe data in the state's message wihout freeing any data * * @param state The state that should be wipe */ __attribute__((leaf, nonnull, nothrow, optimize("-O0"))) +void libkeccak_state_wipe_message(volatile libkeccak_state_t* restrict state); + +/** + * Wipe data in the state's sponge wihout freeing any data + * + * @param state The state that should be wipe + */ +__attribute__((leaf, nonnull, nothrow, optimize("-O0"))) +void libkeccak_state_wipe_sponge(volatile libkeccak_state_t* restrict state); + +/** + * Wipe sensitive data wihout freeing any data + * + * @param state The state that should be wipe + */ +__attribute__((nonnull, nothrow, optimize("-O0"))) void libkeccak_state_wipe(volatile libkeccak_state_t* restrict state); |