]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
siv: add internal implementation based on Nettle
authorMiroslav Lichvar <mlichvar@redhat.com>
Wed, 21 Aug 2019 12:09:37 +0000 (14:09 +0200)
committerMiroslav Lichvar <mlichvar@redhat.com>
Thu, 5 Mar 2020 15:02:15 +0000 (16:02 +0100)
This adds an internal implementation of the AES-SIV-CMAC-256 cipher
based on GNU Nettle and the following patch (which was later reworked
and included in Nettle):

https://gitlab.com/gnutls/gnutls/uploads/1ab02c51e317264f9dba07ddfbc01d9a/0001-Added-support-for-AES_SIV_CMAC_256-and-AES_SIV_CMAC_.patch

This implementation will be dropped when the cipher is widely supported
by gnutls or Nettle.

configure
siv_nettle.c
siv_nettle_int.c [new file with mode: 0644]

index 3f2eaa925d9e7f958c9d7f5fc45ac1ff987aac2c..597fd4dcbd3a04f8dbbf35f77f43d92ca50bd801 100755 (executable)
--- a/configure
+++ b/configure
@@ -923,12 +923,14 @@ LIBS="$LIBS $HASH_LINK"
 if true && \
     echo "$HASH_LINK" | grep 'nettle' > /dev/null; then
 
+    EXTRA_OBJECTS="$EXTRA_OBJECTS siv_nettle.o"
+    add_def HAVE_SIV
+
     if test_code 'SIV in nettle' \
       'nettle/siv-cmac.h' "" "$LIBS" \
       'siv_cmac_aes128_set_key(NULL, NULL);'
     then
-      EXTRA_OBJECTS="$EXTRA_OBJECTS siv_nettle.o"
-      add_def HAVE_SIV
+      add_def HAVE_NETTLE_SIV_CMAC
     fi
 fi
 
index 1ace933fb663328f814547c2124eb2937bd6ffa5..a08a8d1bfbccd9993d4d57b63e8d0b5278b8a234 100644 (file)
 
 #include "sysincl.h"
 
+#ifdef HAVE_NETTLE_SIV_CMAC
 #include <nettle/siv-cmac.h>
+#else
+#include "siv_nettle_int.c"
+#endif
 
 #include "memory.h"
 #include "siv.h"
diff --git a/siv_nettle_int.c b/siv_nettle_int.c
new file mode 100644 (file)
index 0000000..714eff6
--- /dev/null
@@ -0,0 +1,452 @@
+/* This is a single-file implementation of AES-SIV-CMAC-256 based on
+   a patch for GNU Nettle by Nikos Mavrogiannopoulos */
+
+/*
+   AES-CMAC-128 (rfc 4493)
+   Copyright (C) Stefan Metzmacher 2012
+   Copyright (C) Jeremy Allison 2012
+   Copyright (C) Michael Adam 2012
+   Copyright (C) 2017, Red Hat Inc.
+
+   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/.
+*/
+/* siv-aes128.c, siv-cmac.c, siv.h
+
+   AES-SIV, RFC5297
+   SIV-CMAC, RFC5297
+
+   Copyright (C) 2017 Nikos Mavrogiannopoulos
+
+   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/.
+*/
+/* cmac.h, siv-cmac.h, cmac-aes128.c
+
+   CMAC mode, as specified in RFC4493
+   SIV-CMAC mode, as specified in RFC5297
+   CMAC using AES128 as the underlying cipher.
+
+   Copyright (C) 2017 Red Hat, Inc.
+
+   Contributed by Nikos Mavrogiannopoulos
+
+   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/.
+*/
+
+# include "config.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include "nettle/aes.h"
+#include "nettle/ctr.h"
+#include "nettle/macros.h"
+#include "nettle/memxor.h"
+#include "nettle/memops.h"
+
+#include "nettle/nettle-types.h"
+
+/* For SIV, the block size of the block cipher shall be 128 bits. */
+#define SIV_BLOCK_SIZE  16
+#define SIV_DIGEST_SIZE 16
+#define SIV_MIN_NONCE_SIZE 1
+
+/*
+ * SIV mode requires the aad and plaintext when building the IV, which
+ * prevents streaming processing and it incompatible with the AEAD API.
+ */
+
+/* AES_SIV_CMAC_256 */
+struct siv_cmac_aes128_ctx {
+    struct aes128_ctx         cipher;
+    uint8_t s2vk[AES128_KEY_SIZE];
+};
+
+struct cmac128_ctx
+{
+  /* Key */
+  union nettle_block16 K1;
+  union nettle_block16 K2;
+
+  /* MAC state */
+  union nettle_block16 X;
+
+  /* Block buffer */
+  union nettle_block16 block;
+  size_t index;
+};
+
+/* shift one and XOR with 0x87. */
+static void
+_cmac128_block_mulx(union nettle_block16 *dst,
+          const union nettle_block16 *src)
+{
+  uint64_t b1 = READ_UINT64(src->b);
+  uint64_t b2 = READ_UINT64(src->b+8);
+
+  b1 = (b1 << 1) | (b2 >> 63);
+  b2 <<= 1;
+
+  if (src->b[0] & 0x80)
+    b2 ^= 0x87;
+
+  WRITE_UINT64(dst->b, b1);
+  WRITE_UINT64(dst->b+8, b2);
+}
+
+static void
+cmac128_set_key(struct cmac128_ctx *ctx, const void *cipher,
+               nettle_cipher_func *encrypt)
+{
+  static const uint8_t const_zero[] = {
+    0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00
+  };
+  union nettle_block16 *L = &ctx->block;
+  memset(ctx, 0, sizeof(*ctx));
+
+  /* step 1 - generate subkeys k1 and k2 */
+  encrypt(cipher, 16, L->b, const_zero);
+
+  _cmac128_block_mulx(&ctx->K1, L);
+  _cmac128_block_mulx(&ctx->K2, &ctx->K1);
+}
+
+#define MIN(x,y) ((x)<(y)?(x):(y))
+
+static void
+cmac128_update(struct cmac128_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 < 16)
+    {
+      size_t len = MIN(16 - 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, 16);
+  encrypt(cipher, 16, ctx->X.b, Y.b);
+
+  while (msg_len > 16)
+    {
+      memxor3(Y.b, ctx->X.b, msg, 16);
+      encrypt(cipher, 16, ctx->X.b, Y.b);
+      msg += 16;
+      msg_len -= 16;
+    }
+
+  /*
+   * copy the last block, it will be processed in
+   * cmac128_digest().
+   */
+  memcpy(ctx->block.b, msg, msg_len);
+  ctx->index = msg_len;
+}
+
+static void
+cmac128_digest(struct cmac128_ctx *ctx, const void *cipher,
+              nettle_cipher_func *encrypt,
+              unsigned length,
+              uint8_t *dst)
+{
+  union nettle_block16 Y;
+
+  memset(ctx->block.b+ctx->index, 0, sizeof(ctx->block.b)-ctx->index);
+
+  /* re-use ctx->block for memxor output */
+  if (ctx->index < 16)
+    {
+      ctx->block.b[ctx->index] = 0x80;
+      memxor(ctx->block.b, ctx->K2.b, 16);
+    }
+  else
+    {
+      memxor(ctx->block.b, ctx->K1.b, 16);
+    }
+
+  memxor3(Y.b, ctx->block.b, ctx->X.b, 16);
+
+  assert(length <= 16);
+  if (length == 16)
+    {
+      encrypt(cipher, 16, dst, Y.b);
+    }
+  else
+    {
+      encrypt(cipher, 16, 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;
+}
+
+
+#define CMAC128_CTX(type) \
+  { struct cmac128_ctx ctx; type cipher; }
+
+/* NOTE: Avoid using NULL, as we don't include anything defining it. */
+#define CMAC128_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);       \
+    cmac128_set_key(&(self)->ctx, &(self)->cipher,             \
+               (nettle_cipher_func *) (encrypt));              \
+  } while (0)
+
+#define CMAC128_UPDATE(self, encrypt, length, src)             \
+  cmac128_update(&(self)->ctx, &(self)->cipher,                        \
+             (nettle_cipher_func *)encrypt, (length), (src))
+
+#define CMAC128_DIGEST(self, encrypt, length, digest)          \
+  (0 ? (encrypt)(&(self)->cipher, ~(size_t) 0,                 \
+                (uint8_t *) 0, (const uint8_t *) 0)            \
+     : cmac128_digest(&(self)->ctx, &(self)->cipher,           \
+                 (nettle_cipher_func *) (encrypt),             \
+                 (length), (digest)))
+
+struct cmac_aes128_ctx CMAC128_CTX(struct aes128_ctx);
+
+static void
+cmac_aes128_set_key(struct cmac_aes128_ctx *ctx, const uint8_t *key)
+{
+  CMAC128_SET_KEY(ctx, aes128_set_encrypt_key, aes128_encrypt, key);
+}
+
+static void
+cmac_aes128_update (struct cmac_aes128_ctx *ctx,
+                  size_t length, const uint8_t *data)
+{
+  CMAC128_UPDATE (ctx, aes128_encrypt, length, data);
+}
+
+static void
+cmac_aes128_digest(struct cmac_aes128_ctx *ctx,
+                 size_t length, uint8_t *digest)
+{
+  CMAC128_DIGEST(ctx, aes128_encrypt, length, digest);
+}
+
+static const uint8_t const_one[] = {
+       0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x01
+};
+
+static const uint8_t const_zero[] = {
+       0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00
+};
+
+static
+void _siv_s2v(nettle_set_key_func *cmac_set_key,
+             nettle_hash_update_func *cmac_update,
+             nettle_hash_digest_func *cmac_digest,
+             size_t cmac_ctx_size,
+             const uint8_t *s2vk, size_t alength, const uint8_t *adata,
+              size_t nlength, const uint8_t *nonce,
+              size_t plength, const uint8_t *pdata,
+              uint8_t *v)
+{
+  uint8_t ctx[sizeof(struct cmac128_ctx)+sizeof(struct aes_ctx)];
+  union nettle_block16 D, S, T;
+
+  assert(cmac_ctx_size <= sizeof (ctx));
+
+  cmac_set_key(ctx, s2vk);
+
+  if (nlength == 0 && alength == 0) {
+    cmac_update(ctx, 16, const_one);
+    cmac_digest(ctx, 16, v);
+    return;
+  }
+
+  cmac_update(ctx, 16, const_zero);
+  cmac_digest(ctx, 16, D.b);
+
+  if (1) {
+    _cmac128_block_mulx(&D, &D);
+    cmac_update(ctx, alength, adata);
+    cmac_digest(ctx, 16, S.b);
+
+    memxor(D.b, S.b, 16);
+  }
+
+  if (nlength > 0) {
+    _cmac128_block_mulx(&D, &D);
+    cmac_update(ctx, nlength, nonce);
+    cmac_digest(ctx, 16, S.b);
+
+    memxor(D.b, S.b, 16);
+  }
+
+  /* Sn */
+  if (plength >= 16) {
+    cmac_update(ctx, plength-16, pdata);
+
+    pdata += plength-16;
+
+    memxor3(T.b, pdata, D.b, 16);
+  } else {
+    union nettle_block16 pad;
+
+    _cmac128_block_mulx(&T, &D);
+    memcpy(pad.b, pdata, plength);
+    pad.b[plength] = 0x80;
+    if (plength+1 < 16)
+      memset(&pad.b[plength+1], 0, 16-plength-1);
+
+    memxor(T.b, pad.b, 16);
+  }
+
+  cmac_update(ctx, 16, T.b);
+  cmac_digest(ctx, 16, v);
+}
+
+static void
+siv_cmac_aes128_set_key(struct siv_cmac_aes128_ctx *ctx, const uint8_t *key)
+{
+  memcpy(ctx->s2vk, key, 16);
+  aes128_set_encrypt_key(&ctx->cipher, key+16);
+}
+
+static void
+siv_cmac_aes128_encrypt_message(struct siv_cmac_aes128_ctx *ctx,
+                               size_t nlength, const uint8_t *nonce,
+                               size_t alength, const uint8_t *adata,
+                               size_t clength, uint8_t *dst, const uint8_t *src)
+{
+  union nettle_block16 siv;
+  size_t slength;
+
+  assert (clength >= SIV_DIGEST_SIZE);
+  slength = clength - SIV_DIGEST_SIZE;
+
+  /* create CTR nonce */
+  _siv_s2v((nettle_set_key_func*)cmac_aes128_set_key,
+          (nettle_hash_update_func*)cmac_aes128_update,
+          (nettle_hash_digest_func*)cmac_aes128_digest,
+          sizeof(struct cmac_aes128_ctx), ctx->s2vk, alength, adata,
+          nlength, nonce, slength, src, siv.b);
+  memcpy(dst, siv.b, SIV_DIGEST_SIZE);
+  siv.b[8] &= ~0x80;
+  siv.b[12] &= ~0x80;
+
+  ctr_crypt(&ctx->cipher, (nettle_cipher_func *)aes128_encrypt, AES_BLOCK_SIZE,
+            siv.b, slength, dst+SIV_DIGEST_SIZE, src);
+}
+
+static int
+siv_cmac_aes128_decrypt_message(struct siv_cmac_aes128_ctx *ctx,
+                               size_t nlength, const uint8_t *nonce,
+                               size_t alength, const uint8_t *adata,
+                               size_t mlength, uint8_t *dst, const uint8_t *src)
+{
+  union nettle_block16 siv;
+  union nettle_block16 ctr;
+
+  memcpy(ctr.b, src, SIV_DIGEST_SIZE);
+  ctr.b[8] &= ~0x80;
+  ctr.b[12] &= ~0x80;
+
+  ctr_crypt(&ctx->cipher, (nettle_cipher_func *)aes128_encrypt, AES_BLOCK_SIZE,
+            ctr.b, mlength, dst, src+SIV_DIGEST_SIZE);
+
+  /* create CTR nonce */
+  _siv_s2v((nettle_set_key_func*)cmac_aes128_set_key,
+          (nettle_hash_update_func*)cmac_aes128_update,
+          (nettle_hash_digest_func*)cmac_aes128_digest,
+          sizeof(struct cmac_aes128_ctx), ctx->s2vk, alength, adata,
+          nlength, nonce, mlength, dst, siv.b);
+
+  return memeql_sec(siv.b, src, SIV_DIGEST_SIZE);
+}
+