From 961e38b2b03c50a50859dbc484559b9b848e8d84 Mon Sep 17 00:00:00 2001 From: Gary Lin Date: Thu, 14 Aug 2025 14:32:41 +0800 Subject: [PATCH] lib/crypto: Introduce new HMAC functions to reuse buffers 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 Reviewed-by: Daniel Kiper --- 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 292b747b2..c29eeb333 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; @@ -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); + hnd->md->write (hnd->ctx2, p, hnd->md->mdlen); + hnd->md->final (hnd->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_memcpy (out, hnd->md->read (ctx2), hnd->md->mdlen); - grub_memset (ctx2, 0, hnd->md->contextsize); - grub_free (ctx2); - + 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; } diff --git a/include/grub/crypto.h b/include/grub/crypto.h index 125502582..68f5c10c3 100644 --- a/include/grub/crypto.h +++ b/include/grub/crypto.h @@ -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,