diff options
author | Niels Möller <nisse@lysator.liu.se> | 2022-02-18 21:14:49 +0100 |
---|---|---|
committer | Niels Möller <nisse@lysator.liu.se> | 2022-02-18 21:14:49 +0100 |
commit | 1d438ad40aa983cf9dc3c0f41cabb6bea70af977 (patch) | |
tree | 9e3c83c277738045adb111c08a5a740dbb5ad373 | |
parent | bdf820df0b90f210222ef56a27f95e0710c36c92 (diff) | |
download | nettle-1d438ad40aa983cf9dc3c0f41cabb6bea70af977.tar.gz |
Refactor GCM C implementation.
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.
-rw-r--r-- | ChangeLog | 24 | ||||
-rw-r--r-- | Makefile.in | 4 | ||||
-rw-r--r-- | gcm-internal.h | 68 | ||||
-rw-r--r-- | gcm.c | 197 | ||||
-rw-r--r-- | ghash-internal.h | 72 | ||||
-rw-r--r-- | ghash-set-key.c | 68 | ||||
-rw-r--r-- | ghash-update.c | 144 | ||||
-rw-r--r-- | testsuite/gcm-test.c | 9 |
8 files changed, 360 insertions, 226 deletions
@@ -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 diff --git a/Makefile.in b/Makefile.in index f6bc2155..116b1cc2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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 index 0b2d7cef..00000000 --- a/gcm-internal.h +++ /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 */ @@ -49,138 +49,31 @@ #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 index 00000000..d0bfae1e --- /dev/null +++ b/ghash-internal.h @@ -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 index 00000000..e8813a5e --- /dev/null +++ b/ghash-set-key.c @@ -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 index 00000000..00940ae5 --- /dev/null +++ b/ghash-update.c @@ -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); +} diff --git a/testsuite/gcm-test.c b/testsuite/gcm-test.c index d68af4e0..8955e9b8 100644 --- a/testsuite/gcm-test.c +++ b/testsuite/gcm-test.c @@ -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"); |