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 <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
This commit is contained in:
Gary Lin 2025-08-14 14:32:41 +08:00 committed by Daniel Kiper
parent 59304a7b51
commit 961e38b2b0
3 changed files with 74 additions and 29 deletions

View 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,

View 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);
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;
}

View 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,