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,