]> git.ipfire.org Git - thirdparty/nettle.git/commitdiff
cmac: add 64-bit mode CMAC
authorDmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Tue, 9 Jul 2019 18:58:42 +0000 (21:58 +0300)
committerNiels Möller <nisse@lysator.liu.se>
Wed, 10 Jul 2019 20:31:08 +0000 (22:31 +0200)
Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Makefile.in
cmac.h
cmac64.c [new file with mode: 0644]
nettle-types.h

index b54e64b053c3cf57a3266299765f6d90c721e823..bad2baf3a29ed06b0122a93c8ed4e1ed76fb2115 100644 (file)
@@ -102,7 +102,7 @@ nettle_SOURCES = aes-decrypt-internal.c aes-decrypt.c \
                 gcm-aes256.c gcm-aes256-meta.c \
                 gcm-camellia128.c gcm-camellia128-meta.c \
                 gcm-camellia256.c gcm-camellia256-meta.c \
-                cmac.c cmac-aes128.c cmac-aes256.c \
+                cmac.c cmac64.c cmac-aes128.c cmac-aes256.c \
                 gosthash94.c gosthash94-meta.c \
                 hmac.c hmac-md5.c hmac-ripemd160.c hmac-sha1.c \
                 hmac-sha224.c hmac-sha256.c hmac-sha384.c hmac-sha512.c \
diff --git a/cmac.h b/cmac.h
index 3c5b7bea3e5537f2e2efedf8341bbb53394c255a..0cf9462d2120386ef0d4278f312930784ce6e213 100644 (file)
--- a/cmac.h
+++ b/cmac.h
@@ -44,6 +44,7 @@ extern "C" {
 #endif
 
 #define CMAC128_DIGEST_SIZE 16
+#define CMAC64_DIGEST_SIZE 8
 
 #define cmac128_set_key nettle_cmac128_set_key
 #define cmac128_init nettle_cmac128_init
@@ -56,6 +57,11 @@ extern "C" {
 #define cmac_aes256_update nettle_cmac_aes256_update
 #define cmac_aes256_digest nettle_cmac_aes256_digest
 
+#define cmac64_set_key nettle_cmac64_set_key
+#define cmac64_init nettle_cmac64_init
+#define cmac64_update nettle_cmac64_update
+#define cmac64_digest nettle_cmac64_digest
+
 struct cmac128_key
 {
   union nettle_block16 K1;
@@ -72,6 +78,22 @@ struct cmac128_ctx
   size_t index;
 };
 
+struct cmac64_key
+{
+  union nettle_block8 K1;
+  union nettle_block8 K2;
+};
+
+struct cmac64_ctx
+{
+  /* MAC state */
+  union nettle_block8 X;
+
+  /* Block buffer */
+  union nettle_block8 block;
+  size_t index;
+};
+
 void
 cmac128_set_key(struct cmac128_key *key, const void *cipher,
                nettle_cipher_func *encrypt);
@@ -118,6 +140,53 @@ cmac128_digest(struct cmac128_ctx *ctx, const struct cmac128_key *key,
                      (nettle_cipher_func *) (encrypt),         \
                      (length), (digest)))
 
+void
+cmac64_set_key(struct cmac64_key *key, const void *cipher,
+               nettle_cipher_func *encrypt);
+
+void
+cmac64_init(struct cmac64_ctx *ctx);
+
+void
+cmac64_update(struct cmac64_ctx *ctx, const void *cipher,
+              nettle_cipher_func *encrypt,
+              size_t msg_len, const uint8_t *msg);
+
+void
+cmac64_digest(struct cmac64_ctx *ctx, const struct cmac64_key *key,
+              const void *cipher, nettle_cipher_func *encrypt,
+              unsigned length, uint8_t *digest);
+
+
+#define CMAC64_CTX(type) \
+  { struct cmac64_key key; struct cmac64_ctx ctx; type cipher; }
+
+/* NOTE: Avoid using NULL, as we don't include anything defining it. */
+#define CMAC64_SET_KEY(self, set_key, encrypt, cmac_key)       \
+  do {                                                         \
+    (set_key)(&(self)->cipher, (cmac_key));                    \
+    if (0) (encrypt)(&(self)->cipher, ~(size_t) 0,             \
+                    (uint8_t *) 0, (const uint8_t *) 0);       \
+    cmac64_set_key(&(self)->key, &(self)->cipher,              \
+                   (nettle_cipher_func *) (encrypt));          \
+    cmac64_init(&(self)->ctx);                                 \
+  } while (0)
+
+#define CMAC64_UPDATE(self, encrypt, length, src)              \
+  (0 ? (encrypt)(&(self)->cipher, ~(size_t) 0,                 \
+                (uint8_t *) 0, (const uint8_t *) 0)            \
+     : cmac64_update(&(self)->ctx, &(self)->cipher,            \
+                     (nettle_cipher_func *)encrypt,            \
+                     (length), (src)))
+
+#define CMAC64_DIGEST(self, encrypt, length, digest)           \
+  (0 ? (encrypt)(&(self)->cipher, ~(size_t) 0,                 \
+                (uint8_t *) 0, (const uint8_t *) 0)            \
+     : cmac64_digest(&(self)->ctx, &(self)->key,               \
+                     &(self)->cipher,                          \
+                     (nettle_cipher_func *) (encrypt),         \
+                     (length), (digest)))
+
 struct cmac_aes128_ctx CMAC128_CTX(struct aes128_ctx);
 
 void
diff --git a/cmac64.c b/cmac64.c
new file mode 100644 (file)
index 0000000..9b711d6
--- /dev/null
+++ b/cmac64.c
@@ -0,0 +1,177 @@
+/*
+   AES-CMAC-128 (rfc 4493) / CMAC-64
+   Copyright (C) Stefan Metzmacher 2012
+   Copyright (C) Jeremy Allison 2012
+   Copyright (C) Michael Adam 2012
+   Copyright (C) 2017, Red Hat Inc.
+   Copyright (C) 2019, Dmitry Eremin-Solenikov
+
+   This file is part of GNU Nettle.
+
+   GNU Nettle is free software: you can redistribute it and/or
+   modify it under the terms of either:
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at your
+       option) any later version.
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at your
+       option) any later version.
+
+   or both in parallel, as here.
+
+   GNU Nettle 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
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cmac.h"
+
+#include "memxor.h"
+#include "nettle-internal.h"
+#include "macros.h"
+
+/* shift one and XOR with 0x87. */
+#if WORDS_BIGENDIAN
+static void
+_cmac64_block_mulx(union nettle_block8 *dst,
+           const union nettle_block8 *src)
+{
+  uint64_t carry = src->u64 >> 63;
+
+  dst->u64 = (src->u64 << 1) ^ (0x1b & -carry);
+}
+#else /* !WORDS_BIGENDIAN */
+#define LE_SHIFT(x) ((((x) & 0x7f7f7f7f7f7f7f7f) << 1) | \
+                     (((x) & 0x8080808080808080) >> 15))
+static void
+_cmac64_block_mulx(union nettle_block8 *dst,
+          const union nettle_block8 *src)
+{
+  uint64_t carry = (src->u64 & 0x80) >> 7;
+
+  dst->u64 = LE_SHIFT(src->u64) ^ (0x1b00000000000000 & -carry);
+}
+#endif /* !WORDS_BIGENDIAN */
+
+void
+cmac64_set_key(struct cmac64_key *key, const void *cipher,
+              nettle_cipher_func *encrypt)
+{
+  static const union nettle_block8 zero_block;
+  union nettle_block8 L;
+
+  /* step 1 - generate subkeys k1 and k2 */
+  encrypt(cipher, 8, L.b, zero_block.b);
+
+  _cmac64_block_mulx(&key->K1, &L);
+  _cmac64_block_mulx(&key->K2, &key->K1);
+}
+
+void
+cmac64_init(struct cmac64_ctx *ctx)
+{
+  memset(&ctx->X, 0, sizeof(ctx->X));
+  ctx->index = 0;
+}
+
+#define MIN(x,y) ((x)<(y)?(x):(y))
+
+void
+cmac64_update(struct cmac64_ctx *ctx, const void *cipher,
+             nettle_cipher_func *encrypt,
+             size_t msg_len, const uint8_t *msg)
+{
+  union nettle_block16 Y;
+  /*
+   * check if we expand the block
+   */
+  if (ctx->index < 8)
+    {
+      size_t len = MIN(8 - ctx->index, msg_len);
+      memcpy(&ctx->block.b[ctx->index], msg, len);
+      msg += len;
+      msg_len -= len;
+      ctx->index += len;
+    }
+
+  if (msg_len == 0) {
+    /* if it is still the last block, we are done */
+    return;
+  }
+
+  /*
+   * now checksum everything but the last block
+   */
+  memxor3(Y.b, ctx->X.b, ctx->block.b, 8);
+  encrypt(cipher, 8, ctx->X.b, Y.b);
+
+  while (msg_len > 8)
+    {
+      memxor3(Y.b, ctx->X.b, msg, 8);
+      encrypt(cipher, 8, ctx->X.b, Y.b);
+      msg += 8;
+      msg_len -= 8;
+    }
+
+  /*
+   * copy the last block, it will be processed in
+   * cmac64_digest().
+   */
+  memcpy(ctx->block.b, msg, msg_len);
+  ctx->index = msg_len;
+}
+
+void
+cmac64_digest(struct cmac64_ctx *ctx, const struct cmac64_key *key,
+             const void *cipher, nettle_cipher_func *encrypt,
+             unsigned length, uint8_t *dst)
+{
+  union nettle_block8 Y;
+
+  memset(ctx->block.b+ctx->index, 0, sizeof(ctx->block.b)-ctx->index);
+
+  /* re-use ctx->block for memxor output */
+  if (ctx->index < 8)
+    {
+      ctx->block.b[ctx->index] = 0x80;
+      memxor(ctx->block.b, key->K2.b, 8);
+    }
+  else
+    {
+      memxor(ctx->block.b, key->K1.b, 8);
+    }
+
+  memxor3(Y.b, ctx->block.b, ctx->X.b, 8);
+
+  assert(length <= 8);
+  if (length == 8)
+    {
+      encrypt(cipher, 8, dst, Y.b);
+    }
+  else
+    {
+      encrypt(cipher, 8, ctx->block.b, Y.b);
+      memcpy(dst, ctx->block.b, length);
+    }
+
+  /* reset state for re-use */
+  memset(&ctx->X, 0, sizeof(ctx->X));
+  ctx->index = 0;
+}
index 87292ac697305d0b57c3b6fc252366f9540b8a8b..5addf3600d69495f8515d801aa491dcfb6836e05 100644 (file)
@@ -65,6 +65,12 @@ union nettle_block16
   uint64_t u64[2];
 };
 
+union nettle_block8
+{
+  uint8_t b[8];
+  uint64_t u64;
+};
+
 /* Randomness. Used by key generation and dsa signature creation. */
 typedef void nettle_random_func(void *ctx,
                                size_t length, uint8_t *dst);