[PATCH gnupg 1/1] Addition of cSHAKE and KMAC

Falko Strenzke falko.strenzke at mtg.de
Mon Oct 2 16:00:02 CEST 2023


---
 cipher/cshake-common.c | 142 +++++++++++++++
 cipher/cshake-common.h |  63 +++++++
 cipher/keccak.c        | 215 +++++++++++++++++++++++
 cipher/keccak.h        |  36 ++++
 cipher/mac-internal.h  |  22 +++
 cipher/mac-kmac.c      | 380 +++++++++++++++++++++++++++++++++++++++++
 cipher/mac.c           |  14 ++
 cipher/md.c            |  50 +++++-
 configure.ac           |   2 +-
 doc/gcrypt.texi        |  31 +++-
 src/cipher.h           |   2 +
 src/fips.c             |   2 +
 src/gcrypt-int.h       |   1 +
 src/gcrypt.h.in        |  14 +-
 src/visibility.c       |   1 +
 src/visibility.h       |   1 +
 tests/Makefile.am      |   2 +-
 tests/basic.c          | 313 ++++++++++++++++++++++++++++++++-
 tests/cshake.c         | 335 ++++++++++++++++++++++++++++++++++++
 19 files changed, 1615 insertions(+), 11 deletions(-)
 create mode 100644 cipher/cshake-common.c
 create mode 100644 cipher/cshake-common.h
 create mode 100644 cipher/keccak.h
 create mode 100644 cipher/mac-kmac.c
 create mode 100644 tests/cshake.c

diff --git a/cipher/cshake-common.c b/cipher/cshake-common.c
new file mode 100644
index 00000000..e0ef15ee
--- /dev/null
+++ b/cipher/cshake-common.c
@@ -0,0 +1,142 @@
+/* cshake-common.c  -  Some helpers for cSHAKE and KMAC
+ * Copyright (C) 2023 MTG AG
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser general Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cshake-common.h"
+
+
+
+/**
+ * @brief Append data to a buffer
+ *
+ * @param buf the buffer to append data to
+ * @param data data to append
+ * @param len length of the data
+ *
+ * @return 0 on success, 1 if the buffer is overfilled
+ */
+int
+_gcry_cshake_append_to_buffer (gcry_buffer_t *buf,
+                               const unsigned char *data,
+                               size_t len)
+{
+  if (buf->size - buf->len < len)
+    {
+      return 1;
+    }
+  memcpy (((unsigned char*) buf->data) + buf->len, data, len);
+  buf->len += len;
+  return 0;
+}
+
+static int
+append_byte_to_buffer (gcry_buffer_t *buf, const unsigned char b)
+{
+  return _gcry_cshake_append_to_buffer (buf, &b, 1);
+}
+
+/**
+ * Performs left_encode or right_encode as defined in
+ * https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-185.pdf.
+ * Caller must ensure that sufficient capacity is left in the output buffer.
+ * The function appends at most one byte more (one because of additional length
+ * octed) than the byte size
+ * needed to represent the value of the input parameter s.
+ */
+static size_t
+left_or_right_encode (size_t s,
+                      gcry_buffer_t *output_buffer,
+                      encoded_direction_t dir)
+{
+  int i;
+  size_t bytes_appended = 0;
+  // determine number of octets needed to encode s
+  for (i = sizeof (s); i > 0; i--)
+    {
+      unsigned char t = (s >> ((i - 1) * 8) & (size_t)0xFF);
+      if (t != 0)
+        {
+          break;
+        }
+    }
+  if (i == 0)
+    {
+      i = 1;
+    }
+  if (dir == left)
+    {
+      if (append_byte_to_buffer (output_buffer, i))
+        {
+          /* error */
+          return 0;
+        }
+      bytes_appended++;
+    }
+  // big endian encoding of s
+  for (int j = i; j > 0; j--)
+    {
+      if (append_byte_to_buffer (output_buffer,
+                                 s >> (j - 1) * 8 & ((size_t)0xFF)))
+        {
+          /* error */
+          return 0;
+        }
+      bytes_appended++;
+    }
+  if (dir == right)
+    {
+      if (append_byte_to_buffer (output_buffer, (unsigned char)i))
+        {
+          /* error */
+          return 0;
+        }
+      bytes_appended++;
+    }
+  return bytes_appended;
+}
+
+size_t
+_gcry_cshake_left_encode (size_t s,
+                          gcry_buffer_t *output_buffer)
+{
+  return left_or_right_encode (s, output_buffer, left);
+}
+
+size_t
+_gcry_cshake_right_encode (size_t s,
+                           gcry_buffer_t *output_buffer)
+{
+  size_t result = left_or_right_encode (s, output_buffer, right);
+  return result;
+}
+
+/**
+ * Convert byte length to bit length. Returns zero on overflow, i.e.
+ * precondition that bit length fits into size_t has to be checked by the
+ * caller.
+ */
+size_t
+_gcry_cshake_bit_len_from_byte_len (size_t byte_length)
+{
+  size_t bit_length = 8 * byte_length;
+  if (bit_length < byte_length)
+    {
+      return 0;
+    }
+  return bit_length;
+}
diff --git a/cipher/cshake-common.h b/cipher/cshake-common.h
new file mode 100644
index 00000000..c05e4b39
--- /dev/null
+++ b/cipher/cshake-common.h
@@ -0,0 +1,63 @@
+/* cshake-common.h  -  Some helpers for cSHAKE and KMAC
+ * Copyright (C) 2012-2017 Jussi Kivilinna <jussi.kivilinna at iki.fi>
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef GCRYPT_CSHAKE_COMMON_H
+#define GCRYPT_CSHAKE_COMMON_H
+
+
+#include <config.h>
+#include "g10lib.h"
+#include <stddef.h>
+#include "gcrypt.h"
+
+typedef enum
+{
+  left  = 1,
+  right = 2
+} encoded_direction_t;
+
+size_t _gcry_cshake_bit_len_from_byte_len (size_t byte_length);
+
+
+int _gcry_cshake_append_byte_to_buffer (gcry_buffer_t *buf,
+                                        const unsigned char byte);
+
+/**
+ * Performs left_encode as defined in
+ * https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-185.pdf.
+ * Caller must ensure that sufficient capacity is left in the output buffer to
+ * perform the encoding. The function appends at most one byte more (one
+ * because of additional length octed) than the byte size needed to represent
+ * the value of the input parameter s.
+ */
+size_t _gcry_cshake_left_encode (size_t s, gcry_buffer_t *output_buffer);
+
+
+/**
+ * Performs right_encode as defined in
+ * https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-185.pdf.
+ * Caller must ensure that sufficient capacity is left in the output buffer to
+ * perform the encoding. The function appends at most one byte more (one
+ * because of additional length octed) than the byte size needed to represent
+ * the value of the input parameter s.
+ */
+size_t _gcry_cshake_right_encode (size_t s, gcry_buffer_t *output_buffer);
+
+
+
+#endif
diff --git a/cipher/keccak.c b/cipher/keccak.c
index 9883af4d..8d7b9f87 100644
--- a/cipher/keccak.c
+++ b/cipher/keccak.c
@@ -25,6 +25,8 @@
 #include "bufhelp.h"
 #include "cipher.h"
 #include "hash-common.h"
+#include "keccak.h"
+#include "cshake-common.h"
 
 
 
@@ -112,6 +114,7 @@
 
 #define SHA3_DELIMITED_SUFFIX 0x06
 #define SHAKE_DELIMITED_SUFFIX 0x1F
+#define CSHAKE_DELIMITED_SUFFIX 0x04
 
 
 typedef struct
@@ -154,6 +157,14 @@ typedef struct KECCAK_CONTEXT_S
 #endif
 } KECCAK_CONTEXT;
 
+typedef struct CSHAKE_CONTEXT_S
+{
+  KECCAK_CONTEXT keccak_ctx;
+  unsigned int rate_in_bytes;
+  size_t written_bytes_n_s;
+  int n_set;
+  int s_set;
+} CSHAKE_CONTEXT;
 
 
 #ifdef NEED_COMMON64
@@ -1025,11 +1036,13 @@ keccak_init (int algo, void *context, unsigned int flags)
       ctx->blocksize = 576 / 8;
       ctx->outlen = 512 / 8;
       break;
+    case GCRY_MD_CSHAKE128:
     case GCRY_MD_SHAKE128:
       ctx->suffix = SHAKE_DELIMITED_SUFFIX;
       ctx->blocksize = 1344 / 8;
       ctx->outlen = 256 / 8;
       break;
+    case GCRY_MD_CSHAKE256:
     case GCRY_MD_SHAKE256:
       ctx->suffix = SHAKE_DELIMITED_SUFFIX;
       ctx->blocksize = 1088 / 8;
@@ -1059,9 +1072,11 @@ keccak_init (int algo, void *context, unsigned int flags)
 	case GCRY_MD_SHA3_512:
 	  kimd_func = KMID_FUNCTION_SHA3_512;
 	  break;
+  case GCRY_MD_CSHAKE128:
 	case GCRY_MD_SHAKE128:
 	  kimd_func = KMID_FUNCTION_SHAKE128;
 	  break;
+  case GCRY_MD_CSHAKE256:
 	case GCRY_MD_SHAKE256:
 	  kimd_func = KMID_FUNCTION_SHAKE256;
 	  break;
@@ -1112,6 +1127,27 @@ shake256_init (void *context, unsigned int flags)
   keccak_init (GCRY_MD_SHAKE256, context, flags);
 }
 
+
+static void
+cshake128_init (void *context, unsigned int flags)
+{
+  CSHAKE_CONTEXT *cshake_context = (CSHAKE_CONTEXT *)context;
+  cshake_context->rate_in_bytes  = 168;
+  cshake_context->n_set          = 0;
+  cshake_context->s_set          = 0;
+  keccak_init (GCRY_MD_CSHAKE128, context, flags);
+}
+
+static void
+cshake256_init (void *context, unsigned int flags)
+{
+  CSHAKE_CONTEXT *cshake_context = (CSHAKE_CONTEXT *)context;
+  cshake_context->rate_in_bytes  = 136;
+  cshake_context->n_set          = 0;
+  cshake_context->s_set          = 0;
+  keccak_init (GCRY_MD_CSHAKE256, context, flags);
+}
+
 /* The routine final terminates the computation and
  * returns the digest.
  * The handle is prepared for a new cycle, but adding bytes to the
@@ -1423,6 +1459,147 @@ _gcry_shake256_hash_buffers (void *outbuf, size_t nbytes,
 			   &_gcry_digest_spec_shake256);
 }
 
+
+/** cSHAKE related functions **/
+
+
+/* may only be called with values of n_len that, multiplied by 8 still fit into a size_t */
+static gpg_err_code_t
+_gcry_cshake_input_n (CSHAKE_CONTEXT *cshake_ctx, const void *n, size_t n_len)
+{
+
+  // KECCAK[512](bytepad(encode_string(N)
+  size_t bit_len;
+  unsigned char array[20];
+  int err_flag      = 0;
+  gpg_err_code_t rc = 0;
+  gcry_buffer_t buf1;
+  buf1.size = sizeof (array);
+  buf1.data = array;
+  buf1.len  = 0;
+
+  if (rc)
+    {
+      return rc;
+    }
+  _gcry_cshake_left_encode (cshake_ctx->rate_in_bytes, &buf1);
+  /* perform encode_string as left-encoding the length and then the buffer */
+  bit_len = _gcry_cshake_bit_len_from_byte_len (n_len);
+  _gcry_cshake_left_encode (bit_len, &buf1);
+  if (err_flag)
+    {
+      return GPG_ERR_INTERNAL;
+    }
+  keccak_write (&cshake_ctx->keccak_ctx, buf1.data, buf1.len);
+  keccak_write (&cshake_ctx->keccak_ctx, n, n_len);
+  cshake_ctx->written_bytes_n_s = buf1.len + n_len;
+  cshake_ctx->n_set             = 1;
+  return GPG_ERR_NO_ERROR;
+}
+
+
+/* may only be called with values of n_len that, multiplied by 8 still fit into a size_t */
+static void
+_gcry_cshake_input_s (CSHAKE_CONTEXT *cshake_ctx, const void *s, size_t s_len)
+{
+
+  // KECCAK[(256 or 512)](bytepad(encode_string(N)
+  // KECCAK[(256 or 512)](bytepad(...<already fed> || encode_string(S), w = (168 or 136))
+  size_t bit_len;
+  unsigned char array[20];
+  size_t rem;
+  gcry_buffer_t buf1;
+  buf1.size = sizeof (array);
+  buf1.data = array;
+  buf1.len  = 0;
+
+  /* perform encode_string as left-encoding the length and then the buffer */
+  bit_len = _gcry_cshake_bit_len_from_byte_len (s_len);
+
+  _gcry_cshake_left_encode (bit_len, &buf1);
+
+  keccak_write (&cshake_ctx->keccak_ctx, buf1.data, buf1.len);
+  keccak_write (&cshake_ctx->keccak_ctx, s, s_len);
+  cshake_ctx->written_bytes_n_s += buf1.len + s_len;
+  cshake_ctx->s_set = 1;
+
+  /* complete byte_bad operation */
+  rem = cshake_ctx->written_bytes_n_s % cshake_ctx->rate_in_bytes;
+  if (rem != 0)
+    {
+      rem = cshake_ctx->rate_in_bytes - rem;
+      memset (array, 0, sizeof (array));
+    }
+
+  while (rem > 0)
+    {
+      unsigned to_use = rem > sizeof (array) ? sizeof (array) : rem;
+      keccak_write (&cshake_ctx->keccak_ctx, array, to_use);
+      rem -= to_use;
+    }
+}
+
+gpg_err_code_t
+_gcry_cshake_add_input (void *context,
+                        enum gcry_ctl_cmds addin_type,
+                        const void *v,
+                        size_t v_len)
+{
+  gpg_err_code_t rc              = 0;
+  CSHAKE_CONTEXT *cshake_context = (CSHAKE_CONTEXT *)context;
+  /* if s is already set, then we cannot add further input special input */
+  if (cshake_context->s_set)
+    {
+      return GPG_ERR_INV_STATE;
+    }
+  /* catch overly long input already here that will cause a problem when it's
+   * byte length is converted to bit length */
+  if ( DOES_MULT_OVERFL_SIZE_T(8, v_len) || v_len > 0xFFFFFFFF)
+    {
+      return GPG_ERR_TOO_LARGE;
+    }
+  /* when either N or S is set as non-empty, then actually use a different
+   * delimeter than in SHAKE */
+  if (v_len > 0)
+    {
+      cshake_context->keccak_ctx.suffix = CSHAKE_DELIMITED_SUFFIX;
+    }
+  if (addin_type == GCRYCTL_CSHAKE_N)
+    {
+      if (cshake_context->n_set)
+        {
+          return GPG_ERR_INV_STATE;
+        }
+      return _gcry_cshake_input_n (cshake_context, v, v_len);
+    }
+  else if (addin_type == GCRYCTL_CSHAKE_S)
+    {
+      if (!cshake_context->n_set)
+        {
+          rc = _gcry_cshake_input_n (cshake_context, NULL, 0);
+          if (rc)
+            {
+              return rc;
+            }
+        }
+      _gcry_cshake_input_s (cshake_context, v, v_len);
+    }
+  return GPG_ERR_NO_ERROR;
+}
+
+
+static void
+cshake_write (void *context, const void *inbuf_arg, size_t inlen)
+{
+
+  CSHAKE_CONTEXT *cshake_context = (CSHAKE_CONTEXT *)context;
+  if (cshake_context->n_set && !cshake_context->s_set)
+    {
+      _gcry_cshake_input_s (cshake_context, NULL, 0);
+    }
+  return keccak_write (&cshake_context->keccak_ctx, inbuf_arg, inlen);
+}
+
 
 /*
      Self-test section.
@@ -1505,6 +1682,7 @@ selftests_keccak (int algo, int extended, selftest_report_func_t report)
       hash_len = 64;
       break;
 
+    case GCRY_MD_CSHAKE128:
     case GCRY_MD_SHAKE128:
       short_hash =
 	"\x58\x81\x09\x2d\xd8\x18\xbf\x5c\xf8\xa3\xdd\xb7\x93\xfb\xcb\xa7"
@@ -1518,6 +1696,7 @@ selftests_keccak (int algo, int extended, selftest_report_func_t report)
       hash_len = 32;
       break;
 
+    case GCRY_MD_CSHAKE256:
     case GCRY_MD_SHAKE256:
       short_hash =
 	"\x48\x33\x66\x60\x13\x60\xa8\x77\x1c\x68\x63\x08\x0c\xc4\x11\x4d"
@@ -1577,7 +1756,9 @@ run_selftests (int algo, int extended, selftest_report_func_t report)
     case GCRY_MD_SHA3_256:
     case GCRY_MD_SHA3_384:
     case GCRY_MD_SHA3_512:
+    case GCRY_MD_CSHAKE128:
     case GCRY_MD_SHAKE128:
+    case GCRY_MD_CSHAKE256:
     case GCRY_MD_SHAKE256:
       ec = selftests_keccak (algo, extended, report);
       break;
@@ -1697,3 +1878,37 @@ const gcry_md_spec_t _gcry_digest_spec_shake256 =
     sizeof (KECCAK_CONTEXT),
     run_selftests
   };
+
+const gcry_md_spec_t _gcry_digest_spec_cshake128
+    = {GCRY_MD_CSHAKE128,
+       {0, 1},
+       "CSHAKE128",
+       shake128_asn,
+       DIM (shake128_asn),
+       NULL /* no oid_spec */,
+       32,
+       cshake128_init,
+       cshake_write,
+       keccak_final,
+       keccak_shake_read,
+       keccak_extract,
+       _gcry_shake128_hash_buffers,
+       sizeof (CSHAKE_CONTEXT),
+       run_selftests};
+const gcry_md_spec_t _gcry_digest_spec_cshake256 = {
+    GCRY_MD_CSHAKE256,
+    {0, 1},
+    "CSHAKE256",
+    shake256_asn,
+    DIM (shake256_asn),
+    NULL /* no oid_spec */,
+    64,
+    cshake256_init,
+    cshake_write,
+    keccak_final,
+    keccak_shake_read,
+    keccak_extract,
+    _gcry_shake256_hash_buffers,
+    sizeof (CSHAKE_CONTEXT),
+    run_selftests,
+};
diff --git a/cipher/keccak.h b/cipher/keccak.h
new file mode 100644
index 00000000..6b5a3fca
--- /dev/null
+++ b/cipher/keccak.h
@@ -0,0 +1,36 @@
+/* keccak.h  -  internal keccak-related functionality
+ * Copyright (C) 2023 MTG AG
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser general Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "g10lib.h"
+#include "cipher.h"
+#include "gcrypt.h"
+
+
+#define DOES_MULT_OVERFL_SIZE_T(a, b) (a != 0 && ((size_t) (a*b))/a != b)
+
+gpg_err_code_t _gcry_cshake_add_input(void* context,
+                        enum gcry_ctl_cmds addin_type,
+                        const void *v,
+                        size_t v_len);
diff --git a/cipher/mac-internal.h b/cipher/mac-internal.h
index 142ef69e..371a8ab5 100644
--- a/cipher/mac-internal.h
+++ b/cipher/mac-internal.h
@@ -129,6 +129,19 @@ struct gcry_mac_handle
       unsigned int count;
       unsigned char lastiv[8]; /* IMIT blocksize */
     } imit;
+    struct {
+      gcry_md_hd_t md_ctx;
+      unsigned char* computed_mac;
+      int have_computed_mac;
+      int md_algo;
+      unsigned cshake_rate_in_bytes;
+      unsigned char* buffered_key;
+      size_t buffered_key_len;
+      unsigned output_byte_len;
+      int s_set;
+      int key_set;
+      int finalized;
+    } kmac;
   } u;
 };
 
@@ -288,3 +301,12 @@ extern const gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_sm4;
 #if USE_ARIA
 extern const gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_aria;
 #endif
+
+/*
+ * KMAC algorithms (mac-kmac.c)
+ */
+
+#if USE_SHA3
+extern const gcry_mac_spec_t _gcry_mac_type_spec_kmac128_128;
+extern const gcry_mac_spec_t _gcry_mac_type_spec_kmac256_256;
+#endif
diff --git a/cipher/mac-kmac.c b/cipher/mac-kmac.c
new file mode 100644
index 00000000..ad80cb63
--- /dev/null
+++ b/cipher/mac-kmac.c
@@ -0,0 +1,380 @@
+/* mac-kmac.c  -  KMAC glue for MAC API
+ * Copyright (C) 2023 MTG AG
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser general Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "g10lib.h"
+#include "./mac-internal.h"
+#include "gcrypt.h"
+
+#include <stddef.h>
+#include "cshake-common.h"
+#include "bufhelp.h"
+#include "keccak.h"
+
+static void
+write_encoded_key (gcry_mac_hd_t h, const unsigned char *key, size_t keylen)
+{
+
+  size_t written_bytes = 0;
+  size_t bit_len;
+  gcry_buffer_t buf1;
+  unsigned char array[20];
+  unsigned rate_in_bytes = h->u.kmac.cshake_rate_in_bytes;
+  size_t rem;
+
+  /* catch overly large size of key early that would cause problem in
+   * subseuqently invoked conversion routines */
+  buf1.size = sizeof (array);
+  buf1.data = array;
+  buf1.len  = 0;
+  /* bytepad(encode_string(key), <keccak_rate>) */
+  /* inside bytepad: leading encoding of w */
+  _gcry_cshake_left_encode (h->u.kmac.cshake_rate_in_bytes, &buf1);
+
+  /* encode_string(key) */
+  bit_len = _gcry_cshake_bit_len_from_byte_len (keylen);
+  _gcry_cshake_left_encode (bit_len, &buf1);
+  _gcry_md_write (h->u.kmac.md_ctx, buf1.data, buf1.len);
+  written_bytes += buf1.len;
+  _gcry_md_write (h->u.kmac.md_ctx, key, keylen);
+  written_bytes += keylen;
+
+
+  /* complete bytebad operation by applying padding */
+  rem = written_bytes % rate_in_bytes;
+  if (rem != 0)
+    {
+      rem = rate_in_bytes - rem;
+      memset (array, 0, sizeof (array));
+    }
+
+  while (rem > 0)
+    {
+      unsigned to_use = rem > sizeof (array) ? sizeof (array) : rem;
+      _gcry_md_write (h->u.kmac.md_ctx, array, to_use);
+      rem -= to_use;
+    }
+  return;
+}
+
+static gpg_err_code_t
+kmac_finalize (gcry_mac_hd_t h)
+{
+
+  size_t bit_len;
+  unsigned char array[20];
+
+  gcry_buffer_t buf1;
+  buf1.size = sizeof (array);
+  buf1.data = array;
+  buf1.len  = 0;
+  bit_len   = _gcry_cshake_bit_len_from_byte_len (h->u.kmac.output_byte_len);
+  _gcry_cshake_right_encode (bit_len, &buf1);
+  _gcry_md_write (h->u.kmac.md_ctx, buf1.data, buf1.len);
+  h->u.kmac.finalized = 1;
+  return GPG_ERR_NO_ERROR;
+}
+
+static gcry_err_code_t
+kmac_open (gcry_mac_hd_t h)
+{
+  gcry_err_code_t err;
+  gcry_md_hd_t hd;
+  int secure = (h->magic == CTX_MAC_MAGIC_SECURE);
+  unsigned int flags;
+  int md_algo;
+  unsigned rate_in_bytes, output_byte_len;
+  switch (h->spec->algo)
+    {
+    case GCRY_MAC_KMAC128_128:
+      md_algo         = GCRY_MD_CSHAKE128;
+      rate_in_bytes   = 168;
+      output_byte_len = 256 / 8;
+      break;
+    case GCRY_MAC_KMAC256_256:
+      md_algo         = GCRY_MD_CSHAKE256;
+      rate_in_bytes   = 136;
+      output_byte_len = 512 / 8;
+      break;
+    default:
+      return GPG_ERR_INV_ARG;
+    }
+  h->u.kmac.buffered_key         = NULL;
+  h->u.kmac.md_algo              = md_algo;
+  h->u.kmac.s_set                = 0;
+  h->u.kmac.key_set              = 0;
+  h->u.kmac.output_byte_len      = output_byte_len;
+  h->u.kmac.finalized            = 0;
+  h->u.kmac.cshake_rate_in_bytes = rate_in_bytes;
+  h->u.kmac.computed_mac         = NULL;
+  h->u.kmac.have_computed_mac    = 0;
+  flags                          = (secure ? GCRY_MD_FLAG_SECURE : 0);
+
+  err = _gcry_md_open (&hd, md_algo, flags);
+  if (err)
+    {
+      return err;
+    }
+  h->u.kmac.md_ctx = hd;
+
+  err = _gcry_md_ctl (hd, GCRYCTL_CSHAKE_N, (unsigned char *)"KMAC", 4);
+  if (err)
+    {
+      return err;
+    }
+  h->u.kmac.computed_mac = secure ? xtrymalloc_secure (output_byte_len)
+                                  : xtrymalloc (output_byte_len);
+  if (!h->u.kmac.computed_mac)
+    {
+      return gpg_err_code_from_syserror ();
+    }
+
+  return GPG_ERR_NO_ERROR;
+}
+
+
+static void
+kmac_close (gcry_mac_hd_t h)
+{
+  _gcry_md_close (h->u.kmac.md_ctx);
+  h->u.kmac.md_ctx = NULL;
+  xfree (h->u.kmac.computed_mac);
+  xfree (h->u.kmac.buffered_key);
+}
+
+static gcry_err_code_t
+kmac_setkey (gcry_mac_hd_t h, const unsigned char *key, size_t keylen)
+{
+  gcry_err_code_t err = GPG_ERR_NO_ERROR;
+
+  /* catch overly large size of key early that would cause problem in
+   * subseuqently invoked conversion routines */
+  if (DOES_MULT_OVERFL_SIZE_T (8, keylen) || keylen > 0xFFFFFFFF)
+    {
+      return GPG_ERR_TOO_LARGE;
+    }
+  /* if IV=S was set already, then encode and write key to cSHAKE, else
+   * store it. */
+  if (!h->u.kmac.s_set)
+    {
+      h->u.kmac.buffered_key = xtrymalloc_secure (keylen);
+      if (!h->u.kmac.buffered_key)
+        {
+          return GPG_ERR_ENOMEM;
+        }
+      memcpy (h->u.kmac.buffered_key, key, keylen);
+      h->u.kmac.buffered_key_len = keylen;
+    }
+  else
+    {
+      write_encoded_key (h, key, keylen);
+    }
+  h->u.kmac.key_set = 1;
+  return err;
+}
+
+gcry_err_code_t
+kmac_setiv (gcry_mac_hd_t h, const unsigned char *iv, size_t ivlen)
+{
+  gpg_err_code_t err = GPG_ERR_NO_ERROR;
+
+  /* catch overly large size of IV early that would cause problem in
+   * subseuqently invoked conversion routines */
+  if (DOES_MULT_OVERFL_SIZE_T (8, ivlen) || ivlen > 0xFFFFFFFF)
+    {
+      return GPG_ERR_TOO_LARGE;
+    }
+  if (h->u.kmac.s_set)
+    {
+      return GPG_ERR_INV_STATE;
+    }
+  err = _gcry_md_ctl (
+      h->u.kmac.md_ctx, GCRYCTL_CSHAKE_S, (unsigned char *)iv, ivlen);
+  if (err)
+    {
+      return err;
+    }
+  h->u.kmac.s_set = 1;
+  /* if key is stored in context already, then write it after having set
+   * S in cshake and free the buffer */
+  if (h->u.kmac.buffered_key != NULL)
+    {
+      write_encoded_key (
+          h, h->u.kmac.buffered_key, h->u.kmac.buffered_key_len);
+      xfree (h->u.kmac.buffered_key);
+      h->u.kmac.buffered_key     = NULL;
+      h->u.kmac.buffered_key_len = 0;
+    }
+  return GPG_ERR_NO_ERROR;
+}
+
+
+static gcry_err_code_t
+kmac_reset (gcry_mac_hd_t h)
+{
+  /* clear all fields and state */
+  kmac_close (h);
+  return kmac_open (h);
+}
+
+
+static gcry_err_code_t
+kmac_write (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen)
+{
+  gpg_err_code_t err = 0;
+
+  /* If IV (=S in KMAC) was not set, it is implicitly empty */
+  if (!h->u.kmac.s_set)
+    {
+      err = kmac_setiv (h, NULL, 0);
+      if (err)
+        {
+          return err;
+        }
+    }
+  if (!h->u.kmac.key_set || h->u.kmac.finalized)
+    {
+      return GPG_ERR_INV_STATE;
+    }
+  _gcry_md_write (h->u.kmac.md_ctx, buf, buflen);
+  return GPG_ERR_NO_ERROR;
+}
+
+
+static gcry_err_code_t
+kmac_read (gcry_mac_hd_t h, unsigned char *outbuf, size_t *outlen_ptr)
+{
+
+  if (outlen_ptr && *outlen_ptr > h->u.kmac.output_byte_len)
+    {
+      *outlen_ptr = h->u.kmac.output_byte_len;
+    }
+  /* Both read and verify may be called in any order. Thus the KMAC context
+   * holds the computed MAC in a buffer. */
+  if (!h->u.kmac.have_computed_mac)
+    {
+      gpg_err_code_t err = GPG_ERR_NO_ERROR;
+      err                = kmac_finalize (h);
+      if (err)
+        {
+          return err;
+        }
+
+      err = _gcry_md_extract (h->u.kmac.md_ctx,
+                              h->u.kmac.md_algo,
+                              h->u.kmac.computed_mac,
+                              h->u.kmac.output_byte_len);
+      if (err)
+        {
+          return err;
+        }
+      h->u.kmac.have_computed_mac = 1;
+    }
+  if (outlen_ptr)
+    {
+      memcpy (outbuf, h->u.kmac.computed_mac, *outlen_ptr);
+    }
+  return GPG_ERR_NO_ERROR;
+}
+
+
+static gcry_err_code_t
+kmac_verify (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen)
+{
+  /* This function verifies full MACs only. If a too short MAC is provided by
+   * the caller, the verification fails. Note that for instance HMAC in
+   * libgcrypt behaves differently: if there a MAC is provided to the verify
+   * function that is shorter than the regular MAC length, the verification
+   * succeeds if that shorter MAC is a matching the start of the regular MAC.
+   * This behaviour incurs the risk that an implementation issues the
+   * verification of a one-byte-length attacker controlled MAC that then
+   * verifies correctly with probability 1/256 (the case of zero-length MACs is
+   * caught by the higher-level generic MAC API).
+   */
+  gpg_err_code_t err = GPG_ERR_NO_ERROR;
+  size_t outlen      = h->u.kmac.output_byte_len;
+  if (buflen != outlen)
+    {
+      return GPG_ERR_INV_LENGTH;
+    }
+  err = kmac_read (h, NULL, NULL);
+  if (err)
+    {
+      return err;
+    }
+  return buf_eq_const (buf, h->u.kmac.computed_mac, outlen) ? 0
+                                                            : GPG_ERR_CHECKSUM;
+}
+static unsigned int
+kmac_get_maclen (int algo)
+{
+  switch (algo)
+    {
+    case GCRY_MAC_KMAC128_128:
+      return 256 / 8;
+    case GCRY_MAC_KMAC256_256:
+      return 512 / 8;
+    default:
+      return 0;
+    }
+}
+
+
+static unsigned int
+kmac_get_keylen (int algo)
+{
+  /* The key length for KMAC is arbitrary. Here, we return values
+   * corresponding to the security level. */
+  switch (algo)
+    {
+    case GCRY_MAC_KMAC128_128:
+      return 128 / 8;
+    case GCRY_MAC_KMAC256_256:
+      return 256 / 8;
+    default:
+      /* return the minimum reasonable value */
+      return 128;
+    }
+}
+
+static const gcry_mac_spec_ops_t kmac_ops = {
+    kmac_open,
+    kmac_close,
+    kmac_setkey,
+    kmac_setiv,
+    kmac_reset,
+    kmac_write,
+    kmac_read,
+    kmac_verify,
+    kmac_get_maclen,
+    kmac_get_keylen,
+    NULL,
+    NULL /* no kmac_selftest */
+};
+
+const gcry_mac_spec_t _gcry_mac_type_spec_kmac128_128
+    = {GCRY_MAC_KMAC128_128, {0, 0}, "KMAC128(128)", &kmac_ops};
+
+const gcry_mac_spec_t _gcry_mac_type_spec_kmac256_256
+    = {GCRY_MAC_KMAC256_256, {0, 0}, "KMAC256(256)", &kmac_ops};
diff --git a/cipher/mac.c b/cipher/mac.c
index 6305f51e..82bf1d98 100644
--- a/cipher/mac.c
+++ b/cipher/mac.c
@@ -407,6 +407,18 @@ static const gcry_mac_spec_t * const mac_list_algo501[] =
 #endif
   };
 
+/* KMAC algorithms start with index 601 (enum gcry_mac_algos). The postfixed number indicates the output length in bits. */
+static const gcry_mac_spec_t * const mac_list_algo601[] =
+  {
+#if USE_SHA3
+    &_gcry_mac_type_spec_kmac128_128,
+    &_gcry_mac_type_spec_kmac256_256
+#else
+    NULL,
+    NULL
+#endif
+  };
+
 
 
 
@@ -433,6 +445,8 @@ spec_from_algo (int algo)
     spec = mac_list_algo401[algo - 401];
   else if (algo >= 501 && algo < 501 + DIM(mac_list_algo501))
     spec = mac_list_algo501[algo - 501];
+  else if (algo >= 601 && algo < 601 + DIM(mac_list_algo601))
+    spec = mac_list_algo601[algo - 601];
 #if USE_GOST28147
   else if (algo == GCRY_MAC_GOST28147_IMIT)
     spec = &_gcry_mac_type_spec_gost28147_imit;
diff --git a/cipher/md.c b/cipher/md.c
index a128dd82..81a036d7 100644
--- a/cipher/md.c
+++ b/cipher/md.c
@@ -27,6 +27,8 @@
 
 #include "g10lib.h"
 #include "cipher.h"
+#include "gcrypt.h"
+#include "keccak.h"
 
 
 /* This is the list of the digest implementations included in
@@ -58,6 +60,8 @@ static const gcry_md_spec_t * const digest_list[] =
      &_gcry_digest_spec_sha3_512,
      &_gcry_digest_spec_shake128,
      &_gcry_digest_spec_shake256,
+     &_gcry_digest_spec_cshake128,
+     &_gcry_digest_spec_cshake256,
 #endif
 #if USE_GOST_R_3411_94
      &_gcry_digest_spec_gost3411_94,
@@ -240,7 +244,9 @@ static const gcry_md_spec_t * const digest_list_algo301[] =
 #endif
 #if USE_SHA512
     &_gcry_digest_spec_sha512_256,
-    &_gcry_digest_spec_sha512_224
+    &_gcry_digest_spec_sha512_224,
+    &_gcry_digest_spec_cshake128,
+    &_gcry_digest_spec_cshake256
 #else
     NULL,
     NULL
@@ -996,6 +1002,44 @@ prepare_macpads (gcry_md_hd_t a, const unsigned char *key, size_t keylen)
 }
 
 
+
+static gcry_err_code_t
+_gcry_md_set_add_input (gcry_md_hd_t h,
+                        enum gcry_ctl_cmds addin_type,
+                        const void *v,
+                        size_t v_len)
+{
+  gcry_err_code_t rc = 0;
+  int did_set       = 0;
+  GcryDigestEntry *r;
+  if (!h->ctx->list)
+    return GPG_ERR_DIGEST_ALGO; /* Might happen if no algo is enabled.  */
+  for (r = h->ctx->list; r; r = r->next)
+    {
+      switch (r->spec->algo)
+        {
+        case GCRY_MD_CSHAKE128:
+        case GCRY_MD_CSHAKE256:
+          rc = _gcry_cshake_add_input (r->context, addin_type, v, v_len);
+          if (!rc)
+            {
+              did_set = 1;
+            }
+          else
+            {
+              return rc;
+            }
+          break;
+        }
+    }
+  if (!did_set)
+    {
+      rc = GPG_ERR_DIGEST_ALGO;
+    }
+  return rc;
+}
+
+
 gcry_err_code_t
 _gcry_md_ctl (gcry_md_hd_t hd, int cmd, void *buffer, size_t buflen)
 {
@@ -1014,6 +1058,10 @@ _gcry_md_ctl (gcry_md_hd_t hd, int cmd, void *buffer, size_t buflen)
     case GCRYCTL_STOP_DUMP:
       md_stop_debug ( hd );
       break;
+    case GCRYCTL_CSHAKE_N:
+    case GCRYCTL_CSHAKE_S:
+      rc = _gcry_md_set_add_input(hd, cmd, buffer, buflen);
+      break;
     default:
       rc = GPG_ERR_INV_OP;
     }
diff --git a/configure.ac b/configure.ac
index 4f7c3a52..6ffc209e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3514,7 +3514,7 @@ fi
 
 LIST_MEMBER(sha3, $enabled_digests)
 if test "$found" = "1" ; then
-   GCRYPT_DIGESTS="$GCRYPT_DIGESTS keccak.lo"
+   GCRYPT_DIGESTS="$GCRYPT_DIGESTS keccak.lo cshake-common.lo mac-kmac.lo"
    AC_DEFINE(USE_SHA3, 1, [Defined if this module should be included])
 
    case "${host}" in
diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index e31c9019..04332214 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -3606,7 +3606,7 @@ are also supported.
 @c begin table of hash algorithms
 @cindex SHA-1
 @cindex SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA-512/256
- at cindex SHA3-224, SHA3-256, SHA3-384, SHA3-512, SHAKE128, SHAKE256
+ at cindex SHA3-224, SHA3-256, SHA3-384, SHA3-512, SHAKE128, SHAKE256, cSHAKE128, cSHAKE256
 @cindex RIPE-MD-160
 @cindex MD2, MD4, MD5
 @cindex TIGER, TIGER1, TIGER2
@@ -3716,6 +3716,21 @@ This is the SHAKE256 extendable-output function (XOF) algorithm with 256 bit
 security strength.
 See FIPS 202 for the specification.
 
+ at item GCRY_MD_CSHAKE128
+This is the cSHAKE128 extendable-output function (XOF) algorithm with 128 bit
+security strength defined in NIST SP 800-185. cSHAKE takes optional additional
+inputs N and S, which can be set by using _gcry_md_ctl() with the control
+commands GCRYCTL_CSHAKE_N and GCRYCTL_CSHAKE_S. If both N and S are set, then N
+has to be set before S. If chosen to be non-empty, N and/or S have to be set
+before the first call to _gcry_md_write(). The lengths of N or S is limited to
+a bit length which can be represented by a size_t and does not exceed a byte
+size of 2^(32) - 1.
+
+ at item GCRY_MD_CSHAKE256
+This is the cSHAKE256 extendable-output function (XOF) algorithm with 256 bit
+security strength defined in NIST SP 800-185. Regarding the usage of the
+optional additional inputs N and S, see the above description of cSHAKE128.
+
 @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
@@ -4394,6 +4409,18 @@ key and one-time nonce.
 @item GCRY_MAC_GOST28147_IMIT
 This is MAC construction defined in GOST 28147-89 (see RFC 5830 Section 8).
 
+ at item GCRY_MAC_KMAC128_128
+This is the KMAC-128 message authentication code defined in NIST SP 800-185
+with an output length of 128 bits (i.e., L=128).  The length of the key and of
+the optional customisation string S, which is modelled as the IV, is limited to
+a bit length which can be represented by a size_t and does not exceed a byte
+length of 2^(32) - 1.
+
+ at item GCRY_MAC_KMAC256_256
+This is the KMAC-256 message authentication code defined in NIST SP 800-185
+with an output length of 256 bits (i.e., L=256). Regarding the limitations of
+the key and the customization string S, see GCRY_MAC_KMAC128_128.
+
 @end table
 @c end table of MAC algorithms
 
@@ -4444,7 +4471,7 @@ which can be performed with function:
 
 @deftypefun gcry_error_t gcry_mac_setiv (gcry_mac_hd_t @var{h}, const void *@var{iv}, size_t @var{ivlen})
 
-Set the IV to the value of @var{iv} of length @var{ivlen} bytes.
+Set the IV to the value of @var{iv} of length @var{ivlen} bytes. For KMAC, this function is used to se the value of S, the optional customisation string.
 @end deftypefun
 
 
diff --git a/src/cipher.h b/src/cipher.h
index 3c48c2c5..3f63295e 100644
--- a/src/cipher.h
+++ b/src/cipher.h
@@ -200,6 +200,8 @@ extern const gcry_md_spec_t _gcry_digest_spec_sha3_512;
 extern const gcry_md_spec_t _gcry_digest_spec_sha3_384;
 extern const gcry_md_spec_t _gcry_digest_spec_shake128;
 extern const gcry_md_spec_t _gcry_digest_spec_shake256;
+extern const gcry_md_spec_t _gcry_digest_spec_cshake128;
+extern const gcry_md_spec_t _gcry_digest_spec_cshake256;
 extern const gcry_md_spec_t _gcry_digest_spec_tiger;
 extern const gcry_md_spec_t _gcry_digest_spec_tiger1;
 extern const gcry_md_spec_t _gcry_digest_spec_tiger2;
diff --git a/src/fips.c b/src/fips.c
index 574776ac..cf91baa8 100644
--- a/src/fips.c
+++ b/src/fips.c
@@ -422,6 +422,8 @@ _gcry_fips_indicator_md (va_list arg_ptr)
     case GCRY_MD_SHA3_512:
     case GCRY_MD_SHAKE128:
     case GCRY_MD_SHAKE256:
+    case GCRY_MD_CSHAKE128:
+    case GCRY_MD_CSHAKE256:
       return GPG_ERR_NO_ERROR;
     default:
       return GPG_ERR_NOT_SUPPORTED;
diff --git a/src/gcrypt-int.h b/src/gcrypt-int.h
index ba52fa8e..1f3f1bfb 100644
--- a/src/gcrypt-int.h
+++ b/src/gcrypt-int.h
@@ -164,6 +164,7 @@ const char *_gcry_md_algo_name (int algo) _GCRY_GCC_ATTR_PURE;
 int _gcry_md_map_name (const char* name) _GCRY_GCC_ATTR_PURE;
 gpg_err_code_t _gcry_md_setkey (gcry_md_hd_t hd,
                                 const void *key, size_t keylen);
+
 void _gcry_md_debug (gcry_md_hd_t hd, const char *suffix);
 
 #define _gcry_md_test_algo(a) \
diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
index 7dc1196b..1a9aa9f5 100644
--- a/src/gcrypt.h.in
+++ b/src/gcrypt.h.in
@@ -333,7 +333,9 @@ enum gcry_ctl_cmds
     GCRYCTL_FIPS_SERVICE_INDICATOR_FUNCTION = 84,
     GCRYCTL_FIPS_SERVICE_INDICATOR_MAC = 85,
     GCRYCTL_FIPS_SERVICE_INDICATOR_MD = 86,
-    GCRYCTL_FIPS_SERVICE_INDICATOR_PK_FLAGS = 87
+    GCRYCTL_FIPS_SERVICE_INDICATOR_PK_FLAGS = 87,
+    GCRYCTL_CSHAKE_N = 88,
+    GCRYCTL_CSHAKE_S = 89
   };
 
 /* Perform various operations defined by CMD. */
@@ -1304,7 +1306,9 @@ enum gcry_md_algos
     GCRY_MD_BLAKE2S_128   = 325,
     GCRY_MD_SM3           = 326,
     GCRY_MD_SHA512_256    = 327,
-    GCRY_MD_SHA512_224    = 328
+    GCRY_MD_SHA512_224    = 328,
+    GCRY_MD_CSHAKE128     = 329,
+    GCRY_MD_CSHAKE256     = 330
   };
 
 /* Flags used with the open function.  */
@@ -1315,6 +1319,7 @@ enum gcry_md_flags
     GCRY_MD_FLAG_BUGEMU1 = 0x0100
   };
 
+
 /* (Forward declaration.)  */
 struct gcry_md_context;
 
@@ -1533,7 +1538,10 @@ enum gcry_mac_algos
     GCRY_MAC_POLY1305_SERPENT   = 505,
     GCRY_MAC_POLY1305_SEED      = 506,
     GCRY_MAC_POLY1305_SM4       = 507,
-    GCRY_MAC_POLY1305_ARIA      = 508
+    GCRY_MAC_POLY1305_ARIA      = 508,
+
+    GCRY_MAC_KMAC128_128        = 601,
+    GCRY_MAC_KMAC256_256        = 602
   };
 
 /* Flags used with the open function.  */
diff --git a/src/visibility.c b/src/visibility.c
index 9b29c4f1..d3447e3f 100644
--- a/src/visibility.c
+++ b/src/visibility.c
@@ -1371,6 +1371,7 @@ gcry_md_setkey (gcry_md_hd_t hd, const void *key, size_t keylen)
   return gpg_error (_gcry_md_setkey (hd, key, keylen));
 }
 
+
 void
 gcry_md_debug (gcry_md_hd_t hd, const char *suffix)
 {
diff --git a/src/visibility.h b/src/visibility.h
index 6aef3278..12286021 100644
--- a/src/visibility.h
+++ b/src/visibility.h
@@ -402,6 +402,7 @@ MARK_VISIBLEX (_gcry_mpi_get_const)
 #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
+#define gcry_md_set_add_input       _gcry_USE_THE_UNDERSCORED_FUNCTION
 #define gcry_md_debug               _gcry_USE_THE_UNDERSCORED_FUNCTION
 
 #define gcry_mac_algo_info          _gcry_USE_THE_UNDERSCORED_FUNCTION
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 9920bae8..690bdbd7 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -25,7 +25,7 @@ tests_bin = \
         version t-secmem mpitests t-sexp t-convert \
 	t-mpi-bit t-mpi-point t-lock \
 	prime basic keygen pubkey hmac hashtest t-kdf keygrip \
-	aeswrap random
+	aeswrap random cshake
 
 if USE_RSA
 tests_bin += pkcs1v2 t-rsa-pss t-rsa-15 t-rsa-testparm
diff --git a/tests/basic.c b/tests/basic.c
index a405c82c..bfbd67f3 100644
--- a/tests/basic.c
+++ b/tests/basic.c
@@ -14924,6 +14924,249 @@ check_digests (void)
 	"\x1b\xeb\x65\x53\xf2\x81\xfa\x75\x69\x48\xc4\x38\x49\x4b\x19\xb4"
 	"\xee\x69\xa5\x43\x6b\x22\x2b\xc9\x88\xed\xa4\xac\x60\x00\x24\xc9",
 	0, 512, },
+      { GCRY_MD_CSHAKE128,
+	"",
+	"\x7F\x9C\x2B\xA4\xE8\x8F\x82\x7D\x61\x60\x45\x50\x76\x05\x85\x3E"
+	"\xD7\x3B\x80\x93\xF6\xEF\xBC\x88\xEB\x1A\x6E\xAC\xFA\x66\xEF\x26"
+	"\x3C\xB1\xEE\xA9\x88\x00\x4B\x93\x10\x3C\xFB\x0A\xEE\xFD\x2A\x68"
+	"\x6E\x01\xFA\x4A\x58\xE8\xA3\x63\x9C\xA8\xA1\xE3\xF9\xAE\x57\xE2"
+	"\x35\xB8\xCC\x87\x3C\x23\xDC\x62\xB8\xD2\x60\x16\x9A\xFA\x2F\x75"
+	"\xAB\x91\x6A\x58\xD9\x74\x91\x88\x35\xD2\x5E\x6A\x43\x50\x85\xB2"
+	"\xBA\xDF\xD6\xDF\xAA\xC3\x59\xA5\xEF\xBB\x7B\xCC\x4B\x59\xD5\x38"
+	"\xDF\x9A\x04\x30\x2E\x10\xC8\xBC\x1C\xBF\x1A\x0B\x3A\x51\x20\xEA"
+	"\x17\xCD\xA7\xCF\xAD\x76\x5F\x56\x23\x47\x4D\x36\x8C\xCC\xA8\xAF"
+	"\x00\x07\xCD\x9F\x5E\x4C\x84\x9F\x16\x7A\x58\x0B\x14\xAA\xBD\xEF"
+	"\xAE\xE7\xEE\xF4\x7C\xB0\xFC\xA9\x76\x7B\xE1\xFD\xA6\x94\x19\xDF"
+	"\xB9\x27\xE9\xDF\x07\x34\x8B\x19\x66\x91\xAB\xAE\xB5\x80\xB3\x2D"
+	"\xEF\x58\x53\x8B\x8D\x23\xF8\x77\x32\xEA\x63\xB0\x2B\x4F\xA0\xF4"
+	"\x87\x33\x60\xE2\x84\x19\x28\xCD\x60\xDD\x4C\xEE\x8C\xC0\xD4\xC9"
+	"\x22\xA9\x61\x88\xD0\x32\x67\x5C\x8A\xC8\x50\x93\x3C\x7A\xFF\x15"
+	"\x33\xB9\x4C\x83\x4A\xDB\xB6\x9C\x61\x15\xBA\xD4\x69\x2D\x86\x19"
+	"\xF9\x0B\x0C\xDF\x8A\x7B\x9C\x26\x40\x29\xAC\x18\x5B\x70\xB8\x3F"
+	"\x28\x01\xF2\xF4\xB3\xF7\x0C\x59\x3E\xA3\xAE\xEB\x61\x3A\x7F\x1B"
+	"\x1D\xE3\x3F\xD7\x50\x81\xF5\x92\x30\x5F\x2E\x45\x26\xED\xC0\x96"
+	"\x31\xB1\x09\x58\xF4\x64\xD8\x89\xF3\x1B\xA0\x10\x25\x0F\xDA\x7F"
+	"\x13\x68\xEC\x29\x67\xFC\x84\xEF\x2A\xE9\xAF\xF2\x68\xE0\xB1\x70"
+	"\x0A\xFF\xC6\x82\x0B\x52\x3A\x3D\x91\x71\x35\xF2\xDF\xF2\xEE\x06"
+	"\xBF\xE7\x2B\x31\x24\x72\x1D\x4A\x26\xC0\x4E\x53\xA7\x5E\x30\xE7"
+	"\x3A\x7A\x9C\x4A\x95\xD9\x1C\x55\xD4\x95\xE9\xF5\x1D\xD0\xB5\xE9"
+	"\xD8\x3C\x6D\x5E\x8C\xE8\x03\xAA\x62\xB8\xD6\x54\xDB\x53\xD0\x9B"
+	"\x8D\xCF\xF2\x73\xCD\xFE\xB5\x73\xFA\xD8\xBC\xD4\x55\x78\xBE\xC2"
+	"\xE7\x70\xD0\x1E\xFD\xE8\x6E\x72\x1A\x3F\x7C\x6C\xCE\x27\x5D\xAB"
+	"\xE6\xE2\x14\x3F\x1A\xF1\x8D\xA7\xEF\xDD\xC4\xC7\xB7\x0B\x5E\x34"
+	"\x5D\xB9\x3C\xC9\x36\xBE\xA3\x23\x49\x1C\xCB\x38\xA3\x88\xF5\x46"
+	"\xA9\xFF\x00\xDD\x4E\x13\x00\xB9\xB2\x15\x3D\x20\x41\xD2\x05\xB4"
+	"\x43\xE4\x1B\x45\xA6\x53\xF2\xA5\xC4\x49\x2C\x1A\xDD\x54\x45\x12"
+	"\xDD\xA2\x52\x98\x33\x46\x2B\x71\xA4\x1A\x45\xBE\x97\x29\x0B\x6F",
+	0, 512, },
+      { GCRY_MD_CSHAKE128,
+	"",
+	"\x7F\x9C\x2B\xA4\xE8\x8F\x82\x7D\x61\x60\x45\x50\x76\x05\x85\x3E"
+	"\xD7\x3B\x80\x93\xF6\xEF\xBC\x88\xEB\x1A\x6E\xAC\xFA\x66\xEF\x26",
+	0, 0, /* test md_read interface */ },
+      { GCRY_MD_CSHAKE128,
+	"\x5A\xAB\x62\x75\x6D\x30\x7A\x66\x9D\x14\x6A\xBA\x98\x8D\x90\x74"
+	"\xC5\xA1\x59\xB3\xDE\x85\x15\x1A\x81\x9B\x11\x7C\xA1\xFF\x65\x97"
+	"\xF6\x15\x6E\x80\xFD\xD2\x8C\x9C\x31\x76\x83\x51\x64\xD3\x7D\xA7"
+	"\xDA\x11\xD9\x4E\x09\xAD\xD7\x70\xB6\x8A\x6E\x08\x1C\xD2\x2C\xA0"
+	"\xC0\x04\xBF\xE7\xCD\x28\x3B\xF4\x3A\x58\x8D\xA9\x1F\x50\x9B\x27"
+	"\xA6\x58\x4C\x47\x4A\x4A\x2F\x3E\xE0\xF1\xF5\x64\x47\x37\x92\x40"
+	"\xA5\xAB\x1F\xB7\x7F\xDC\xA4\x9B\x30\x5F\x07\xBA\x86\xB6\x27\x56"
+	"\xFB\x9E\xFB\x4F\xC2\x25\xC8\x68\x45\xF0\x26\xEA\x54\x20\x76\xB9"
+	"\x1A\x0B\xC2\xCD\xD1\x36\xE1\x22\xC6\x59\xBE\x25\x9D\x98\xE5\x84"
+	"\x1D\xF4\xC2\xF6\x03\x30\xD4\xD8\xCD\xEE\x7B\xF1\xA0\xA2\x44\x52"
+	"\x4E\xEC\xC6\x8F\xF2\xAE\xF5\xBF\x00\x69\xC9\xE8\x7A\x11\xC6\xE5"
+	"\x19\xDE\x1A\x40\x62\xA1\x0C\x83\x83\x73\x88\xF7\xEF\x58\x59\x8A"
+	"\x38\x46\xF4\x9D\x49\x96\x82\xB6\x83\xC4\xA0\x62\xB4\x21\x59\x4F"
+	"\xAF\xBC\x13\x83\xC9\x43\xBA\x83\xBD\xEF\x51\x5E\xFC\xF1\x0D",
+	"\xF0\x71\x5D\xE3\x56\x92\xFD\x70\x12\x3D\xC6\x83\x68\xD0\xFE\xEC"
+	"\x06\xA0\xC7\x4C\xF8\xAD\xB0\x5D\xDC\x25\x54\x87\xB1\xA8\xD4\xD1"
+	"\x21\x3E\x9E\xAB\xAF\x41\xF1\x16\x17\x19\xD0\x65\xD7\x94\xB7\x50"
+	"\xF8\x4B\xE3\x2A\x32\x34\xB4\xD5\x36\x46\x0D\x55\x20\x68\x8A\x5A"
+	"\x79\xA1\x7A\x4B\xA8\x98\x7F\xCB\x61\xBF\x7D\xAA\x8B\x54\x7B\xF5"
+	"\xC1\xCE\x36\xB5\x6A\x73\x25\x7D\xBB\xF1\xBA\xBB\x64\xF2\x49\xBD"
+	"\xCE\xB6\x7B\xA1\xC8\x88\x37\x0A\x96\x3D\xFD\x6B\x6A\x2A\xDE\x2C"
+	"\xEF\xD1\x4C\x32\x52\xCB\x37\x58\x52\x0F\x0C\x65\xF4\x52\x46\x82"
+	"\x77\x24\x99\x46\x3A\xE1\xA3\x41\x80\x01\x83\xAA\x60\xEF\xA0\x51"
+	"\x18\xA2\x82\x01\x74\x4F\x7B\xA0\xB0\xA3\x92\x8D\xD7\xC0\x26\x3F"
+	"\xD2\x64\xB7\xCD\x7B\x2E\x2E\x09\xB3\x22\xBF\xCE\xA8\xEE\xD0\x42"
+	"\x75\x79\x5B\xE7\xC0\xF0\x0E\x11\x38\x27\x37\x0D\x05\x1D\x50\x26"
+	"\x95\x80\x30\x00\x05\xAC\x12\x88\xFE\xA6\xCD\x9A\xE9\xF4\xF3\x7C"
+	"\xE0\xF8\xAC\xE8\xBF\x3E\xBE\x1D\x70\x56\x25\x59\x54\xC7\x61\x93"
+	"\x1D\x3C\x42\xED\x62\xF7\xF1\xCE\x1B\x94\x5C\xDE\xCC\x0A\x74\x32"
+	"\x2D\x7F\x64\xD6\x00\x4F\xF2\x16\x84\x14\x93\x07\x28\x8B\x44\x8E"
+	"\x45\x43\x34\x75\xB1\xEA\x13\x14\xB0\x0F\x1F\xC4\x50\x08\x9A\x9D"
+	"\x1F\x77\x10\xC6\xD7\x65\x2E\xCF\x65\x4F\x3B\x48\x7D\x02\x83\xD4"
+	"\xD8\xA2\x8E\xFB\x50\x66\xC4\x25\x0D\x5A\xD6\x98\xE1\x5D\xBA\x88"
+	"\xE9\x25\xE4\xDE\x99\xB6\x9B\xC3\x83\xAC\x80\x45\xB7\xF1\x02\x2A"
+	"\xDD\x39\xD4\x43\x54\x6A\xE0\x92\x4F\x13\xF4\x89\x60\x96\xDF\xDF"
+	"\x37\xCA\x72\x20\x79\x87\xC4\xA7\x70\x5A\x7A\xBE\x72\x4B\x7F\xA1"
+	"\x0C\x90\x9F\x39\x25\x44\x9F\x01\x0D\x61\xE2\x07\xAD\xD9\x52\x19"
+	"\x07\x1A\xCE\xED\xB9\xB9\xDC\xED\x32\xA9\xE1\x23\x56\x1D\x60\x82"
+	"\xD4\x6A\xEF\xAE\x07\xEE\x1B\xD1\x32\x76\x5E\x3E\x51\x3C\x66\x50"
+	"\x1B\x38\x7A\xB2\xEE\x09\xA0\x4A\xE6\x3E\x25\x80\x85\x17\xAF\xEA"
+	"\x3E\x05\x11\x69\xCF\xD2\xFF\xF8\xC5\x85\x8E\x2D\x96\x23\x89\x7C"
+	"\x9E\x85\x17\x5A\xC5\xA8\x63\x94\xCD\x0A\x32\xA0\xA6\x2A\x8F\x5D"
+	"\x6C\xCC\xBF\x49\x3D\xAA\x43\xF7\x83\x62\xBB\xCA\x40\xAD\xF7\x33"
+	"\xF8\x71\xE0\xC0\x09\x98\xD9\xBF\xD6\x88\x06\x56\x66\x6C\xD7\xBE"
+	"\x4F\xE9\x89\x2C\x61\xDC\xD5\xCD\x23\xA5\xE4\x27\x7E\xEE\x8B\x4A"
+	"\xFD\x29\xB6\x9B\xBA\x55\x66\x0A\x21\x71\x12\xFF\x6E\x34\x56\xB1",
+	223, 512, },
+      { GCRY_MD_CSHAKE128,
+	"!",
+	"\x9d\x22\x2c\x79\xc4\xff\x9d\x09\x2c\xf6\xca\x86\x14\x3a\xa4\x11"
+	"\xe3\x69\x97\x38\x08\xef\x97\x09\x32\x55\x82\x6c\x55\x72\xef\x58"
+	"\x42\x4c\x4b\x5c\x28\x47\x5f\xfd\xcf\x98\x16\x63\x86\x7f\xec\x63"
+	"\x21\xc1\x26\x2e\x38\x7b\xcc\xf8\xca\x67\x68\x84\xc4\xa9\xd0\xc1"
+	"\x3b\xfa\x68\x69\x76\x3d\x5a\xe4\xbb\xc9\xb3\xcc\xd0\x9d\x1c\xa5"
+	"\xea\x74\x46\x53\x8d\x69\xb3\xfb\x98\xc7\x2b\x59\xa2\xb4\x81\x7d"
+	"\xb5\xea\xdd\x90\x11\xf9\x0f\xa7\x10\x91\x93\x1f\x81\x34\xf4\xf0"
+	"\x0b\x56\x2e\x2f\xe1\x05\x93\x72\x70\x36\x1c\x19\x09\x86\x2a\xd4"
+	"\x50\x46\xe3\x93\x2f\x5d\xd3\x11\xec\x72\xfe\xc5\xf8\xfb\x8f\x60"
+	"\xb4\x5a\x3b\xee\x3f\x85\xbb\xf7\xfc\xed\xc6\xa5\x55\x67\x76\x48"
+	"\xe0\x65\x4b\x38\x19\x41\xa8\x6b\xd3\xe5\x12\x65\x7b\x0d\x57\xa7"
+	"\x99\x1f\xc4\x54\x3f\x89\xd8\x29\x04\x92\x22\x2c\xe4\xa3\x3e\x17"
+	"\x60\x2b\x3b\x99\xc0\x09\xf7\x65\x5f\x87\x53\x5c\xda\xa3\x71\x6f"
+	"\x58\xc4\x7b\x8a\x15\x7a\xd1\x95\xf0\x28\x09\xf2\x75\x00\xb9\x25"
+	"\x49\x79\x31\x1c\x6b\xb4\x15\x96\x8c\xd1\x04\x31\x16\x9a\x27\xd5"
+	"\xa8\xd6\x1e\x13\xa6\xb8\xb7\x7a\xf1\xf8\xb6\xdd\x2e\xef\xde\xa0"
+	"\x40\x78\x96\x80\x49\x0b\x5e\xdc\xb1\xd3\xe5\x38\xa4\x66\xf7\x57"
+	"\xad\x71\x8f\xe1\xfd\x9f\xae\xef\xa4\x72\x46\xad\x5e\x36\x7f\x87"
+	"\xd3\xb4\x85\x0d\x44\x86\xeb\x21\x99\xe9\x4a\x79\x79\xe2\x09\x1a"
+	"\xbc\xdf\x3b\xc1\x33\x79\xc8\x96\xdc\xeb\x79\xa8\xfd\x08\xf1\x10"
+	"\x73\xf3\x3e\x3f\x99\x23\x22\xb3\x12\x02\xde\xe2\x34\x33\x0c\xf3"
+	"\x30\x4a\x58\x8f\x0d\x59\xda\xe4\xe6\x3b\xa2\xac\x3c\xe6\x82\xcc"
+	"\x19\xd4\xe3\x41\x67\x8c\xc3\xa6\x7a\x47\xc1\x13\xb4\xdb\x89\x0f"
+	"\x30\xa9\x2a\xa0\x8a\x1f\x6d\xc8\xfb\x64\x63\xf8\x03\x8c\x2b\x40"
+	"\xb2\x53\x00\x77\xb2\x36\xce\x88\xaf\xcc\xcd\xa0\x8a\xd6\xd7\x5e"
+	"\xee\x18\x99\xb1\x0c\xd8\x00\xc2\xce\x53\x72\xbf\xf2\x2e\xe3\xa3"
+	"\x39\xd4\xb9\xc1\xa2\xf5\xf4\xb8\x20\xf6\x87\xe5\x51\x9b\xd0\x5b"
+	"\x1f\xc5\xda\x0e\xb4\x53\x36\x81\x4f\x48\x13\x2c\x64\x0e\x66\xc3"
+	"\xa0\x2a\x22\xe6\x35\x98\xf9\x4f\x22\xf3\x51\x84\x11\x04\x46\xb6"
+	"\x48\xcf\x84\x74\xf3\x0c\x43\xea\xd5\x83\x09\xfb\x25\x90\x16\x09"
+	"\xe2\x41\x87\xe8\x01\xc8\x09\x56\x1a\x64\x80\x94\x50\xe6\x03\xc4"
+	"\xa8\x03\x95\x25\xc4\x76\xb5\x8e\x32\xce\x2c\x47\xb3\x7d\xa5\x91",
+	0, 512, },
+      { GCRY_MD_CSHAKE256,
+	"",
+	"\x46\xB9\xDD\x2B\x0B\xA8\x8D\x13\x23\x3B\x3F\xEB\x74\x3E\xEB\x24"
+	"\x3F\xCD\x52\xEA\x62\xB8\x1B\x82\xB5\x0C\x27\x64\x6E\xD5\x76\x2F"
+	"\xD7\x5D\xC4\xDD\xD8\xC0\xF2\x00\xCB\x05\x01\x9D\x67\xB5\x92\xF6"
+	"\xFC\x82\x1C\x49\x47\x9A\xB4\x86\x40\x29\x2E\xAC\xB3\xB7\xC4\xBE"
+	"\x14\x1E\x96\x61\x6F\xB1\x39\x57\x69\x2C\xC7\xED\xD0\xB4\x5A\xE3"
+	"\xDC\x07\x22\x3C\x8E\x92\x93\x7B\xEF\x84\xBC\x0E\xAB\x86\x28\x53"
+	"\x34\x9E\xC7\x55\x46\xF5\x8F\xB7\xC2\x77\x5C\x38\x46\x2C\x50\x10"
+	"\xD8\x46\xC1\x85\xC1\x51\x11\xE5\x95\x52\x2A\x6B\xCD\x16\xCF\x86"
+	"\xF3\xD1\x22\x10\x9E\x3B\x1F\xDD\x94\x3B\x6A\xEC\x46\x8A\x2D\x62"
+	"\x1A\x7C\x06\xC6\xA9\x57\xC6\x2B\x54\xDA\xFC\x3B\xE8\x75\x67\xD6"
+	"\x77\x23\x13\x95\xF6\x14\x72\x93\xB6\x8C\xEA\xB7\xA9\xE0\xC5\x8D"
+	"\x86\x4E\x8E\xFD\xE4\xE1\xB9\xA4\x6C\xBE\x85\x47\x13\x67\x2F\x5C"
+	"\xAA\xAE\x31\x4E\xD9\x08\x3D\xAB\x4B\x09\x9F\x8E\x30\x0F\x01\xB8"
+	"\x65\x0F\x1F\x4B\x1D\x8F\xCF\x3F\x3C\xB5\x3F\xB8\xE9\xEB\x2E\xA2"
+	"\x03\xBD\xC9\x70\xF5\x0A\xE5\x54\x28\xA9\x1F\x7F\x53\xAC\x26\x6B"
+	"\x28\x41\x9C\x37\x78\xA1\x5F\xD2\x48\xD3\x39\xED\xE7\x85\xFB\x7F"
+	"\x5A\x1A\xAA\x96\xD3\x13\xEA\xCC\x89\x09\x36\xC1\x73\xCD\xCD\x0F"
+	"\xAB\x88\x2C\x45\x75\x5F\xEB\x3A\xED\x96\xD4\x77\xFF\x96\x39\x0B"
+	"\xF9\xA6\x6D\x13\x68\xB2\x08\xE2\x1F\x7C\x10\xD0\x4A\x3D\xBD\x4E"
+	"\x36\x06\x33\xE5\xDB\x4B\x60\x26\x01\xC1\x4C\xEA\x73\x7D\xB3\xDC"
+	"\xF7\x22\x63\x2C\xC7\x78\x51\xCB\xDD\xE2\xAA\xF0\xA3\x3A\x07\xB3"
+	"\x73\x44\x5D\xF4\x90\xCC\x8F\xC1\xE4\x16\x0F\xF1\x18\x37\x8F\x11"
+	"\xF0\x47\x7D\xE0\x55\xA8\x1A\x9E\xDA\x57\xA4\xA2\xCF\xB0\xC8\x39"
+	"\x29\xD3\x10\x91\x2F\x72\x9E\xC6\xCF\xA3\x6C\x6A\xC6\xA7\x58\x37"
+	"\x14\x30\x45\xD7\x91\xCC\x85\xEF\xF5\xB2\x19\x32\xF2\x38\x61\xBC"
+	"\xF2\x3A\x52\xB5\xDA\x67\xEA\xF7\xBA\xAE\x0F\x5F\xB1\x36\x9D\xB7"
+	"\x8F\x3A\xC4\x5F\x8C\x4A\xC5\x67\x1D\x85\x73\x5C\xDD\xDB\x09\xD2"
+	"\xB1\xE3\x4A\x1F\xC0\x66\xFF\x4A\x16\x2C\xB2\x63\xD6\x54\x12\x74"
+	"\xAE\x2F\xCC\x86\x5F\x61\x8A\xBE\x27\xC1\x24\xCD\x8B\x07\x4C\xCD"
+	"\x51\x63\x01\xB9\x18\x75\x82\x4D\x09\x95\x8F\x34\x1E\xF2\x74\xBD"
+	"\xAB\x0B\xAE\x31\x63\x39\x89\x43\x04\xE3\x58\x77\xB0\xC2\x8A\x9B"
+	"\x1F\xD1\x66\xC7\x96\xB9\xCC\x25\x8A\x06\x4A\x8F\x57\xE2\x7F\x2A",
+	0, 512, },
+      { GCRY_MD_CSHAKE256,
+	"",
+	"\x46\xB9\xDD\x2B\x0B\xA8\x8D\x13\x23\x3B\x3F\xEB\x74\x3E\xEB\x24"
+	"\x3F\xCD\x52\xEA\x62\xB8\x1B\x82\xB5\x0C\x27\x64\x6E\xD5\x76\x2F"
+	"\xD7\x5D\xC4\xDD\xD8\xC0\xF2\x00\xCB\x05\x01\x9D\x67\xB5\x92\xF6"
+	"\xFC\x82\x1C\x49\x47\x9A\xB4\x86\x40\x29\x2E\xAC\xB3\xB7\xC4\xBE",
+	0, 0, /* test md_read interface */ },
+      { GCRY_MD_CSHAKE256,
+	"\xB3\x2D\x95\xB0\xB9\xAA\xD2\xA8\x81\x6D\xE6\xD0\x6D\x1F\x86\x00"
+	"\x85\x05\xBD\x8C\x14\x12\x4F\x6E\x9A\x16\x3B\x5A\x2A\xDE\x55\xF8"
+	"\x35\xD0\xEC\x38\x80\xEF\x50\x70\x0D\x3B\x25\xE4\x2C\xC0\xAF\x05"
+	"\x0C\xCD\x1B\xE5\xE5\x55\xB2\x30\x87\xE0\x4D\x7B\xF9\x81\x36\x22"
+	"\x78\x0C\x73\x13\xA1\x95\x4F\x87\x40\xB6\xEE\x2D\x3F\x71\xF7\x68"
+	"\xDD\x41\x7F\x52\x04\x82\xBD\x3A\x08\xD4\xF2\x22\xB4\xEE\x9D\xBD"
+	"\x01\x54\x47\xB3\x35\x07\xDD\x50\xF3\xAB\x42\x47\xC5\xDE\x9A\x8A"
+	"\xBD\x62\xA8\xDE\xCE\xA0\x1E\x3B\x87\xC8\xB9\x27\xF5\xB0\x8B\xEB"
+	"\x37\x67\x4C\x6F\x8E\x38\x0C\x04",
+	"\xCC\x2E\xAA\x04\xEE\xF8\x47\x9C\xDA\xE8\x56\x6E\xB8\xFF\xA1\x10"
+	"\x0A\x40\x79\x95\xBF\x99\x9A\xE9\x7E\xDE\x52\x66\x81\xDC\x34\x90"
+	"\x61\x6F\x28\x44\x2D\x20\xDA\x92\x12\x4C\xE0\x81\x58\x8B\x81\x49"
+	"\x1A\xED\xF6\x5C\xAA\xF0\xD2\x7E\x82\xA4\xB0\xE1\xD1\xCA\xB2\x38"
+	"\x33\x32\x8F\x1B\x8D\xA4\x30\xC8\xA0\x87\x66\xA8\x63\x70\xFA\x84"
+	"\x8A\x79\xB5\x99\x8D\xB3\xCF\xFD\x05\x7B\x96\xE1\xE2\xEE\x0E\xF2"
+	"\x29\xEC\xA1\x33\xC1\x55\x48\xF9\x83\x99\x02\x04\x37\x30\xE4\x4B"
+	"\xC5\x2C\x39\xFA\xDC\x1D\xDE\xEA\xD9\x5F\x99\x39\xF2\x20\xCA\x30"
+	"\x06\x61\x54\x0D\xF7\xED\xD9\xAF\x37\x8A\x5D\x4A\x19\xB2\xB9\x3E"
+	"\x6C\x78\xF4\x9C\x35\x33\x43\xA0\xB5\xF1\x19\x13\x2B\x53\x12\xD0"
+	"\x04\x83\x1D\x01\x76\x9A\x31\x6D\x2F\x51\xBF\x64\xCC\xB2\x0A\x21"
+	"\xC2\xCF\x7A\xC8\xFB\x6F\x6E\x90\x70\x61\x26\xBD\xAE\x06\x11\xDD"
+	"\x13\x96\x2E\x8B\x53\xD6\xEA\xE2\x6C\x7B\x0D\x25\x51\xDA\xF6\x24"
+	"\x8E\x9D\x65\x81\x73\x82\xB0\x4D\x23\x39\x2D\x10\x8E\x4D\x34\x43"
+	"\xDE\x5A\xDC\x72\x73\xC7\x21\xA8\xF8\x32\x0E\xCF\xE8\x17\x7A\xC0"
+	"\x67\xCA\x8A\x50\x16\x9A\x6E\x73\x00\x0E\xBC\xDC\x1E\x4E\xE6\x33"
+	"\x9F\xC8\x67\xC3\xD7\xAE\xAB\x84\x14\x63\x98\xD7\xBA\xDE\x12\x1D"
+	"\x19\x89\xFA\x45\x73\x35\x56\x4E\x97\x57\x70\xA3\xA0\x02\x59\xCA"
+	"\x08\x70\x61\x08\x26\x1A\xA2\xD3\x4D\xE0\x0F\x8C\xAC\x7D\x45\xD3"
+	"\x5E\x5A\xA6\x3E\xA6\x9E\x1D\x1A\x2F\x7D\xAB\x39\x00\xD5\x1E\x0B"
+	"\xC6\x53\x48\xA2\x55\x54\x00\x70\x39\xA5\x2C\x3C\x30\x99\x80\xD1"
+	"\x7C\xAD\x20\xF1\x15\x63\x10\xA3\x9C\xD3\x93\x76\x0C\xFE\x58\xF6"
+	"\xF8\xAD\xE4\x21\x31\x28\x82\x80\xA3\x5E\x1D\xB8\x70\x81\x83\xB9"
+	"\x1C\xFA\xF5\x82\x7E\x96\xB0\xF7\x74\xC4\x50\x93\xB4\x17\xAF\xF9"
+	"\xDD\x64\x17\xE5\x99\x64\xA0\x1B\xD2\xA6\x12\xFF\xCF\xBA\x18\xA0"
+	"\xF1\x93\xDB\x29\x7B\x9A\x6C\xC1\xD2\x70\xD9\x7A\xAE\x8F\x8A\x3A"
+	"\x6B\x26\x69\x5A\xB6\x64\x31\xC2\x02\xE1\x39\xD6\x3D\xD3\xA2\x47"
+	"\x78\x67\x6C\xEF\xE3\xE2\x1B\x02\xEC\x4E\x8F\x5C\xFD\x66\x58\x7A"
+	"\x12\xB4\x40\x78\xFC\xD3\x9E\xEE\x44\xBB\xEF\x4A\x94\x9A\x63\xC0"
+	"\xDF\xD5\x8C\xF2\xFB\x2C\xD5\xF0\x02\xE2\xB0\x21\x92\x66\xCF\xC0"
+	"\x31\x81\x74\x86\xDE\x70\xB4\x28\x5A\x8A\x70\xF3\xD3\x8A\x61\xD3"
+	"\x15\x5D\x99\xAA\xF4\xC2\x53\x90\xD7\x36\x45\xAB\x3E\x8D\x80\xF0",
+	136, 512, },
+      { GCRY_MD_CSHAKE256,
+	"!",
+	"\x35\x78\xa7\xa4\xca\x91\x37\x56\x9c\xdf\x76\xed\x61\x7d\x31\xbb"
+	"\x99\x4f\xca\x9c\x1b\xbf\x8b\x18\x40\x13\xde\x82\x34\xdf\xd1\x3a"
+	"\x3f\xd1\x24\xd4\xdf\x76\xc0\xa5\x39\xee\x7d\xd2\xf6\xe1\xec\x34"
+	"\x61\x24\xc8\x15\xd9\x41\x0e\x14\x5e\xb5\x61\xbc\xd9\x7b\x18\xab"
+	"\x6c\xe8\xd5\x55\x3e\x0e\xab\x3d\x1f\x7d\xfb\x8f\x9d\xee\xfe\x16"
+	"\x84\x7e\x21\x92\xf6\xf6\x1f\xb8\x2f\xb9\x0d\xde\x60\xb1\x90\x63"
+	"\xc5\x6a\x4c\x55\xcd\xd7\xb6\x72\xb7\x5b\xf5\x15\xad\xbf\xe2\x04"
+	"\x90\x3c\x8c\x00\x36\xde\x54\xa2\x99\x9a\x92\x0d\xe9\x0f\x66\xd7"
+	"\xff\x6e\xc8\xe4\xc9\x3d\x24\xae\x34\x6f\xdc\xb3\xa5\xa5\xbd\x57"
+	"\x39\xec\x15\xa6\xed\xdb\x5c\xe5\xb0\x2d\xa5\x30\x39\xfa\xc6\x3e"
+	"\x19\x55\x5f\xaa\x2e\xdd\xc6\x93\xb1\xf0\xc2\xa6\xfc\xbe\x7c\x0a"
+	"\x0a\x09\x1d\x0e\xe7\x00\xd7\x32\x2e\x4b\x0f\xf0\x95\x90\xde\x16"
+	"\x64\x22\xf9\xea\xd5\xda\x4c\x99\x3d\x60\x5f\xe4\xd9\xc6\x34\x84"
+	"\x3a\xa1\x78\xb1\x76\x72\xc6\x56\x8c\x8a\x2e\x62\xab\xeb\xea\x2c"
+	"\x21\xc3\x02\xbd\x36\x6a\xd6\x98\x95\x9e\x1f\x6e\x43\x4a\xf1\x55"
+	"\x56\x8b\x27\x34\xd8\x37\x9f\xcd\x3f\xfe\x64\x89\xba\xff\xa6\xd7"
+	"\x11\x09\x44\x2e\x1b\x34\x4f\x13\x8a\x09\xca\xe3\xe2\xd3\x94\x2e"
+	"\xee\x82\x8f\xc4\x7e\x64\xde\xb5\xe0\x0a\x02\x4a\xe1\xf2\xc0\x77"
+	"\xe6\xb7\xb1\x33\xf6\xc1\xde\x91\x30\x92\xd4\xe8\x29\xec\xd2\xb2"
+	"\xef\x28\xca\x80\x20\x82\x1e\x2b\x8b\xe5\x17\xd9\x3e\xd0\x88\x36"
+	"\xf6\xf0\x66\xcc\x3d\x03\xb6\x25\xd8\x49\x7f\x29\xdb\xc1\xc3\x9e"
+	"\x6f\xe4\x63\x22\x6f\x85\xc1\x28\xa2\xc2\x98\x88\x11\x2e\x06\xa9"
+	"\x9c\x5d\x17\xb2\x5e\x90\x0d\x20\x4f\x39\x72\x31\xcd\xf7\x9c\x31"
+	"\x34\x46\x53\x2d\xad\x07\xf4\xc0\xbd\x9f\xba\x1d\xd4\x13\xd8\xa7"
+	"\xe6\xcb\xc0\xa0\x86\x2c\xc7\x69\x23\x9a\x89\xf9\xdb\x08\x5b\x78"
+	"\xa0\x54\x59\x6a\xd7\x08\x0d\xdf\x96\x01\x9b\x73\x99\xb5\x03\x48"
+	"\x0e\x5a\x65\xa2\x20\x8d\x74\x72\x4c\x98\x7d\x32\x5e\x9b\x0e\x82"
+	"\xfe\xcd\x4f\x27\xf3\x13\x5b\x1d\x9e\x27\xb4\x8e\x69\xdd\x6f\x59"
+	"\x62\xb8\xa6\x3b\x48\x92\x1e\xc8\xee\x53\x86\x9f\x1a\xc1\xc8\x18"
+	"\x23\x87\xee\x0d\x6c\xfe\xf6\x53\xff\x8b\xf6\x05\xf1\x47\x04\xb7"
+	"\x1b\xeb\x65\x53\xf2\x81\xfa\x75\x69\x48\xc4\x38\x49\x4b\x19\xb4"
+	"\xee\x69\xa5\x43\x6b\x22\x2b\xc9\x88\xed\xa4\xac\x60\x00\x24\xc9",
+	0, 512, },
       { GCRY_MD_BLAKE2B_512, "abc",
 	"\xBA\x80\xA5\x3F\x98\x1C\x4D\x0D\x6A\x27\x97\xB6\x9F\x12\xF6\xE9"
 	"\x4C\x21\x2F\x14\x68\x5A\xC4\xB7\x4B\x12\xBB\x6F\xDB\xFF\xA2\xD1"
@@ -15556,6 +15799,8 @@ check_one_hmac (int algo, const char *data, int datalen,
   gcry_md_close (hd2);
 }
 
+
+
 static void
 check_hmac (void)
 {
@@ -15924,6 +16169,19 @@ check_one_mac (int algo, const char *data, int datalen,
       return;
     }
 
+
+  /* test different order of setting IV and key for one KMAC variant */
+  if (algo == GCRY_MAC_KMAC128_128 && ivlen && iv)
+    {
+      clutter_vector_registers();
+      err = gcry_mac_setiv (hd, iv, ivlen);
+      if (err)
+        fail("algo %d, mac gcry_mac_setiv failed: %s\n", algo,
+             gpg_strerror (err));
+      if (err)
+        goto out;
+    }
+
   clutter_vector_registers();
   err = gcry_mac_setkey (hd, key, keylen);
   if (err)
@@ -15940,12 +16198,12 @@ check_one_mac (int algo, const char *data, int datalen,
       goto out;
     }
 
-  if (ivlen && iv)
+  if (algo != GCRY_MAC_KMAC128_128 && ivlen && iv)
     {
       clutter_vector_registers();
       err = gcry_mac_setiv (hd, iv, ivlen);
       if (err)
-        fail("algo %d, mac gcry_mac_ivkey failed: %s\n", algo,
+        fail("algo %d, mac gcry_mac_setiv failed: %s\n", algo,
              gpg_strerror (err));
       if (err)
         goto out;
@@ -16964,6 +17222,55 @@ check_mac (void)
         NULL,
         16, 32 },
 #endif /* USE_GOST28147 */
+#if USE_SHA3
+      { GCRY_MAC_KMAC128_128,
+        "\x00\x01\x02\x03",
+        "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f",
+        "\xE5\x78\x0B\x0D\x3E\xA6\xF7\xD3\xA4\x29\xC5\x70\x6A\xA4\x3A\x00\xFA\xDB\xD7\xD4\x96\x28\x83\x9E\x31\x87\x24\x3F\x45\x6E\xE1\x4E",
+        "",
+        4, 0
+      },
+      { GCRY_MAC_KMAC128_128,
+        "\x00\x01\x02\x03",
+        "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f",
+        "\x3B\x1F\xBA\x96\x3C\xD8\xB0\xB5\x9E\x8C\x1A\x6D\x71\x88\x8B\x71\x43\x65\x1A\xF8\xBA\x0A\x70\x70\xC0\x97\x9E\x28\x11\x32\x4A\xA5",
+        "My Tagged Application",
+        4, 0
+      },
+      { GCRY_MAC_KMAC128_128,
+        "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2A\x2B\x2C\x2D\x2E\x2F\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4A\x4B\x4C\x4D\x4E\x4F\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5A\x5B\x5C\x5D\x5E\x5F\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6A\x6B\x6C\x6D\x6E\x6F\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7A\x7B\x7C\x7D\x7E\x7F\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7",
+        "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f",
+        "\x1F\x5B\x4E\x6C\xCA\x02\x20\x9E\x0D\xCB\x5C\xA6\x35\xB8\x9A\x15\xE2\x71\xEC\xC7\x60\x07\x1D\xFD\x80\x5F\xAA\x38\xF9\x72\x92\x30",
+        "My Tagged Application",
+        200, 0
+      },
+      { GCRY_MAC_KMAC256_256,
+        "\x00\x01\x02\x03",
+        "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f",
+        "\x20\xC5\x70\xC3\x13\x46\xF7\x03\xC9\xAC\x36\xC6\x1C\x03\xCB\x64\xC3\x97\x0D\x0C\xFC\x78\x7E\x9B\x79\x59\x9D\x27\x3A\x68\xD2\xF7\xF6\x9D\x4C\xC3\xDE\x9D\x10\x4A\x35\x16\x89\xF2\x7C\xF6\xF5\x95\x1F\x01\x03\xF3\x3F\x4F\x24\x87\x10\x24\xD9\xC2\x77\x73\xA8\xDD",
+        "My Tagged Application",
+         4, 0
+      },
+      {
+        /* sample 5 from https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/KMAC_samples.pdf#page=21 */
+        GCRY_MAC_KMAC256_256,
+        "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2A\x2B\x2C\x2D\x2E\x2F\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4A\x4B\x4C\x4D\x4E\x4F\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5A\x5B\x5C\x5D\x5E\x5F\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6A\x6B\x6C\x6D\x6E\x6F\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7A\x7B\x7C\x7D\x7E\x7F\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7",
+        "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f",
+        "\x75\x35\x8C\xF3\x9E\x41\x49\x4E\x94\x97\x07\x92\x7C\xEE\x0A\xF2\x0A\x3F\xF5\x53\x90\x4C\x86\xB0\x8F\x21\xCC\x41\x4B\xCF\xD6\x91\x58\x9D\x27\xCF\x5E\x15\x36\x9C\xBB\xFF\x8B\x9A\x4C\x2E\xB1\x78\x00\x85\x5D\x02\x35\xFF\x63\x5D\xA8\x25\x33\xEC\x6B\x75\x9B\x69",
+        "",
+        200, 0
+      },
+      {
+        /* sample 6 from https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/KMAC_samples.pdf#page=27 */
+        GCRY_MAC_KMAC256_256,
+        "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2A\x2B\x2C\x2D\x2E\x2F\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4A\x4B\x4C\x4D\x4E\x4F\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5A\x5B\x5C\x5D\x5E\x5F\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6A\x6B\x6C\x6D\x6E\x6F\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7A\x7B\x7C\x7D\x7E\x7F\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7",
+        "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f",
+        "\xB5\x86\x18\xF7\x1F\x92\xE1\xD5\x6C\x1B\x8C\x55\xDD\xD7\xCD\x18\x8B\x97\xB4\xCA\x4D\x99\x83\x1E\xB2\x69\x9A\x83\x7D\xA2\xE4\xD9\x70\xFB\xAC\xFD\xE5\x00\x33\xAE\xA5\x85\xF1\xA2\x70\x85\x10\xC3\x2D\x07\x88\x08\x01\xBD\x18\x28\x98\xFE\x47\x68\x76\xFC\x89\x65",
+        "My Tagged Application",
+        200, 0
+      },
+
+#endif
       { 0 },
     };
   gcry_error_t err;
@@ -17000,7 +17307,7 @@ check_mac (void)
 		 gcry_mac_algo_name (algos[i].algo),
 		 algos[i].algo, (int)strlen(algos[i].key),
                  (!strcmp(algos[i].data, "!") || !strcmp(algos[i].data, "?"))
-                   ? 1000000 : (int)strlen(algos[i].data));
+                   ? 1000000 : ( algos[i].dlen ?  algos[i].dlen : (int)strlen(algos[i].data)));
 
       klen = algos[i].klen ? algos[i].klen : strlen(algos[i].key);
       dlen = algos[i].dlen ? algos[i].dlen : strlen (algos[i].data);
diff --git a/tests/cshake.c b/tests/cshake.c
new file mode 100644
index 00000000..9bac4fba
--- /dev/null
+++ b/tests/cshake.c
@@ -0,0 +1,335 @@
+/* cshake.c  -  cSHAKE xof hash regression tests
+ * Copyright (C) 2001, 2002, 2003, 2005, 2008,
+ *               2009 Free Software Foundation, Inc.
+ * Copyright (C) 2013 g10 Code GmbH
+ * Copyright (C) 2023 MTG AG
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <assert.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h> /* uintptr_t */
+#elif defined(HAVE_INTTYPES_H)
+#include <inttypes.h>
+#else
+/* In this case, uintptr_t is provided by config.h. */
+#endif
+
+// #include "../src/gcrypt-int.h"
+// #include "../src/gcrypt-testapi.h"
+
+#define PGM "cSHAKE"
+#include "t-common.h"
+#include "gcrypt.h"
+
+#if __GNUC__ >= 4
+#define ALWAYS_INLINE __attribute__ ((always_inline))
+#else
+#define ALWAYS_INLINE
+#endif
+
+typedef struct
+{
+
+  enum gcry_md_algos algo;
+  const char *data_hex;
+  const char *n;
+  const char *s;
+  unsigned output_size_bytes;
+  const char *expected_output_hex;
+
+} test_vec_t;
+
+test_vec_t test_vecs[] = {
+
+  { /* from
+       https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/cSHAKE_samples.pdf
+     */
+    GCRY_MD_CSHAKE128,
+    "00010203",
+    "",
+    "Email Signature",
+    32,
+    "C1C36925B6409A04F1B504FCBCA9D82B4017277CB5ED2B2065FC1D3814D5AAF5" },
+  { /* from
+       https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/cSHAKE_samples.pdf
+     */
+    GCRY_MD_CSHAKE128,
+    "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222"
+    "32"
+    "425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F4041424344454647"
+    "48"
+    "494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6"
+    "C6"
+    "D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F90"
+    "91"
+    "92939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B"
+    "5B"
+    "6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7",
+    "",
+    "Email Signature",
+    32,
+    "C5221D50E4F822D96A2E8881A961420F294B7B24FE3D2094BAED2C6524CC166B" },
+
+  { /* from
+       https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/cSHAKE_samples.pdf
+     */
+    GCRY_MD_CSHAKE256,
+    "00010203",
+    "",
+    "Email Signature",
+    64,
+    "D008828E2B80AC9D2218FFEE1D070C48B8E4C87BFF32C9699D5B6896EEE0EDD164020E2"
+    "BE"
+    "0560858D9C00C037E34A96937C561A74C412BB4C746469527281C8C" },
+
+  { /* from
+       https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/cSHAKE_samples.pdf
+     */
+    GCRY_MD_CSHAKE256,
+    "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222"
+    "32"
+    "425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F4041424344454647"
+    "48"
+    "494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6"
+    "C6"
+    "D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F90"
+    "91"
+    "92939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B"
+    "5B"
+    "6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7",
+    "",
+    "Email Signature",
+    64,
+    "07DC27B11E51FBAC75BC7B3C1D983E8B4B85FB1DEFAF218912AC86430273091727F42B1"
+    "7ED1DF63E8EC118F04B23633C1DFB1574C8FB55CB45DA8E25AFB092BB" },
+  { /* Created with https://asecuritysite.com/golang/cs */
+    GCRY_MD_CSHAKE128,
+    "00010203",
+    "ABC",
+    "Email Signature",
+    32,
+    "5CF74DC523ADC0B97EC3614E703835277E9F818879AA1EAE5B2B4E4472EB6A68" },
+  { /* Created with https://asecuritysite.com/golang/cs */
+    GCRY_MD_CSHAKE256,
+    "00010203",
+    "ABC",
+    "Email Signature",
+    32,
+    "0C34C14C4A56E5FC01BE8C04C759DA61437E86B88DF3E21A934436D427A85E9D" },
+  { /* Created with https://asecuritysite.com/golang/cs */
+    GCRY_MD_CSHAKE128,
+    "00010203",
+    "ABC",
+    "",
+    32,
+    "266035DF0BEC07A61073571CB3DEB195002955D8A7C88B821A0B1D20ECAC6B5B" },
+  { /* Created with https://asecuritysite.com/golang/cs */
+    GCRY_MD_CSHAKE256,
+    "00010203",
+    "ABC",
+    "",
+    32,
+    "89D888D030A5CF82CAFB3D9D2B7869C91B46D186700306265606CC97D3DAE42A" }
+};
+
+
+static void *
+hex2buffer (const char *string, size_t *r_length)
+{
+  const char *s;
+  unsigned char *buffer;
+  size_t length;
+
+  buffer = xmalloc (strlen (string) / 2 + 1);
+  length = 0;
+  for (s = string; *s; s += 2)
+    {
+      if (!hexdigitp (s) || !hexdigitp (s + 1))
+        die ("invalid hex digits in \"%s\"\n", string);
+      ((unsigned char *)buffer)[length++] = xtoi_2 (s);
+    }
+  *r_length = length;
+  return buffer;
+}
+
+
+int
+main (int argc, char **argv)
+{
+  gpg_error_t err = GPG_ERR_NO_ERROR;
+  int last_argc   = -1;
+
+  unsigned test_cnt = 0;
+
+  if (argc)
+    {
+      argc--;
+      argv++;
+    }
+
+  while (argc && last_argc != argc)
+    {
+      last_argc = argc;
+      if (!strcmp (*argv, "--"))
+        {
+          argc--;
+          argv++;
+          break;
+        }
+      else if (!strcmp (*argv, "--verbose"))
+        {
+          verbose++;
+          argc--;
+          argv++;
+        }
+      else if (!strcmp (*argv, "--debug"))
+        {
+          verbose = debug = 1;
+          argc--;
+          argv++;
+        }
+    }
+  for (unsigned i = 0; i < DIM (test_vecs); i++)
+    {
+      gcry_md_hd_t hd, hd2;
+      enum gcry_md_algos algo = test_vecs[i].algo;
+      test_vec_t *test        = &test_vecs[i];
+      unsigned char result_buf[256];
+      unsigned char result_buf2[256];
+      void *compare_buf, *data_buf;
+      size_t compare_len, data_len;
+      /* vary the secure flag in each test */
+      int flags = i % 2 ? GCRY_MD_FLAG_SECURE : 0;
+      err       = gcry_md_open (&hd, algo, flags);
+      if (err)
+        {
+          fail (
+              "algo %d, gcry_md_open failed: %s\n", algo, gpg_strerror (err));
+          goto leave;
+        }
+      if (strlen (test->n))
+        {
+          err = gcry_md_ctl(
+              hd, GCRYCTL_CSHAKE_N, (unsigned char*) test->n, strlen (test->n));
+          if (err)
+            {
+              fail ("algo %d, gcry_md_set_add_input (N) failed: %s\n",
+                    algo,
+                    gpg_strerror (err));
+              goto leave;
+            }
+        }
+      if (strlen (test->s))
+        {
+          err = gcry_md_ctl(
+              hd, GCRYCTL_CSHAKE_S, (unsigned char*) test->s, strlen (test->s));
+          if (err)
+            {
+              fail ("algo %d, gcry_md_set_add_input (S) failed: %s\n",
+                    algo,
+                    gpg_strerror (err));
+              goto leave;
+            }
+        }
+      {
+        gcry_err_code_t exp_err = GPG_ERR_INV_STATE;
+        if (strlen (test->n))
+          {
+            /* try to set n or s again */
+            exp_err = gcry_md_ctl(
+                hd, GCRYCTL_CSHAKE_N, (unsigned char*) test->n, strlen (test->n));
+          }
+        else if (strlen (test->s))
+          {
+            exp_err = gcry_md_ctl(
+                hd, GCRYCTL_CSHAKE_S, (unsigned char*) test->s, strlen (test->s));
+          }
+
+        if (exp_err != gpg_error(GPG_ERR_INV_STATE))
+          {
+            fail ("algo %d: wrong error code when setting additional "
+                  "input in wrong order: "
+                  "%d (%s), but "
+                  "expected %d (%s)\n",
+                  algo,
+                  exp_err,
+                  gpg_strerror (exp_err),
+                  gpg_error(GPG_ERR_INV_STATE),
+                  gpg_strerror (GPG_ERR_INV_STATE));
+          }
+      }
+      data_buf = hex2buffer (test->data_hex, &data_len);
+      gcry_md_write (hd, data_buf, data_len);
+      err = gcry_md_copy (&hd2, hd);
+      if (err)
+        {
+          fail ("algo %d, problem with copying of hash context object\n",
+                algo);
+        }
+      else
+        {
+          gcry_md_extract (hd2, algo, result_buf2, test->output_size_bytes);
+        }
+      gcry_md_extract (hd, algo, result_buf, test->output_size_bytes);
+      if (!err)
+        {
+          if (memcmp (result_buf, result_buf2, test->output_size_bytes))
+            {
+              fail ("algo %d, result comparison with that copied of copied MD "
+                    "CTX object failed in test %u\n",
+                    algo,
+                    i);
+            }
+        }
+      /* restore the clean error state after the copy operation */
+      err         = GPG_ERR_NO_ERROR;
+      compare_buf = hex2buffer (test->expected_output_hex, &compare_len);
+      test_cnt++;
+      if (compare_len != test->output_size_bytes)
+        {
+          fail ("algo %d, internal problem with test data lengths\n", algo);
+          goto leave;
+        }
+      if (memcmp (compare_buf, result_buf, test->output_size_bytes))
+        {
+
+          fail ("algo %d, result comparison failed in test %u\n", algo, i);
+        }
+      xfree (compare_buf);
+      xfree (data_buf);
+      gcry_md_close (hd);
+      gcry_md_close (hd2);
+    }
+
+
+  if (verbose)
+    fprintf (stderr, "\nAll %u tests completed. \n", test_cnt);
+  if (error_count || verbose)
+    {
+      fprintf (stderr, "\nThere were %i errors\n", error_count);
+    }
+leave:
+  return err;
+}
-- 
2.30.2




More information about the Gcrypt-devel mailing list