]> git.ipfire.org Git - thirdparty/nettle.git/commitdiff
Allow gcm_update to be called with any size.
authorNiels Möller <nisse@lysator.liu.se>
Sun, 10 Mar 2024 08:27:57 +0000 (09:27 +0100)
committerNiels Möller <nisse@lysator.liu.se>
Sun, 10 Mar 2024 08:46:49 +0000 (09:46 +0100)
gcm.c
gcm.h
md-internal.h
poly1305-update.c
sha256.c
testsuite/testutils.c

diff --git a/gcm.c b/gcm.c
index 1e015b9db2837f56d8f8c43601c938dcfcc23f37..f75290d934ef3e220f9a4824b5b64dacb6e6ea3e 100644 (file)
--- 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 39af5ab03bb16bd8cc2826d6bfb949378ca116b7..7a81bbca88c477aa6a1ca99d6dc1d9ce14db4c8b 100644 (file)
--- 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;
index a97b7b903d3ad12c6ea89900c5bb000a41f1bd30..fa9f90b6b55ff1ec2a126f6fc426f6c8eeac75d6 100644 (file)
 
 #include <string.h>
 
-/* 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)
index 15ee32311b7a8e8da728383dac80edba4444aa9b..a00e5adda8df7ae526c6379d69432e3602de59f7 100644 (file)
@@ -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 */
index 44551224c20a2de415373abf7ffe5c1f96fc71fe..169d9837548daf142b5be44ca88c3c5ab95cf99a 100644 (file)
--- 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++;
     }
index ac9d8f634c1b058d28e4a89593282092ba62f612..8b4fbd1134046a815b055a027b1789e55cd70bd7 100644 (file)
@@ -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))
            {