[PATCH 2/4] md: add variable length output interface

Jussi Kivilinna jussi.kivilinna at iki.fi
Wed Oct 28 18:55:47 CET 2015


* cipher/crc.c (_gcry_digest_spec_crc32)
(_gcry_digest_spec_crc32_rfc1510, _gcry_digest_spec_crc24_rfc2440): Set
'extract' NULL.
* cipher/gostr3411-94.c (_gcry_digest_spec_gost3411_94)
(_gcry_digest_spec_gost3411_cp): Ditto.
* cipher/keccak.c (_gcry_digest_spec_sha3_224)
(_gcry_digest_spec_sha3_256, _gcry_digest_spec_sha3_384)
(_gcry_digest_spec_sha3_512): Ditto.
* cipher/md2.c (_gcry_digest_spec_md2): Ditto.
* cipher/md4.c (_gcry_digest_spec_md4): Ditto.
* cipher/md5.c (_gcry_digest_spec_md5): Ditto.
* cipher/rmd160.c (_gcry_digest_spec_rmd160): Ditto.
* cipher/sha1.c (_gcry_digest_spec_sha1): Ditto.
* cipher/sha256.c (_gcry_digest_spec_sha224)
(_gcry_digest_spec_sha256): Ditto.
* cipher/sha512.c (_gcry_digest_spec_sha384)
(_gcry_digest_spec_sha512): Ditto.
* cipher/stribog.c (_gcry_digest_spec_stribog_256)
(_gcry_digest_spec_stribog_512): Ditto.
* cipher/tiger.c (_gcry_digest_spec_tiger)
(_gcry_digest_spec_tiger1, _gcry_digest_spec_tiger2): Ditto.
* cipher/whirlpool.c (_gcry_digest_spec_whirlpool): Ditto.
* cipher/md.c (md_enable): Do not allow combination of HMAC and
'expandable-output function'.
(md_final): Check if spec->read is NULL before calling.
(md_read): Ditto.
(md_extract, _gcry_md_extract): New.
* doc/gcrypt.texi: Add SHA3 algorithms and gcry_md_extract.
* src/cipher-proto.h (gcry_md_extract_t): New.
(gcry_md_spec_t): Add 'extract'.
* src/gcrypt.h.in (gcry_md_extract): New.
* src/libgcrypt.def: Add gcry_md_extract.
* src/libgcrypt.vers: Add gcry_md_extract.
* src/visibility.c (gcry_md_extract): New.
* src/visibility.h (gcry_md_extract): New.
--

Patch adds new interface for reading output from 'expandable-output
function' MD algorithms that can give variable length output (ie.
SHAKE algorithms from FIPS-202). New function to read output is

 gpg_error_t gcry_md_extract(gcry_md_hd_t md, int algo,
			     void *buffer, size_t length);

Function implicitly finalizes algorithm so that no new input can
be given. Subsequents calls of the function return more output
bytes from the algorithm.

Signed-off-by: Jussi Kivilinna <jussi.kivilinna at iki.fi>
---
 cipher/crc.c          |    8 ++----
 cipher/gostr3411-94.c |    4 +--
 cipher/keccak.c       |    8 +++---
 cipher/md.c           |   67 ++++++++++++++++++++++++++++++++++++++++++++++++-
 cipher/md2.c          |    2 +
 cipher/md4.c          |    2 +
 cipher/md5.c          |    2 +
 cipher/rmd160.c       |    2 +
 cipher/sha1.c         |    2 +
 cipher/sha256.c       |    4 +--
 cipher/sha512.c       |    4 +--
 cipher/stribog.c      |    2 +
 cipher/tiger.c        |    6 ++--
 cipher/whirlpool.c    |    2 +
 doc/gcrypt.texi       |   67 +++++++++++++++++++++++++++++++++++++++++++------
 src/cipher-proto.h    |    4 +++
 src/gcrypt.h.in       |    9 +++++--
 src/libgcrypt.def     |    1 +
 src/libgcrypt.vers    |    2 +
 src/visibility.c      |    6 ++++
 src/visibility.h      |    2 +
 21 files changed, 169 insertions(+), 37 deletions(-)

diff --git a/cipher/crc.c b/cipher/crc.c
index 9105dfe..46a185a 100644
--- a/cipher/crc.c
+++ b/cipher/crc.c
@@ -785,7 +785,7 @@ gcry_md_spec_t _gcry_digest_spec_crc32 =
   {
     GCRY_MD_CRC32, {0, 1},
     "CRC32", NULL, 0, NULL, 4,
-    crc32_init, crc32_write, crc32_final, crc32_read,
+    crc32_init, crc32_write, crc32_final, crc32_read, NULL,
     sizeof (CRC_CONTEXT)
   };
 
@@ -793,8 +793,7 @@ gcry_md_spec_t _gcry_digest_spec_crc32_rfc1510 =
   {
     GCRY_MD_CRC32_RFC1510, {0, 1},
     "CRC32RFC1510", NULL, 0, NULL, 4,
-    crc32rfc1510_init, crc32_write,
-    crc32rfc1510_final, crc32_read,
+    crc32rfc1510_init, crc32_write, crc32rfc1510_final, crc32_read, NULL,
     sizeof (CRC_CONTEXT)
   };
 
@@ -802,7 +801,6 @@ gcry_md_spec_t _gcry_digest_spec_crc24_rfc2440 =
   {
     GCRY_MD_CRC24_RFC2440, {0, 1},
     "CRC24RFC2440", NULL, 0, NULL, 3,
-    crc24rfc2440_init, crc24rfc2440_write,
-    crc24rfc2440_final, crc32_read,
+    crc24rfc2440_init, crc24rfc2440_write, crc24rfc2440_final, crc32_read, NULL,
     sizeof (CRC_CONTEXT)
   };
diff --git a/cipher/gostr3411-94.c b/cipher/gostr3411-94.c
index 7b16e61..a782427 100644
--- a/cipher/gostr3411-94.c
+++ b/cipher/gostr3411-94.c
@@ -343,13 +343,13 @@ gcry_md_spec_t _gcry_digest_spec_gost3411_94 =
   {
     GCRY_MD_GOSTR3411_94, {0, 0},
     "GOSTR3411_94", NULL, 0, NULL, 32,
-    gost3411_init, _gcry_md_block_write, gost3411_final, gost3411_read,
+    gost3411_init, _gcry_md_block_write, gost3411_final, gost3411_read, NULL,
     sizeof (GOSTR3411_CONTEXT)
   };
 gcry_md_spec_t _gcry_digest_spec_gost3411_cp =
   {
     GCRY_MD_GOSTR3411_CP, {0, 0},
     "GOSTR3411_CP", asn, DIM (asn), oid_spec_gostr3411, 32,
-    gost3411_cp_init, _gcry_md_block_write, gost3411_final, gost3411_read,
+    gost3411_cp_init, _gcry_md_block_write, gost3411_final, gost3411_read, NULL,
     sizeof (GOSTR3411_CONTEXT)
   };
diff --git a/cipher/keccak.c b/cipher/keccak.c
index 3a72294..d46d9cb 100644
--- a/cipher/keccak.c
+++ b/cipher/keccak.c
@@ -927,7 +927,7 @@ gcry_md_spec_t _gcry_digest_spec_sha3_224 =
   {
     GCRY_MD_SHA3_224, {0, 1},
     "SHA3-224", sha3_224_asn, DIM (sha3_224_asn), oid_spec_sha3_224, 28,
-    sha3_224_init, keccak_write, keccak_final, keccak_read,
+    sha3_224_init, keccak_write, keccak_final, keccak_read, NULL,
     sizeof (KECCAK_CONTEXT),
     run_selftests
   };
@@ -935,7 +935,7 @@ gcry_md_spec_t _gcry_digest_spec_sha3_256 =
   {
     GCRY_MD_SHA3_256, {0, 1},
     "SHA3-256", sha3_256_asn, DIM (sha3_256_asn), oid_spec_sha3_256, 32,
-    sha3_256_init, keccak_write, keccak_final, keccak_read,
+    sha3_256_init, keccak_write, keccak_final, keccak_read, NULL,
     sizeof (KECCAK_CONTEXT),
     run_selftests
   };
@@ -943,7 +943,7 @@ gcry_md_spec_t _gcry_digest_spec_sha3_384 =
   {
     GCRY_MD_SHA3_384, {0, 1},
     "SHA3-384", sha3_384_asn, DIM (sha3_384_asn), oid_spec_sha3_384, 48,
-    sha3_384_init, keccak_write, keccak_final, keccak_read,
+    sha3_384_init, keccak_write, keccak_final, keccak_read, NULL,
     sizeof (KECCAK_CONTEXT),
     run_selftests
   };
@@ -951,7 +951,7 @@ gcry_md_spec_t _gcry_digest_spec_sha3_512 =
   {
     GCRY_MD_SHA3_512, {0, 1},
     "SHA3-512", sha3_512_asn, DIM (sha3_512_asn), oid_spec_sha3_512, 64,
-    sha3_512_init, keccak_write, keccak_final, keccak_read,
+    sha3_512_init, keccak_write, keccak_final, keccak_read, NULL,
     sizeof (KECCAK_CONTEXT),
     run_selftests
   };
diff --git a/cipher/md.c b/cipher/md.c
index 948d269..6ef8fee 100644
--- a/cipher/md.c
+++ b/cipher/md.c
@@ -408,6 +408,12 @@ md_enable (gcry_md_hd_t hd, int algorithm)
         }
     }
 
+  if (!err && h->flags.hmac && spec->read == NULL)
+    {
+      /* Expandable output function cannot act as part of HMAC. */
+      err = GPG_ERR_DIGEST_ALGO;
+    }
+
   if (!err)
     {
       size_t size = (sizeof (*entry)
@@ -638,11 +644,16 @@ md_final (gcry_md_hd_t a)
 
   for (r = a->ctx->list; r; r = r->next)
     {
-      byte *p = r->spec->read (&r->context.c);
+      byte *p;
       size_t dlen = r->spec->mdlen;
       byte *hash;
       gcry_err_code_t err;
 
+      if (r->spec->read == NULL)
+        continue;
+
+      p = r->spec->read (&r->context.c);
+
       if (a->ctx->flags.secure)
         hash = xtrymalloc_secure (dlen);
       else
@@ -821,6 +832,8 @@ md_read( gcry_md_hd_t a, int algo )
         {
           if (r->next)
             log_debug ("more than one algorithm in md_read(0)\n");
+          if (r->spec->read == NULL)
+            return NULL;
           return r->spec->read (&r->context.c);
         }
     }
@@ -828,7 +841,11 @@ md_read( gcry_md_hd_t a, int algo )
     {
       for (r = a->ctx->list; r; r = r->next)
 	if (r->spec->algo == algo)
-	  return r->spec->read (&r->context.c);
+	  {
+	    if (r->spec->read == NULL)
+	      return NULL;
+	    return r->spec->read (&r->context.c);
+	  }
     }
   BUG();
   return NULL;
@@ -850,6 +867,52 @@ _gcry_md_read (gcry_md_hd_t hd, int algo)
 }
 
 
+/****************
+ * If ALGO is null get the digest for the used algo (which should be
+ * only one)
+ */
+static gcry_err_code_t
+md_extract(gcry_md_hd_t a, int algo, void *out, size_t outlen)
+{
+  GcryDigestEntry *r = a->ctx->list;
+
+  if (!algo)
+    {
+      /* Return the first algorithm */
+      if (r && r->spec->extract)
+	{
+	  if (r->next)
+	    log_debug ("more than one algorithm in md_extract(0)\n");
+	  r->spec->extract (&r->context.c, out, outlen);
+	  return 0;
+	}
+    }
+  else
+    {
+      for (r = a->ctx->list; r; r = r->next)
+	if (r->spec->algo == algo && r->spec->extract)
+	  {
+	    r->spec->extract (&r->context.c, out, outlen);
+	    return 0;
+	  }
+    }
+
+  return GPG_ERR_DIGEST_ALGO;
+}
+
+
+/*
+ * Expand the output from XOF class digest, this function implictly finalizes
+ * the hash.
+ */
+gcry_err_code_t
+_gcry_md_extract (gcry_md_hd_t hd, int algo, void *out, size_t outlen)
+{
+  _gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0);
+  return md_extract (hd, algo, out, outlen);
+}
+
+
 /*
  * Read out an intermediate digest.  Not yet functional.
  */
diff --git a/cipher/md2.c b/cipher/md2.c
index 97682e5..e339b28 100644
--- a/cipher/md2.c
+++ b/cipher/md2.c
@@ -177,6 +177,6 @@ gcry_md_spec_t _gcry_digest_spec_md2 =
   {
     GCRY_MD_MD2, {0, 0},
     "MD2", asn, DIM (asn), oid_spec_md2, 16,
-    md2_init, _gcry_md_block_write, md2_final, md2_read,
+    md2_init, _gcry_md_block_write, md2_final, md2_read, NULL,
     sizeof (MD2_CONTEXT)
   };
diff --git a/cipher/md4.c b/cipher/md4.c
index c9b4154..afa6382 100644
--- a/cipher/md4.c
+++ b/cipher/md4.c
@@ -286,6 +286,6 @@ gcry_md_spec_t _gcry_digest_spec_md4 =
   {
     GCRY_MD_MD4, {0, 0},
     "MD4", asn, DIM (asn), oid_spec_md4,16,
-    md4_init, _gcry_md_block_write, md4_final, md4_read,
+    md4_init, _gcry_md_block_write, md4_final, md4_read, NULL,
     sizeof (MD4_CONTEXT)
   };
diff --git a/cipher/md5.c b/cipher/md5.c
index f17af7a..66cc5f6 100644
--- a/cipher/md5.c
+++ b/cipher/md5.c
@@ -312,6 +312,6 @@ gcry_md_spec_t _gcry_digest_spec_md5 =
   {
     GCRY_MD_MD5, {0, 1},
     "MD5", asn, DIM (asn), oid_spec_md5, 16,
-    md5_init, _gcry_md_block_write, md5_final, md5_read,
+    md5_init, _gcry_md_block_write, md5_final, md5_read, NULL,
     sizeof (MD5_CONTEXT)
   };
diff --git a/cipher/rmd160.c b/cipher/rmd160.c
index 2695db2..cf7531e 100644
--- a/cipher/rmd160.c
+++ b/cipher/rmd160.c
@@ -526,6 +526,6 @@ gcry_md_spec_t _gcry_digest_spec_rmd160 =
   {
     GCRY_MD_RMD160, {0, 0},
     "RIPEMD160", asn, DIM (asn), oid_spec_rmd160, 20,
-    rmd160_init, _gcry_md_block_write, rmd160_final, rmd160_read,
+    rmd160_init, _gcry_md_block_write, rmd160_final, rmd160_read, NULL,
     sizeof (RMD160_CONTEXT)
   };
diff --git a/cipher/sha1.c b/cipher/sha1.c
index 554d55c..0de8412 100644
--- a/cipher/sha1.c
+++ b/cipher/sha1.c
@@ -573,7 +573,7 @@ gcry_md_spec_t _gcry_digest_spec_sha1 =
   {
     GCRY_MD_SHA1, {0, 1},
     "SHA1", asn, DIM (asn), oid_spec_sha1, 20,
-    sha1_init, _gcry_md_block_write, sha1_final, sha1_read,
+    sha1_init, _gcry_md_block_write, sha1_final, sha1_read, NULL,
     sizeof (SHA1_CONTEXT),
     run_selftests
   };
diff --git a/cipher/sha256.c b/cipher/sha256.c
index 63869d5..bc326e0 100644
--- a/cipher/sha256.c
+++ b/cipher/sha256.c
@@ -633,7 +633,7 @@ gcry_md_spec_t _gcry_digest_spec_sha224 =
   {
     GCRY_MD_SHA224, {0, 1},
     "SHA224", asn224, DIM (asn224), oid_spec_sha224, 28,
-    sha224_init, _gcry_md_block_write, sha256_final, sha256_read,
+    sha224_init, _gcry_md_block_write, sha256_final, sha256_read, NULL,
     sizeof (SHA256_CONTEXT),
     run_selftests
   };
@@ -642,7 +642,7 @@ gcry_md_spec_t _gcry_digest_spec_sha256 =
   {
     GCRY_MD_SHA256, {0, 1},
     "SHA256", asn256, DIM (asn256), oid_spec_sha256, 32,
-    sha256_init, _gcry_md_block_write, sha256_final, sha256_read,
+    sha256_init, _gcry_md_block_write, sha256_final, sha256_read, NULL,
     sizeof (SHA256_CONTEXT),
     run_selftests
   };
diff --git a/cipher/sha512.c b/cipher/sha512.c
index 4be1cab..1196db9 100644
--- a/cipher/sha512.c
+++ b/cipher/sha512.c
@@ -877,7 +877,7 @@ gcry_md_spec_t _gcry_digest_spec_sha512 =
   {
     GCRY_MD_SHA512, {0, 1},
     "SHA512", sha512_asn, DIM (sha512_asn), oid_spec_sha512, 64,
-    sha512_init, _gcry_md_block_write, sha512_final, sha512_read,
+    sha512_init, _gcry_md_block_write, sha512_final, sha512_read, NULL,
     sizeof (SHA512_CONTEXT),
     run_selftests
   };
@@ -903,7 +903,7 @@ gcry_md_spec_t _gcry_digest_spec_sha384 =
   {
     GCRY_MD_SHA384, {0, 1},
     "SHA384", sha384_asn, DIM (sha384_asn), oid_spec_sha384, 48,
-    sha384_init, _gcry_md_block_write, sha512_final, sha512_read,
+    sha384_init, _gcry_md_block_write, sha512_final, sha512_read, NULL,
     sizeof (SHA512_CONTEXT),
     run_selftests
   };
diff --git a/cipher/stribog.c b/cipher/stribog.c
index de167a7..7f38e6f 100644
--- a/cipher/stribog.c
+++ b/cipher/stribog.c
@@ -1326,6 +1326,7 @@ gcry_md_spec_t _gcry_digest_spec_stribog_256 =
     GCRY_MD_STRIBOG256, {0, 0},
     "STRIBOG256", NULL, 0, NULL, 32,
     stribog_init_256, _gcry_md_block_write, stribog_final, stribog_read_256,
+    NULL,
     sizeof (STRIBOG_CONTEXT)
   };
 
@@ -1334,5 +1335,6 @@ gcry_md_spec_t _gcry_digest_spec_stribog_512 =
     GCRY_MD_STRIBOG512, {0, 0},
     "STRIBOG512", NULL, 0, NULL, 64,
     stribog_init_512, _gcry_md_block_write, stribog_final, stribog_read_512,
+    NULL,
     sizeof (STRIBOG_CONTEXT)
   };
diff --git a/cipher/tiger.c b/cipher/tiger.c
index 8a08953..078133a 100644
--- a/cipher/tiger.c
+++ b/cipher/tiger.c
@@ -840,7 +840,7 @@ gcry_md_spec_t _gcry_digest_spec_tiger =
   {
     GCRY_MD_TIGER, {0, 0},
     "TIGER192", NULL, 0, NULL, 24,
-    tiger_init, _gcry_md_block_write, tiger_final, tiger_read,
+    tiger_init, _gcry_md_block_write, tiger_final, tiger_read, NULL,
     sizeof (TIGER_CONTEXT)
   };
 
@@ -863,7 +863,7 @@ gcry_md_spec_t _gcry_digest_spec_tiger1 =
   {
     GCRY_MD_TIGER1, {0, 0},
     "TIGER", asn1, DIM (asn1), oid_spec_tiger1, 24,
-    tiger1_init, _gcry_md_block_write, tiger_final, tiger_read,
+    tiger1_init, _gcry_md_block_write, tiger_final, tiger_read, NULL,
     sizeof (TIGER_CONTEXT)
   };
 
@@ -874,7 +874,7 @@ gcry_md_spec_t _gcry_digest_spec_tiger2 =
   {
     GCRY_MD_TIGER2, {0, 0},
     "TIGER2", NULL, 0, NULL, 24,
-    tiger2_init, _gcry_md_block_write, tiger_final, tiger_read,
+    tiger2_init, _gcry_md_block_write, tiger_final, tiger_read, NULL,
     sizeof (TIGER_CONTEXT)
   };
 
diff --git a/cipher/whirlpool.c b/cipher/whirlpool.c
index 5f224a1..8a06939 100644
--- a/cipher/whirlpool.c
+++ b/cipher/whirlpool.c
@@ -1525,6 +1525,6 @@ gcry_md_spec_t _gcry_digest_spec_whirlpool =
   {
     GCRY_MD_WHIRLPOOL, {0, 0},
     "WHIRLPOOL", NULL, 0, NULL, 64,
-    whirlpool_init, whirlpool_write, whirlpool_final, whirlpool_read,
+    whirlpool_init, whirlpool_write, whirlpool_final, whirlpool_read, NULL,
     sizeof (whirlpool_context_t)
   };
diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index f13695a..3450bb2 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -3036,6 +3036,7 @@ are also supported.
 @c begin table of hash algorithms
 @cindex SHA-1
 @cindex SHA-224, SHA-256, SHA-384, SHA-512
+ at cindex SHA3-224, SHA3-256, SHA3-384, SHA3-512
 @cindex RIPE-MD-160
 @cindex MD2, MD4, MD5
 @cindex TIGER, TIGER1, TIGER2
@@ -3108,6 +3109,22 @@ See FIPS 180-2 for the specification.
 This is the SHA-384 algorithm which yields a message digest of 64 bytes.
 See FIPS 180-2 for the specification.
 
+ at item GCRY_MD_SHA3_224
+This is the SHA3-224 algorithm which yields a message digest of 28 bytes.
+See FIPS 202 for the specification.
+
+ at item GCRY_MD_SHA3_256
+This is the SHA3-256 algorithm which yields a message digest of 32 bytes.
+See FIPS 202 for the specification.
+
+ at item GCRY_MD_SHA3_384
+This is the SHA3-384 algorithm which yields a message digest of 48 bytes.
+See FIPS 202 for the specification.
+
+ at item GCRY_MD_SHA3_512
+This is the SHA3-384 algorithm which yields a message digest of 64 bytes.
+See FIPS 202 for the specification.
+
 @item GCRY_MD_CRC32
 This is the ISO 3309 and ITU-T V.42 cyclic redundancy check.  It yields
 an output of 4 bytes.  Note that this is not a hash algorithm in the
@@ -3170,11 +3187,12 @@ this is the hashed data is highly confidential.
 @item GCRY_MD_FLAG_HMAC
 @cindex HMAC
 Turn the algorithm into a HMAC message authentication algorithm.  This
-only works if just one algorithm is enabled for the handle.  Note that
-the function @code{gcry_md_setkey} must be used to set the MAC key.
-The size of the MAC is equal to the message digest of the underlying
-hash algorithm.  If you want CBC message authentication codes based on
-a cipher, see @xref{Working with cipher handles}.
+only works if just one algorithm is enabled for the handle and that
+algorithm is not an extendable-output function.  Note that the function
+ at code{gcry_md_setkey} must be used to set the MAC key.  The size of the
+MAC is equal to the message digest of the underlying hash algorithm.
+If you want CBC message authentication codes based on a cipher,
+see @xref{Working with cipher handles}.
 
 @item GCRY_MD_FLAG_BUGEMU1
 @cindex bug emulation
@@ -3293,9 +3311,9 @@ message digest or some padding.
 @deftypefun void gcry_md_final (gcry_md_hd_t @var{h})
 
 Finalize the message digest calculation.  This is not really needed
-because @code{gcry_md_read} does this implicitly.  After this has been
-done no further updates (by means of @code{gcry_md_write} or
- at code{gcry_md_putc} should be done; However, to mitigate timing
+because @code{gcry_md_read} and @code{gcry_md_extract} do this implicitly.
+After this has been done no further updates (by means of @code{gcry_md_write}
+or @code{gcry_md_putc} should be done; However, to mitigate timing
 attacks it is sometimes useful to keep on updating the context after
 having stored away the actual digest.  Only the first call to this function
 has an effect. It is implemented as a macro.
@@ -3318,6 +3336,22 @@ The function does return @code{NULL} if the requested algorithm has not
 been enabled.
 @end deftypefun
 
+The way to read output of extendable-output function is by using the
+function:
+
+ at deftypefun gpg_err_code_t gcry_md_extract (gcry_md_hd_t @var{h}, @
+  int @var{algo}, void *@var{buffer}, size_t @var{length})
+
+ at code{gcry_mac_read} returns output from extendable-output function.
+This function may be used as often as required to generate more output
+byte stream from the algorithm.  Function extracts the new output bytes
+to @var{buffer} of the length @var{length}.  Buffer will be fully
+populated with new output.  @var{algo} may be given as 0 to return the only
+enabled message digest or it may specify one of the enabled algorithms.
+The function does return non-zero value if the requested algorithm has not
+been enabled.
+ at end deftypefun
+
 Because it is often necessary to get the message digest of blocks of
 memory, two fast convenience function are available for this task:
 
@@ -3493,6 +3527,7 @@ provided by Libgcrypt.
 @c begin table of MAC algorithms
 @cindex HMAC-SHA-1
 @cindex HMAC-SHA-224, HMAC-SHA-256, HMAC-SHA-384, HMAC-SHA-512
+ at cindex HMAC-SHA3-224, HMAC-SHA3-256, HMAC-SHA3-384, HMAC-SHA3-512
 @cindex HMAC-RIPE-MD-160
 @cindex HMAC-MD2, HMAC-MD4, HMAC-MD5
 @cindex HMAC-TIGER1
@@ -3520,6 +3555,22 @@ algorithm.
 This is HMAC message authentication algorithm based on the SHA-384 hash
 algorithm.
 
+ at item GCRY_MAC_HMAC_SHA3_256
+This is HMAC message authentication algorithm based on the SHA3-384 hash
+algorithm.
+
+ at item GCRY_MAC_HMAC_SHA3_224
+This is HMAC message authentication algorithm based on the SHA3-224 hash
+algorithm.
+
+ at item GCRY_MAC_HMAC_SHA3_512
+This is HMAC message authentication algorithm based on the SHA3-512 hash
+algorithm.
+
+ at item GCRY_MAC_HMAC_SHA3_384
+This is HMAC message authentication algorithm based on the SHA3-384 hash
+algorithm.
+
 @item GCRY_MAC_HMAC_SHA1
 This is HMAC message authentication algorithm based on the SHA-1 hash
 algorithm.
diff --git a/src/cipher-proto.h b/src/cipher-proto.h
index 8267791..3bca9c7 100644
--- a/src/cipher-proto.h
+++ b/src/cipher-proto.h
@@ -215,6 +215,9 @@ typedef void (*gcry_md_final_t) (void *c);
 /* Type for the md_read function.  */
 typedef unsigned char *(*gcry_md_read_t) (void *c);
 
+/* Type for the md_extract function.  */
+typedef void (*gcry_md_extract_t) (void *c, void *outbuf, size_t nbytes);
+
 typedef struct gcry_md_oid_spec
 {
   const char *oidstring;
@@ -237,6 +240,7 @@ typedef struct gcry_md_spec
   gcry_md_write_t write;
   gcry_md_final_t final;
   gcry_md_read_t read;
+  gcry_md_extract_t extract;
   size_t contextsize; /* allocate this amount of context */
   selftest_func_t selftest;
 } gcry_md_spec_t;
diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
index 585da6a..39be37a 100644
--- a/src/gcrypt.h.in
+++ b/src/gcrypt.h.in
@@ -473,7 +473,7 @@ char *gcry_sexp_nth_string (gcry_sexp_t list, int number);
    value can't be converted to an MPI, `NULL' is returned.  */
 gcry_mpi_t gcry_sexp_nth_mpi (gcry_sexp_t list, int number, int mpifmt);
 
-/* Convenience fucntion to extract parameters from an S-expression
+/* Convenience function to extract parameters from an S-expression
  * using a list of single letter parameters.  */
 gpg_error_t gcry_sexp_extract_param (gcry_sexp_t sexp,
                                      const char *path,
@@ -1170,7 +1170,7 @@ enum gcry_md_algos
     GCRY_MD_GOSTR3411_94  = 308, /* GOST R 34.11-94.  */
     GCRY_MD_STRIBOG256    = 309, /* GOST R 34.11-2012, 256 bit.  */
     GCRY_MD_STRIBOG512    = 310, /* GOST R 34.11-2012, 512 bit.  */
-    GCRY_MD_GOSTR3411_CP  = 311,  /* GOST R 34.11-94 with CryptoPro-A S-Box.  */
+    GCRY_MD_GOSTR3411_CP  = 311, /* GOST R 34.11-94 with CryptoPro-A S-Box.  */
     GCRY_MD_SHA3_224      = 312,
     GCRY_MD_SHA3_256      = 313,
     GCRY_MD_SHA3_384      = 314,
@@ -1239,6 +1239,11 @@ void gcry_md_write (gcry_md_hd_t hd, const void *buffer, size_t length);
    algorithm ALGO. */
 unsigned char *gcry_md_read (gcry_md_hd_t hd, int algo);
 
+/* Read more output from algorithm ALGO to BUFFER of size LENGTH from
+ * digest object HD. Algorithm needs to be 'expendable-output function'. */
+gpg_error_t gcry_md_extract (gcry_md_hd_t hd, int algo, void *buffer,
+                             size_t length);
+
 /* Convenience function to calculate the hash from the data in BUFFER
    of size LENGTH using the algorithm ALGO avoiding the creating of a
    hash object.  The hash is returned in the caller provided buffer
diff --git a/src/libgcrypt.def b/src/libgcrypt.def
index 924f17f..f3e074b 100644
--- a/src/libgcrypt.def
+++ b/src/libgcrypt.def
@@ -278,5 +278,6 @@ EXPORTS
 
       gcry_mpi_ec_sub           @244
 
+      gcry_md_extract           @245
 
 ;; end of file with public symbols for Windows.
diff --git a/src/libgcrypt.vers b/src/libgcrypt.vers
index 7e8df3f..5b3d419 100644
--- a/src/libgcrypt.vers
+++ b/src/libgcrypt.vers
@@ -41,7 +41,7 @@ GCRYPT_1.6 {
     gcry_md_get_algo; gcry_md_get_algo_dlen; gcry_md_hash_buffer;
     gcry_md_hash_buffers;
     gcry_md_info; gcry_md_is_enabled; gcry_md_is_secure;
-    gcry_md_map_name; gcry_md_open; gcry_md_read;
+    gcry_md_map_name; gcry_md_open; gcry_md_read; gcry_md_extract;
     gcry_md_reset; gcry_md_setkey;
     gcry_md_write; gcry_md_debug;
 
diff --git a/src/visibility.c b/src/visibility.c
index cbf24e7..23a2705 100644
--- a/src/visibility.c
+++ b/src/visibility.c
@@ -1165,6 +1165,12 @@ gcry_md_read (gcry_md_hd_t hd, int algo)
   return _gcry_md_read (hd, algo);
 }
 
+gcry_err_code_t
+gcry_md_extract (gcry_md_hd_t hd, int algo, void *buffer, size_t length)
+{
+  return _gcry_md_extract(hd, algo, buffer, length);
+}
+
 void
 gcry_md_hash_buffer (int algo, void *digest,
                      const void *buffer, size_t length)
diff --git a/src/visibility.h b/src/visibility.h
index fa3c763..bb25de0 100644
--- a/src/visibility.h
+++ b/src/visibility.h
@@ -110,6 +110,7 @@ MARK_VISIBLEX (gcry_md_is_secure)
 MARK_VISIBLEX (gcry_md_map_name)
 MARK_VISIBLEX (gcry_md_open)
 MARK_VISIBLEX (gcry_md_read)
+MARK_VISIBLEX (gcry_md_extract)
 MARK_VISIBLEX (gcry_md_reset)
 MARK_VISIBLEX (gcry_md_setkey)
 MARK_VISIBLEX (gcry_md_write)
@@ -374,6 +375,7 @@ MARK_VISIBLEX (_gcry_mpi_get_const)
 #define gcry_md_map_name            _gcry_USE_THE_UNDERSCORED_FUNCTION
 #define gcry_md_open                _gcry_USE_THE_UNDERSCORED_FUNCTION
 #define gcry_md_read                _gcry_USE_THE_UNDERSCORED_FUNCTION
+#define gcry_md_extract             _gcry_USE_THE_UNDERSCORED_FUNCTION
 #define gcry_md_reset               _gcry_USE_THE_UNDERSCORED_FUNCTION
 #define gcry_md_setkey              _gcry_USE_THE_UNDERSCORED_FUNCTION
 #define gcry_md_write               _gcry_USE_THE_UNDERSCORED_FUNCTION




More information about the Gcrypt-devel mailing list