summaryrefslogtreecommitdiff
path: root/drivers/staging/skein/skein_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/skein/skein_api.c')
-rw-r--r--drivers/staging/skein/skein_api.c239
1 files changed, 239 insertions, 0 deletions
diff --git a/drivers/staging/skein/skein_api.c b/drivers/staging/skein/skein_api.c
new file mode 100644
index 000000000000..6e700eefc00c
--- /dev/null
+++ b/drivers/staging/skein/skein_api.c
@@ -0,0 +1,239 @@
+/*
+Copyright (c) 2010 Werner Dittmann
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <linux/string.h>
+#include "skein_api.h"
+
+int skein_ctx_prepare(struct skein_ctx *ctx, enum skein_size size)
+{
+ skein_assert_ret(ctx && size, SKEIN_FAIL);
+
+ memset(ctx , 0, sizeof(struct skein_ctx));
+ ctx->skein_size = size;
+
+ return SKEIN_SUCCESS;
+}
+
+int skein_init(struct skein_ctx *ctx, size_t hash_bit_len)
+{
+ int ret = SKEIN_FAIL;
+ size_t x_len = 0;
+ u64 *x = NULL;
+ u64 tree_info = SKEIN_CFG_TREE_INFO_SEQUENTIAL;
+
+ skein_assert_ret(ctx, SKEIN_FAIL);
+ /*
+ * The following two lines rely of the fact that the real Skein
+ * contexts are a union in out context and thus have tha maximum
+ * memory available. The beauty of C :-) .
+ */
+ x = ctx->m.s256.x;
+ x_len = ctx->skein_size/8;
+ /*
+ * If size is the same and hash bit length is zero then reuse
+ * the save chaining variables.
+ */
+ switch (ctx->skein_size) {
+ case SKEIN_256:
+ ret = skein_256_init_ext(&ctx->m.s256, hash_bit_len,
+ tree_info, NULL, 0);
+ break;
+ case SKEIN_512:
+ ret = skein_512_init_ext(&ctx->m.s512, hash_bit_len,
+ tree_info, NULL, 0);
+ break;
+ case SKEIN_1024:
+ ret = skein_1024_init_ext(&ctx->m.s1024, hash_bit_len,
+ tree_info, NULL, 0);
+ break;
+ }
+
+ if (ret == SKEIN_SUCCESS) {
+ /*
+ * Save chaining variables for this combination of size and
+ * hash_bit_len
+ */
+ memcpy(ctx->x_save, x, x_len);
+ }
+ return ret;
+}
+
+int skein_mac_init(struct skein_ctx *ctx, const u8 *key, size_t key_len,
+ size_t hash_bit_len)
+{
+ int ret = SKEIN_FAIL;
+ u64 *x = NULL;
+ size_t x_len = 0;
+ u64 tree_info = SKEIN_CFG_TREE_INFO_SEQUENTIAL;
+
+ skein_assert_ret(ctx, SKEIN_FAIL);
+
+ x = ctx->m.s256.x;
+ x_len = ctx->skein_size/8;
+
+ skein_assert_ret(hash_bit_len, SKEIN_BAD_HASHLEN);
+
+ switch (ctx->skein_size) {
+ case SKEIN_256:
+ ret = skein_256_init_ext(&ctx->m.s256, hash_bit_len,
+ tree_info,
+ (const u8 *)key, key_len);
+
+ break;
+ case SKEIN_512:
+ ret = skein_512_init_ext(&ctx->m.s512, hash_bit_len,
+ tree_info,
+ (const u8 *)key, key_len);
+ break;
+ case SKEIN_1024:
+ ret = skein_1024_init_ext(&ctx->m.s1024, hash_bit_len,
+ tree_info,
+ (const u8 *)key, key_len);
+
+ break;
+ }
+ if (ret == SKEIN_SUCCESS) {
+ /*
+ * Save chaining variables for this combination of key,
+ * key_len, hash_bit_len
+ */
+ memcpy(ctx->x_save, x, x_len);
+ }
+ return ret;
+}
+
+void skein_reset(struct skein_ctx *ctx)
+{
+ size_t x_len = 0;
+ u64 *x = NULL;
+
+ /*
+ * The following two lines rely of the fact that the real Skein
+ * contexts are a union in out context and thus have tha maximum
+ * memory available. The beautiy of C :-) .
+ */
+ x = ctx->m.s256.x;
+ x_len = ctx->skein_size/8;
+ /* Restore the chaing variable, reset byte counter */
+ memcpy(x, ctx->x_save, x_len);
+
+ /* Setup context to process the message */
+ skein_start_new_type(&ctx->m, MSG);
+}
+
+int skein_update(struct skein_ctx *ctx, const u8 *msg,
+ size_t msg_byte_cnt)
+{
+ int ret = SKEIN_FAIL;
+
+ skein_assert_ret(ctx, SKEIN_FAIL);
+
+ switch (ctx->skein_size) {
+ case SKEIN_256:
+ ret = skein_256_update(&ctx->m.s256, (const u8 *)msg,
+ msg_byte_cnt);
+ break;
+ case SKEIN_512:
+ ret = skein_512_update(&ctx->m.s512, (const u8 *)msg,
+ msg_byte_cnt);
+ break;
+ case SKEIN_1024:
+ ret = skein_1024_update(&ctx->m.s1024, (const u8 *)msg,
+ msg_byte_cnt);
+ break;
+ }
+ return ret;
+
+}
+
+int skein_update_bits(struct skein_ctx *ctx, const u8 *msg,
+ size_t msg_bit_cnt)
+{
+ /*
+ * I've used the bit pad implementation from skein_test.c (see NIST CD)
+ * and modified it to use the convenience functions and added some
+ * pointer arithmetic.
+ */
+ size_t length;
+ u8 mask;
+ u8 *up;
+
+ /*
+ * only the final Update() call is allowed do partial bytes, else
+ * assert an error
+ */
+ skein_assert_ret((ctx->m.h.T[1] & SKEIN_T1_FLAG_BIT_PAD) == 0 ||
+ msg_bit_cnt == 0, SKEIN_FAIL);
+
+ /* if number of bits is a multiple of bytes - that's easy */
+ if ((msg_bit_cnt & 0x7) == 0)
+ return skein_update(ctx, msg, msg_bit_cnt >> 3);
+
+ skein_update(ctx, msg, (msg_bit_cnt >> 3) + 1);
+
+ /*
+ * The next line rely on the fact that the real Skein contexts
+ * are a union in our context. After the addition the pointer points to
+ * Skein's real partial block buffer.
+ * If this layout ever changes we have to adapt this as well.
+ */
+ up = (u8 *)ctx->m.s256.x + ctx->skein_size / 8;
+
+ /* set tweak flag for the skein_final call */
+ skein_set_bit_pad_flag(ctx->m.h);
+
+ /* now "pad" the final partial byte the way NIST likes */
+ /* get the b_cnt value (same location for all block sizes) */
+ length = ctx->m.h.b_cnt;
+ /* internal sanity check: there IS a partial byte in the buffer! */
+ skein_assert(length != 0);
+ /* partial byte bit mask */
+ mask = (u8) (1u << (7 - (msg_bit_cnt & 7)));
+ /* apply bit padding on final byte (in the buffer) */
+ up[length-1] = (u8)((up[length-1] & (0-mask))|mask);
+
+ return SKEIN_SUCCESS;
+}
+
+int skein_final(struct skein_ctx *ctx, u8 *hash)
+{
+ int ret = SKEIN_FAIL;
+
+ skein_assert_ret(ctx, SKEIN_FAIL);
+
+ switch (ctx->skein_size) {
+ case SKEIN_256:
+ ret = skein_256_final(&ctx->m.s256, (u8 *)hash);
+ break;
+ case SKEIN_512:
+ ret = skein_512_final(&ctx->m.s512, (u8 *)hash);
+ break;
+ case SKEIN_1024:
+ ret = skein_1024_final(&ctx->m.s1024, (u8 *)hash);
+ break;
+ }
+ return ret;
+}