From 57d88c953e15d5dbeafe4ecca2eefeaf01d013c8 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Niels=20M=C3=B6ller?= Date: Sun, 10 Mar 2024 09:27:57 +0100 Subject: [PATCH] Allow gcm_update to be called with any size. --- gcm.c | 65 +++++++++++++++++++++++++++++++++++++------ gcm.h | 3 +- md-internal.h | 18 ++++-------- poly1305-update.c | 3 ++ sha256.c | 2 +- testsuite/testutils.c | 20 +++++++------ 6 files changed, 80 insertions(+), 31 deletions(-) diff --git a/gcm.c b/gcm.c index 1e015b9d..f75290d9 100644 --- a/gcm.c +++ b/gcm.c @@ -53,6 +53,7 @@ #include "memxor.h" #include "nettle-internal.h" #include "macros.h" +#include "md-internal.h" #include "ctr-internal.h" #include "block-internal.h" #include "bswap-internal.h" @@ -123,11 +124,7 @@ gcm_set_iv(struct gcm_ctx *ctx, const struct gcm_key *key, gcm_hash_sizes(key, &ctx->iv, 0, length); } - 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. */ + /* Reset the message-dependent state. */ block16_zero(&ctx->x); ctx->auth_size = ctx->data_size = 0; } @@ -136,12 +133,39 @@ void gcm_update(struct gcm_ctx *ctx, const struct gcm_key *key, size_t length, const uint8_t *data) { - assert(ctx->auth_size % GCM_BLOCK_SIZE == 0); - assert(ctx->data_size == 0); + unsigned index; - gcm_hash(key, &ctx->x, length, data); + assert (!ctx->data_size); + if (!length) + return; + index = ctx->auth_size & (GCM_BLOCK_SIZE - 1); ctx->auth_size += length; + + if (index > 0) + { + /* Attempt to fill buffer. */ + MD_FILL_OR_RETURN (ctx->ctr.b, index, length, data); + _ghash_update (key, &ctx->x, 1, ctx->ctr.b); + } + + data = _ghash_update (key, &ctx->x, length / GCM_BLOCK_SIZE, data); + /* Copy leftover data. */ + index = length & (GCM_BLOCK_SIZE - 1); + memcpy (ctx->ctr.b, data, index); +} + +/* Must be called at end of accociated data, i.e., by the first call + of either gcm_encrypt, gcm_decrypt or gcm_digest. */ +static void +gcm_pad_adata (struct gcm_ctx *ctx, const struct gcm_key *key) +{ + unsigned index = ctx->auth_size & (GCM_BLOCK_SIZE - 1); + if (index > 0) + { + memset (ctx->ctr.b + index, 0, GCM_BLOCK_SIZE - index); + _ghash_update (key, &ctx->x, 1, ctx->ctr.b); + } } static nettle_fill16_func gcm_fill; @@ -202,6 +226,17 @@ gcm_fill(uint8_t *ctr, size_t blocks, union nettle_block16 *buffer) } #endif +/* Pad any associated data, and then initialize the ctr field for + encrypt/decrypt operation. */ +static void +gcm_init_crypt (struct gcm_ctx *ctx, const struct gcm_key *key) +{ + gcm_pad_adata (ctx, key); + ctx->ctr = ctx->iv; + /* Increment the rightmost 32 bits. */ + INCREMENT (4, ctx->ctr.b + GCM_BLOCK_SIZE - 4); +} + void gcm_encrypt (struct gcm_ctx *ctx, const struct gcm_key *key, const void *cipher, nettle_cipher_func *f, @@ -209,6 +244,12 @@ gcm_encrypt (struct gcm_ctx *ctx, const struct gcm_key *key, { assert(ctx->data_size % GCM_BLOCK_SIZE == 0); + if (!length) + return; + + if (!ctx->data_size) + gcm_init_crypt (ctx, key); + _nettle_ctr_crypt16(cipher, f, gcm_fill, ctx->ctr.b, length, dst, src); gcm_hash(key, &ctx->x, length, dst); @@ -222,6 +263,12 @@ gcm_decrypt(struct gcm_ctx *ctx, const struct gcm_key *key, { assert(ctx->data_size % GCM_BLOCK_SIZE == 0); + if (!length) + return; + + if (!ctx->data_size) + gcm_init_crypt (ctx, key); + gcm_hash(key, &ctx->x, length, src); _nettle_ctr_crypt16(cipher, f, gcm_fill, ctx->ctr.b, length, dst, src); @@ -236,6 +283,8 @@ gcm_digest(struct gcm_ctx *ctx, const struct gcm_key *key, union nettle_block16 buffer; assert (length <= GCM_BLOCK_SIZE); + if (!ctx->data_size) + gcm_pad_adata (ctx, key); gcm_hash_sizes(key, &ctx->x, ctx->auth_size, ctx->data_size); diff --git a/gcm.h b/gcm.h index 39af5ab0..7a81bbca 100644 --- a/gcm.h +++ b/gcm.h @@ -118,7 +118,8 @@ struct gcm_key struct gcm_ctx { /* Original counter block */ union nettle_block16 iv; - /* Updated for each block. */ + /* Used as block buffer for associated data, and ctr for + encrypt/decrypt. */ union nettle_block16 ctr; /* Hashing state */ union nettle_block16 x; diff --git a/md-internal.h b/md-internal.h index a97b7b90..fa9f90b6 100644 --- a/md-internal.h +++ b/md-internal.h @@ -34,23 +34,17 @@ #include -/* Internal helper macros for Merkle-Damgård hash functions. Assumes the context - structs includes the following fields: - - uint8_t block[...]; // Buffer holding one block - unsigned int index; // Index into block -*/ - -#define MD_FILL_OR_RETURN(ctx, length, data) \ +/* Internal helper macros for Merkle-Damgård hash functions. */ +#define MD_FILL_OR_RETURN(block, index, length, data) \ do { \ - unsigned __md_left = sizeof((ctx)->block) - (ctx)->index; \ + unsigned __md_left = sizeof(block) - index; \ if ((length) < __md_left) \ { \ - memcpy((ctx)->block + (ctx)->index, (data), (length)); \ - (ctx)->index += (length); \ + memcpy(block + index, (data), (length)); \ + index += (length); \ return; \ } \ - memcpy((ctx)->block + (ctx)->index, (data), __md_left); \ + memcpy(block + index, (data), __md_left); \ (data) += __md_left; \ (length) -= __md_left; \ } while(0) diff --git a/poly1305-update.c b/poly1305-update.c index 15ee3231..a00e5add 100644 --- a/poly1305-update.c +++ b/poly1305-update.c @@ -57,6 +57,9 @@ _nettle_poly1305_update (struct poly1305_ctx *ctx, uint8_t *block, unsigned index, size_t length, const uint8_t *m) { + if (!length) + return index; + if (index > 0) { /* Try to fill partial block */ diff --git a/sha256.c b/sha256.c index 44551224..169d9837 100644 --- a/sha256.c +++ b/sha256.c @@ -111,7 +111,7 @@ sha256_update(struct sha256_ctx *ctx, if (ctx->index > 0) { /* Try to fill partial block */ - MD_FILL_OR_RETURN (ctx, length, data); + MD_FILL_OR_RETURN (ctx->block, ctx->index, length, data); sha256_compress (ctx->state, ctx->block); ctx->count++; } diff --git a/testsuite/testutils.c b/testsuite/testutils.c index ac9d8f63..8b4fbd11 100644 --- a/testsuite/testutils.c +++ b/testsuite/testutils.c @@ -864,15 +864,17 @@ test_aead(const struct nettle_aead *aead, assert (nonce->length == aead->nonce_size); aead->set_nonce(ctx, nonce->data); } - if (aead->update && authtext->length) - aead->update(ctx, authtext->length, authtext->data); - - if (offset > 0) - aead->encrypt(ctx, offset, out + out_align, in + in_align); - - if (offset < cleartext->length) - aead->encrypt(ctx, cleartext->length - offset, - out + out_align + offset, in + in_align + offset); + if (aead->update) + { + size_t a_offset = offset <= authtext->length ? offset : authtext->length; + aead->update(ctx, a_offset, authtext->data); + aead->update(ctx, 0, NULL); + aead->update(ctx, authtext->length - a_offset, authtext->data + a_offset); + } + aead->encrypt(ctx, offset, out + out_align, in + in_align); + aead->encrypt(ctx, 0, out + out_align, NULL); + aead->encrypt(ctx, cleartext->length - offset, + out + out_align + offset, in + in_align + offset); if (!MEMEQ(cleartext->length, out + out_align, ciphertext->data)) { -- 2.47.2