Mailing List Archive

[PATCH] Add XOF output support for internal _gcry_md_hash_buffers
* cipher/ecc-eddsa.c (_gcry_ecc_eddsa_compute_h_d, _gcry_ecc_eddsa_sign)
(_gcry_ecc_eddsa_verify): Use same _gcry_md_hash_buffers_extract code
path for SHA512 and SHAKE256.
* cipher/md.c (_gcry_md_hash_buffers): Rename to ...
(_gcry_md_hash_buffers_extract): ... this; Add digestlen and handling
for XOF algorithms (SHAKE128, SHAKE256).
(_gcry_md_hash_buffers): New.
* src/gcrypt-int.h (_gcry_md_hash_buffers_extract): New.
--

Signed-off-by: Jussi Kivilinna <jussi.kivilinna@iki.fi>
---
cipher/ecc-eddsa.c | 440 +++++++++++++++++----------------------------
cipher/md.c | 51 ++++--
src/gcrypt-int.h | 4 +
3 files changed, 212 insertions(+), 283 deletions(-)

diff --git a/cipher/ecc-eddsa.c b/cipher/ecc-eddsa.c
index 2a1a8907..baea1bf5 100644
--- a/cipher/ecc-eddsa.c
+++ b/cipher/ecc-eddsa.c
@@ -500,7 +500,8 @@ _gcry_ecc_eddsa_compute_h_d (unsigned char **r_digest, mpi_ec_t ec)
unsigned char *rawmpi = NULL;
unsigned int rawmpilen;
unsigned char *digest;
- int hashalgo, b;
+ int hashalgo, b, digestlen;
+ gcry_buffer_t hvec[2];

*r_digest = NULL;

@@ -511,11 +512,15 @@ _gcry_ecc_eddsa_compute_h_d (unsigned char **r_digest, mpi_ec_t ec)
* For now, it's determine by the bit size of the field.
*/
if (ec->nbits == 255)
- hashalgo = GCRY_MD_SHA512;
+ {
+ hashalgo = GCRY_MD_SHA512;
+ digestlen = 64;
+ }
else if (ec->nbits == 448)
{
b++;
hashalgo = GCRY_MD_SHAKE256;
+ digestlen = 2 * b;
}
else
return GPG_ERR_NOT_IMPLEMENTED;
@@ -533,35 +538,14 @@ _gcry_ecc_eddsa_compute_h_d (unsigned char **r_digest, mpi_ec_t ec)
return gpg_err_code_from_syserror ();
}

- if (hashalgo == GCRY_MD_SHAKE256)
- {
- gcry_error_t err;
- gcry_md_hd_t hd;
+ memset (hvec, 0, sizeof hvec);

- err = _gcry_md_open (&hd, hashalgo, 0);
- if (err)
- rc = gcry_err_code (err);
- else
- {
- _gcry_md_write (hd, rawmpi, rawmpilen);
- _gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0);
- _gcry_md_extract (hd, GCRY_MD_SHAKE256, digest, 2*b);
- _gcry_md_close (hd);
- rc = 0;
- }
- }
- else
- {
- gcry_buffer_t hvec[2];
-
- memset (hvec, 0, sizeof hvec);
-
- hvec[0].data = digest;
- hvec[0].len = b > rawmpilen? b - rawmpilen : 0;
- hvec[1].data = rawmpi;
- hvec[1].len = rawmpilen;
- rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 2);
- }
+ hvec[0].data = digest;
+ hvec[0].len = (hashalgo == GCRY_MD_SHA512 && b > rawmpilen)
+ ? b - rawmpilen : 0;
+ hvec[1].data = rawmpi;
+ hvec[1].len = rawmpilen;
+ rc = _gcry_md_hash_buffers_extract (hashalgo, 0, digest, digestlen, hvec, 2);

xfree (rawmpi);
if (rc)
@@ -702,16 +686,29 @@ _gcry_ecc_eddsa_sign (gcry_mpi_t input, mpi_ec_t ec,
unsigned int encpklen;
mpi_point_struct I; /* Intermediate value. */
gcry_mpi_t a, x, y, r;
- int b;
+ const char *dom;
+ int domlen, digestlen;
+ int b, i;
unsigned char x_olen[2];
unsigned char prehashed_msg[64];
+ gcry_buffer_t hvec[6];
+ gcry_buffer_t hvec2[1];

b = (ec->nbits+7)/8;

if (ec->nbits == 255)
- ;
+ {
+ dom = DOM25519;
+ domlen = DOM25519_LEN;
+ digestlen = 64;
+ }
else if (ec->nbits == 448)
- b++;
+ {
+ b++;
+ dom = DOM448;
+ domlen = DOM448_LEN;
+ digestlen = 2 * b;
+ }
else
return GPG_ERR_NOT_IMPLEMENTED;

@@ -751,98 +748,58 @@ _gcry_ecc_eddsa_sign (gcry_mpi_t input, mpi_ec_t ec,
if (DBG_CIPHER)
log_printhex (" m", mbuf, mlen);

- if (ctx->hash_algo == GCRY_MD_SHAKE256)
+ memset (hvec, 0, sizeof hvec);
+ i = 0;
+
+ if ((ctx->flags & PUBKEY_FLAG_PREHASH) || ctx->labellen || ec->nbits == 448)
{
- gcry_error_t err;
- gcry_md_hd_t hd;
+ hvec[i].data = (void *)dom;
+ hvec[i].len = domlen;
+ i++;
+ x_olen[0] = !!(ctx->flags & PUBKEY_FLAG_PREHASH);
+ x_olen[1] = ctx->labellen;
+ hvec[i].data = x_olen;
+ hvec[i].len = 2;
+ i++;
+ if (ctx->labellen)
+ {
+ hvec[i].data = ctx->label;
+ hvec[i].len = ctx->labellen;
+ i++;
+ }
+ }

- err = _gcry_md_open (&hd, ctx->hash_algo, 0);
- if (err)
- rc = gcry_err_code (err);
- else
- {
- _gcry_md_write (hd, DOM448, DOM448_LEN);
- x_olen[0] = !!(ctx->flags & PUBKEY_FLAG_PREHASH);
- x_olen[1] = ctx->labellen;
- _gcry_md_write (hd, x_olen, 2);
- if (ctx->labellen)
- _gcry_md_write (hd, ctx->label, ctx->labellen);
- _gcry_md_write (hd, digest+b, b);
- if ((ctx->flags & PUBKEY_FLAG_PREHASH))
- {
- gcry_md_hd_t hd2;
+ hvec[i].data = digest;
+ hvec[i].off = b;
+ hvec[i].len = b;
+ i++;
+ if ((ctx->flags & PUBKEY_FLAG_PREHASH))
+ {
+ memset (hvec2, 0, sizeof hvec2);

- err = _gcry_md_open (&hd2, ctx->hash_algo, 0);
- if (err)
- {
- rc = gcry_err_code (err);
- _gcry_md_close (hd);
- goto leave;
- }
- _gcry_md_write (hd2, mbuf, mlen);
- _gcry_md_ctl (hd2, GCRYCTL_FINALIZE, NULL, 0);
- _gcry_md_extract (hd2, GCRY_MD_SHAKE256, prehashed_msg, 64);
- _gcry_md_close (hd2);
- _gcry_md_write (hd, prehashed_msg, 64);
- }
- else
- _gcry_md_write (hd, mbuf, mlen);
- _gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0);
- _gcry_md_extract (hd, GCRY_MD_SHAKE256, digest, 2*b);
- _gcry_md_close (hd);
- rc = 0;
- }
+ hvec2[0].data = (char*)mbuf;
+ hvec2[0].len = mlen;
+
+ _gcry_md_hash_buffers_extract (ctx->hash_algo, 0, prehashed_msg, 64,
+ hvec2, 1);
+ hvec[i].data = (char*)prehashed_msg;
+ hvec[i].len = 64;
}
else
{
- gcry_buffer_t hvec[6];
- int i = 0;
-
- memset (hvec, 0, sizeof hvec);
-
- if ((ctx->flags & PUBKEY_FLAG_PREHASH) || ctx->labellen)
- {
- hvec[i].data = (void *)DOM25519;
- hvec[i].len = DOM25519_LEN;
- i++;
- x_olen[0] = !!(ctx->flags & PUBKEY_FLAG_PREHASH);
- x_olen[1] = ctx->labellen;
- hvec[i].data = x_olen;
- hvec[i].len = 2;
- i++;
- if (ctx->labellen)
- {
- hvec[i].data = ctx->label;
- hvec[i].len = ctx->labellen;
- i++;
- }
- }
-
- hvec[i].data = digest;
- hvec[i].off = b;
- hvec[i].len = b;
- i++;
- if ((ctx->flags & PUBKEY_FLAG_PREHASH))
- {
- _gcry_md_hash_buffer (ctx->hash_algo, prehashed_msg, mbuf, mlen);
- hvec[i].data = (char*)prehashed_msg;
- hvec[i].len = 64;
- }
- else
- {
- hvec[i].data = (char*)mbuf;
- hvec[i].len = mlen;
- }
- i++;
- rc = _gcry_md_hash_buffers (ctx->hash_algo, 0, digest, hvec, i);
+ hvec[i].data = (char*)mbuf;
+ hvec[i].len = mlen;
}
+ i++;

+ rc = _gcry_md_hash_buffers_extract (ctx->hash_algo, 0, digest, digestlen,
+ hvec, i);
if (rc)
goto leave;
- reverse_buffer (digest, 2*b);
+ reverse_buffer (digest, digestlen);
if (DBG_CIPHER)
- log_printhex (" r", digest, 2*b);
- _gcry_mpi_set_buffer (r, digest, 2*b, 0);
+ log_printhex (" r", digest, digestlen);
+ _gcry_mpi_set_buffer (r, digest, digestlen, 0);
mpi_mod (r, r, ec->n);
_gcry_mpi_ec_mul_point (&I, r, ec->G, ec);
if (DBG_CIPHER)
@@ -855,80 +812,48 @@ _gcry_ecc_eddsa_sign (gcry_mpi_t input, mpi_ec_t ec,
if (DBG_CIPHER)
log_printhex (" e_r", rawmpi, rawmpilen);

- if (ctx->hash_algo == GCRY_MD_SHAKE256)
+ memset (hvec, 0, sizeof hvec);
+ i = 0;
+
+ if ((ctx->flags & PUBKEY_FLAG_PREHASH) || ctx->labellen || ec->nbits == 448)
{
- gcry_error_t err;
- gcry_md_hd_t hd;
+ hvec[i].data = (void *)dom;
+ hvec[i].len = domlen;
+ i++;
+ x_olen[0] = !!(ctx->flags & PUBKEY_FLAG_PREHASH);
+ x_olen[1] = ctx->labellen;
+ hvec[i].data = x_olen;
+ hvec[i].len = 2;
+ i++;
+ if (ctx->labellen)
+ {
+ hvec[i].data = ctx->label;
+ hvec[i].len = ctx->labellen;
+ i++;
+ }
+ }

- err = _gcry_md_open (&hd, ctx->hash_algo, 0);
- if (err)
- rc = gcry_err_code (err);
- else
- {
- _gcry_md_write (hd, DOM448, DOM448_LEN);
- x_olen[0] = !!(ctx->flags & PUBKEY_FLAG_PREHASH);
- x_olen[1] = ctx->labellen;
- _gcry_md_write (hd, x_olen, 2);
- if (ctx->labellen)
- _gcry_md_write (hd, ctx->label, ctx->labellen);
- _gcry_md_write (hd, rawmpi, rawmpilen);
- _gcry_md_write (hd, encpk, encpklen);
- if ((ctx->flags & PUBKEY_FLAG_PREHASH))
- _gcry_md_write (hd, prehashed_msg, 64);
- else
- _gcry_md_write (hd, mbuf, mlen);
- _gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0);
- _gcry_md_extract (hd, GCRY_MD_SHAKE256, digest, 2*b);
- _gcry_md_close (hd);
- rc = 0;
- }
+ /* S = r + a * H(dom2(F,C)+encodepoint(R)+encodepoint(pk)+m) mod n */
+ hvec[i].data = rawmpi; /* (this is R) */
+ hvec[i].len = rawmpilen;
+ i++;
+ hvec[i].data = encpk;
+ hvec[i].len = encpklen;
+ i++;
+ if ((ctx->flags & PUBKEY_FLAG_PREHASH))
+ {
+ hvec[i].data = (char*)prehashed_msg;
+ hvec[i].len = 64;
}
else
{
- gcry_buffer_t hvec[6];
- int i = 0;
-
- memset (hvec, 0, sizeof hvec);
-
- if ((ctx->flags & PUBKEY_FLAG_PREHASH) || ctx->labellen)
- {
- hvec[i].data = (void *)DOM25519;
- hvec[i].len = DOM25519_LEN;
- i++;
- x_olen[0] = !!(ctx->flags & PUBKEY_FLAG_PREHASH);
- x_olen[1] = ctx->labellen;
- hvec[i].data = x_olen;
- hvec[i].len = 2;
- i++;
- if (ctx->labellen)
- {
- hvec[i].data = ctx->label;
- hvec[i].len = ctx->labellen;
- i++;
- }
- }
-
- /* S = r + a * H(dom2(F,C)+encodepoint(R)+encodepoint(pk)+m) mod n */
- hvec[i].data = rawmpi; /* (this is R) */
- hvec[i].len = rawmpilen;
- i++;
- hvec[i].data = encpk;
- hvec[i].len = encpklen;
- i++;
- if ((ctx->flags & PUBKEY_FLAG_PREHASH))
- {
- hvec[i].data = (char*)prehashed_msg;
- hvec[i].len = 64;
- }
- else
- {
- hvec[i].data = (char*)mbuf;
- hvec[i].len = mlen;
- }
- i++;
- rc = _gcry_md_hash_buffers (ctx->hash_algo, 0, digest, hvec, i);
+ hvec[i].data = (char*)mbuf;
+ hvec[i].len = mlen;
}
+ i++;

+ rc = _gcry_md_hash_buffers_extract (ctx->hash_algo, 0, digest, digestlen,
+ hvec, i);
if (rc)
goto leave;

@@ -936,10 +861,10 @@ _gcry_ecc_eddsa_sign (gcry_mpi_t input, mpi_ec_t ec,
mpi_set_opaque (r_r, rawmpi, rawmpilen*8);
rawmpi = NULL;

- reverse_buffer (digest, 2*b);
+ reverse_buffer (digest, digestlen);
if (DBG_CIPHER)
- log_printhex (" H(R+)", digest, 2*b);
- _gcry_mpi_set_buffer (s, digest, 2*b, 0);
+ log_printhex (" H(R+)", digest, digestlen);
+ _gcry_mpi_set_buffer (s, digest, digestlen, 0);
mpi_mulm (s, s, a, ec->n);
mpi_addm (s, s, r, ec->n);
rc = eddsa_encodempi (s, ec->nbits, &rawmpi, &rawmpilen);
@@ -985,8 +910,13 @@ _gcry_ecc_eddsa_verify (gcry_mpi_t input, mpi_ec_t ec,
unsigned char digest[114];
gcry_mpi_t h, s;
mpi_point_struct Ia, Ib;
+ const char *dom;
+ int domlen, digestlen;
+ int i;
unsigned char x_olen[2];
unsigned char prehashed_msg[64];
+ gcry_buffer_t hvec[6];
+ gcry_buffer_t hvec2[1];

if (!mpi_is_opaque (input) || !mpi_is_opaque (r_in) || !mpi_is_opaque (s_in))
return GPG_ERR_INV_DATA;
@@ -999,9 +929,18 @@ _gcry_ecc_eddsa_verify (gcry_mpi_t input, mpi_ec_t ec,
b = (ec->nbits+7)/8;

if (ec->nbits == 255)
- ;
+ {
+ dom = DOM25519;
+ domlen = DOM25519_LEN;
+ digestlen = 64;
+ }
else if (ec->nbits == 448)
- b++;
+ {
+ b++;
+ dom = DOM448;
+ domlen = DOM448_LEN;
+ digestlen = 2 * b;
+ }
else
return GPG_ERR_NOT_IMPLEMENTED;

@@ -1038,102 +977,61 @@ _gcry_ecc_eddsa_verify (gcry_mpi_t input, mpi_ec_t ec,
goto leave;
}

- if (ctx->hash_algo == GCRY_MD_SHAKE256)
+ memset (hvec, 0, sizeof hvec);
+ i = 0;
+
+ /* h = H(dom2(F,C)+encodepoint(R)+encodepoint(pk)+m) */
+ if ((ctx->flags & PUBKEY_FLAG_PREHASH) || ctx->labellen || ec->nbits == 448)
{
- gcry_error_t err;
- gcry_md_hd_t hd;
+ hvec[i].data = (void *)dom;
+ hvec[i].len = domlen;
+ i++;
+ x_olen[0] = !!(ctx->flags & PUBKEY_FLAG_PREHASH);
+ x_olen[1] = ctx->labellen;
+ hvec[i].data = x_olen;
+ hvec[i].len = 2;
+ i++;
+ if (ctx->labellen)
+ {
+ hvec[i].data = ctx->label;
+ hvec[i].len = ctx->labellen;
+ i++;
+ }
+ }

- err = _gcry_md_open (&hd, ctx->hash_algo, 0);
- if (err)
- rc = gcry_err_code (err);
- else
- {
- _gcry_md_write (hd, DOM448, DOM448_LEN);
- x_olen[0] = !!(ctx->flags & PUBKEY_FLAG_PREHASH);
- x_olen[1] = ctx->labellen;
- _gcry_md_write (hd, x_olen, 2);
- if (ctx->labellen)
- _gcry_md_write (hd, ctx->label, ctx->labellen);
- _gcry_md_write (hd, rbuf, rlen);
- _gcry_md_write (hd, encpk, encpklen);
- if ((ctx->flags & PUBKEY_FLAG_PREHASH))
- {
- gcry_md_hd_t hd2;
+ hvec[i].data = (char*)rbuf;
+ hvec[i].len = rlen;
+ i++;
+ hvec[i].data = encpk;
+ hvec[i].len = encpklen;
+ i++;
+ if ((ctx->flags & PUBKEY_FLAG_PREHASH))
+ {
+ memset (hvec2, 0, sizeof hvec2);

- err = _gcry_md_open (&hd2, ctx->hash_algo, 0);
- if (err)
- {
- rc = gcry_err_code (err);
- _gcry_md_close (hd);
- goto leave;
- }
- _gcry_md_write (hd2, mbuf, mlen);
- _gcry_md_ctl (hd2, GCRYCTL_FINALIZE, NULL, 0);
- _gcry_md_extract (hd2, GCRY_MD_SHAKE256, prehashed_msg, 64);
- _gcry_md_close (hd2);
- _gcry_md_write (hd, prehashed_msg, 64);
- }
- else
- _gcry_md_write (hd, mbuf, mlen);
- _gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0);
- _gcry_md_extract (hd, GCRY_MD_SHAKE256, digest, 2*b);
- _gcry_md_close (hd);
- rc = 0;
- }
+ hvec2[0].data = (char*)mbuf;
+ hvec2[0].len = mlen;
+
+ _gcry_md_hash_buffers_extract (ctx->hash_algo, 0, prehashed_msg, 64,
+ hvec2, 1);
+ hvec[i].data = (char*)prehashed_msg;
+ hvec[i].len = 64;
}
else
{
- gcry_buffer_t hvec[6];
- int i = 0;
-
- memset (hvec, 0, sizeof hvec);
-
- /* h = H(dom2(F,C)+encodepoint(R)+encodepoint(pk)+m) */
- if ((ctx->flags & PUBKEY_FLAG_PREHASH) || ctx->labellen)
- {
- hvec[i].data = (void *)DOM25519;
- hvec[i].len = DOM25519_LEN;
- i++;
- x_olen[0] = !!(ctx->flags & PUBKEY_FLAG_PREHASH);
- x_olen[1] = ctx->labellen;
- hvec[i].data = x_olen;
- hvec[i].len = 2;
- i++;
- if (ctx->labellen)
- {
- hvec[i].data = ctx->label;
- hvec[i].len = ctx->labellen;
- i++;
- }
- }
-
- hvec[i].data = (char*)rbuf;
- hvec[i].len = rlen;
- i++;
- hvec[i].data = encpk;
- hvec[i].len = encpklen;
- i++;
- if ((ctx->flags & PUBKEY_FLAG_PREHASH))
- {
- _gcry_md_hash_buffer (ctx->hash_algo, prehashed_msg, mbuf, mlen);
- hvec[i].data = (char*)prehashed_msg;
- hvec[i].len = 64;
- }
- else
- {
- hvec[i].data = (char*)mbuf;
- hvec[i].len = mlen;
- }
- i++;
- rc = _gcry_md_hash_buffers (ctx->hash_algo, 0, digest, hvec, i);
+ hvec[i].data = (char*)mbuf;
+ hvec[i].len = mlen;
}
+ i++;

+ rc = _gcry_md_hash_buffers_extract (ctx->hash_algo, 0, digest, digestlen,
+ hvec, i);
if (rc)
goto leave;
- reverse_buffer (digest, 2*b);
+ reverse_buffer (digest, digestlen);
if (DBG_CIPHER)
- log_printhex (" H(R+)", digest, 2*b);
- _gcry_mpi_set_buffer (h, digest, 2*b, 0);
+ log_printhex (" H(R+)", digest, digestlen);
+ _gcry_mpi_set_buffer (h, digest, digestlen, 0);

/* According to the paper the best way for verification is:
encodepoint(sG - h·Q) = encodepoint(r)
diff --git a/cipher/md.c b/cipher/md.c
index efb7376a..87979059 100644
--- a/cipher/md.c
+++ b/cipher/md.c
@@ -1251,11 +1251,15 @@ _gcry_md_hash_buffer (int algo, void *digest,
used as the key.

On success 0 is returned and resulting hash or HMAC is stored at
- DIGEST which must have been provided by the caller with an
- appropriate length. */
+ DIGEST. DIGESTLEN may be given as -1, in which case DIGEST must
+ have been provided by the caller with an appropriate length.
+ DIGESTLEN may also be the appropriate length or, in case of XOF
+ algorithms, DIGESTLEN indicates number bytes to extract from XOF
+ to DIGEST. */
gpg_err_code_t
-_gcry_md_hash_buffers (int algo, unsigned int flags, void *digest,
- const gcry_buffer_t *iov, int iovcnt)
+_gcry_md_hash_buffers_extract (int algo, unsigned int flags, void *digest,
+ int digestlen, const gcry_buffer_t *iov,
+ int iovcnt)
{
gcry_md_spec_t *spec;
int hmac;
@@ -1287,6 +1291,11 @@ _gcry_md_hash_buffers (int algo, unsigned int flags, void *digest,
}
}

+ if (spec->mdlen > 0 && digestlen != -1 && digestlen != spec->mdlen)
+ return GPG_ERR_DIGEST_ALGO;
+ if (spec->mdlen == 0 && digestlen == -1)
+ return GPG_ERR_DIGEST_ALGO;
+
if (!hmac && spec->hash_buffers)
{
spec->hash_buffers (digest, iov, iovcnt);
@@ -1297,13 +1306,6 @@ _gcry_md_hash_buffers (int algo, unsigned int flags, void *digest,
normal functions. */
gcry_md_hd_t h;
gpg_err_code_t rc;
- int dlen;
-
- /* Detect SHAKE128 like algorithms which we can't use because
- * our API does not allow for a variable length digest. */
- dlen = md_digest_length (algo);
- if (!dlen)
- return GPG_ERR_DIGEST_ALGO;

rc = md_open (&h, algo, (hmac? GCRY_MD_FLAG_HMAC:0));
if (rc)
@@ -1324,7 +1326,10 @@ _gcry_md_hash_buffers (int algo, unsigned int flags, void *digest,
for (;iovcnt; iov++, iovcnt--)
md_write (h, (const char*)iov[0].data + iov[0].off, iov[0].len);
md_final (h);
- memcpy (digest, md_read (h, algo), dlen);
+ if (spec->mdlen > 0)
+ memcpy (digest, md_read (h, algo), spec->mdlen);
+ else if (digestlen > 0)
+ md_extract (h, algo, digest, digestlen);
md_close (h);
}

@@ -1332,6 +1337,28 @@ _gcry_md_hash_buffers (int algo, unsigned int flags, void *digest,
}


+/* Shortcut function to hash multiple buffers with a given algo. In
+ contrast to gcry_md_hash_buffer, this function returns an error on
+ invalid arguments or on other problems; disabled algorithms are
+ _not_ ignored but flagged as an error.
+
+ The data to sign is taken from the array IOV which has IOVCNT items.
+
+ The only supported flag in FLAGS is GCRY_MD_FLAG_HMAC which turns
+ this function into a HMAC function; the first item in IOV is then
+ used as the key.
+
+ On success 0 is returned and resulting hash or HMAC is stored at
+ DIGEST which must have been provided by the caller with an
+ appropriate length. */
+gpg_err_code_t
+_gcry_md_hash_buffers (int algo, unsigned int flags, void *digest,
+ const gcry_buffer_t *iov, int iovcnt)
+{
+ return _gcry_md_hash_buffers_extract(algo, flags, digest, -1, iov, iovcnt);
+}
+
+
static int
md_get_algo (gcry_md_hd_t a)
{
diff --git a/src/gcrypt-int.h b/src/gcrypt-int.h
index 086953d7..d8b6d407 100644
--- a/src/gcrypt-int.h
+++ b/src/gcrypt-int.h
@@ -128,6 +128,10 @@ gpg_err_code_t _gcry_md_extract (gcry_md_hd_t hd, int algo, void *buffer,
size_t length);
void _gcry_md_hash_buffer (int algo, void *digest,
const void *buffer, size_t length);
+gpg_err_code_t _gcry_md_hash_buffers_extract (int algo, unsigned int flags,
+ void *digest, int digestlen,
+ const gcry_buffer_t *iov,
+ int iovcnt);
gpg_err_code_t _gcry_md_hash_buffers (int algo, unsigned int flags,
void *digest,
const gcry_buffer_t *iov, int iovcnt);
--
2.27.0


_______________________________________________
Gcrypt-devel mailing list
Gcrypt-devel@gnupg.org
http://lists.gnupg.org/mailman/listinfo/gcrypt-devel