summaryrefslogtreecommitdiff
path: root/umac64.c
diff options
context:
space:
mode:
authorNiels Möller <nisse@lysator.liu.se>2013-04-11 14:57:24 +0200
committerNiels Möller <nisse@lysator.liu.se>2013-04-11 14:57:24 +0200
commit34aef19b0f571e24b575a92d0262df7fe755bf6b (patch)
tree121ae6bd0c4d973de2891a215f1e9da33c199d71 /umac64.c
parentc6f38f5f318f4d1cc816385157cbf09197c54d07 (diff)
downloadnettle-34aef19b0f571e24b575a92d0262df7fe755bf6b.tar.gz
Implemented umac.
Diffstat (limited to 'umac64.c')
-rw-r--r--umac64.c135
1 files changed, 135 insertions, 0 deletions
diff --git a/umac64.c b/umac64.c
new file mode 100644
index 00000000..015cefd0
--- /dev/null
+++ b/umac64.c
@@ -0,0 +1,135 @@
+/* umac64.c
+ */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2013 Niels Möller
+ *
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ *
+ * The nettle library 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 Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02111-1301, USA.
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+#include <string.h>
+
+#include "umac.h"
+
+#include "macros.h"
+
+void
+umac64_set_key (struct umac64_ctx *ctx, const uint8_t *key)
+{
+ _umac_set_key (ctx->l1_key, ctx->l2_key, ctx->l3_key1, ctx->l3_key2,
+ &ctx->pdf_key, key, 2);
+
+ /* Clear nonce */
+ memset (ctx->nonce, 0, sizeof(ctx->nonce));
+ ctx->nonce_low = 0;
+ ctx->nonce_length = sizeof(ctx->nonce);
+
+ /* Initialize buffer */
+ ctx->count = ctx->index = 0;
+}
+
+void
+umac64_set_nonce (struct umac64_ctx *ctx,
+ unsigned nonce_length, const uint8_t *nonce)
+{
+ assert (nonce_length > 0);
+ assert (nonce_length <= AES_BLOCK_SIZE);
+
+ memcpy (ctx->nonce, nonce, nonce_length);
+ memset (ctx->nonce + nonce_length, 0, AES_BLOCK_SIZE - nonce_length);
+
+ ctx->nonce_low = ctx->nonce[nonce_length - 1] & 1;
+ ctx->nonce[nonce_length - 1] &= ~1;
+ ctx->nonce_length = nonce_length;
+}
+
+#define UMAC64_BLOCK(ctx, block) do { \
+ uint64_t __umac64_y[2]; \
+ _umac_nh_n (__umac64_y, 2, ctx->l1_key, UMAC_BLOCK_SIZE, block); \
+ __umac64_y[0] += 8*UMAC_BLOCK_SIZE; \
+ __umac64_y[1] += 8*UMAC_BLOCK_SIZE; \
+ _umac_l2 (ctx->l2_key, ctx->l2_state, 2, ctx->count++, \
+ ctx->l1_out, __umac64_y); \
+ } while (0)
+
+void
+umac64_update (struct umac64_ctx *ctx,
+ unsigned length, const uint8_t *data)
+{
+ MD_UPDATE (ctx, length, data, UMAC64_BLOCK, (void)0);
+}
+
+
+void
+umac64_digest (struct umac64_ctx *ctx,
+ unsigned length, uint8_t *digest)
+{
+ uint32_t tag[2];
+ uint32_t *pad;
+
+ assert (length > 0);
+ assert (length <= 8);
+
+ if (ctx->index > 0 || ctx->count == 0)
+ {
+ /* Zero pad to multiple of 32 */
+ uint64_t y[2];
+ unsigned pad = (ctx->index > 0) ? 31 & - ctx->index : 32;
+ memset (ctx->block + ctx->index, 0, pad);
+
+ _umac_nh_n (y, 2, ctx->l1_key, ctx->index + pad, ctx->block);
+ y[0] += 8 * ctx->index;
+ y[1] += 8 * ctx->index;
+ _umac_l2 (ctx->l2_key, ctx->l2_state, 2, ctx->count++,
+ ctx->l1_out, y);
+ }
+ assert (ctx->count > 0);
+ if ( !(ctx->nonce_low & _UMAC_NONCE_CACHED))
+ aes_encrypt (&ctx->pdf_key, AES_BLOCK_SIZE,
+ (uint8_t *) ctx->pad_cache, ctx->nonce);
+
+ pad = ctx->pad_cache + 2*(ctx->nonce_low & 1);
+
+ /* Increment nonce */
+ ctx->nonce_low++;
+ if ( !(ctx->nonce_low & 1))
+ {
+ unsigned i = ctx->nonce_length - 1;
+
+ ctx->nonce_low = 0;
+ ctx->nonce[i] += 2;
+
+ if (ctx->nonce[i] == 0)
+ while (i > 0)
+ if (++ctx->nonce[--i] == 0)
+ break;
+ }
+
+ _umac_l2_final (ctx->l2_key, ctx->l2_state, 2, ctx->count, ctx->l1_out);
+ tag[0] = pad[0] ^ _umac_l3 (ctx->l3_key1, ctx->l3_key2[0], ctx->l2_state);
+ tag[1] = pad[1] ^ _umac_l3 (ctx->l3_key1 + 8, ctx->l3_key2[1],
+ ctx->l2_state + 2);
+ memcpy (digest, tag, length);
+
+ /* Reinitialize */
+ ctx->count = ctx->index = 0;
+}