]> git.ipfire.org Git - thirdparty/nettle.git/commitdiff
Refactor GCM C implementation.
authorNiels Möller <nisse@lysator.liu.se>
Fri, 18 Feb 2022 20:14:49 +0000 (21:14 +0100)
committerNiels Möller <nisse@lysator.liu.se>
Fri, 18 Feb 2022 20:14:49 +0000 (21:14 +0100)
Assembly implementations not yet updated.

* Makefile.in (nettle_SOURCES): Add ghash-set-key.c ghash-update.c.
(DISTFILES): Replaced gcm-internal.h with ghash-internal.h.

* testsuite/gcm-test.c (test_ghash_internal): Updated to use
_ghash_set_key and _ghash_update.

* gcm.c (INC32): Deleted macro, used in only one place.
(gcm_set_key): Update to use _ghash_set_key.
(gcm_hash): Renamed, was _gcm_hash, and implemented in terms of
_ghash_update.
(bswap_if_le): New function (copied from nist-keywrap.c).
(gcm_hash_sizes): Use bswap_if_le and _ghash_update.
(gcm_set_iv): Updated to use gcm_hash and block16_zero.
(gcm_digest): Use _ghash_digest.

* ghash-internal.h: New file, declaring new internal ghash interface.
* gcm-internal.h: Deleted file.
* ghash-update.c (gcm_gf_shift_8): Moved here (from gcm.c)
(gcm_gf_mul): Likewise.
(_ghash_update): New function, extracted from _nettle_gcm_hash_c.
(_ghash_digest): New function.
* ghash-set-key.c (_ghash_set_key): New file and function.
Extracted from _nettle_gcm_init_key_c and _nettle_gcm_set_key.

ChangeLog
Makefile.in
gcm-internal.h [deleted file]
gcm.c
ghash-internal.h [new file with mode: 0644]
ghash-set-key.c [new file with mode: 0644]
ghash-update.c [new file with mode: 0644]
testsuite/gcm-test.c

index 4ec5b49a5e2739a3754822bb2115af393314a43e..edfd411ae54f27002de0075b82c9d1a7d04871e7 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,30 @@
 
        * block-internal.h (block16_zero): New function.
 
+       * ghash-internal.h: New file, declaring new internal ghash interface.
+       * gcm-internal.h: Deleted file.
+       * ghash-update.c (gcm_gf_shift_8): Moved here (from gcm.c)
+       (gcm_gf_mul): Likewise.
+       (_ghash_update): New function, extracted from _nettle_gcm_hash_c.
+       (_ghash_digest): New function.
+       * ghash-set-key.c (_ghash_set_key): New file and function.
+       Extracted from _nettle_gcm_init_key_c and _nettle_gcm_set_key.
+
+       * gcm.c (INC32): Deleted macro, used in only one place.
+       (gcm_set_key): Update to use _ghash_set_key.
+       (gcm_hash): Renamed, was _gcm_hash, and implemented in terms of
+       _ghash_update.
+       (bswap_if_le): New function (copied from nist-keywrap.c).
+       (gcm_hash_sizes): Use bswap_if_le and _ghash_update.
+       (gcm_set_iv): Updated to use gcm_hash and block16_zero.
+       (gcm_digest): Use _ghash_digest.
+
+       * testsuite/gcm-test.c (test_ghash_internal): Updated to use
+       _ghash_set_key and _ghash_update.
+
+       * Makefile.in (nettle_SOURCES): Add ghash-set-key.c ghash-update.c.
+       (DISTFILES): Replaced gcm-internal.h with ghash-internal.h.
+
 2022-02-17  Niels Möller  <nisse@lysator.liu.se>
 
        * gcm.c: Require that GCM_TABLE_BITS == 8. Delete old code for
index f6bc2155caa5c0103175b7c034affd50818423b0..116b1cc2648ca1e64e628bf2309243e3ee264d45 100644 (file)
@@ -106,7 +106,7 @@ nettle_SOURCES = aes-decrypt-internal.c aes-decrypt.c aes-decrypt-table.c \
                 chacha-set-key.c chacha-set-nonce.c \
                 ctr.c ctr16.c des.c des3.c \
                 eax.c eax-aes128.c eax-aes128-meta.c \
-                gcm.c gcm-aes.c \
+                ghash-set-key.c ghash-update.c gcm.c gcm-aes.c \
                 gcm-aes128.c gcm-aes128-meta.c \
                 gcm-aes192.c gcm-aes192-meta.c \
                 gcm-aes256.c gcm-aes256-meta.c \
@@ -258,7 +258,7 @@ DISTFILES = $(SOURCES) $(HEADERS) getopt.h getopt_int.h \
        nettle.pc.in hogweed.pc.in \
        desdata.stamp $(des_headers) descore.README \
        aes-internal.h block-internal.h blowfish-internal.h camellia-internal.h \
-       gcm-internal.h gost28147-internal.h poly1305-internal.h \
+       ghash-internal.h gost28147-internal.h poly1305-internal.h \
        serpent-internal.h cast128_sboxes.h desinfo.h desCode.h \
        ripemd160-internal.h sha2-internal.h \
        memxor-internal.h nettle-internal.h nettle-write.h \
diff --git a/gcm-internal.h b/gcm-internal.h
deleted file mode 100644 (file)
index 0b2d7ce..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/* gcm-internal.h
-
-   Copyright (C) 2020 Niels Möller
-
-   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/.
-*/
-
-#ifndef NETTLE_GCM_INTERNAL_H_INCLUDED
-#define NETTLE_GCM_INTERNAL_H_INCLUDED
-
-/* Arrange so that _gcm_hash is an alias for the right implementation. */
-#if HAVE_NATIVE_gcm_hash || HAVE_NATIVE_fat_gcm_hash
-# define _gcm_hash _nettle_gcm_hash
-#elif HAVE_NATIVE_gcm_hash8
-# define _gcm_hash _nettle_gcm_hash8
-#else
-# define _gcm_hash _nettle_gcm_hash_c
-#endif
-
-/* Declare all variants, if defined depends on configuration. */
-void
-_nettle_gcm_set_key (struct gcm_key *gcm, const uint8_t *key);
-
-void
-_nettle_gcm_hash(const struct gcm_key *key, union nettle_block16 *x,
-                size_t length, const uint8_t *data);
-
-void
-_nettle_gcm_hash8(const struct gcm_key *key, union nettle_block16 *x,
-                 size_t length, const uint8_t *data);
-
-void
-_nettle_gcm_hash_c(const struct gcm_key *key, union nettle_block16 *x,
-                 size_t length, const uint8_t *data);
-
-void
-_nettle_gcm_init_key (union nettle_block16 *table);
-
-#if HAVE_NATIVE_fat_gcm_init_key
-void
-_nettle_gcm_init_key_c (union nettle_block16 *table);
-#endif
-
-#endif /* NETTLE_GCM_INTERNAL_H_INCLUDED */
diff --git a/gcm.c b/gcm.c
index e70c6887a25af6e65ea42b561c3afa22b62b6330..cccac08f1e5a9e4163eda291e9fb11191d98a9cd 100644 (file)
--- a/gcm.c
+++ b/gcm.c
 
 #include "gcm.h"
 
-#include "gcm-internal.h"
+#include "ghash-internal.h"
 #include "memxor.h"
 #include "nettle-internal.h"
 #include "macros.h"
 #include "ctr-internal.h"
 #include "block-internal.h"
 
-#if GCM_TABLE_BITS != 8
-# error Unsupported table size.
-#endif
-
-#if !HAVE_NATIVE_gcm_hash
-
-# if WORDS_BIGENDIAN
-#  define W(left,right) (0x##left##right)
-# else
-#  define W(left,right) (0x##right##left)
-# endif
-
-# if !HAVE_NATIVE_gcm_hash8
-static const uint16_t
-shift_table[0x100] = {
-  W(00,00),W(01,c2),W(03,84),W(02,46),W(07,08),W(06,ca),W(04,8c),W(05,4e),
-  W(0e,10),W(0f,d2),W(0d,94),W(0c,56),W(09,18),W(08,da),W(0a,9c),W(0b,5e),
-  W(1c,20),W(1d,e2),W(1f,a4),W(1e,66),W(1b,28),W(1a,ea),W(18,ac),W(19,6e),
-  W(12,30),W(13,f2),W(11,b4),W(10,76),W(15,38),W(14,fa),W(16,bc),W(17,7e),
-  W(38,40),W(39,82),W(3b,c4),W(3a,06),W(3f,48),W(3e,8a),W(3c,cc),W(3d,0e),
-  W(36,50),W(37,92),W(35,d4),W(34,16),W(31,58),W(30,9a),W(32,dc),W(33,1e),
-  W(24,60),W(25,a2),W(27,e4),W(26,26),W(23,68),W(22,aa),W(20,ec),W(21,2e),
-  W(2a,70),W(2b,b2),W(29,f4),W(28,36),W(2d,78),W(2c,ba),W(2e,fc),W(2f,3e),
-  W(70,80),W(71,42),W(73,04),W(72,c6),W(77,88),W(76,4a),W(74,0c),W(75,ce),
-  W(7e,90),W(7f,52),W(7d,14),W(7c,d6),W(79,98),W(78,5a),W(7a,1c),W(7b,de),
-  W(6c,a0),W(6d,62),W(6f,24),W(6e,e6),W(6b,a8),W(6a,6a),W(68,2c),W(69,ee),
-  W(62,b0),W(63,72),W(61,34),W(60,f6),W(65,b8),W(64,7a),W(66,3c),W(67,fe),
-  W(48,c0),W(49,02),W(4b,44),W(4a,86),W(4f,c8),W(4e,0a),W(4c,4c),W(4d,8e),
-  W(46,d0),W(47,12),W(45,54),W(44,96),W(41,d8),W(40,1a),W(42,5c),W(43,9e),
-  W(54,e0),W(55,22),W(57,64),W(56,a6),W(53,e8),W(52,2a),W(50,6c),W(51,ae),
-  W(5a,f0),W(5b,32),W(59,74),W(58,b6),W(5d,f8),W(5c,3a),W(5e,7c),W(5f,be),
-  W(e1,00),W(e0,c2),W(e2,84),W(e3,46),W(e6,08),W(e7,ca),W(e5,8c),W(e4,4e),
-  W(ef,10),W(ee,d2),W(ec,94),W(ed,56),W(e8,18),W(e9,da),W(eb,9c),W(ea,5e),
-  W(fd,20),W(fc,e2),W(fe,a4),W(ff,66),W(fa,28),W(fb,ea),W(f9,ac),W(f8,6e),
-  W(f3,30),W(f2,f2),W(f0,b4),W(f1,76),W(f4,38),W(f5,fa),W(f7,bc),W(f6,7e),
-  W(d9,40),W(d8,82),W(da,c4),W(db,06),W(de,48),W(df,8a),W(dd,cc),W(dc,0e),
-  W(d7,50),W(d6,92),W(d4,d4),W(d5,16),W(d0,58),W(d1,9a),W(d3,dc),W(d2,1e),
-  W(c5,60),W(c4,a2),W(c6,e4),W(c7,26),W(c2,68),W(c3,aa),W(c1,ec),W(c0,2e),
-  W(cb,70),W(ca,b2),W(c8,f4),W(c9,36),W(cc,78),W(cd,ba),W(cf,fc),W(ce,3e),
-  W(91,80),W(90,42),W(92,04),W(93,c6),W(96,88),W(97,4a),W(95,0c),W(94,ce),
-  W(9f,90),W(9e,52),W(9c,14),W(9d,d6),W(98,98),W(99,5a),W(9b,1c),W(9a,de),
-  W(8d,a0),W(8c,62),W(8e,24),W(8f,e6),W(8a,a8),W(8b,6a),W(89,2c),W(88,ee),
-  W(83,b0),W(82,72),W(80,34),W(81,f6),W(84,b8),W(85,7a),W(87,3c),W(86,fe),
-  W(a9,c0),W(a8,02),W(aa,44),W(ab,86),W(ae,c8),W(af,0a),W(ad,4c),W(ac,8e),
-  W(a7,d0),W(a6,12),W(a4,54),W(a5,96),W(a0,d8),W(a1,1a),W(a3,5c),W(a2,9e),
-  W(b5,e0),W(b4,22),W(b6,64),W(b7,a6),W(b2,e8),W(b3,2a),W(b1,6c),W(b0,ae),
-  W(bb,f0),W(ba,32),W(b8,74),W(b9,b6),W(bc,f8),W(bd,3a),W(bf,7c),W(be,be),
-};
-
-static void
-gcm_gf_shift_8(union nettle_block16 *x)
-{
-  uint64_t reduce;
-
-  /* Shift uses big-endian representation. */
+/* FIXME: Duplicated in nist-keywrap.c */
 #if WORDS_BIGENDIAN
-  reduce = shift_table[x->u64[1] & 0xff];
-  x->u64[1] = (x->u64[1] >> 8) | ((x->u64[0] & 0xff) << 56);
-  x->u64[0] = (x->u64[0] >> 8) ^ (reduce << 48);
-#else /* ! WORDS_BIGENDIAN */
-  reduce = shift_table[(x->u64[1] >> 56) & 0xff];
-  x->u64[1] = (x->u64[1] << 8) | (x->u64[0] >> 56);
-  x->u64[0] = (x->u64[0] << 8) ^ reduce;
-#endif /* ! WORDS_BIGENDIAN */
-}
-
-static void
-gcm_gf_mul (union nettle_block16 *x, const union nettle_block16 *table)
-{
-  union nettle_block16 Z;
-  unsigned i;
-
-  memcpy(Z.b, table[x->b[GCM_BLOCK_SIZE-1]].b, GCM_BLOCK_SIZE);
-
-  for (i = GCM_BLOCK_SIZE-2; i > 0; i--)
-    {
-      gcm_gf_shift_8(&Z);
-      block16_xor(&Z, &table[x->b[i]]);
-    }
-  gcm_gf_shift_8(&Z);
-  block16_xor3(x, &Z, &table[x->b[0]]);
-}
-# endif /* ! HAVE_NATIVE_gcm_hash8 */
-
-# undef W
-#endif /* !HAVE_NATIVE_gcm_hash */
-
-
-/* Increment the rightmost 32 bits. */
-#define INC32(block) INCREMENT(4, (block.b) + GCM_BLOCK_SIZE - 4)
-
-#if !HAVE_NATIVE_gcm_init_key
-# if !HAVE_NATIVE_fat_gcm_hash
-#  define _nettle_gcm_init_key _nettle_gcm_init_key_c
-static
-# endif
-void
-_nettle_gcm_init_key_c(union nettle_block16 *table)
-{
-  /* Middle element if GCM_TABLE_BITS > 0, otherwise the first
-     element */
-  unsigned i = (1<<GCM_TABLE_BITS)/2;
-
-  /* Algorithm 3 from the gcm paper. First do powers of two, then do
-     the rest by adding. */
-  while (i /= 2)
-    block16_mulx_ghash(&table[i], &table[2*i]);
-  for (i = 2; i < 1<<GCM_TABLE_BITS; i *= 2)
-    {
-      unsigned j;
-      for (j = 1; j < i; j++)
-       block16_xor3(&table[i+j], &table[i], &table[j]);
-    }
-}
-#endif /* !HAVE_NATIVE_gcm_init_key */
-
-void
-_nettle_gcm_set_key (struct gcm_key *gcm, const uint8_t *key)
+#define bswap_if_le(x) (x)
+#elif HAVE_BUILTIN_BSWAP64
+#define bswap_if_le(x) (__builtin_bswap64 (x))
+#else
+static uint64_t
+bswap_if_le (uint64_t x)
 {
-  memset (gcm->h[0].b, 0, GCM_BLOCK_SIZE);
-  /* Middle element if GCM_TABLE_BITS > 0, otherwise the first
-     element */
-  memcpy (gcm->h[(1<<GCM_TABLE_BITS)/2].b, key, GCM_BLOCK_SIZE);
-  _nettle_gcm_init_key(gcm->h);
+  x = ((x >> 32) & UINT64_C (0xffffffff))
+    | ((x & UINT64_C (0xffffffff)) << 32);
+  x = ((x >> 16) & UINT64_C (0xffff0000ffff))
+    | ((x & UINT64_C (0xffff0000ffff)) << 16);
+  x = ((x >> 8) & UINT64_C (0xff00ff00ff00ff))
+    | ((x & UINT64_C (0xff00ff00ff00ff)) << 8);
+  return x;
 }
+#endif
 
 /* Initialization of GCM.
  * @ctx: The context of GCM
@@ -195,41 +88,37 @@ gcm_set_key(struct gcm_key *key,
   union nettle_block16 key_block;
   f (cipher, GCM_BLOCK_SIZE, key_block.b, zero_block.b);
 
-  _nettle_gcm_set_key (key, key_block.b);
+  _ghash_set_key (key, &key_block);
 }
 
-#if !(HAVE_NATIVE_gcm_hash || HAVE_NATIVE_gcm_hash8)
-void
-_nettle_gcm_hash_c(const struct gcm_key *key, union nettle_block16 *x,
-                  size_t length, const uint8_t *data)
-{
-  for (; length >= GCM_BLOCK_SIZE;
-       length -= GCM_BLOCK_SIZE, data += GCM_BLOCK_SIZE)
-    {
-      memxor (x->b, data, GCM_BLOCK_SIZE);
-      gcm_gf_mul (x, key->h);
-    }
+/* Call _ghash_update, with zero padding of any partial final block. */
+static void
+gcm_hash (const struct gcm_key *key, union nettle_block16 *x,
+         size_t length, const uint8_t *data) {
+  data = _ghash_update (key, x, length / GCM_BLOCK_SIZE, data);
+  length &= (GCM_BLOCK_SIZE - 1);
   if (length > 0)
     {
-      memxor (x->b, data, length);
-      gcm_gf_mul (x, key->h);
+      union nettle_block16 block;
+      block16_zero (&block);
+      memcpy (block.b, data, length);
+      _ghash_update (key, x, 1, block.b);
     }
 }
-#endif /* !(HAVE_NATIVE_gcm_hash || HAVE_NATIVE_gcm_hash8) */
 
 static void
 gcm_hash_sizes(const struct gcm_key *key, union nettle_block16 *x,
               uint64_t auth_size, uint64_t data_size)
 {
-  uint8_t buffer[GCM_BLOCK_SIZE];
+  union nettle_block16 buffer;
 
   data_size *= 8;
   auth_size *= 8;
 
-  WRITE_UINT64 (buffer, auth_size);
-  WRITE_UINT64 (buffer + 8, data_size);
+  buffer.u64[0] = bswap_if_le (auth_size);
+  buffer.u64[1] = bswap_if_le (data_size);
 
-  _gcm_hash(key, x, GCM_BLOCK_SIZE, buffer);
+  _ghash_update (key, x, 1, buffer.b);
 }
 
 /* NOTE: The key is needed only if length != GCM_IV_SIZE */
@@ -247,16 +136,17 @@ gcm_set_iv(struct gcm_ctx *ctx, const struct gcm_key *key,
     }
   else
     {
-      memset(ctx->iv.b, 0, GCM_BLOCK_SIZE);
-      _gcm_hash(key, &ctx->iv, length, iv);
+      block16_zero(&ctx->iv);
+      gcm_hash(key, &ctx->iv, length, iv);
       gcm_hash_sizes(key, &ctx->iv, 0, length);
     }
 
-  memcpy (ctx->ctr.b, ctx->iv.b, GCM_BLOCK_SIZE);
-  INC32 (ctx->ctr);
+  ctx->ctr = ctx->iv;
+  /* Increment the rightmost 32 bits. */
+  INCREMENT (4, ctx->ctr.b + GCM_BLOCK_SIZE - 4);
 
   /* Reset the rest of the message-dependent state. */
-  memset(ctx->x.b, 0, sizeof(ctx->x));
+  block16_zero(&ctx->x);
   ctx->auth_size = ctx->data_size = 0;
 }
 
@@ -267,7 +157,7 @@ gcm_update(struct gcm_ctx *ctx, const struct gcm_key *key,
   assert(ctx->auth_size % GCM_BLOCK_SIZE == 0);
   assert(ctx->data_size == 0);
 
-  _gcm_hash(key, &ctx->x, length, data);
+  gcm_hash(key, &ctx->x, length, data);
 
   ctx->auth_size += length;
 }
@@ -338,7 +228,7 @@ gcm_encrypt (struct gcm_ctx *ctx, const struct gcm_key *key,
   assert(ctx->data_size % GCM_BLOCK_SIZE == 0);
 
   _nettle_ctr_crypt16(cipher, f, gcm_fill, ctx->ctr.b, length, dst, src);
-  _gcm_hash(key, &ctx->x, length, dst);
+  gcm_hash(key, &ctx->x, length, dst);
 
   ctx->data_size += length;
 }
@@ -350,7 +240,7 @@ gcm_decrypt(struct gcm_ctx *ctx, const struct gcm_key *key,
 {
   assert(ctx->data_size % GCM_BLOCK_SIZE == 0);
 
-  _gcm_hash(key, &ctx->x, length, src);
+  gcm_hash(key, &ctx->x, length, src);
   _nettle_ctr_crypt16(cipher, f, gcm_fill, ctx->ctr.b, length, dst, src);
 
   ctx->data_size += length;
@@ -361,14 +251,15 @@ gcm_digest(struct gcm_ctx *ctx, const struct gcm_key *key,
           const void *cipher, nettle_cipher_func *f,
           size_t length, uint8_t *digest)
 {
-  uint8_t buffer[GCM_BLOCK_SIZE];
+  union nettle_block16 buffer;
 
   assert (length <= GCM_BLOCK_SIZE);
 
   gcm_hash_sizes(key, &ctx->x, ctx->auth_size, ctx->data_size);
 
-  f (cipher, GCM_BLOCK_SIZE, buffer, ctx->iv.b);
-  memxor3 (digest, ctx->x.b, buffer, length);
+  f (cipher, GCM_BLOCK_SIZE, buffer.b, ctx->iv.b);
+  _ghash_digest (&ctx->x, &buffer);
+  memcpy (digest, buffer.b, length);
 
   return;
 }
diff --git a/ghash-internal.h b/ghash-internal.h
new file mode 100644 (file)
index 0000000..d0bfae1
--- /dev/null
@@ -0,0 +1,72 @@
+/* ghash-internal.h
+
+   Copyright (C) 2022 Niels Möller
+
+   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/.
+*/
+
+#ifndef NETTLE_GHASH_INTERNAL_H_INCLUDED
+#define NETTLE_GHASH_INTERNAL_H_INCLUDED
+
+#include "nettle-types.h"
+#include "gcm.h"
+
+/* Name mangling */
+#define _ghash_set_key _nettle_ghash_set_key
+#define _ghash_update _nettle_ghash_update
+#define _ghash_digest _nettle_ghash_digest
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The CTX a struct gcm_key (even if struct ghash_key might be a more
+ * appropriate name). An array of blocks, exact contents depends on
+ * the implementation. STATE is only a single block. Initial state is
+ * all zero, otherwise, usage (e.g., byte order) depends on
+ * implementation. */
+
+/* Expands KEY as needed, for corresponding _ghash_update */
+void
+_ghash_set_key (struct gcm_key *ctx, const union nettle_block16 *key);
+
+/* Updates STATE by hashing DATA, which must be an integral number of
+   blocks. For convenience, returns a pointer to the end of the
+   data. */
+const uint8_t *
+_ghash_update (const struct gcm_key *ctx, union nettle_block16 *state,
+              size_t blocks, const uint8_t *data);
+
+/* Produces final digest, and XORS into the digest block. */
+void 
+_ghash_digest (const union nettle_block16 *state, union nettle_block16 *digest);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_GHASH_INTERNAL_H_INCLUDED */
diff --git a/ghash-set-key.c b/ghash-set-key.c
new file mode 100644 (file)
index 0000000..e8813a5
--- /dev/null
@@ -0,0 +1,68 @@
+/* ghash-set-key.c
+
+   Galois counter mode, specified by NIST,
+   http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf
+
+   See also the gcm paper at
+   http://www.cryptobarn.com/papers/gcm-spec.pdf.
+
+   Copyright (C) 2011 Katholieke Universiteit Leuven
+   Copyright (C) 2011, 2013, 2018, 2022 Niels Möller
+   Copyright (C) 2018 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/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "ghash-internal.h"
+#include "block-internal.h"
+
+/* Implements a lookup table for processors without carryless-mul
+   instruction. */
+void
+_ghash_set_key (struct gcm_key *ctx, const union nettle_block16 *key)
+{
+  /* Middle element if GCM_TABLE_BITS > 0, otherwise the first
+     element */
+  unsigned i = (1<<GCM_TABLE_BITS)/2;
+  block16_zero (&ctx->h[0]);
+  ctx->h[i] = *key;
+
+  /* Algorithm 3 from the gcm paper. First do powers of two, then do
+     the rest by adding. */
+  while (i /= 2)
+    block16_mulx_ghash (&ctx->h[i], &ctx->h[2*i]);
+  for (i = 2; i < 1<<GCM_TABLE_BITS; i *= 2)
+    {
+      unsigned j;
+      for (j = 1; j < i; j++)
+       block16_xor3 (&ctx->h[i+j], &ctx->h[i], &ctx->h[j]);
+    }
+}
diff --git a/ghash-update.c b/ghash-update.c
new file mode 100644 (file)
index 0000000..00940ae
--- /dev/null
@@ -0,0 +1,144 @@
+/* ghash-update.c
+
+   Galois counter mode, specified by NIST,
+   http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf
+
+   See also the gcm paper at
+   http://www.cryptobarn.com/papers/gcm-spec.pdf.
+
+   Copyright (C) 2011 Katholieke Universiteit Leuven
+   Copyright (C) 2011, 2013, 2018, 2022 Niels Möller
+   Copyright (C) 2018 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/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "ghash-internal.h"
+#include "block-internal.h"
+
+#if GCM_TABLE_BITS != 8
+# error Unsupported table size.
+#endif
+
+#if WORDS_BIGENDIAN
+# define W(left,right) (0x##left##right)
+#else
+# define W(left,right) (0x##right##left)
+#endif
+
+static const uint16_t
+shift_table[0x100] = {
+  W(00,00),W(01,c2),W(03,84),W(02,46),W(07,08),W(06,ca),W(04,8c),W(05,4e),
+  W(0e,10),W(0f,d2),W(0d,94),W(0c,56),W(09,18),W(08,da),W(0a,9c),W(0b,5e),
+  W(1c,20),W(1d,e2),W(1f,a4),W(1e,66),W(1b,28),W(1a,ea),W(18,ac),W(19,6e),
+  W(12,30),W(13,f2),W(11,b4),W(10,76),W(15,38),W(14,fa),W(16,bc),W(17,7e),
+  W(38,40),W(39,82),W(3b,c4),W(3a,06),W(3f,48),W(3e,8a),W(3c,cc),W(3d,0e),
+  W(36,50),W(37,92),W(35,d4),W(34,16),W(31,58),W(30,9a),W(32,dc),W(33,1e),
+  W(24,60),W(25,a2),W(27,e4),W(26,26),W(23,68),W(22,aa),W(20,ec),W(21,2e),
+  W(2a,70),W(2b,b2),W(29,f4),W(28,36),W(2d,78),W(2c,ba),W(2e,fc),W(2f,3e),
+  W(70,80),W(71,42),W(73,04),W(72,c6),W(77,88),W(76,4a),W(74,0c),W(75,ce),
+  W(7e,90),W(7f,52),W(7d,14),W(7c,d6),W(79,98),W(78,5a),W(7a,1c),W(7b,de),
+  W(6c,a0),W(6d,62),W(6f,24),W(6e,e6),W(6b,a8),W(6a,6a),W(68,2c),W(69,ee),
+  W(62,b0),W(63,72),W(61,34),W(60,f6),W(65,b8),W(64,7a),W(66,3c),W(67,fe),
+  W(48,c0),W(49,02),W(4b,44),W(4a,86),W(4f,c8),W(4e,0a),W(4c,4c),W(4d,8e),
+  W(46,d0),W(47,12),W(45,54),W(44,96),W(41,d8),W(40,1a),W(42,5c),W(43,9e),
+  W(54,e0),W(55,22),W(57,64),W(56,a6),W(53,e8),W(52,2a),W(50,6c),W(51,ae),
+  W(5a,f0),W(5b,32),W(59,74),W(58,b6),W(5d,f8),W(5c,3a),W(5e,7c),W(5f,be),
+  W(e1,00),W(e0,c2),W(e2,84),W(e3,46),W(e6,08),W(e7,ca),W(e5,8c),W(e4,4e),
+  W(ef,10),W(ee,d2),W(ec,94),W(ed,56),W(e8,18),W(e9,da),W(eb,9c),W(ea,5e),
+  W(fd,20),W(fc,e2),W(fe,a4),W(ff,66),W(fa,28),W(fb,ea),W(f9,ac),W(f8,6e),
+  W(f3,30),W(f2,f2),W(f0,b4),W(f1,76),W(f4,38),W(f5,fa),W(f7,bc),W(f6,7e),
+  W(d9,40),W(d8,82),W(da,c4),W(db,06),W(de,48),W(df,8a),W(dd,cc),W(dc,0e),
+  W(d7,50),W(d6,92),W(d4,d4),W(d5,16),W(d0,58),W(d1,9a),W(d3,dc),W(d2,1e),
+  W(c5,60),W(c4,a2),W(c6,e4),W(c7,26),W(c2,68),W(c3,aa),W(c1,ec),W(c0,2e),
+  W(cb,70),W(ca,b2),W(c8,f4),W(c9,36),W(cc,78),W(cd,ba),W(cf,fc),W(ce,3e),
+  W(91,80),W(90,42),W(92,04),W(93,c6),W(96,88),W(97,4a),W(95,0c),W(94,ce),
+  W(9f,90),W(9e,52),W(9c,14),W(9d,d6),W(98,98),W(99,5a),W(9b,1c),W(9a,de),
+  W(8d,a0),W(8c,62),W(8e,24),W(8f,e6),W(8a,a8),W(8b,6a),W(89,2c),W(88,ee),
+  W(83,b0),W(82,72),W(80,34),W(81,f6),W(84,b8),W(85,7a),W(87,3c),W(86,fe),
+  W(a9,c0),W(a8,02),W(aa,44),W(ab,86),W(ae,c8),W(af,0a),W(ad,4c),W(ac,8e),
+  W(a7,d0),W(a6,12),W(a4,54),W(a5,96),W(a0,d8),W(a1,1a),W(a3,5c),W(a2,9e),
+  W(b5,e0),W(b4,22),W(b6,64),W(b7,a6),W(b2,e8),W(b3,2a),W(b1,6c),W(b0,ae),
+  W(bb,f0),W(ba,32),W(b8,74),W(b9,b6),W(bc,f8),W(bd,3a),W(bf,7c),W(be,be),
+};
+#undef W
+
+static void
+gcm_gf_shift_8(union nettle_block16 *x)
+{
+  uint64_t reduce;
+
+  /* Shift uses big-endian representation. */
+#if WORDS_BIGENDIAN
+  reduce = shift_table[x->u64[1] & 0xff];
+  x->u64[1] = (x->u64[1] >> 8) | ((x->u64[0] & 0xff) << 56);
+  x->u64[0] = (x->u64[0] >> 8) ^ (reduce << 48);
+#else /* ! WORDS_BIGENDIAN */
+  reduce = shift_table[(x->u64[1] >> 56) & 0xff];
+  x->u64[1] = (x->u64[1] << 8) | (x->u64[0] >> 56);
+  x->u64[0] = (x->u64[0] << 8) ^ reduce;
+#endif /* ! WORDS_BIGENDIAN */
+}
+
+static void
+gcm_gf_mul (union nettle_block16 *x, const union nettle_block16 *table)
+{
+  union nettle_block16 Z;
+  unsigned i;
+
+  Z = table[x->b[GCM_BLOCK_SIZE-1]];
+
+  for (i = GCM_BLOCK_SIZE-2; i > 0; i--)
+    {
+      gcm_gf_shift_8(&Z);
+      block16_xor(&Z, &table[x->b[i]]);
+    }
+  gcm_gf_shift_8(&Z);
+  block16_xor3(x, &Z, &table[x->b[0]]);
+}
+
+const uint8_t *
+_ghash_update (const struct gcm_key *ctx, union nettle_block16 *state,
+              size_t blocks, const uint8_t *data)
+{
+  for (; blocks-- > 0; data += GCM_BLOCK_SIZE)
+    {
+      memxor (state->b, data, GCM_BLOCK_SIZE);
+      gcm_gf_mul (state, ctx->h);
+    }
+  return data;
+}
+
+void
+_ghash_digest (const union nettle_block16 *state, union nettle_block16 *digest)
+{
+  block16_xor (digest, state);
+}
index d68af4e0fbbe146c7c8f6955a09301891711266f..8955e9b80ce9de586d979b546c41401d948beaf4 100644 (file)
@@ -4,7 +4,7 @@
 #include "testutils.h"
 #include "nettle-internal.h"
 #include "gcm.h"
-#include "gcm-internal.h"
+#include "ghash-internal.h"
 
 static void
 test_gcm_hash (const struct tstring *msg, const struct tstring *ref)
@@ -38,12 +38,15 @@ test_ghash_internal (const struct tstring *key,
   ASSERT (key->length == GCM_BLOCK_SIZE);
   ASSERT (iv->length == GCM_BLOCK_SIZE);
   ASSERT (digest->length == GCM_BLOCK_SIZE);
+  ASSERT (message->length % GCM_BLOCK_SIZE == 0);
   struct gcm_key gcm_key;
   union nettle_block16 state;
 
-  _nettle_gcm_set_key (&gcm_key, key->data);
+  memcpy (state.b, key->data, GCM_BLOCK_SIZE);
+  _ghash_set_key (&gcm_key, &state);
+
   memcpy (state.b, iv->data, GCM_BLOCK_SIZE);
-  _gcm_hash (&gcm_key, &state, message->length, message->data);
+  _ghash_update (&gcm_key, &state, message->length / GCM_BLOCK_SIZE, message->data);
   if (!MEMEQ(GCM_BLOCK_SIZE, state.b, digest->data))
     {
       fprintf (stderr, "gcm_hash (internal) failed\n");