]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
lib/crypto: Introduce new HMAC functions to reuse buffers
authorGary Lin <glin@suse.com>
Thu, 14 Aug 2025 06:32:41 +0000 (14:32 +0800)
committerDaniel Kiper <daniel.kiper@oracle.com>
Thu, 23 Oct 2025 17:14:59 +0000 (19:14 +0200)
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. The grub_crypto_hmac_reset() restores these cached
states for new operations which avoids redundant hashing of the keys.

Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
grub-core/disk/geli.c
grub-core/lib/crypto.c
include/grub/crypto.h

index 722910d648ca855def95909168432d8f4fcc873e..bf22ebb63ee5b91499ef29b8228494b16311886d 100644 (file)
@@ -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,
index 292b747b2e6025dee1cc6976cf5157f603455f7f..c29eeb3330a4c0d129924b376713493b62d582be 100644 (file)
@@ -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;
@@ -443,7 +445,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;
 
@@ -454,6 +457,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);
@@ -483,26 +498,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;
@@ -516,37 +545,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
@@ -561,7 +601,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;
 }
 
 
index 12550258261d3378ac38feff32e8cf09695ee0ee..68f5c10c319e90582e04fac24cc9fbc06e995c3e 100644 (file)
@@ -511,8 +511,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,