linux/drivers/staging/skein/skein_api.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2010 Werner Dittmann
   3 *
   4 * Permission is hereby granted, free of charge, to any person
   5 * obtaining a copy of this software and associated documentation
   6 * files (the "Software"), to deal in the Software without
   7 * restriction, including without limitation the rights to use,
   8 * copy, modify, merge, publish, distribute, sublicense, and/or sell
   9 * copies of the Software, and to permit persons to whom the
  10 * Software is furnished to do so, subject to the following
  11 * conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be
  14 * included in all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  18 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  20 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  23 * OTHER DEALINGS IN THE SOFTWARE.
  24 */
  25
  26#include <linux/string.h>
  27#include "skein_api.h"
  28
  29int skein_ctx_prepare(struct skein_ctx *ctx, enum skein_size size)
  30{
  31        skein_assert_ret(ctx && size, SKEIN_FAIL);
  32
  33        memset(ctx, 0, sizeof(struct skein_ctx));
  34        ctx->skein_size = size;
  35
  36        return SKEIN_SUCCESS;
  37}
  38
  39int skein_init(struct skein_ctx *ctx, size_t hash_bit_len)
  40{
  41        int ret = SKEIN_FAIL;
  42        size_t x_len = 0;
  43        u64 *x = NULL;
  44        u64 tree_info = SKEIN_CFG_TREE_INFO_SEQUENTIAL;
  45
  46        skein_assert_ret(ctx, SKEIN_FAIL);
  47        /*
  48         * The following two lines rely of the fact that the real Skein
  49         * contexts are a union in out context and thus have tha maximum
  50         * memory available.  The beauty of C :-) .
  51         */
  52        x = ctx->m.s256.x;
  53        x_len = ctx->skein_size / 8;
  54        /*
  55         * If size is the same and hash bit length is zero then reuse
  56         * the save chaining variables.
  57         */
  58        switch (ctx->skein_size) {
  59        case SKEIN_256:
  60                ret = skein_256_init_ext(&ctx->m.s256, hash_bit_len,
  61                                         tree_info, NULL, 0);
  62                break;
  63        case SKEIN_512:
  64                ret = skein_512_init_ext(&ctx->m.s512, hash_bit_len,
  65                                         tree_info, NULL, 0);
  66                break;
  67        case SKEIN_1024:
  68                ret = skein_1024_init_ext(&ctx->m.s1024, hash_bit_len,
  69                                          tree_info, NULL, 0);
  70                break;
  71        }
  72
  73        if (ret == SKEIN_SUCCESS) {
  74                /*
  75                 * Save chaining variables for this combination of size and
  76                 * hash_bit_len
  77                 */
  78                memcpy(ctx->x_save, x, x_len);
  79        }
  80        return ret;
  81}
  82
  83int skein_mac_init(struct skein_ctx *ctx, const u8 *key, size_t key_len,
  84                   size_t hash_bit_len)
  85{
  86        int ret = SKEIN_FAIL;
  87        u64 *x = NULL;
  88        size_t x_len = 0;
  89        u64 tree_info = SKEIN_CFG_TREE_INFO_SEQUENTIAL;
  90
  91        skein_assert_ret(ctx, SKEIN_FAIL);
  92
  93        x = ctx->m.s256.x;
  94        x_len = ctx->skein_size / 8;
  95
  96        skein_assert_ret(hash_bit_len, SKEIN_BAD_HASHLEN);
  97
  98        switch (ctx->skein_size) {
  99        case SKEIN_256:
 100                ret = skein_256_init_ext(&ctx->m.s256, hash_bit_len,
 101                                         tree_info,
 102                                         (const u8 *)key, key_len);
 103
 104                break;
 105        case SKEIN_512:
 106                ret = skein_512_init_ext(&ctx->m.s512, hash_bit_len,
 107                                         tree_info,
 108                                         (const u8 *)key, key_len);
 109                break;
 110        case SKEIN_1024:
 111                ret = skein_1024_init_ext(&ctx->m.s1024, hash_bit_len,
 112                                          tree_info,
 113                                          (const u8 *)key, key_len);
 114
 115                break;
 116        }
 117        if (ret == SKEIN_SUCCESS) {
 118                /*
 119                 * Save chaining variables for this combination of key,
 120                 * key_len, hash_bit_len
 121                 */
 122                memcpy(ctx->x_save, x, x_len);
 123        }
 124        return ret;
 125}
 126
 127void skein_reset(struct skein_ctx *ctx)
 128{
 129        size_t x_len = 0;
 130        u64 *x;
 131
 132        /*
 133         * The following two lines rely of the fact that the real Skein
 134         * contexts are a union in out context and thus have tha maximum
 135         * memory available.  The beautiy of C :-) .
 136         */
 137        x = ctx->m.s256.x;
 138        x_len = ctx->skein_size / 8;
 139        /* Restore the chaing variable, reset byte counter */
 140        memcpy(x, ctx->x_save, x_len);
 141
 142        /* Setup context to process the message */
 143        skein_start_new_type(&ctx->m, MSG);
 144}
 145
 146int skein_update(struct skein_ctx *ctx, const u8 *msg,
 147                 size_t msg_byte_cnt)
 148{
 149        int ret = SKEIN_FAIL;
 150
 151        skein_assert_ret(ctx, SKEIN_FAIL);
 152
 153        switch (ctx->skein_size) {
 154        case SKEIN_256:
 155                ret = skein_256_update(&ctx->m.s256, (const u8 *)msg,
 156                                       msg_byte_cnt);
 157                break;
 158        case SKEIN_512:
 159                ret = skein_512_update(&ctx->m.s512, (const u8 *)msg,
 160                                       msg_byte_cnt);
 161                break;
 162        case SKEIN_1024:
 163                ret = skein_1024_update(&ctx->m.s1024, (const u8 *)msg,
 164                                        msg_byte_cnt);
 165                break;
 166        }
 167        return ret;
 168}
 169
 170int skein_update_bits(struct skein_ctx *ctx, const u8 *msg,
 171                      size_t msg_bit_cnt)
 172{
 173        /*
 174         * I've used the bit pad implementation from skein_test.c (see NIST CD)
 175         * and modified it to use the convenience functions and added some
 176         * pointer arithmetic.
 177         */
 178        size_t length;
 179        u8 mask;
 180        u8 *up;
 181
 182        /*
 183         * only the final Update() call is allowed do partial bytes, else
 184         * assert an error
 185         */
 186        skein_assert_ret((ctx->m.h.T[1] & SKEIN_T1_FLAG_BIT_PAD) == 0 ||
 187                         msg_bit_cnt == 0, SKEIN_FAIL);
 188
 189        /* if number of bits is a multiple of bytes - that's easy */
 190        if ((msg_bit_cnt & 0x7) == 0)
 191                return skein_update(ctx, msg, msg_bit_cnt >> 3);
 192
 193        skein_update(ctx, msg, (msg_bit_cnt >> 3) + 1);
 194
 195        /*
 196         * The next line rely on the fact that the real Skein contexts
 197         * are a union in our context. After the addition the pointer points to
 198         * Skein's real partial block buffer.
 199         * If this layout ever changes we have to adapt this as well.
 200         */
 201        up = (u8 *)ctx->m.s256.x + ctx->skein_size / 8;
 202
 203        /* set tweak flag for the skein_final call */
 204        skein_set_bit_pad_flag(ctx->m.h);
 205
 206        /* now "pad" the final partial byte the way NIST likes */
 207        /* get the b_cnt value (same location for all block sizes) */
 208        length = ctx->m.h.b_cnt;
 209        /* internal sanity check: there IS a partial byte in the buffer! */
 210        skein_assert(length != 0);
 211        /* partial byte bit mask */
 212        mask = (u8)(1u << (7 - (msg_bit_cnt & 7)));
 213        /* apply bit padding on final byte (in the buffer) */
 214        up[length - 1]  = (u8)((up[length - 1] & (0 - mask)) | mask);
 215
 216        return SKEIN_SUCCESS;
 217}
 218
 219int skein_final(struct skein_ctx *ctx, u8 *hash)
 220{
 221        int ret = SKEIN_FAIL;
 222
 223        skein_assert_ret(ctx, SKEIN_FAIL);
 224
 225        switch (ctx->skein_size) {
 226        case SKEIN_256:
 227                ret = skein_256_final(&ctx->m.s256, (u8 *)hash);
 228                break;
 229        case SKEIN_512:
 230                ret = skein_512_final(&ctx->m.s512, (u8 *)hash);
 231                break;
 232        case SKEIN_1024:
 233                ret = skein_1024_final(&ctx->m.s1024, (u8 *)hash);
 234                break;
 235        }
 236        return ret;
 237}
 238