* [PATCH 1/2] lib/crypto: Introduce new HMAC functions to reuse buffers
2025-08-14 6:32 [PATCH 0/2] Optimize PBKDF2 Gary Lin via Grub-devel
@ 2025-08-14 6:32 ` Gary Lin via Grub-devel
2025-08-14 6:32 ` [PATCH 2/2] lib/pbkdf2: Optimize PBKDF2 by reusing HMAC handle Gary Lin via Grub-devel
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Gary Lin via Grub-devel @ 2025-08-14 6:32 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Vladimir 'phcoder' Serbinenko,
Glenn Washburn, Michael Chang, Steffen Winterfeldt
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 <glin@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
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH 2/2] lib/pbkdf2: Optimize PBKDF2 by reusing HMAC handle
2025-08-14 6:32 [PATCH 0/2] Optimize PBKDF2 Gary Lin via Grub-devel
2025-08-14 6:32 ` [PATCH 1/2] lib/crypto: Introduce new HMAC functions to reuse buffers Gary Lin via Grub-devel
@ 2025-08-14 6:32 ` Gary Lin via Grub-devel
2025-08-14 8:32 ` [PATCH 0/2] Optimize PBKDF2 Gary Lin via Grub-devel
2025-10-16 18:02 ` Daniel Kiper
3 siblings, 0 replies; 5+ messages in thread
From: Gary Lin via Grub-devel @ 2025-08-14 6:32 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Vladimir 'phcoder' Serbinenko,
Glenn Washburn, Michael Chang, Steffen Winterfeldt
The previous PBKDF2 implementation used grub_crypto_hmac_buffer(), which
allocates and frees an HMAC handle on every call. This approach caused
significant performance overhead, slowing down the boot process
considerably.
This commit refactors the PBKDF2 code to use the new HMAC functions,
allowing the HMAC handle and its buffers to be allocated once and reused
across multiple operations. This change significantly reduces disk
unlocking time.
In a QEMU/OVMF test environment, this patch reduced the time to unlock a
LUKS2(*) partition from approximately 15 seconds to 4 seconds.
(*) PBKDF2 SHA256 with 3454944 iterations
Signed-off-by: Gary Lin <glin@suse.com>
---
grub-core/lib/pbkdf2.c | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)
diff --git a/grub-core/lib/pbkdf2.c b/grub-core/lib/pbkdf2.c
index 28aa96c46..410eff580 100644
--- a/grub-core/lib/pbkdf2.c
+++ b/grub-core/lib/pbkdf2.c
@@ -39,6 +39,7 @@ grub_crypto_pbkdf2 (const struct gcry_md_spec *md,
unsigned int c,
grub_uint8_t *DK, grub_size_t dkLen)
{
+ struct grub_crypto_hmac_handle *hnd = NULL;
unsigned int hLen = md->mdlen;
grub_uint8_t U[GRUB_CRYPTO_MAX_MDLEN];
grub_uint8_t T[GRUB_CRYPTO_MAX_MDLEN];
@@ -47,7 +48,6 @@ grub_crypto_pbkdf2 (const struct gcry_md_spec *md,
unsigned int r;
unsigned int i;
unsigned int k;
- gcry_err_code_t rc;
grub_uint8_t *tmp;
grub_size_t tmplen = Slen + 4;
@@ -72,6 +72,13 @@ grub_crypto_pbkdf2 (const struct gcry_md_spec *md,
grub_memcpy (tmp, S, Slen);
+ hnd = grub_crypto_hmac_init (md, P, Plen);
+ if (hnd == NULL)
+ {
+ grub_free (tmp);
+ return GPG_ERR_OUT_OF_MEMORY;
+ }
+
for (i = 1; i - 1 < l; i++)
{
grub_memset (T, 0, hLen);
@@ -85,16 +92,13 @@ grub_crypto_pbkdf2 (const struct gcry_md_spec *md,
tmp[Slen + 2] = (i & 0x0000ff00) >> 8;
tmp[Slen + 3] = (i & 0x000000ff) >> 0;
- rc = grub_crypto_hmac_buffer (md, P, Plen, tmp, tmplen, U);
+ grub_crypto_hmac_write (hnd, tmp, tmplen);
}
else
- rc = grub_crypto_hmac_buffer (md, P, Plen, U, hLen, U);
+ grub_crypto_hmac_write (hnd, U, hLen);
- if (rc != GPG_ERR_NO_ERROR)
- {
- grub_free (tmp);
- return rc;
- }
+ grub_crypto_hmac_final (hnd, U);
+ grub_crypto_hmac_reset (hnd);
for (k = 0; k < hLen; k++)
T[k] ^= U[k];
@@ -103,6 +107,7 @@ grub_crypto_pbkdf2 (const struct gcry_md_spec *md,
grub_memcpy (DK + (i - 1) * hLen, T, i == l ? r : hLen);
}
+ grub_crypto_hmac_free (hnd);
grub_free (tmp);
return GPG_ERR_NO_ERROR;
--
2.43.0
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 5+ messages in thread