From c417e7045b70345f59643fb2db67b0e7fbd7fbd0 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 18 Mar 2026 23:17:04 -0700 Subject: lib/crypto: gf128hash: Add GHASH support Add GHASH support to the gf128hash module. This will replace the GHASH support in the crypto_shash API. It will be used by the "gcm" template and by the AES-GCM library (when an arch-optimized implementation of the full AES-GCM is unavailable). This consists of a simple API that mirrors the existing POLYVAL API, a generic implementation of that API based on the existing efficient and side-channel-resistant polyval_mul_generic(), and the framework for architecture-optimized implementations of the GHASH functions. The GHASH accumulator is stored in POLYVAL format rather than GHASH format, since this is what most modern GHASH implementations actually need. The few implementations that expect the accumulator in GHASH format will just convert the accumulator to/from GHASH format temporarily. (Supporting architecture-specific accumulator formats would be possible, but doesn't seem worth the complexity.) However, architecture-specific formats of struct ghash_key will be supported, since a variety of formats will be needed there anyway. The default format is just the key in POLYVAL format. Acked-by: Ard Biesheuvel Link: https://lore.kernel.org/r/20260319061723.1140720-4-ebiggers@kernel.org Signed-off-by: Eric Biggers --- include/crypto/gf128hash.h | 95 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) (limited to 'include') diff --git a/include/crypto/gf128hash.h b/include/crypto/gf128hash.h index 1052041e3499..5090fbaa87f8 100644 --- a/include/crypto/gf128hash.h +++ b/include/crypto/gf128hash.h @@ -11,6 +11,8 @@ #include #include +#define GHASH_BLOCK_SIZE 16 +#define GHASH_DIGEST_SIZE 16 #define POLYVAL_BLOCK_SIZE 16 #define POLYVAL_DIGEST_SIZE 16 @@ -33,6 +35,16 @@ struct polyval_elem { }; }; +/** + * struct ghash_key - Prepared key for GHASH + * + * Use ghash_preparekey() to initialize this. + */ +struct ghash_key { + /** @h: The hash key H, in POLYVAL format */ + struct polyval_elem h; +}; + /** * struct polyval_key - Prepared key for POLYVAL * @@ -54,6 +66,20 @@ struct polyval_key { #endif }; +/** + * struct ghash_ctx - Context for computing a GHASH value + * @key: Pointer to the prepared GHASH key. The user of the API is + * responsible for ensuring that the key lives as long as the context. + * @acc: The accumulator. It is stored in POLYVAL format rather than GHASH + * format, since most implementations want it in POLYVAL format. + * @partial: Number of data bytes processed so far modulo GHASH_BLOCK_SIZE + */ +struct ghash_ctx { + const struct ghash_key *key; + struct polyval_elem acc; + size_t partial; +}; + /** * struct polyval_ctx - Context for computing a POLYVAL value * @key: Pointer to the prepared POLYVAL key. The user of the API is @@ -67,6 +93,18 @@ struct polyval_ctx { size_t partial; }; +/** + * ghash_preparekey() - Prepare a GHASH key + * @key: (output) The key structure to initialize + * @raw_key: The raw hash key + * + * Initialize a GHASH key structure from a raw key. + * + * Context: Any context. + */ +void ghash_preparekey(struct ghash_key *key, + const u8 raw_key[GHASH_BLOCK_SIZE]); + /** * polyval_preparekey() - Prepare a POLYVAL key * @key: (output) The key structure to initialize @@ -81,6 +119,18 @@ struct polyval_ctx { void polyval_preparekey(struct polyval_key *key, const u8 raw_key[POLYVAL_BLOCK_SIZE]); +/** + * ghash_init() - Initialize a GHASH context for a new message + * @ctx: The context to initialize + * @key: The key to use. Note that a pointer to the key is saved in the + * context, so the key must live at least as long as the context. + */ +static inline void ghash_init(struct ghash_ctx *ctx, + const struct ghash_key *key) +{ + *ctx = (struct ghash_ctx){ .key = key }; +} + /** * polyval_init() - Initialize a POLYVAL context for a new message * @ctx: The context to initialize @@ -125,6 +175,18 @@ static inline void polyval_export_blkaligned(const struct polyval_ctx *ctx, *acc = ctx->acc; } +/** + * ghash_update() - Update a GHASH context with message data + * @ctx: The context to update; must have been initialized + * @data: The message data + * @len: The data length in bytes. Doesn't need to be block-aligned. + * + * This can be called any number of times. + * + * Context: Any context. + */ +void ghash_update(struct ghash_ctx *ctx, const u8 *data, size_t len); + /** * polyval_update() - Update a POLYVAL context with message data * @ctx: The context to update; must have been initialized @@ -137,6 +199,20 @@ static inline void polyval_export_blkaligned(const struct polyval_ctx *ctx, */ void polyval_update(struct polyval_ctx *ctx, const u8 *data, size_t len); +/** + * ghash_final() - Finish computing a GHASH value + * @ctx: The context to finalize + * @out: The output value + * + * If the total data length isn't a multiple of GHASH_BLOCK_SIZE, then the + * final block is automatically zero-padded. + * + * After finishing, this zeroizes @ctx. So the caller does not need to do it. + * + * Context: Any context. + */ +void ghash_final(struct ghash_ctx *ctx, u8 out[GHASH_BLOCK_SIZE]); + /** * polyval_final() - Finish computing a POLYVAL value * @ctx: The context to finalize @@ -151,6 +227,25 @@ void polyval_update(struct polyval_ctx *ctx, const u8 *data, size_t len); */ void polyval_final(struct polyval_ctx *ctx, u8 out[POLYVAL_BLOCK_SIZE]); +/** + * ghash() - Compute a GHASH value + * @key: The prepared key + * @data: The message data + * @len: The data length in bytes. Doesn't need to be block-aligned. + * @out: The output value + * + * Context: Any context. + */ +static inline void ghash(const struct ghash_key *key, const u8 *data, + size_t len, u8 out[GHASH_BLOCK_SIZE]) +{ + struct ghash_ctx ctx; + + ghash_init(&ctx, key); + ghash_update(&ctx, data, len); + ghash_final(&ctx, out); +} + /** * polyval() - Compute a POLYVAL value * @key: The prepared key -- cgit v1.2.3