diff options
-rw-r--r-- | src/libkeccak/state.c | 169 | ||||
-rw-r--r-- | src/libkeccak/state.h | 52 |
2 files changed, 214 insertions, 7 deletions
diff --git a/src/libkeccak/state.c b/src/libkeccak/state.c new file mode 100644 index 0000000..4985467 --- /dev/null +++ b/src/libkeccak/state.c @@ -0,0 +1,169 @@ +/** + * libkeccak – Keccak-family hashing library + * + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include "state.h" + +#include <string.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 x; + state->r = spec->bitrate; + state->n = spec->output; + state->c = spec->capacity; + state->b = r + c; + state->w = x = b / 25; + state->l = 0; + if ((x & 0xFF00) != 0) state->l |= 8, x >>= 8; + if ((x & 0x00F0) != 0) state->l |= 4, x >>= 4; + if ((x & 0x000C) != 0) state->l |= 2, x >>= 2; + if ((x & 0x0002) != 0) state->l |= 1; + state->nr = 12 + (l << 1); + state->wmod = (state->w == 64) ? ~0LL : ((1LL << w) - 1); + for (x = 0; x < 25; x++) + state->S[x] = 0; + state->mptr = 0; + state->mlen = (r * b) >> 2; + state->M = malloc(state->mlen * sizeof(char)); + return state->M == NULL ? -1 : 0; +} + + +/** + * Wipe sensitive data wihout freeing any data, this is intended + * be called from `libkeccak_state_destroy` + * + * @param state The state that should be wipe + */ +void libkeccak_state_wipe(volatile libkeccak_state_t* restrict state) +{ + volatile int_fast64_t* restrict S; + volatile char* restrict M; + size_t i; + S = state->S; + M = state->M; + for (i = 0; i < 25; i++) + S[i] = 0; + for (i = 0; i < state->mlen; i++) + M[i] = 0; +} + + +/** + * 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 == NULL) + return dest->M = NULL, NULL; + 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, char* restrict data) +{ +#define set(type, var) *((type*)data) = state->var, data += sizeof(type) / sizeof(char) + size_t i; + set(long, r); + set(long, c); + set(long, n); + set(long, b); + set(long, w); + set(int_fast64_t, wmod); + set(long, l); + set(long, 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 char* restrict data) +{ +#define get(type, var) state->var = *((type*)data), data += sizeof(type) / sizeof(char) + size_t i; + get(long, r); + get(long, c); + get(long, n); + get(long, b); + get(long, w); + get(int_fast64_t, wmod); + get(long, l); + get(long, 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 == NULL) + 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 char* restrict data) +{ + data += (7 * sizeof(long) + 26 * sizeof(int_fast64_t)) / sizeof(char); + return sizeof(libkeccak_state_t) - sizeof(char*) + *(size_t*)data * sizeof(char); +} + diff --git a/src/libkeccak/state.h b/src/libkeccak/state.h index 4345c06..54e1c6a 100644 --- a/src/libkeccak/state.h +++ b/src/libkeccak/state.h @@ -79,6 +79,21 @@ typedef struct libkeccak_state */ int_fast64_t S[25]; + /** + * Pointer for `M` + */ + size_t mptr; + + /** + * Size of `M` + */ + size_t mlen; + + /** + * Left over water to fill the sponge with at next update + */ + char* M; + } libkeccak_state_t; @@ -99,8 +114,24 @@ int libkeccak_state_initialise(libkeccak_state_t* restrict state, const libkecca * * @param state The state that should be destroyed */ -__attribute__((leaf)) -void libkeccak_state_fast_destroy(libkeccak_state_t* restrict state); +static inline __attribute__((leaf)) +void libkeccak_state_fast_destroy(libkeccak_state_t* restrict state) +{ + if (state == NULL) + return; + free(state->M); + state->M = NULL; +} + + +/** + * Wipe sensitive data wihout freeing any data, this is intended + * be called from `libkeccak_state_destroy` + * + * @param state The state that should be wipe + */ +__attribute__((leaf, nonnull, nothrow, optimize("-O0"))) +void libkeccak_state_wipe(volatile libkeccak_state_t* restrict state); /** @@ -108,8 +139,15 @@ void libkeccak_state_fast_destroy(libkeccak_state_t* restrict state); * * @param state The state that should be destroyed */ -__attribute__((leaf)) -void libkeccak_state_destroy(libkeccak_state_t* restrict state); +static inline __attribute__((unused, optimize("-O0"))) +void libkeccak_state_destroy(volatile libkeccak_state_t* restrict state) +{ + if (state == NULL) + return; + libkeccak_state_wipe(state); + free(state->M); + state->M = NULL; +} /** @@ -147,8 +185,8 @@ void libkeccak_state_fast_free(libkeccak_state_t* restrict state) * * @param state The state that should be freed */ -static inline __attribute__((unused)) -void libkeccak_state_free(libkeccak_state_t* restrict state) +static inline __attribute__((unused, optimize("-O0"))) +void libkeccak_state_free(volatile libkeccak_state_t* restrict state) { libkeccak_state_destroy(state); free(state); @@ -193,7 +231,7 @@ libkeccak_state_t* libkeccak_state_duplicate(const libkeccak_state_t* restrict s static inline __attribute__((leaf, nonnull, nothrow, unused, warn_unused_result, pure)) size_t libkeccak_state_marshal_size(const libkeccak_state_t* restrict state) { - return sizeof(libkeccak_state_t); + return sizeof(libkeccak_state_t) - sizeof(char*) + state->mptr * sizeof(char); } |