aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/libkeccak/state.c169
-rw-r--r--src/libkeccak/state.h52
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);
}