To enable more efficient buffer reuse for HMAC operations, three new
functions have been introduced. This change prevents the need to
reallocate memory for each HMAC operation.

* grub_crypto_hmac_reset(): Reinitializes the hash contexts in the HMAC
  handle.

* grub_crypto_hmac_final(): Provides the final HMAC result without
  freeing the handle, allowing it to be reused immediately.

* grub_crypto_hmac_free(): Deallocates the HMAC handle and its
  associated memory.

To further facilitate buffer reuse, 'ctx2' is now included within the HMAC
handle struct, and the initialization of 'ctx2' is moved to
grub_crypto_hmac_init().

The intermediate hash states ('ctx' and 'ctx2') for the inner and outer
padded keys are now cached. grub_crypto_hmac_reset() restores these cached
states for new operations, which avoids redundant hashing of the keys.

Signed-off-by: Gary Lin <g...@suse.com>
---
 grub-core/disk/geli.c  |  4 +-
 grub-core/lib/crypto.c | 91 ++++++++++++++++++++++++++++++------------
 include/grub/crypto.h  |  8 +++-
 3 files changed, 74 insertions(+), 29 deletions(-)

diff --git a/grub-core/disk/geli.c b/grub-core/disk/geli.c
index 722910d64..bf22ebb63 100644
--- a/grub-core/disk/geli.c
+++ b/grub-core/disk/geli.c
@@ -464,9 +464,7 @@ geli_recover_key (grub_disk_t source, grub_cryptodisk_t 
dev, grub_cryptomount_ar
       grub_crypto_hmac_write (hnd, header.salt, sizeof (header.salt));
       grub_crypto_hmac_write (hnd, cargs->key_data, cargs->key_len);
 
-      gcry_err = grub_crypto_hmac_fini (hnd, geomkey);
-      if (gcry_err)
-       return grub_crypto_gcry_error (gcry_err);
+      grub_crypto_hmac_fini (hnd, geomkey);
     }
 
   gcry_err = grub_crypto_hmac_buffer (dev->hash, geomkey,
diff --git a/grub-core/lib/crypto.c b/grub-core/lib/crypto.c
index dd60dd4ac..436910e3b 100644
--- a/grub-core/lib/crypto.c
+++ b/grub-core/lib/crypto.c
@@ -31,7 +31,9 @@ struct grub_crypto_hmac_handle
 {
   const struct gcry_md_spec *md;
   void *ctx;
-  void *opad;
+  void *ctx2;
+  void *ctx_cache;
+  void *ctx2_cache;
 };
 
 static gcry_cipher_spec_t *grub_ciphers = NULL;
@@ -439,7 +441,8 @@ grub_crypto_hmac_init (const struct gcry_md_spec *md,
 {
   grub_uint8_t *helpkey = NULL;
   grub_uint8_t *ipad = NULL, *opad = NULL;
-  void *ctx = NULL;
+  void *ctx = NULL, *ctx2 = NULL;
+  void *ctx_cache = NULL, *ctx2_cache = NULL;
   struct grub_crypto_hmac_handle *ret = NULL;
   unsigned i;
 
@@ -450,6 +453,18 @@ grub_crypto_hmac_init (const struct gcry_md_spec *md,
   if (!ctx)
     goto err;
 
+  ctx2 = grub_malloc (md->contextsize);
+  if (!ctx2)
+    goto err;
+
+  ctx_cache = grub_malloc (md->contextsize);
+  if (!ctx_cache)
+    goto err;
+
+  ctx2_cache = grub_malloc (md->contextsize);
+  if (!ctx2_cache)
+    goto err;
+
   if ( keylen > md->blocksize )
     {
       helpkey = grub_malloc (md->mdlen);
@@ -479,26 +494,40 @@ grub_crypto_hmac_init (const struct gcry_md_spec *md,
   grub_free (helpkey);
   helpkey = NULL;
 
+  /* inner pad */
   md->init (ctx, 0);
-
-  md->write (ctx, ipad, md->blocksize); /* inner pad */
+  md->write (ctx, ipad, md->blocksize);
+  grub_memcpy (ctx_cache, ctx, md->contextsize);
   grub_memset (ipad, 0, md->blocksize);
   grub_free (ipad);
   ipad = NULL;
 
+  /* outer pad */
+  md->init (ctx2, 0);
+  md->write (ctx2, opad, md->blocksize);
+  grub_memcpy (ctx2_cache, ctx2, md->contextsize);
+  grub_memset (opad, 0, md->blocksize);
+  grub_free (opad);
+  opad = NULL;
+
   ret = grub_malloc (sizeof (*ret));
   if (!ret)
     goto err;
 
   ret->md = md;
   ret->ctx = ctx;
-  ret->opad = opad;
+  ret->ctx2 = ctx2;
+  ret->ctx_cache = ctx_cache;
+  ret->ctx2_cache = ctx2_cache;
 
   return ret;
 
  err:
   grub_free (helpkey);
   grub_free (ctx);
+  grub_free (ctx2);
+  grub_free (ctx_cache);
+  grub_free (ctx2_cache);
   grub_free (ipad);
   grub_free (opad);
   return NULL;
@@ -512,37 +541,48 @@ grub_crypto_hmac_write (struct grub_crypto_hmac_handle 
*hnd,
   hnd->md->write (hnd->ctx, data, datalen);
 }
 
-gcry_err_code_t
+void
 grub_crypto_hmac_fini (struct grub_crypto_hmac_handle *hnd, void *out)
 {
-  grub_uint8_t *p;
-  grub_uint8_t *ctx2;
+  grub_crypto_hmac_final (hnd, out);
+  grub_crypto_hmac_free (hnd);
+}
 
-  ctx2 = grub_malloc (hnd->md->contextsize);
-  if (!ctx2)
-    return GPG_ERR_OUT_OF_MEMORY;
+void
+grub_crypto_hmac_reset (struct grub_crypto_hmac_handle *hnd)
+{
+  grub_memcpy (hnd->ctx, hnd->ctx_cache, hnd->md->contextsize);
+  grub_memcpy (hnd->ctx2, hnd->ctx2_cache, hnd->md->contextsize);
+}
+
+void
+grub_crypto_hmac_final (struct grub_crypto_hmac_handle *hnd, void *out)
+{
+  grub_uint8_t *p;
 
   hnd->md->final (hnd->ctx);
   hnd->md->read (hnd->ctx);
   p = hnd->md->read (hnd->ctx);
 
-  hnd->md->init (ctx2, 0);
-  hnd->md->write (ctx2, hnd->opad, hnd->md->blocksize);
-  hnd->md->write (ctx2, p, hnd->md->mdlen);
-  hnd->md->final (ctx2);
-  grub_memset (hnd->opad, 0, hnd->md->blocksize);
-  grub_free (hnd->opad);
-  grub_memset (hnd->ctx, 0, hnd->md->contextsize);
-  grub_free (hnd->ctx);
+  hnd->md->write (hnd->ctx2, p, hnd->md->mdlen);
+  hnd->md->final (hnd->ctx2);
 
-  grub_memcpy (out, hnd->md->read (ctx2), hnd->md->mdlen);
-  grub_memset (ctx2, 0, hnd->md->contextsize);
-  grub_free (ctx2);
+  grub_memcpy (out, hnd->md->read (hnd->ctx2), hnd->md->mdlen);
+}
 
+void
+grub_crypto_hmac_free (struct grub_crypto_hmac_handle *hnd)
+{
+  grub_memset (hnd->ctx, 0, hnd->md->contextsize);
+  grub_free (hnd->ctx);
+  grub_memset (hnd->ctx2, 0, hnd->md->contextsize);
+  grub_free (hnd->ctx2);
+  grub_memset (hnd->ctx_cache, 0, hnd->md->contextsize);
+  grub_free (hnd->ctx_cache);
+  grub_memset (hnd->ctx2_cache, 0, hnd->md->contextsize);
+  grub_free (hnd->ctx2_cache);
   grub_memset (hnd, 0, sizeof (*hnd));
   grub_free (hnd);
-
-  return GPG_ERR_NO_ERROR;
 }
 
 gcry_err_code_t
@@ -557,7 +597,8 @@ grub_crypto_hmac_buffer (const struct gcry_md_spec *md,
     return GPG_ERR_OUT_OF_MEMORY;
 
   grub_crypto_hmac_write (hnd, data, datalen);
-  return grub_crypto_hmac_fini (hnd, out);
+  grub_crypto_hmac_fini (hnd, out);
+  return GPG_ERR_NO_ERROR;
 }
 
 
diff --git a/include/grub/crypto.h b/include/grub/crypto.h
index b0d7add1d..2a7fbd31b 100644
--- a/include/grub/crypto.h
+++ b/include/grub/crypto.h
@@ -499,8 +499,14 @@ void
 grub_crypto_hmac_write (struct grub_crypto_hmac_handle *hnd,
                        const void *data,
                        grub_size_t datalen);
-gcry_err_code_t
+void
 grub_crypto_hmac_fini (struct grub_crypto_hmac_handle *hnd, void *out);
+void
+grub_crypto_hmac_reset (struct grub_crypto_hmac_handle *hnd);
+void
+grub_crypto_hmac_final (struct grub_crypto_hmac_handle *hnd, void *out);
+void
+grub_crypto_hmac_free (struct grub_crypto_hmac_handle *hnd);
 
 gcry_err_code_t
 grub_crypto_hmac_buffer (const struct gcry_md_spec *md,
-- 
2.43.0


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to