+2022-02-08 Niels Möller <nisse@lysator.liu.se>
+
+ * gcm-internal.h (_gcm_hash): Arrange so that this is an alias for
+ the appropriate implementation. Updated all users.
+ * gcm.c (_nettle_gcm_set_key): New internal function, intended to
+ make tests of internal ghash functions easier.
+ (gcm_set_key): Use it.
+ * testsuite/gcm-test.c (test_ghash_internal): New function.
+ (test_main): Add tests of internal ghash functions, with keys
+ corresponding to various single-bit polynomials.
+
2022-01-28 Niels Möller <nisse@lysator.liu.se>
* testsuite/poly1305-test.c (poly1305_internal): Renamed function,
#ifndef NETTLE_GCM_INTERNAL_H_INCLUDED
#define NETTLE_GCM_INTERNAL_H_INCLUDED
-/* Functions available only in some configurations */
+#if GCM_TABLE_BITS != 8
+/* The native implementations (currently ppc64 only) depend on the
+ GCM_TABLE_BITS == 8 layout */
+#undef HAVE_NATIVE_gcm_hash
+#undef HAVE_NATIVE_gcm_init_key
+#undef HAVE_NATIVE_fat_gcm_hash
+#undef HAVE_NATIVE_fat_gcm_init_key
+#endif
+
+/* 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 GCM_TABLE_BITS == 8 && 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_init_key (union nettle_block16 *table);
+_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);
-#if HAVE_NATIVE_fat_gcm_init_key
void
-_nettle_gcm_init_key_c (union nettle_block16 *table);
-#endif
+_nettle_gcm_hash8(const struct gcm_key *key, union nettle_block16 *x,
+ size_t length, const uint8_t *data);
-#if HAVE_NATIVE_fat_gcm_hash
void
-_nettle_gcm_hash_c (const struct gcm_key *key, union nettle_block16 *x,
- size_t length, const uint8_t *data);
+_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 */
#include "ctr-internal.h"
#include "block-internal.h"
-#if GCM_TABLE_BITS != 8
-/* The native implementations (currently ppc64 only) depend on the
- GCM_TABLE_BITS == 8 layout */
-#undef HAVE_NATIVE_gcm_hash
-#undef HAVE_NATIVE_gcm_init_key
-#undef HAVE_NATIVE_fat_gcm_hash
-#undef HAVE_NATIVE_fat_gcm_init_key
-#endif
-
#if !HAVE_NATIVE_gcm_hash
# if GCM_TABLE_BITS == 0
/* Sets x <- x * y mod r, using the plain bitwise algorithm from the
memcpy (x->b, Z.b, sizeof(Z));
}
# elif GCM_TABLE_BITS == 8
-# if HAVE_NATIVE_gcm_hash8
-
-#define _nettle_gcm_hash _nettle_gcm_hash8
-void
-_nettle_gcm_hash8 (const struct gcm_key *key, union nettle_block16 *x,
- size_t length, const uint8_t *data);
-# else /* !HAVE_NATIVE_gcm_hash8 */
+# 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),
}
#endif /* !HAVE_NATIVE_gcm_init_key */
+void
+_nettle_gcm_set_key (struct gcm_key *gcm, const uint8_t *key)
+{
+ 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);
+}
+
/* Initialization of GCM.
* @ctx: The context of GCM
* @cipher: The context of the underlying block cipher
gcm_set_key(struct gcm_key *key,
const void *cipher, nettle_cipher_func *f)
{
- /* Middle element if GCM_TABLE_BITS > 0, otherwise the first
- element */
- unsigned i = (1<<GCM_TABLE_BITS)/2;
+ static const union nettle_block16 zero_block;
+ union nettle_block16 key_block;
+ f (cipher, GCM_BLOCK_SIZE, key_block.b, zero_block.b);
- /* H */
- memset(key->h[0].b, 0, GCM_BLOCK_SIZE);
- f (cipher, GCM_BLOCK_SIZE, key->h[i].b, key->h[0].b);
-
- _nettle_gcm_init_key(key->h);
+ _nettle_gcm_set_key (key, key_block.b);
}
#if !(HAVE_NATIVE_gcm_hash || HAVE_NATIVE_gcm_hash8)
-# if !HAVE_NATIVE_fat_gcm_hash
-# define _nettle_gcm_hash _nettle_gcm_hash_c
-static
-# endif
void
_nettle_gcm_hash_c(const struct gcm_key *key, union nettle_block16 *x,
size_t length, const uint8_t *data)
WRITE_UINT64 (buffer, auth_size);
WRITE_UINT64 (buffer + 8, data_size);
- _nettle_gcm_hash(key, x, GCM_BLOCK_SIZE, buffer);
+ _gcm_hash(key, x, GCM_BLOCK_SIZE, buffer);
}
/* NOTE: The key is needed only if length != GCM_IV_SIZE */
else
{
memset(ctx->iv.b, 0, GCM_BLOCK_SIZE);
- _nettle_gcm_hash(key, &ctx->iv, length, iv);
+ _gcm_hash(key, &ctx->iv, length, iv);
gcm_hash_sizes(key, &ctx->iv, 0, length);
}
assert(ctx->auth_size % GCM_BLOCK_SIZE == 0);
assert(ctx->data_size == 0);
- _nettle_gcm_hash(key, &ctx->x, length, data);
+ _gcm_hash(key, &ctx->x, length, data);
ctx->auth_size += length;
}
assert(ctx->data_size % GCM_BLOCK_SIZE == 0);
_nettle_ctr_crypt16(cipher, f, gcm_fill, ctx->ctr.b, length, dst, src);
- _nettle_gcm_hash(key, &ctx->x, length, dst);
+ _gcm_hash(key, &ctx->x, length, dst);
ctx->data_size += length;
}
{
assert(ctx->data_size % GCM_BLOCK_SIZE == 0);
- _nettle_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;
#include "testutils.h"
#include "nettle-internal.h"
#include "gcm.h"
+#include "gcm-internal.h"
static void
test_gcm_hash (const struct tstring *msg, const struct tstring *ref)
}
}
+static void
+test_ghash_internal (const struct tstring *key,
+ const struct tstring *iv,
+ const struct tstring *message,
+ const struct tstring *digest)
+{
+ ASSERT (key->length == GCM_BLOCK_SIZE);
+ ASSERT (iv->length == GCM_BLOCK_SIZE);
+ ASSERT (digest->length == GCM_BLOCK_SIZE);
+ struct gcm_key gcm_key;
+ union nettle_block16 state;
+
+ _nettle_gcm_set_key (&gcm_key, key->data);
+ memcpy (state.b, iv->data, GCM_BLOCK_SIZE);
+ _gcm_hash (&gcm_key, &state, message->length, message->data);
+ if (!MEMEQ(GCM_BLOCK_SIZE, state.b, digest->data))
+ {
+ fprintf (stderr, "gcm_hash (internal) failed\n");
+ fprintf(stderr, "Key: ");
+ tstring_print_hex(key);
+ fprintf(stderr, "\nIV: ");
+ tstring_print_hex(iv);
+ fprintf(stderr, "\nMessage: ");
+ tstring_print_hex(message);
+ fprintf(stderr, "\nOutput: ");
+ print_hex(GCM_BLOCK_SIZE, state.b);
+ fprintf(stderr, "\nExpected:");
+ tstring_print_hex(digest);
+ fprintf(stderr, "\n");
+ FAIL();
+ }
+}
+
static nettle_set_key_func gcm_unified_aes128_set_key;
static nettle_set_key_func gcm_unified_aes128_set_iv;
static void
SHEX("65f8245330febf15 6fd95e324304c258"));
test_gcm_hash (SDATA("abcdefghijklmnopqr"),
SHEX("d07259e85d4fc998 5a662eed41c8ed1d"));
-}
+ /* Test internal ghash function. */
+ test_ghash_internal(SHEX("0000000000000000 0000000000000000"),
+ SHEX("0000000000000000 0000000000000000"),
+ SHEX("0011223344556677 89abcdef01234567"),
+ SHEX("0000000000000000 0000000000000000"));
+
+ test_ghash_internal(SHEX("8000000000000000 0000000000000000"), /* 1 polynomial */
+ SHEX("0000000000000000 0000000000000000"),
+ SHEX("0011223344556677 89abcdef01234567"),
+ SHEX("0011223344556677 89abcdef01234567"));
+
+ test_ghash_internal(SHEX("8000000000000000 0000000000000000"),
+ SHEX("0123456789abcdef fedcba9876543210"), /* XOR:ed to the message */
+ SHEX("0011223344556677 89abcdef01234567"),
+ SHEX("01326754cdfeab98 7777777777777777"));
+
+ test_ghash_internal(SHEX("4000000000000000 0000000000000000"), /* x polynomial */
+ SHEX("0000000000000000 0000000000000000"),
+ SHEX("0011223344556677 89abcdef01234567"),
+ SHEX("e1089119a22ab33b c4d5e6f78091a2b3"));
+
+ test_ghash_internal(SHEX("0800000000000000 0000000000000000"), /* x^4 polynomial */
+ SHEX("0000000000000000 0000000000000000"),
+ SHEX("0011223344556677 89abcdef01234567"),
+ SHEX("54e1122334455667 789abcdef0123456"));
+
+ test_ghash_internal(SHEX("0000000080000000 0000000000000000"), /* x^32 polynomial */
+ SHEX("0000000000000000 0000000000000000"),
+ SHEX("0011223344556677 89abcdef01234567"),
+ SHEX("01f870078e112233 4455667789abcdef"));
+
+ test_ghash_internal(SHEX("0000000000000001 0000000000000000"), /* x^63 polynomial */
+ SHEX("0000000000000000 0000000000000000"),
+ SHEX("0011223344556677 89abcdef01234567"),
+ SHEX("1e0f1ff13ff0e00f 1c22446688aaccef"));
+
+ test_ghash_internal(SHEX("0000000000000000 8000000000000000"), /* x^64 polynomial */
+ SHEX("0000000000000000 0000000000000000"),
+ SHEX("0011223344556677 89abcdef01234567"),
+ SHEX("ee078ff89ff87007 8e11223344556677"));
+
+ test_ghash_internal(SHEX("0000000000000000 0000000100000000"), /* x^95 polynomial */
+ SHEX("0000000000000000 0000000000000000"),
+ SHEX("0011223344556677 89abcdef01234567"),
+ SHEX("efc44c3a800f1ff1 3ff0e00f1c224466"));
+
+ test_ghash_internal(SHEX("0000000000000000 0000000080000000"), /* x^96 polynomial */
+ SHEX("0000000000000000 0000000000000000"),
+ SHEX("0011223344556677 89abcdef01234567"),
+ SHEX("77e2261d40078ff8 9ff870078e112233"));
+
+ test_ghash_internal(SHEX("0000000000000000 0000000000000001"), /* x^127 polynomial */
+ SHEX("0000000000000000 0000000000000000"),
+ SHEX("0011223344556677 89abcdef01234567"),
+ SHEX("1503b3c4a3c44c3a 800f1ff13ff0e00f"));
+}