Commit 9c73843141 for openssl.org

commit 9c738431411e9f87d144793802b74e5ffd019403
Author: slontis <shane.lontis@oracle.com>
Date:   Wed Sep 3 17:48:30 2025 +1000

    Add support for CSHAKE.

    Unlike SHAKE this has default values set for the xof length.

    CSHAKE uses either SHAKE or KECCAK[c] depending on whether
    custom strings are set or not. If either string is set, it encodes
    the strings and uses KECCAK[c], otherwise it behaves the same as
    SHAKE (without the default xof length problem).

    Reviewed-by: Paul Dale <paul.dale@oracle.com>
    Reviewed-by: Norbert Pocs <norbertp@openssl.org>
    MergeDate: Fri Jan 23 14:07:53 2026
    (Merged from https://github.com/openssl/openssl/pull/28432)

diff --git a/.gitignore b/.gitignore
index ba7f69828b..8cf5c16e43 100644
--- a/.gitignore
+++ b/.gitignore
@@ -163,6 +163,7 @@ providers/implementations/digests/mdc2_prov.inc
 providers/implementations/digests/sha2_prov.inc
 providers/implementations/digests/sha3_prov.inc
 providers/implementations/digests/ml_dsa_mu_prov.inc
+providers/implementations/digests/cshake_prov.inc
 providers/implementations/include/prov/blake2_params.inc
 providers/implementations/kdfs/snmpkdf.inc
 providers/implementations/kdfs/srtpkdf.inc
diff --git a/CHANGES.md b/CHANGES.md
index 9901b34609..fbf06a1029 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -32,6 +32,10 @@ OpenSSL 4.0

 ### Changes between 3.6 and 4.0 [xx XXX xxxx]

+ * Added CSHAKE as per [SP 800-185]
+
+   *Shane Lontis*
+
  * Added configure options to disable KDF algorithms for
    hmac-drbg-kdf, kbkdf, krb5kdf, pvkkdf, snmpkdf, sskdf, sshkdf, x942kdf and x963kdf.

@@ -21936,3 +21940,4 @@ ndif
 [ESV]: https://csrc.nist.gov/Projects/cryptographic-module-validation-program/entropy-validations
 [SP 800-132]: https://csrc.nist.gov/pubs/sp/800/132/final
 [SP 800-208]: https://csrc.nist.gov/pubs/sp/800/208/final
+[SP 800-185]: https://csrc.nist.gov/pubs/sp/800/185/final
diff --git a/build.info b/build.info
index d6c4c2ba3e..5e20a7ed7c 100644
--- a/build.info
+++ b/build.info
@@ -120,6 +120,7 @@ DEPEND[]=include/openssl/asn1.h \
          providers/implementations/digests/sha2_prov.inc \
          providers/implementations/digests/sha3_prov.inc \
          providers/implementations/digests/ml_dsa_mu_prov.inc \
+         providers/implementations/digests/cshake_prov.inc \
          providers/implementations/include/prov/blake2_params.inc \
          providers/implementations/macs/cmac_prov.inc \
          providers/implementations/macs/gmac_prov.inc \
@@ -242,6 +243,7 @@ DEPEND[providers/implementations/asymciphers/rsa_enc.inc \
        providers/implementations/digests/mdc2_prov.inc \
        providers/implementations/digests/sha2_prov.inc \
        providers/implementations/digests/sha3_prov.inc \
+       providers/implementations/digests/cshake_prov.inc \
        providers/implementations/include/prov/blake2_params.inc \
        providers/implementations/macs/cmac_prov.inc \
        providers/implementations/macs/gmac_prov.inc \
@@ -257,6 +259,7 @@ DEPEND[providers/implementations/asymciphers/rsa_enc.inc \
        providers/implementations/rands/seed_src_jitter.inc \
        providers/implementations/rands/test_rng.inc \
        include/openssl/core_names.h]=util/perl|OpenSSL/paramnames.pm
+
 GENERATE[providers/implementations/asymciphers/rsa_enc.inc]=\
     providers/implementations/asymciphers/rsa_enc.inc.in
 GENERATE[providers/implementations/asymciphers/sm2_enc.inc]=\
@@ -405,6 +408,8 @@ GENERATE[providers/implementations/digests/sha2_prov.inc]=\
     providers/implementations/digests/sha2_prov.inc.in
 GENERATE[providers/implementations/digests/sha3_prov.inc]=\
     providers/implementations/digests/sha3_prov.inc.in
+GENERATE[providers/implementations/digests/cshake_prov.inc]=\
+    providers/implementations/digests/cshake_prov.inc.in
 GENERATE[providers/implementations/include/prov/blake2_params.inc]=\
     providers/implementations/include/prov/blake2_params.inc.in
 GENERATE[providers/implementations/digests/ml_dsa_mu_prov.inc]=\
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index da6a2e70ec..b391287743 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -1073,6 +1073,7 @@ PROV_R_INVALID_DIGEST_LENGTH:166:invalid digest length
 PROV_R_INVALID_DIGEST_SIZE:218:invalid digest size
 PROV_R_INVALID_EDDSA_INSTANCE_FOR_ATTEMPTED_OPERATION:243:\
 	invalid eddsa instance for attempted operation
+PROV_R_INVALID_FUNCTION_NAME:256:invalid function name
 PROV_R_INVALID_INPUT_LENGTH:230:invalid input length
 PROV_R_INVALID_ITERATION_COUNT:123:invalid iteration count
 PROV_R_INVALID_IV_LENGTH:109:invalid iv length
@@ -1588,23 +1589,6 @@ SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES:362:srtp could not allocate profiles
 SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG:363:\
 	srtp protection profile list too long
 SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE:364:srtp unknown protection profile
-SSL_R_TLS_EXT_INVALID_MAX_FRAGMENT_LENGTH:232:\
-	ssl3 ext invalid max fragment length
-SSL_R_TLS_EXT_INVALID_SERVERNAME:319:ssl3 ext invalid servername
-SSL_R_TLS_EXT_INVALID_SERVERNAME_TYPE:320:ssl3 ext invalid servername type
-SSL_R_TLS_SESSION_ID_TOO_LONG:300:ssl3 session id too long
-SSL_R_TLS_ALERT_BAD_CERTIFICATE:1042:ssl/tls alert bad certificate
-SSL_R_TLS_ALERT_BAD_RECORD_MAC:1020:ssl/tls alert bad record mac
-SSL_R_TLS_ALERT_CERTIFICATE_EXPIRED:1045:ssl/tls alert certificate expired
-SSL_R_TLS_ALERT_CERTIFICATE_REVOKED:1044:ssl/tls alert certificate revoked
-SSL_R_TLS_ALERT_CERTIFICATE_UNKNOWN:1046:ssl/tls alert certificate unknown
-SSL_R_TLS_ALERT_DECOMPRESSION_FAILURE:1030:ssl/tls alert decompression failure
-SSL_R_TLS_ALERT_HANDSHAKE_FAILURE:1040:ssl/tls alert handshake failure
-SSL_R_TLS_ALERT_ILLEGAL_PARAMETER:1047:ssl/tls alert illegal parameter
-SSL_R_TLS_ALERT_NO_CERTIFICATE:1041:ssl/tls alert no certificate
-SSL_R_TLS_ALERT_UNEXPECTED_MESSAGE:1010:ssl/tls alert unexpected message
-SSL_R_TLS_ALERT_UNSUPPORTED_CERTIFICATE:1043:\
-	ssl/tls alert unsupported certificate
 SSL_R_SSL_COMMAND_SECTION_EMPTY:117:ssl command section empty
 SSL_R_SSL_COMMAND_SECTION_NOT_FOUND:125:ssl command section not found
 SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION:228:ssl ctx has no default ssl version
@@ -1649,8 +1633,25 @@ SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE:1113:\
 SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE:1111:tlsv1 certificate unobtainable
 SSL_R_TLSV1_UNRECOGNIZED_NAME:1112:tlsv1 unrecognized name
 SSL_R_TLSV1_UNSUPPORTED_EXTENSION:1110:tlsv1 unsupported extension
+SSL_R_TLS_ALERT_BAD_CERTIFICATE:1042:ssl/tls alert bad certificate
+SSL_R_TLS_ALERT_BAD_RECORD_MAC:1020:ssl/tls alert bad record mac
+SSL_R_TLS_ALERT_CERTIFICATE_EXPIRED:1045:ssl/tls alert certificate expired
+SSL_R_TLS_ALERT_CERTIFICATE_REVOKED:1044:ssl/tls alert certificate revoked
+SSL_R_TLS_ALERT_CERTIFICATE_UNKNOWN:1046:ssl/tls alert certificate unknown
+SSL_R_TLS_ALERT_DECOMPRESSION_FAILURE:1030:ssl/tls alert decompression failure
+SSL_R_TLS_ALERT_HANDSHAKE_FAILURE:1040:ssl/tls alert handshake failure
+SSL_R_TLS_ALERT_ILLEGAL_PARAMETER:1047:ssl/tls alert illegal parameter
+SSL_R_TLS_ALERT_NO_CERTIFICATE:1041:ssl/tls alert no certificate
+SSL_R_TLS_ALERT_UNEXPECTED_MESSAGE:1010:ssl/tls alert unexpected message
+SSL_R_TLS_ALERT_UNSUPPORTED_CERTIFICATE:1043:\
+	ssl/tls alert unsupported certificate
+SSL_R_TLS_EXT_INVALID_MAX_FRAGMENT_LENGTH:232:\
+	ssl3 ext invalid max fragment length
+SSL_R_TLS_EXT_INVALID_SERVERNAME:319:ssl3 ext invalid servername
+SSL_R_TLS_EXT_INVALID_SERVERNAME_TYPE:320:ssl3 ext invalid servername type
 SSL_R_TLS_ILLEGAL_EXPORTER_LABEL:367:tls illegal exporter label
 SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST:157:tls invalid ecpointformat list
+SSL_R_TLS_SESSION_ID_TOO_LONG:300:ssl3 session id too long
 SSL_R_TOO_MANY_KEY_UPDATES:132:too many key updates
 SSL_R_TOO_MANY_WARN_ALERTS:409:too many warn alerts
 SSL_R_TOO_MUCH_EARLY_DATA:164:too much early data
diff --git a/crypto/sha/build.info b/crypto/sha/build.info
index c3d927c85a..f495fa7072 100644
--- a/crypto/sha/build.info
+++ b/crypto/sha/build.info
@@ -80,7 +80,7 @@ IF[{- !$disabled{asm} -}]
   ENDIF
 ENDIF

-$COMMON=sha1dgst.c sha256.c sha512.c sha3.c $SHA1ASM $KECCAK1600ASM
+$COMMON=sha1dgst.c sha256.c sha512.c sha3.c sha3_encode.c $SHA1ASM $KECCAK1600ASM
 SOURCE[../../libcrypto]=$COMMON sha1_one.c
 SOURCE[../../providers/libfips.a]= $COMMON

diff --git a/crypto/sha/sha3_encode.c b/crypto/sha/sha3_encode.c
new file mode 100644
index 0000000000..a1c042c091
--- /dev/null
+++ b/crypto/sha/sha3_encode.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/* including crypto/sha.h requires this for SHA256_CTX */
+#include "internal/deprecated.h"
+
+/*
+ * NIST.SP.800-185 Encoding/Padding Methods used for SHA3 derived functions
+ * e.g. It is used by KMAC and cSHAKE
+ */
+
+#include <string.h> /* memcpy */
+#include <openssl/err.h>
+#include <openssl/proverr.h>
+#include "crypto/sha.h"
+#include "internal/common.h" /* ossl_assert */
+
+/* Returns the number of bytes required to store 'bits' into a byte array */
+static unsigned int get_encode_size(size_t bits)
+{
+    unsigned int cnt = 0, sz = sizeof(size_t);
+
+    while (bits && (cnt < sz)) {
+        ++cnt;
+        bits >>= 8;
+    }
+    /* If bits is zero 1 byte is required */
+    if (cnt == 0)
+        cnt = 1;
+    return cnt;
+}
+
+/*
+ * Convert an integer into bytes. The number of bytes is appended
+ * to the end of the buffer.
+ * Returns an array of bytes 'out' of size *out_len.
+ *
+ * e.g if bits = 32, out[2] = { 0x20, 0x01 }
+ */
+int ossl_sp800_185_right_encode(unsigned char *out,
+    size_t out_max_len, size_t *out_len,
+    size_t bits)
+{
+    unsigned int len = get_encode_size(bits);
+    int i;
+
+    if (len >= out_max_len) {
+        ERR_raise(ERR_LIB_PROV, PROV_R_LENGTH_TOO_LARGE);
+        return 0;
+    }
+
+    /* MSB's are at the start of the bytes array */
+    for (i = len - 1; i >= 0; --i) {
+        out[i] = (unsigned char)(bits & 0xFF);
+        bits >>= 8;
+    }
+    /* Tack the length onto the end */
+    out[len] = (unsigned char)len;
+
+    /* The Returned length includes the tacked on byte */
+    *out_len = len + 1;
+    return 1;
+}
+
+/*
+ * Encodes a string with a left encoded length added. Note that the
+ * in_len is converted to bits (* 8).
+ *
+ * e.g- in="KMAC" gives out[6] = { 0x01, 0x20, 0x4B, 0x4D, 0x41, 0x43 }
+ *                                 len   bits    K     M     A     C
+ */
+int ossl_sp800_185_encode_string(unsigned char *out,
+    size_t out_max_len, size_t *out_len,
+    const unsigned char *in, size_t in_len)
+{
+    if (in == NULL) {
+        *out_len = 0;
+    } else {
+        size_t i, bits, len, sz;
+
+        bits = 8 * in_len;
+        len = get_encode_size(bits);
+        sz = 1 + len + in_len;
+
+        if (sz > out_max_len) {
+            ERR_raise(ERR_LIB_PROV, PROV_R_LENGTH_TOO_LARGE);
+            return 0;
+        }
+
+        out[0] = (unsigned char)len;
+        for (i = len; i > 0; --i) {
+            out[i] = (bits & 0xFF);
+            bits >>= 8;
+        }
+        memcpy(out + len + 1, in, in_len);
+        *out_len = sz;
+    }
+    return 1;
+}
+
+/*
+ * Returns a zero padded encoding of the inputs in1 and an optional
+ * in2 (can be NULL). The padded output must be a multiple of the blocksize 'w'.
+ * The value of w is in bytes (< 256).
+ *
+ * The returned output is:
+ *    zero_padded(multiple of w, (left_encode(w) || in1 [|| in2])
+ */
+int ossl_sp800_185_bytepad(unsigned char *out, size_t out_len_max, size_t *out_len,
+    const unsigned char *in1, size_t in1_len,
+    const unsigned char *in2, size_t in2_len,
+    size_t w)
+{
+    size_t len;
+    unsigned char *p = out;
+    size_t sz;
+
+    if (!ossl_assert(w <= 255))
+        return 0;
+    sz = (2 + in1_len + (in2 != NULL ? in2_len : 0) + w - 1) / w * w;
+    if (out_len_max != 0 && sz > out_len_max)
+        return 0;
+
+    if (out == NULL) {
+        if (out_len == NULL) {
+            ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER);
+            return 0;
+        }
+        *out_len = sz;
+        return 1;
+    }
+
+    /* Left encoded w */
+    *p++ = 1;
+    *p++ = (unsigned char)w;
+    /* || in1 */
+    memcpy(p, in1, in1_len);
+    p += in1_len;
+    /* [ || in2 ] */
+    if (in2 != NULL && in2_len > 0) {
+        memcpy(p, in2, in2_len);
+        p += in2_len;
+    }
+    /* Figure out the pad size (divisible by w) */
+    len = p - out;
+    /* zero pad the end of the buffer */
+    if (sz != len)
+        memset(p, 0, sz - len);
+    if (out_len != NULL)
+        *out_len = sz;
+    return 1;
+}
diff --git a/doc/man3/EVP_DigestInit.pod b/doc/man3/EVP_DigestInit.pod
index 7178812f5b..9c45af3cd6 100644
--- a/doc/man3/EVP_DigestInit.pod
+++ b/doc/man3/EVP_DigestInit.pod
@@ -150,8 +150,9 @@ Each Message digest algorithm (such as SHA256) produces a fixed size output
 length which is returned when EVP_DigestFinal_ex() is called.
 Extendable Output Functions (XOF) such as SHAKE256 have a variable sized output
 length I<outlen> which can be used with either EVP_DigestFinalXOF() or
-EVP_DigestSqueeze(). EVP_DigestFinal_ex() may also be used for an XOF, but the
-"xoflen" must be set beforehand (See L</PARAMETERS>).
+EVP_DigestSqueeze(). EVP_DigestFinal_ex() may also be used for XOF algorithms, but
+for XOF algorithms that do not have a default size the "xoflen" must be set
+beforehand (See L</PARAMETERS>).
 Note that EVP_MD_get_size() and EVP_MD_CTX_get_size_ex() behave differently for
 an XOF.

@@ -386,7 +387,7 @@ L<OSSL_LIB_CTX(3)>) will be considered.
 =item EVP_MD_xof()

 Returns 1 if I<md> is an Extendable-output Function (XOF) otherwise it returns
-0. SHAKE128 and SHAKE256 are XOF functions.
+0. SHAKE128, SHAKE256, CSHAKE128 and CSHAKE256 are XOF functions.
 It returns 0 for BLAKE2B algorithms.

 =item EVP_MD_get0_name(),
@@ -531,7 +532,7 @@ following OSSL_PARAM keys:

 Sets or gets the digest length for extendable output functions.
 The value should not exceed what can be given using a B<size_t>.
-It may be used by SHAKE-128 and SHAKE-256 to set the
+It may be used by SHAKE-128, CSHAKE-128, SHAKE-256 and CSHAKE-256, to set the
 output length used by EVP_DigestFinal_ex() and EVP_DigestFinal().

 =item "size" (B<OSSL_DIGEST_PARAM_SIZE>) <unsigned integer>
@@ -552,6 +553,20 @@ EVP_MD_CTX_set_params() can be used with the following OSSL_PARAM keys:
 Sets the padding type.
 It is used by the MDC2 algorithm.

+=item "function-name" (B<OSSL_DIGEST_PARAM_FUNCTION_NAME>)<UTF8 string>
+
+Sets the function name string.
+It is used by L<EVP_MD-CSHAKE(7)>.
+
+=item "customization" (B<OSSL_DIGEST_PARAM_CUSTOMIZATION>)<UTF8 string>
+
+Sets a customisation string.
+It is used by L<EVP_MD-CSHAKE(7)>.
+
+=item "properties" (B<OSSL_DIGEST_PARAM_PROPERTIES>)<UTF8 string>
+
+Sets properties to be used when fetching algorithm implementations.
+
 =back

 EVP_MD_CTX_get_params() can be used with the following OSSL_PARAM keys:
diff --git a/doc/man7/EVP_MD-SHA3.pod b/doc/man7/EVP_MD-SHA3.pod
index bc5c3508be..7d7ce614ed 100644
--- a/doc/man7/EVP_MD-SHA3.pod
+++ b/doc/man7/EVP_MD-SHA3.pod
@@ -30,9 +30,18 @@ default provider, and includes the following varieties:
 This implementation supports the common gettable parameters described
 in L<EVP_MD-common(7)>.

+=head1 CONFORMING TO
+
+=over 4
+
+=item FIPS 202
+
+=back
+
 =head1 SEE ALSO

-L<provider-digest(7)>, L<OSSL_PROVIDER-FIPS(7)>, L<OSSL_PROVIDER-default(7)>
+L<provider-digest(7)>, L<OSSL_PROVIDER-FIPS(7)>, L<OSSL_PROVIDER-default(7)>,
+L<EVP_MD-SHAKE(7)>

 =head1 COPYRIGHT

diff --git a/doc/man7/EVP_MD-SHAKE.pod b/doc/man7/EVP_MD-SHAKE.pod
index 343349d92e..352f7751dc 100644
--- a/doc/man7/EVP_MD-SHAKE.pod
+++ b/doc/man7/EVP_MD-SHAKE.pod
@@ -2,17 +2,20 @@

 =head1 NAME

-EVP_MD-SHAKE, EVP_MD-KECCAK-KMAC
+EVP_MD-SHAKE, EVP_MD-CSHAKE, EVP_MD-CSHAKE-KECCAK,
 - The SHAKE / KECCAK family EVP_MD implementations

 =head1 DESCRIPTION

-Support for computing SHAKE or KECCAK-KMAC digests through the
+Support for computing SHAKE, CSHAKE or CSHAKE-KECCAK digests through the
 B<EVP_MD> API.

-KECCAK-KMAC is an Extendable Output Function (XOF), with a definition
-similar to SHAKE, used by the KMAC EVP_MAC implementation (see
-L<EVP_MAC-KMAC(7)>).
+CSHAKE is an Extendable Output Function (XOF), that allows custom strings
+"n" and "s". If these strings are both empty then it is identical to SHAKE,
+otherwise it uses CSHAKE-KECCAK.
+
+CSHAKE-KECCAK is an Extendable Output Function (XOF), with a definition
+similar to SHAKE but appends 2 extra zero bits. It is used internally by CSHAKE.

 =head2 Identities

@@ -21,28 +24,36 @@ provider, and includes the following varieties:

 =over 4

-=item KECCAK-KMAC-128
+=item SHAKE-128
+
+Known names are "SHAKE-128" and "SHAKE128".
+
+=item SHAKE-256
+
+Known names are "SHAKE-256" and "SHAKE256".
+
+=item CSHAKE-128
+
+Known names are "CSHAKE-128" and "CSHAKE128".

-Known names are "KECCAK-KMAC-128" and "KECCAK-KMAC128".  This is used
+=item CSHAKE-256
+
+Known names are "CSHAKE-256" and "CSHAKE256".
+
+=item CSHAKE-KECCAK-128
+
+Other known names are "KECCAK-KMAC-128" and "KECCAK-KMAC128".  This is used
 by L<EVP_MAC-KMAC128(7)>.  Using the notation from NIST FIPS 202
 (Section 6.2), we have S<KECCAK-KMAC-128(M, d)> = S<KECCAK[256](M || 00, d)>
 (see the description of KMAC128 in Appendix A of NIST SP 800-185).

-=item KECCAK-KMAC-256
+=item CSHAKE-KECCAK-256

-Known names are "KECCAK-KMAC-256" and "KECCAK-KMAC256".  This is used
+Other known names are "KECCAK-KMAC-256" and "KECCAK-KMAC256".  This is used
 by L<EVP_MAC-KMAC256(7)>.  Using the notation from NIST FIPS 202
 (Section 6.2), we have S<KECCAK-KMAC-256(M, d)> = S<KECCAK[512](M || 00, d)>
 (see the description of KMAC256 in Appendix A of NIST SP 800-185).

-=item SHAKE-128
-
-Known names are "SHAKE-128" and "SHAKE128".
-
-=item SHAKE-256
-
-Known names are "SHAKE-256" and "SHAKE256".
-
 =back

 =head2 Parameters
@@ -59,26 +70,62 @@ The length of the "xoflen" parameter should not exceed that of a B<size_t>.
 The SHAKE-128 and SHAKE-256 implementations do not have any default digest
 length.

-This parameter must be set before calling either EVP_DigestFinal_ex() or
-EVP_DigestFinal(), since these functions were not designed to handle variable
-length output. It is recommended to either use EVP_DigestSqueeze() or
+The CSHAKE-128 and CSHAKE-256 implementations have default digest lengths of
+32 and 64 bytes respectively (which correspond to security strengths of 128 and
+256 bits respectively).
+
+For SHAKE this parameter must be set before calling either EVP_DigestFinal_ex()
+or EVP_DigestFinal(), since these functions were not designed to handle
+variable length output. If it is not set CSHAKE will use the default value.
+It is recommended to either use EVP_DigestSqueeze() or
 EVP_DigestFinalXOF() instead.

 =item "size" (B<OSSL_DIGEST_PARAM_SIZE>) <unsigned integer>

 An alias of "xoflen".

+=item "function-name" (B<OSSL_DIGEST_PARAM_FUNCTION_NAME>)<UTF8 string>
+
+Sets the function name string used by CSHAKE that can be set to one of
+"", "TupleHash", "ParallelHash" or "KMAC". The default value is "".
+
+=item "customization" (B<OSSL_DIGEST_PARAM_CUSTOMIZATION>)<UTF8 string>
+
+Sets a customisation string used by CSHAKE.
+It is an optional value with a length of at most 512 bytes, and is
+empty by default.
+
+=item "properties" (B<OSSL_DIGEST_PARAM_PROPERTIES>) <UTF8 string>
+
+An optional property used internally by CSHAKE when fetching either
+SHAKE or KECCAK algorithms.
+
 =back

 See L<EVP_DigestInit(3)/PARAMETERS> for further information related to parameters

 =head1 NOTES

-For SHAKE-128, to ensure the maximum security strength of 128 bits, the output
-length passed to EVP_DigestFinalXOF() should be at least 32.
+For SHAKE-128 and CSHAKE-128, to ensure the maximum security strength of
+128 bits, the output length passed to EVP_DigestFinalXOF() should be at least 32.
+
+For SHAKE-256 and CSHAKE-256, to ensure the maximum security strength of
+256 bits, the output length passed to EVP_DigestFinalXOF() should be at least 64.

-For SHAKE-256, to ensure the maximum security strength of 256 bits, the output
-length passed to EVP_DigestFinalXOF() should be at least 64.
+The SHA3 specification allows bit strings to be used, but OpenSSL only allows
+byte strings for inputs, and outputs.
+
+=head1 CONFORMING TO
+
+=over 4
+
+=item FIPS 202 (SHA3 and SHAKE)
+
+=item SP800-185 Section 3 cSHAKE
+
+=item SP800-185 Section 4 KMAC
+
+=back

 =head1 SEE ALSO

@@ -89,6 +136,8 @@ L<EVP_MD_CTX_set_params(3)>, L<provider-digest(7)>, L<OSSL_PROVIDER-default(7)>
 Since OpenSSL 3.4 the SHAKE-128 and SHAKE-256 implementations have no default
 digest length.

+CSHAKE-128 and CSHAKE-256 were added in OpenSSL 4.0
+
 =head1 COPYRIGHT

 Copyright 2020-2024 The OpenSSL Project Authors. All Rights Reserved.
diff --git a/doc/man7/OSSL_PROVIDER-FIPS.pod b/doc/man7/OSSL_PROVIDER-FIPS.pod
index 70fc2c597e..befc9ad3c4 100644
--- a/doc/man7/OSSL_PROVIDER-FIPS.pod
+++ b/doc/man7/OSSL_PROVIDER-FIPS.pod
@@ -69,9 +69,11 @@ The OpenSSL FIPS provider supports these operations and algorithms:

 =item SHAKE, see L<EVP_MD-SHAKE(7)>

-=item KECCAK-KMAC, see L<EVP_MD-KECCAK-KMAC(7)>
+=item CSHAKE, see L<EVP_MD-CSHAKE(7)>

-KECCAK-KMAC is only used internally as a sub algorithm of KMAC.
+=item CSHAKE-KECCAK, see L<EVP_MD-CSHAKE-KECCAK(7)>
+
+It is used internally as a sub algorithm of CSHAKE.

 =item ML-DSA-MU, see L<EVP_MD-ML-DSA-MU(7)>

@@ -612,6 +614,8 @@ L<https://www.openssl.org/source/>

 The HKDF-SHA256, HKDF-SHA384 and HKDF-SHA512 algorithms were added in OpenSSL 3.6.

+The CSHAKE-128 and CSHAKE-256 algorithms were added in OpenSSL 4.0.
+
 All other functionality was added in OpenSSL 3.0.

 =head1 COPYRIGHT
diff --git a/doc/man7/OSSL_PROVIDER-default.pod b/doc/man7/OSSL_PROVIDER-default.pod
index 207a46ce1e..d49502b5fd 100644
--- a/doc/man7/OSSL_PROVIDER-default.pod
+++ b/doc/man7/OSSL_PROVIDER-default.pod
@@ -59,10 +59,12 @@ The OpenSSL default provider supports these operations and algorithms:

 =item KECCAK, see L<EVP_MD-KECCAK(7)>

-=item KECCAK-KMAC, see L<EVP_MD-KECCAK-KMAC(7)>
-
 =item SHAKE, see L<EVP_MD-SHAKE(7)>

+=item CSHAKE, see L<EVP_MD-CSHAKE(7)>
+
+=item CSHAKE-KECCAK, see L<EVP_MD-CSHAKE-KECCAK(7)>
+
 =item BLAKE2, see L<EVP_MD-BLAKE2(7)>

 =item SM3, see L<EVP_MD-SM3(7)>
@@ -540,6 +542,8 @@ The RIPEMD160 digest was added to the default provider in OpenSSL 3.0.7.

 The HKDF-SHA256, HKDF-SHA384 and HKDF-SHA512 algorithms were added in OpenSSL 3.6.

+The CSHAKE-128 and CSHAKE-256 algorithms were added in OpenSSL 4.0.
+
 All other functionality was added in OpenSSL 3.0.

 =head1 COPYRIGHT
diff --git a/include/crypto/sha.h b/include/crypto/sha.h
index fed23f1a66..27112997bf 100644
--- a/include/crypto/sha.h
+++ b/include/crypto/sha.h
@@ -14,10 +14,25 @@

 #include <openssl/sha.h>

+#ifndef OPENSSL_NO_DEPRECATED_3_0
+/* This is inside a deprecated block because SHA256_CTX was marked deprecated */
 int ossl_sha256_192_init(SHA256_CTX *c);
 int sha512_224_init(SHA512_CTX *);
 int sha512_256_init(SHA512_CTX *);
 int ossl_sha1_ctrl(SHA_CTX *ctx, int cmd, int mslen, void *ms);
+#endif
+
 unsigned char *ossl_sha1(const unsigned char *d, size_t n, unsigned char *md);

+int ossl_sp800_185_right_encode(unsigned char *out,
+    size_t out_max_len, size_t *out_len,
+    size_t bits);
+int ossl_sp800_185_encode_string(unsigned char *out,
+    size_t out_max_len, size_t *out_len,
+    const unsigned char *in, size_t in_len);
+int ossl_sp800_185_bytepad(unsigned char *out, size_t out_len_max, size_t *out_len,
+    const unsigned char *in1, size_t in1_len,
+    const unsigned char *in2, size_t in2_len,
+    size_t w);
+
 #endif
diff --git a/include/internal/sha3.h b/include/internal/sha3.h
index d67aa1e19f..d52780a660 100644
--- a/include/internal/sha3.h
+++ b/include/internal/sha3.h
@@ -17,7 +17,7 @@

 #define KECCAK1600_WIDTH 1600
 #define SHA3_MDSIZE(bitlen) (bitlen / 8)
-#define KMAC_MDSIZE(bitlen) 2 * (bitlen / 8)
+#define CSHAKE_KECCAK_MDSIZE(bitlen) 2 * (bitlen / 8)
 #define SHA3_BLOCKSIZE(bitlen) (KECCAK1600_WIDTH - bitlen * 2) / 8

 typedef struct keccak_st KECCAK1600_CTX;
diff --git a/include/openssl/proverr.h b/include/openssl/proverr.h
index e27048faed..82e1e0fc65 100644
--- a/include/openssl/proverr.h
+++ b/include/openssl/proverr.h
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -65,6 +65,7 @@
 #define PROV_R_INVALID_DIGEST_LENGTH 166
 #define PROV_R_INVALID_DIGEST_SIZE 218
 #define PROV_R_INVALID_EDDSA_INSTANCE_FOR_ATTEMPTED_OPERATION 243
+#define PROV_R_INVALID_FUNCTION_NAME 256
 #define PROV_R_INVALID_INPUT_LENGTH 230
 #define PROV_R_INVALID_ITERATION_COUNT 123
 #define PROV_R_INVALID_IV_LENGTH 109
diff --git a/providers/common/include/prov/proverr.h b/providers/common/include/prov/proverr.h
index a2829caed0..573bb212eb 100644
--- a/providers/common/include/prov/proverr.h
+++ b/providers/common/include/prov/proverr.h
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 2020-2025 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2020-2026 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
diff --git a/providers/common/provider_err.c b/providers/common/provider_err.c
index f8fb4c1679..ed72958abf 100644
--- a/providers/common/provider_err.c
+++ b/providers/common/provider_err.c
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -93,6 +93,8 @@ static const ERR_STRING_DATA PROV_str_reasons[] = {
         "invalid digest size" },
     { ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_EDDSA_INSTANCE_FOR_ATTEMPTED_OPERATION),
         "invalid eddsa instance for attempted operation" },
+    { ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_FUNCTION_NAME),
+        "invalid function name" },
     { ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_INPUT_LENGTH),
         "invalid input length" },
     { ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_ITERATION_COUNT),
diff --git a/providers/defltprov.c b/providers/defltprov.c
index 87c53ca761..6cc6d4bdc6 100644
--- a/providers/defltprov.c
+++ b/providers/defltprov.c
@@ -124,15 +124,18 @@ static const OSSL_ALGORITHM deflt_digests[] = {
      * KECCAK-KMAC-128 and KECCAK-KMAC-256 as hashes are mostly useful for
      * the KMAC-128 and KMAC-256.
      */
-    { PROV_NAMES_KECCAK_KMAC_128, "provider=default",
-        ossl_keccak_kmac_128_functions },
-    { PROV_NAMES_KECCAK_KMAC_256, "provider=default",
-        ossl_keccak_kmac_256_functions },
+    { PROV_NAMES_CSHAKE_KECCAK_128, "provider=default",
+        ossl_cshake_keccak_128_functions },
+    { PROV_NAMES_CSHAKE_KECCAK_256, "provider=default",
+        ossl_cshake_keccak_256_functions },

     /* Our primary name:NIST name */
     { PROV_NAMES_SHAKE_128, "provider=default", ossl_shake_128_functions },
     { PROV_NAMES_SHAKE_256, "provider=default", ossl_shake_256_functions },

+    { PROV_NAMES_CSHAKE_128, "provider=default", ossl_cshake_128_functions },
+    { PROV_NAMES_CSHAKE_256, "provider=default", ossl_cshake_256_functions },
+
 #ifndef OPENSSL_NO_BLAKE2
     /*
      * https://blake2.net/ doesn't specify size variants,
diff --git a/providers/fips/fipsprov.c b/providers/fips/fipsprov.c
index f321990b62..924cb613a7 100644
--- a/providers/fips/fipsprov.c
+++ b/providers/fips/fipsprov.c
@@ -281,23 +281,25 @@ static int fips_self_test(void *provctx)
  * we have used historically.
  */

-#define FIPS_DIGESTS_COMMON()                                                        \
-    { PROV_NAMES_SHA1, FIPS_DEFAULT_PROPERTIES, ossl_sha1_functions },               \
-        { PROV_NAMES_SHA2_224, FIPS_DEFAULT_PROPERTIES, ossl_sha224_functions },     \
-        { PROV_NAMES_SHA2_256, FIPS_DEFAULT_PROPERTIES, ossl_sha256_functions },     \
-        { PROV_NAMES_SHA2_384, FIPS_DEFAULT_PROPERTIES, ossl_sha384_functions },     \
-        { PROV_NAMES_SHA2_512, FIPS_DEFAULT_PROPERTIES, ossl_sha512_functions },     \
-        { PROV_NAMES_SHA2_512_224, FIPS_DEFAULT_PROPERTIES,                          \
-            ossl_sha512_224_functions },                                             \
-        { PROV_NAMES_SHA2_512_256, FIPS_DEFAULT_PROPERTIES,                          \
-            ossl_sha512_256_functions },                                             \
-        { PROV_NAMES_SHA3_224, FIPS_DEFAULT_PROPERTIES, ossl_sha3_224_functions },   \
-        { PROV_NAMES_SHA3_256, FIPS_DEFAULT_PROPERTIES, ossl_sha3_256_functions },   \
-        { PROV_NAMES_SHA3_384, FIPS_DEFAULT_PROPERTIES, ossl_sha3_384_functions },   \
-        { PROV_NAMES_SHA3_512, FIPS_DEFAULT_PROPERTIES, ossl_sha3_512_functions },   \
-        { PROV_NAMES_SHAKE_128, FIPS_DEFAULT_PROPERTIES, ossl_shake_128_functions }, \
-    {                                                                                \
-        PROV_NAMES_SHAKE_256, FIPS_DEFAULT_PROPERTIES, ossl_shake_256_functions      \
+#define FIPS_DIGESTS_COMMON()                                                          \
+    { PROV_NAMES_SHA1, FIPS_DEFAULT_PROPERTIES, ossl_sha1_functions },                 \
+        { PROV_NAMES_SHA2_224, FIPS_DEFAULT_PROPERTIES, ossl_sha224_functions },       \
+        { PROV_NAMES_SHA2_256, FIPS_DEFAULT_PROPERTIES, ossl_sha256_functions },       \
+        { PROV_NAMES_SHA2_384, FIPS_DEFAULT_PROPERTIES, ossl_sha384_functions },       \
+        { PROV_NAMES_SHA2_512, FIPS_DEFAULT_PROPERTIES, ossl_sha512_functions },       \
+        { PROV_NAMES_SHA2_512_224, FIPS_DEFAULT_PROPERTIES,                            \
+            ossl_sha512_224_functions },                                               \
+        { PROV_NAMES_SHA2_512_256, FIPS_DEFAULT_PROPERTIES,                            \
+            ossl_sha512_256_functions },                                               \
+        { PROV_NAMES_SHA3_224, FIPS_DEFAULT_PROPERTIES, ossl_sha3_224_functions },     \
+        { PROV_NAMES_SHA3_256, FIPS_DEFAULT_PROPERTIES, ossl_sha3_256_functions },     \
+        { PROV_NAMES_SHA3_384, FIPS_DEFAULT_PROPERTIES, ossl_sha3_384_functions },     \
+        { PROV_NAMES_SHA3_512, FIPS_DEFAULT_PROPERTIES, ossl_sha3_512_functions },     \
+        { PROV_NAMES_SHAKE_128, FIPS_DEFAULT_PROPERTIES, ossl_shake_128_functions },   \
+        { PROV_NAMES_SHAKE_256, FIPS_DEFAULT_PROPERTIES, ossl_shake_256_functions },   \
+        { PROV_NAMES_CSHAKE_128, FIPS_DEFAULT_PROPERTIES, ossl_cshake_128_functions }, \
+    {                                                                                  \
+        PROV_NAMES_CSHAKE_256, FIPS_DEFAULT_PROPERTIES, ossl_cshake_256_functions      \
     }

 static const OSSL_ALGORITHM fips_digests[] = {
@@ -312,14 +314,10 @@ static const OSSL_ALGORITHM fips_digests_internal[] = {
     /* Used by LMS/HSS */
     { PROV_NAMES_SHA2_256_192, FIPS_DEFAULT_PROPERTIES,
         ossl_sha256_192_internal_functions },
-    /*
-     * KECCAK-KMAC-128 and KECCAK-KMAC-256 as hashes are mostly useful for
-     * KMAC128 and KMAC256.
-     */
-    { PROV_NAMES_KECCAK_KMAC_128, FIPS_DEFAULT_PROPERTIES,
-        ossl_keccak_kmac_128_functions },
-    { PROV_NAMES_KECCAK_KMAC_256, FIPS_DEFAULT_PROPERTIES,
-        ossl_keccak_kmac_256_functions },
+    { PROV_NAMES_CSHAKE_KECCAK_128, FIPS_DEFAULT_PROPERTIES,
+        ossl_cshake_keccak_128_functions },
+    { PROV_NAMES_CSHAKE_KECCAK_256, FIPS_DEFAULT_PROPERTIES,
+        ossl_cshake_keccak_256_functions },
     { NULL, NULL, NULL }
 };

diff --git a/providers/implementations/digests/build.info b/providers/implementations/digests/build.info
index ceaac9816d..8da0e80829 100644
--- a/providers/implementations/digests/build.info
+++ b/providers/implementations/digests/build.info
@@ -26,7 +26,7 @@ ENDIF
 SOURCE[$COMMON_GOAL]=digestcommon.c

 SOURCE[$SHA2_GOAL]=sha2_prov.c
-SOURCE[$SHA3_GOAL]=sha3_prov.c
+SOURCE[$SHA3_GOAL]=sha3_prov.c cshake_prov.c

 SOURCE[$NULL_GOAL]=null_prov.c

diff --git a/providers/implementations/digests/cshake_prov.c b/providers/implementations/digests/cshake_prov.c
new file mode 100644
index 0000000000..b6a1e4daf7
--- /dev/null
+++ b/providers/implementations/digests/cshake_prov.c
@@ -0,0 +1,503 @@
+/*
+ * Copyright 2025-2026 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/* including crypto/sha.h requires this for SHA256_CTX */
+#include "internal/deprecated.h"
+/*
+ * NOTE: By default CSHAKE sets secure xof lengths (OSSL_DIGEST_PARAM_XOFLEN)
+ * that are used by EVP_DigestFinal_ex(). This differs from SHAKE where the
+ * xof length MUST be set (since the initial implementation shipped with BAD
+ * defaults - and the only safe way to fix it was to make the user set the value)
+ */
+#include <string.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/proverr.h>
+#include <openssl/core_names.h>
+#include "crypto/sha.h"
+#include "prov/provider_ctx.h"
+#include "prov/digestcommon.h"
+#include "prov/implementations.h"
+#include "internal/common.h"
+#include "internal/sha3.h"
+#include "providers/implementations/digests/cshake_prov.inc"
+
+/*
+ * Length encoding will be a 1 byte size + length in bits (3 bytes max)
+ * This gives a range of 0..0XFFFFFF bits = 2097151 bytes).
+ */
+#define CSHAKE_MAX_ENCODED_HEADER_LEN (1 + 3)
+
+/*
+ * Restrict the maximum length of the custom strings N & S.
+ * This must not exceed 64 bits = 8k bytes.
+ */
+#define CSHAKE_MAX_STRING 512
+
+/* Maximum size of both the encoded strings (N and S) */
+#define CSHAKE_MAX_ENCODED_STRING (CSHAKE_MAX_STRING + CSHAKE_MAX_ENCODED_HEADER_LEN)
+#define CSHAKE_FLAGS (PROV_DIGEST_FLAG_XOF | PROV_DIGEST_FLAG_ALGID_ABSENT)
+
+typedef struct cshake_ctx_st {
+    OSSL_LIB_CTX *libctx;
+    char *propq;
+    EVP_MD_CTX *mdctx;
+    EVP_MD *md;
+    const uint8_t *func; /* encoded N */
+    uint8_t custom[CSHAKE_MAX_ENCODED_STRING]; /* encoded S */
+    size_t funclen;
+    size_t customlen;
+    size_t bitlen;
+    size_t xoflen;
+    int inited;
+} CSHAKE_CTX;
+
+static OSSL_FUNC_digest_freectx_fn cshake_freectx;
+static OSSL_FUNC_digest_dupctx_fn cshake_dupctx;
+static OSSL_FUNC_digest_init_fn cshake_init;
+static OSSL_FUNC_digest_update_fn cshake_update;
+static OSSL_FUNC_digest_final_fn cshake_final;
+static OSSL_FUNC_digest_squeeze_fn cshake_squeeze;
+static OSSL_FUNC_digest_set_ctx_params_fn cshake_set_ctx_params;
+static OSSL_FUNC_digest_settable_ctx_params_fn cshake_settable_ctx_params;
+static OSSL_FUNC_digest_get_ctx_params_fn cshake_get_ctx_params;
+static OSSL_FUNC_digest_gettable_ctx_params_fn cshake_gettable_ctx_params;
+
+typedef struct name_encode_map_st {
+    const char *name;
+    const uint8_t *encoding;
+    size_t encodinglen;
+} NAME_ENCODE_MAP;
+
+/* Fixed value of encode_string("") */
+static const unsigned char empty_encoded_string[] = {
+    0x01, 0x00
+};
+
+/* Fixed value of encode_string("KMAC") */
+static const unsigned char kmac_encoded_string[] = {
+    0x01, 0x20, 0x4B, 0x4D, 0x41, 0x43
+};
+
+/* Fixed value of encode_string("TupleHash") */
+static const unsigned char tuplehash_encoded_string[] = {
+    0x01, 0x48, 0x54, 0x75, 0x70, 0x6C, 0x65, 0x48, 0x61, 0x73, 0x68
+};
+
+/* Fixed value of encode_string("ParallelHash") */
+static const unsigned char parallelhash_encoded_string[] = {
+    0x01, 0x60, 0x50, 0x61, 0x72, 0x61, 0x6C, 0x6C, 0x65, 0x6C, 0x48, 0x61, 0x73, 0x68
+};
+
+static int cshake_set_func_encode_string(const char *in,
+    const uint8_t **out, size_t *outlen)
+{
+    /*
+     * A list of valid function names to encoded string mappings
+     * See NIST SP800-185 Section 3.4
+     */
+    static NAME_ENCODE_MAP functionNameMap[] = {
+        { "", empty_encoded_string, sizeof(empty_encoded_string) },
+        { "KMAC", kmac_encoded_string, sizeof(kmac_encoded_string) },
+        { "TupleHash", tuplehash_encoded_string, sizeof(tuplehash_encoded_string) },
+        { "ParallelHash", parallelhash_encoded_string, sizeof(parallelhash_encoded_string) },
+        { NULL, NULL, 0 }
+    };
+
+    *out = NULL;
+    *outlen = 0;
+    /*
+     * Don't encode an empty string here - this is done manually later only when
+     * one of the strings is not empty. If both are empty then we don't want it
+     * to encode at all.
+     */
+    if (in == NULL || in[0] == 0)
+        return 1;
+    for (int i = 1; functionNameMap[i].name != NULL; ++i) {
+        if (functionNameMap[i].name[0] == in[0]) {
+            if (OPENSSL_strcasecmp(functionNameMap[i].name, in) == 0) {
+                *out = functionNameMap[i].encoding;
+                *outlen = functionNameMap[i].encodinglen;
+                return 1;
+            }
+            return 0; /* Name does not match a known name */
+        }
+    }
+    return 0; /* Name not found */
+}
+
+static int cshake_set_encode_string(const char *in,
+    uint8_t *out, size_t outmax, size_t *outlen)
+{
+    size_t inlen;
+
+    if (*outlen != 0)
+        OPENSSL_cleanse(out, outmax);
+    *outlen = 0;
+    if (in == NULL)
+        return 1;
+
+    inlen = strlen(in);
+    /*
+     * Don't encode an empty string here - this is done manually later only when
+     * one of the strings is not empty. If both are empty then we don't want it
+     * to encode at all.
+     */
+    if (inlen == 0)
+        return 1;
+    if (inlen >= CSHAKE_MAX_STRING)
+        return 0;
+    return ossl_sp800_185_encode_string(out, outmax, outlen,
+        (const unsigned char *)in, inlen);
+}
+
+/*
+ * Set the xof length, note that if the digest has not been fetched yet then
+ * it is just set into a variable and deferred to later.
+ */
+static int cshake_set_xoflen(CSHAKE_CTX *ctx, size_t xoflen)
+{
+    OSSL_PARAM params[2];
+
+    params[0] = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_XOFLEN, &xoflen);
+    params[1] = OSSL_PARAM_construct_end();
+
+    ctx->xoflen = xoflen;
+    if (ctx->md != NULL)
+        return EVP_MD_CTX_set_params(ctx->mdctx, params);
+    return 1;
+}
+
+/*
+ * Fetch a digest for SHAKE or KECCAK, set its xof len and init it
+ * into an mdctx.
+ */
+static int cshake_set_shake_mode(CSHAKE_CTX *ctx, int shake)
+{
+    OSSL_PARAM params[2];
+    const char *name;
+
+    if (shake)
+        name = (ctx->bitlen == 128 ? "SHAKE128" : "SHAKE256");
+    else
+        name = (ctx->bitlen == 128 ? "CSHAKE-KECCAK-128" : "CSHAKE-KECCAK-256");
+
+    if (ctx->md == NULL || !EVP_MD_is_a(ctx->md, name)) {
+        ctx->md = EVP_MD_fetch(ctx->libctx, name, ctx->propq);
+        if (ctx->md == NULL)
+            return 0;
+    }
+    params[0] = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_XOFLEN,
+        &ctx->xoflen);
+    params[1] = OSSL_PARAM_construct_end();
+    return EVP_DigestInit_ex2(ctx->mdctx, ctx->md, params);
+}
+
+static void *cshake_newctx(void *provctx, size_t bitlen)
+{
+    CSHAKE_CTX *ctx;
+
+    if (ossl_unlikely(!ossl_prov_is_running()))
+        return NULL;
+    ctx = OPENSSL_zalloc(sizeof(*ctx));
+    if (ctx != NULL) {
+        ctx->mdctx = EVP_MD_CTX_create();
+        if (ctx->mdctx == NULL) {
+            OPENSSL_free(ctx);
+            return NULL;
+        }
+        ctx->bitlen = bitlen;
+        ctx->libctx = PROV_LIBCTX_OF(provctx);
+    }
+    return ctx;
+}
+
+static void cshake_freectx(void *vctx)
+{
+    CSHAKE_CTX *ctx = (CSHAKE_CTX *)vctx;
+
+    EVP_MD_free(ctx->md);
+    EVP_MD_CTX_destroy(ctx->mdctx);
+    OPENSSL_clear_free(ctx, sizeof(*ctx));
+}
+
+static void *cshake_dupctx(void *ctx)
+{
+    CSHAKE_CTX *src = (CSHAKE_CTX *)ctx;
+    CSHAKE_CTX *ret = ossl_prov_is_running() ? OPENSSL_malloc(sizeof(*ret))
+                                             : NULL;
+
+    if (ret != NULL) {
+        *ret = *src;
+        ret->md = NULL;
+        ret->mdctx = NULL;
+        ret->propq = NULL;
+
+        if (src->md != NULL && !EVP_MD_up_ref(src->md))
+            goto err;
+        ret->md = src->md;
+
+        if (src->mdctx != NULL) {
+            ret->mdctx = EVP_MD_CTX_new();
+            if (ret->mdctx == NULL
+                || !EVP_MD_CTX_copy_ex(ret->mdctx, src->mdctx))
+                goto err;
+        }
+        if (src->propq != NULL) {
+            ret->propq = OPENSSL_strdup(src->propq);
+            if (ret->propq == NULL)
+                goto err;
+        }
+    }
+    return ret;
+err:
+    cshake_freectx(ret);
+    return NULL;
+}
+
+static int cshake_init(void *vctx, const OSSL_PARAM params[])
+{
+    CSHAKE_CTX *ctx = (CSHAKE_CTX *)vctx;
+
+    if (ossl_unlikely(!ossl_prov_is_running()))
+        return 0;
+    ctx->inited = 0;
+    ctx->xoflen = (ctx->bitlen == 128) ? 32 : 64; /* Set default values here */
+    cshake_set_func_encode_string(NULL, &ctx->func, &ctx->funclen);
+    cshake_set_encode_string(NULL, ctx->custom, sizeof(ctx->custom), &ctx->customlen);
+    return cshake_set_ctx_params(vctx, params);
+}
+
+static const OSSL_PARAM *cshake_settable_ctx_params(ossl_unused void *ctx,
+    ossl_unused void *provctx)
+{
+    return cshake_set_ctx_params_list;
+}
+
+static int set_property_query(CSHAKE_CTX *ctx, const char *propq)
+{
+    OPENSSL_free(ctx->propq);
+    ctx->propq = NULL;
+    if (propq != NULL) {
+        ctx->propq = OPENSSL_strdup(propq);
+        if (ctx->propq == NULL)
+            return 0;
+    }
+    return 1;
+}
+
+static int cshake_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+{
+    CSHAKE_CTX *ctx = (CSHAKE_CTX *)vctx;
+    struct cshake_set_ctx_params_st p;
+
+    if (ctx == NULL || !cshake_set_ctx_params_decoder(params, &p))
+        return 0;
+
+    if (p.xoflen != NULL) {
+        size_t xoflen;
+
+        if (!OSSL_PARAM_get_size_t(p.xoflen, &xoflen)
+            || !cshake_set_xoflen(ctx, xoflen)) {
+            ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
+            return 0;
+        }
+    }
+    if (p.func != NULL) {
+        if (p.func->data_type != OSSL_PARAM_UTF8_STRING)
+            return 0;
+        if (!cshake_set_func_encode_string(p.func->data, &ctx->func, &ctx->funclen)) {
+            ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_FUNCTION_NAME);
+            return 0;
+        }
+    }
+    if (p.custom != NULL) {
+        if (p.custom->data_type != OSSL_PARAM_UTF8_STRING)
+            return 0;
+        if (!cshake_set_encode_string(p.custom->data, ctx->custom, sizeof(ctx->custom), &ctx->customlen))
+            return 0;
+    }
+    if (p.propq != NULL) {
+        if (p.propq->data_type != OSSL_PARAM_UTF8_STRING
+            || !set_property_query(ctx, p.propq->data))
+            return 0;
+    }
+    return 1;
+}
+
+/*
+ * bytepad(encode_string(N) || encode_string(S), w)
+ * See SP800-185 Section 2.3.3 Padding.
+ *
+ * Rather than build an array and do a single keccak operation, we use the
+ * internal keccak buffer to simplify the process.
+ * Note that if the strings are large enough to fill the buffer, it will handle
+ * this internally by absorbing full blocks. The zero padding is also simple
+ * as we just fill the buffer with zeros to make it a multiple of the blocksize.
+ */
+static int cshake_absorb_bytepad_strings(CSHAKE_CTX *ctx)
+{
+    const uint8_t zeros[SHA3_BLOCKSIZE(128)] = { 0 };
+    uint8_t bytepad_header[2] = { 0x01, 0x00 };
+    const uint8_t *n = ctx->func, *s = ctx->custom;
+    size_t nlen = ctx->funclen, slen = ctx->customlen;
+    size_t zlen;
+    size_t w = SHA3_BLOCKSIZE(ctx->bitlen); /* w = 168 or 136 */
+
+    bytepad_header[1] = (uint8_t)w;
+
+    /* Empty strings are still encoded */
+    if (nlen == 0) {
+        n = empty_encoded_string;
+        nlen = sizeof(empty_encoded_string);
+    }
+    if (slen == 0) {
+        s = empty_encoded_string;
+        slen = sizeof(empty_encoded_string);
+    }
+    /* Calculate the number of padding zeros to fill up the block */
+    zlen = ((sizeof(bytepad_header) + nlen + slen) % w);
+    if (zlen != 0)
+        zlen = w - zlen;
+
+    /* left encoded(w) || encodestring(n) || encodestring(s) || zero_padding */
+    return EVP_DigestUpdate(ctx->mdctx, bytepad_header, sizeof(bytepad_header))
+        && EVP_DigestUpdate(ctx->mdctx, n, nlen)
+        && EVP_DigestUpdate(ctx->mdctx, s, slen)
+        && EVP_DigestUpdate(ctx->mdctx, zeros, zlen);
+}
+
+/*
+ * The setup of the EVP_MD gets deferred until after the set_ctx_params
+ * which means that we need to defer to the functions that may be called
+ * afterwards (i.e. The update(), final() or squeeze()).
+ *
+ */
+static int check_init(CSHAKE_CTX *ctx)
+{
+    /*
+     * We have to defer choosing the mode EVP_MD object (SHAKE or KECCAK)
+     * until the first call to either update(), final() or squeeze()
+     * since the strings can be set at any time before this point.
+     */
+    if (ctx->inited == 0) {
+        if (ctx->funclen != 0 || ctx->customlen != 0) {
+            if (!cshake_set_shake_mode(ctx, 0)
+                || !cshake_absorb_bytepad_strings(ctx))
+                return 0;
+        } else {
+            /* Use SHAKE if N and S are both empty strings */
+            if (!cshake_set_shake_mode(ctx, 1))
+                return 0;
+        }
+        ctx->inited = 1;
+    }
+    return 1;
+}
+
+static int cshake_update(void *vctx, const unsigned char *in, size_t inlen)
+{
+    CSHAKE_CTX *ctx = (CSHAKE_CTX *)vctx;
+
+    return check_init(ctx)
+        && EVP_DigestUpdate(ctx->mdctx, in, inlen);
+}
+
+static int cshake_final(void *vctx, uint8_t *out, size_t *outl, size_t outsz)
+{
+    CSHAKE_CTX *ctx = (CSHAKE_CTX *)vctx;
+    unsigned int der = (unsigned int)(*outl);
+    int ret = 1;
+
+    if (ossl_unlikely(!ossl_prov_is_running()))
+        return 0;
+
+    if (outsz > 0)
+        ret = check_init(ctx) && EVP_DigestFinal_ex(ctx->mdctx, out, &der);
+    *outl = der;
+    return ret;
+}
+
+static int cshake_squeeze(void *vctx, uint8_t *out, size_t *outl, size_t outsz)
+{
+    CSHAKE_CTX *ctx = (CSHAKE_CTX *)vctx;
+    int ret = 1;
+
+    if (ossl_unlikely(!ossl_prov_is_running()))
+        return 0;
+
+    if (outsz > 0)
+        ret = check_init(ctx) && EVP_DigestSqueeze(ctx->mdctx, out, outsz);
+    if (ret && outl != NULL)
+        *outl = outsz;
+    return ret;
+}
+
+static const OSSL_PARAM *cshake_gettable_ctx_params(ossl_unused void *ctx,
+    ossl_unused void *provctx)
+{
+    return cshake_get_ctx_params_list;
+}
+
+static int cshake_get_ctx_params(void *vctx, OSSL_PARAM params[])
+{
+    CSHAKE_CTX *ctx = (CSHAKE_CTX *)vctx;
+    struct cshake_get_ctx_params_st p;
+
+    if (ctx == NULL || !cshake_get_ctx_params_decoder(params, &p))
+        return 0;
+
+    /* Size is an alias of xoflen */
+    if (p.xoflen != NULL || p.size != NULL) {
+        size_t xoflen = ctx->xoflen;
+
+        if (ctx->md != NULL)
+            xoflen = EVP_MD_CTX_get_size_ex(ctx->mdctx);
+
+        if (p.size != NULL && !OSSL_PARAM_set_size_t(p.size, xoflen)) {
+            ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
+            return 0;
+        }
+        if (p.xoflen != NULL && !OSSL_PARAM_set_size_t(p.xoflen, xoflen)) {
+            ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
+            return 0;
+        }
+    }
+    return 1;
+}
+
+#define IMPLEMENT_CSHAKE_functions(bitlen)                                          \
+    static OSSL_FUNC_digest_newctx_fn cshake_##bitlen##_newctx;                     \
+    static void *cshake_##bitlen##_newctx(void *provctx)                            \
+    {                                                                               \
+        return cshake_newctx(provctx, bitlen);                                      \
+    }                                                                               \
+    PROV_FUNC_DIGEST_GET_PARAM(cshake_##bitlen, SHA3_BLOCKSIZE(bitlen),             \
+        CSHAKE_KECCAK_MDSIZE(bitlen), CSHAKE_FLAGS)                                 \
+    const OSSL_DISPATCH ossl_cshake_##bitlen##_functions[] = {                      \
+        { OSSL_FUNC_DIGEST_NEWCTX, (void (*)(void))cshake_##bitlen##_newctx },      \
+        { OSSL_FUNC_DIGEST_INIT, (void (*)(void))cshake_init },                     \
+        { OSSL_FUNC_DIGEST_UPDATE, (void (*)(void))cshake_update },                 \
+        { OSSL_FUNC_DIGEST_FINAL, (void (*)(void))cshake_final },                   \
+        { OSSL_FUNC_DIGEST_SQUEEZE, (void (*)(void))cshake_squeeze },               \
+        { OSSL_FUNC_DIGEST_FREECTX, (void (*)(void))cshake_freectx },               \
+        { OSSL_FUNC_DIGEST_DUPCTX, (void (*)(void))cshake_dupctx },                 \
+        { OSSL_FUNC_DIGEST_SET_CTX_PARAMS, (void (*)(void))cshake_set_ctx_params }, \
+        { OSSL_FUNC_DIGEST_SETTABLE_CTX_PARAMS,                                     \
+            (void (*)(void))cshake_settable_ctx_params },                           \
+        { OSSL_FUNC_DIGEST_GET_CTX_PARAMS, (void (*)(void))cshake_get_ctx_params }, \
+        { OSSL_FUNC_DIGEST_GETTABLE_CTX_PARAMS,                                     \
+            (void (*)(void))cshake_gettable_ctx_params },                           \
+        PROV_DISPATCH_FUNC_DIGEST_GET_PARAMS(cshake_##bitlen),                      \
+        PROV_DISPATCH_FUNC_DIGEST_CONSTRUCT_END
+
+/* ossl_cshake_128_functions */
+IMPLEMENT_CSHAKE_functions(128)
+    /* ossl_cshake_256_functions */
+    IMPLEMENT_CSHAKE_functions(256)
diff --git a/providers/implementations/digests/cshake_prov.inc.in b/providers/implementations/digests/cshake_prov.inc.in
new file mode 100644
index 0000000000..42ed97f2c3
--- /dev/null
+++ b/providers/implementations/digests/cshake_prov.inc.in
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2025-2026 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+{-
+use OpenSSL::paramnames qw(produce_param_decoder);
+-}
+
+{- produce_param_decoder('cshake_set_ctx_params',
+                         (['OSSL_DIGEST_PARAM_XOFLEN',   'xoflen',   'size_t'],
+                          ['OSSL_DIGEST_PARAM_SIZE',     'xoflen',   'size_t'],
+                          ['OSSL_DIGEST_PARAM_FUNCTION_NAME', 'func',   'utf8_string'],
+                          ['OSSL_DIGEST_PARAM_CUSTOMIZATION', 'custom', 'utf8_string'],
+                          ['OSSL_DIGEST_PARAM_PROPERTIES', 'propq',  'utf8_string'],
+                         )); -}
+
+{- produce_param_decoder('cshake_get_ctx_params',
+                         (['OSSL_DIGEST_PARAM_XOFLEN',   'xoflen',   'size_t'],
+                          ['OSSL_DIGEST_PARAM_SIZE',     'size',     'size_t'],
+                         )); -}
diff --git a/providers/implementations/digests/sha3_prov.c b/providers/implementations/digests/sha3_prov.c
index 5072cd8e79..67cc691708 100644
--- a/providers/implementations/digests/sha3_prov.c
+++ b/providers/implementations/digests/sha3_prov.c
@@ -25,7 +25,35 @@

 #define SHA3_FLAGS PROV_DIGEST_FLAG_ALGID_ABSENT
 #define SHAKE_FLAGS (PROV_DIGEST_FLAG_XOF | PROV_DIGEST_FLAG_ALGID_ABSENT)
-#define KMAC_FLAGS PROV_DIGEST_FLAG_XOF
+#define CSHAKE_KECCAK_FLAGS PROV_DIGEST_FLAG_XOF
+
+/*
+ * FIPS 202 Section 5.1 Specifies a padding mode that is added to the last
+ * block that consists of a 1 bit followed by padding zero bits and a trailing
+ * 1 bit (where the bits are in LSB order)
+ *
+ * For a given input message special algorithm context bits are appended:
+ * i.e.
+ *   KECCAK[c] = (No tag is used)
+ *   SHA3   = 01
+ *   SHAKE  = 1111
+ *   CSHAKE_KECCAK = 00 (See NIST SP800-185 3.3 : i.e. it has 2 trailing zero bits)
+ * Note that KMAC and TupleHash use CSHAKE_KECCAK.
+ * The OpenSSL implementation only allows input messages that are in bytes,
+ * so the above concatenated bits will start on a byte boundary.
+ * Following these bits will be a 1 bit then the padding zeros which gives
+ *
+ *   KECCAK[c] = 1000
+ *   SHA3   = 0110
+ *   SHAKE  = 11111000
+ *   CSHAKE_KECCAK = 0010 (See NIST SP800-185 3.3 : i.e. KMAC uses cSHAKE with a fixed string)
+ *
+ *   Which gives the following padding values as bytes.
+ */
+#define KECCAK_PADDING 0x01
+#define SHA3_PADDING 0x06
+#define SHAKE_PADDING 0x1f
+#define CSHAKE_KECCAK_PADDING 0x04

 /*
  * Forward declaration of any unique methods implemented here. This is not strictly
@@ -56,7 +84,6 @@ static sha3_squeeze_fn generic_sha3_squeeze;
 #define S390_SHA3 1
 #define S390_SHA3_CAPABLE(name) \
     ((OPENSSL_s390xcap_P.kimd[0] & S390X_CAPBIT(S390X_##name)) && (OPENSSL_s390xcap_P.klmd[0] & S390X_CAPBIT(S390X_##name)))
-
 #endif

 static int keccak_init(void *vctx, ossl_unused const OSSL_PARAM params[])
@@ -320,7 +347,7 @@ static int s390x_keccak_final(void *vctx, unsigned char *out, size_t outlen)
     return s390x_keccakc_final(vctx, out, outlen, 0x01);
 }

-static int s390x_kmac_final(void *vctx, unsigned char *out, size_t outlen)
+static int s390x_cshake_keccak_final(void *vctx, unsigned char *out, size_t outlen)
 {
     return s390x_keccakc_final(vctx, out, outlen, 0x04);
 }
@@ -374,12 +401,12 @@ static int s390x_keccakc_squeeze(void *vctx, unsigned char *out, size_t outlen,

 static int s390x_keccak_squeeze(void *vctx, unsigned char *out, size_t outlen)
 {
-    return s390x_keccakc_squeeze(vctx, out, outlen, 0x01);
+    return s390x_keccakc_squeeze(vctx, out, outlen, KECCAK_PADDING);
 }

-static int s390x_kmac_squeeze(void *vctx, unsigned char *out, size_t outlen)
+static int s390x_cshake_keccak_squeeze(void *vctx, unsigned char *out, size_t outlen)
 {
-    return s390x_keccakc_squeeze(vctx, out, outlen, 0x04);
+    return s390x_keccakc_squeeze(vctx, out, outlen, CSHAKE_KECCAK_PADDING);
 }

 static PROV_SHA3_METHOD sha3_s390x_md = {
@@ -400,10 +427,10 @@ static PROV_SHA3_METHOD shake_s390x_md = {
     s390x_shake_squeeze,
 };

-static PROV_SHA3_METHOD kmac_s390x_md = {
+static PROV_SHA3_METHOD cshake_keccak_s390x_md = {
     s390x_sha3_absorb,
-    s390x_kmac_final,
-    s390x_kmac_squeeze,
+    s390x_cshake_keccak_final,
+    s390x_cshake_keccak_squeeze,
 };

 #define SHAKE_SET_MD(uname, typ)      \
@@ -421,12 +448,12 @@ static PROV_SHA3_METHOD kmac_s390x_md = {
     } else {                         \
         ctx->meth = sha3_generic_md; \
     }
-#define KMAC_SET_MD(bitlen)                  \
+#define CSHAKE_KECCAK_SET_MD(bitlen)         \
     if (S390_SHA3_CAPABLE(SHAKE_##bitlen)) { \
         ctx->pad = S390X_SHAKE_##bitlen;     \
-        ctx->meth = kmac_s390x_md;           \
+        ctx->meth = cshake_keccak_s390x_md;  \
     } else {                                 \
-        ctx->meth = sha3_generic_md;         \
+        ctx->meth = shake_generic_md;        \
     }
 #elif defined(__aarch64__) && defined(KECCAK1600_ASM)
 #include "arm_arch.h"
@@ -467,15 +494,15 @@ static PROV_SHA3_METHOD shake_ARMSHA3_md = {
     } else {                                                  \
         ctx->meth = sha3_generic_md;                          \
     }
-#define KMAC_SET_MD(bitlen)                                   \
+#define CSHAKE_KECCAK_SET_MD(bitlen)                          \
     if (OPENSSL_armcap_P & ARMV8_HAVE_SHA3_AND_WORTH_USING) { \
-        ctx->meth = sha3_ARMSHA3_md;                          \
+        ctx->meth = shake_ARMSHA3_md;                         \
     } else {                                                  \
-        ctx->meth = sha3_generic_md;                          \
+        ctx->meth = shake_generic_md;                         \
     }
 #else
 #define SHA3_SET_MD(uname, typ) ctx->meth = sha3_generic_md;
-#define KMAC_SET_MD(bitlen) ctx->meth = sha3_generic_md;
+#define CSHAKE_KECCAK_SET_MD(bitlen) ctx->meth = shake_generic_md;
 #define SHAKE_SET_MD(uname, typ) ctx->meth = shake_generic_md;
 #endif /* S390_SHA3 */

@@ -509,7 +536,7 @@ static PROV_SHA3_METHOD shake_ARMSHA3_md = {
         return ctx;                                                                 \
     }

-#define KMAC_newctx(uname, bitlen, pad)                                             \
+#define CSHAKE_KECCAK_newctx(uname, bitlen, pad)                                    \
     static OSSL_FUNC_digest_newctx_fn uname##_newctx;                               \
     static void *uname##_newctx(void *provctx)                                      \
     {                                                                               \
@@ -519,7 +546,7 @@ static PROV_SHA3_METHOD shake_ARMSHA3_md = {
         if (ctx == NULL)                                                            \
             return NULL;                                                            \
         ossl_keccak_init(ctx, pad, bitlen, 2 * bitlen);                             \
-        KMAC_SET_MD(bitlen)                                                         \
+        CSHAKE_KECCAK_SET_MD(bitlen)                                                \
         return ctx;                                                                 \
     }

@@ -761,36 +788,37 @@ static int shake_set_ctx_params(void *vctx, const OSSL_PARAM params[])
 #define KECCAK_SER_ID 0x010000
 #define SHAKE_SER_ID 0x020000
 #define SHA3_SER_ID 0x040000
-#define KMAK_SER_ID 0x080000
+#define CSHAKE_KECCAK_SER_ID 0x080000

-#define IMPLEMENT_SHA3_functions(bitlen)                             \
-    SHA3_newctx(sha3, SHA3_##bitlen, sha3_##bitlen, bitlen, '\x06')  \
-        IMPLEMENT_SERIALIZE_FNS(sha3_##bitlen, SHA3_SER_ID + bitlen) \
-            PROV_FUNC_SHA3_DIGEST(sha3_##bitlen, bitlen,             \
-                SHA3_BLOCKSIZE(bitlen), SHA3_MDSIZE(bitlen),         \
+#define IMPLEMENT_SHA3_functions(bitlen)                                           \
+    SHA3_newctx(sha3, SHA3_##bitlen, sha3_##bitlen, bitlen, (uint8_t)SHA3_PADDING) \
+        IMPLEMENT_SERIALIZE_FNS(sha3_##bitlen, SHA3_SER_ID + bitlen)               \
+            PROV_FUNC_SHA3_DIGEST(sha3_##bitlen, bitlen,                           \
+                SHA3_BLOCKSIZE(bitlen), SHA3_MDSIZE(bitlen),                       \
                 SHA3_FLAGS)

-#define IMPLEMENT_KECCAK_functions(bitlen)                                \
-    SHA3_newctx(keccak, KECCAK_##bitlen, keccak_##bitlen, bitlen, '\x01') \
-        IMPLEMENT_SERIALIZE_FNS(keccak_##bitlen, KECCAK_SER_ID + bitlen)  \
-            PROV_FUNC_SHA3_DIGEST(keccak_##bitlen, bitlen,                \
-                SHA3_BLOCKSIZE(bitlen), SHA3_MDSIZE(bitlen),              \
+#define IMPLEMENT_KECCAK_functions(bitlen)                                                 \
+    SHA3_newctx(keccak, KECCAK_##bitlen, keccak_##bitlen, bitlen, (uint8_t)KECCAK_PADDING) \
+        IMPLEMENT_SERIALIZE_FNS(keccak_##bitlen, KECCAK_SER_ID + bitlen)                   \
+            PROV_FUNC_SHA3_DIGEST(keccak_##bitlen, bitlen,                                 \
+                SHA3_BLOCKSIZE(bitlen), SHA3_MDSIZE(bitlen),                               \
                 SHA3_FLAGS)

 #define IMPLEMENT_SHAKE_functions(bitlen)                              \
     SHAKE_newctx(shake, SHAKE_##bitlen, shake_##bitlen, bitlen,        \
-        0 /* no default md length */, '\x1f')                          \
+        0 /* no default md length */, (uint8_t)SHAKE_PADDING)          \
         IMPLEMENT_SERIALIZE_FNS(shake_##bitlen, SHAKE_SER_ID + bitlen) \
             PROV_FUNC_SHAKE_DIGEST(shake_##bitlen, bitlen,             \
                 SHA3_BLOCKSIZE(bitlen), 0,                             \
                 SHAKE_FLAGS)

-#define IMPLEMENT_KMAC_functions(bitlen)                                    \
-    KMAC_newctx(keccak_kmac_##bitlen, bitlen, '\x04')                       \
-        IMPLEMENT_SERIALIZE_FNS(keccak_kmac_##bitlen, KMAK_SER_ID + bitlen) \
-            PROV_FUNC_SHAKE_DIGEST(keccak_kmac_##bitlen, bitlen,            \
-                SHA3_BLOCKSIZE(bitlen), KMAC_MDSIZE(bitlen),                \
-                KMAC_FLAGS)
+#define IMPLEMENT_CSHAKE_KECCAK_functions(bitlen)                                        \
+    CSHAKE_KECCAK_newctx(cshake_keccak_##bitlen, bitlen, (uint8_t)CSHAKE_KECCAK_PADDING) \
+        IMPLEMENT_SERIALIZE_FNS(cshake_keccak_##bitlen, CSHAKE_KECCAK_SER_ID + bitlen)   \
+            PROV_FUNC_SHAKE_DIGEST(cshake_keccak_##bitlen, bitlen,                       \
+                SHA3_BLOCKSIZE(bitlen),                                                  \
+                CSHAKE_KECCAK_MDSIZE(bitlen),                                            \
+                CSHAKE_KECCAK_FLAGS)

 /* ossl_sha3_224_functions */
 IMPLEMENT_SHA3_functions(224)
@@ -812,7 +840,7 @@ IMPLEMENT_KECCAK_functions(512)
 IMPLEMENT_SHAKE_functions(128)
 /* ossl_shake_256_functions */
 IMPLEMENT_SHAKE_functions(256)
-/* ossl_keccak_kmac_128_functions */
-IMPLEMENT_KMAC_functions(128)
-/* ossl_keccak_kmac_256_functions */
-IMPLEMENT_KMAC_functions(256)
+/* ossl_cshake_keccak_128_functions */
+IMPLEMENT_CSHAKE_KECCAK_functions(128)
+    /* ossl_cshake_keccak_256_functions */
+    IMPLEMENT_CSHAKE_KECCAK_functions(256)
diff --git a/providers/implementations/include/prov/implementations.h b/providers/implementations/include/prov/implementations.h
index 990dd25864..a3b0187b80 100644
--- a/providers/implementations/include/prov/implementations.h
+++ b/providers/implementations/include/prov/implementations.h
@@ -27,10 +27,12 @@ extern const OSSL_DISPATCH ossl_keccak_224_functions[];
 extern const OSSL_DISPATCH ossl_keccak_256_functions[];
 extern const OSSL_DISPATCH ossl_keccak_384_functions[];
 extern const OSSL_DISPATCH ossl_keccak_512_functions[];
-extern const OSSL_DISPATCH ossl_keccak_kmac_128_functions[];
-extern const OSSL_DISPATCH ossl_keccak_kmac_256_functions[];
 extern const OSSL_DISPATCH ossl_shake_128_functions[];
 extern const OSSL_DISPATCH ossl_shake_256_functions[];
+extern const OSSL_DISPATCH ossl_cshake_keccak_128_functions[];
+extern const OSSL_DISPATCH ossl_cshake_keccak_256_functions[];
+extern const OSSL_DISPATCH ossl_cshake_128_functions[];
+extern const OSSL_DISPATCH ossl_cshake_256_functions[];
 extern const OSSL_DISPATCH ossl_blake2s256_functions[];
 extern const OSSL_DISPATCH ossl_blake2b512_functions[];
 extern const OSSL_DISPATCH ossl_md5_functions[];
diff --git a/providers/implementations/include/prov/names.h b/providers/implementations/include/prov/names.h
index 04b41d53c8..70c4eb0373 100644
--- a/providers/implementations/include/prov/names.h
+++ b/providers/implementations/include/prov/names.h
@@ -248,12 +248,14 @@
 #define PROV_NAMES_SHAKE_128 "SHAKE-128:SHAKE128:2.16.840.1.101.3.4.2.11"
 #define PROV_NAMES_SHAKE_256 "SHAKE-256:SHAKE256:2.16.840.1.101.3.4.2.12"

-/*
- * KECCAK-KMAC-128 and KECCAK-KMAC-256 as hashes are mostly useful for
- * KMAC128 and KMAC256.
- */
-#define PROV_NAMES_KECCAK_KMAC_128 "KECCAK-KMAC-128:KECCAK-KMAC128"
-#define PROV_NAMES_KECCAK_KMAC_256 "KECCAK-KMAC-256:KECCAK-KMAC256"
+#define PROV_NAMES_CSHAKE_128 "CSHAKE-128:CSHAKE128"
+#define PROV_NAMES_CSHAKE_256 "CSHAKE-256:CSHAKE256"
+
+/* Internal algorithms used by CSHAKE variants */
+#define PROV_NAMES_CSHAKE_KECCAK_128 "CSHAKE-KECCAK-128:KECCAK-KMAC-128:KECCAK-KMAC128"
+#define PROV_NAMES_CSHAKE_KECCAK_256 "CSHAKE-KECCAK-256:KECCAK-KMAC-256:KECCAK-KMAC256"
+#define PROV_NAMES_KECCAK_KMAC_128 PROV_NAMES_CSHAKE_KECCAK_128
+#define PROV_NAMES_KECCAK_KMAC_256 PROV_NAMES_CSHAKE_KECCAK_256
 /*
  * https://blake2.net/ doesn't specify size variants, but mentions that
  * Bouncy Castle uses the names BLAKE2b-160, BLAKE2b-256, BLAKE2b-384, and
diff --git a/providers/implementations/macs/kmac_prov.c b/providers/implementations/macs/kmac_prov.c
index f4726e88ab..68d1083799 100644
--- a/providers/implementations/macs/kmac_prov.c
+++ b/providers/implementations/macs/kmac_prov.c
@@ -62,6 +62,7 @@
 #include "prov/providercommon.h"
 #include "internal/cryptlib.h" /* ossl_assert */
 #include "providers/implementations/macs/kmac_prov.inc"
+#include "crypto/sha.h"

 /*
  * Forward declaration of everything implemented here.  This is not strictly
@@ -139,18 +140,8 @@ struct kmac_data_st {
     OSSL_FIPS_IND_DECLARE
 };

-static int encode_string(unsigned char *out, size_t out_max_len, size_t *out_len,
-    const unsigned char *in, size_t in_len);
-static int right_encode(unsigned char *out, size_t out_max_len, size_t *out_len,
-    size_t bits);
-static int bytepad(unsigned char *out, size_t *out_len,
-    const unsigned char *in1, size_t in1_len,
-    const unsigned char *in2, size_t in2_len,
-    size_t w);
 static int kmac_bytepad_encode_key(unsigned char *out, size_t out_max_len,
-    size_t *out_len,
-    const unsigned char *in, size_t in_len,
-    size_t w);
+    size_t *out_len, const unsigned char *in, size_t in_len, size_t w);

 static void kmac_free(void *vmacctx)
 {
@@ -349,7 +340,7 @@ static int kmac_init(void *vmacctx, const unsigned char *key,
         (void)kmac_set_ctx_params(kctx, cparams);
     }

-    if (!bytepad(NULL, &out_len, kmac_string, sizeof(kmac_string),
+    if (!ossl_sp800_185_bytepad(NULL, 0, &out_len, kmac_string, sizeof(kmac_string),
             kctx->custom, kctx->custom_len, block_len)) {
         ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR);
         return 0;
@@ -357,7 +348,7 @@ static int kmac_init(void *vmacctx, const unsigned char *key,
     out = OPENSSL_malloc(out_len);
     if (out == NULL)
         return 0;
-    res = bytepad(out, NULL, kmac_string, sizeof(kmac_string),
+    res = ossl_sp800_185_bytepad(out, out_len, NULL, kmac_string, sizeof(kmac_string),
               kctx->custom, kctx->custom_len, block_len)
         && EVP_DigestUpdate(ctx, out, out_len)
         && EVP_DigestUpdate(ctx, kctx->key, kctx->key_len);
@@ -388,7 +379,7 @@ static int kmac_final(void *vmacctx, unsigned char *out, size_t *outl,
     /* KMAC XOF mode sets the encoded length to 0 */
     lbits = (kctx->xof_mode ? 0 : (kctx->out_len * 8));

-    ok = right_encode(encoded_outlen, sizeof(encoded_outlen), &len, lbits)
+    ok = ossl_sp800_185_right_encode(encoded_outlen, sizeof(encoded_outlen), &len, lbits)
         && EVP_DigestUpdate(ctx, encoded_outlen, len)
         && EVP_DigestFinalXOF(ctx, out, kctx->out_len);
     *outl = kctx->out_len;
@@ -493,7 +484,8 @@ static int kmac_set_ctx_params(void *vmacctx, const OSSL_PARAM *params)
             ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_CUSTOM_LENGTH);
             return 0;
         }
-        if (!encode_string(kctx->custom, sizeof(kctx->custom), &kctx->custom_len,
+        if (!ossl_sp800_185_encode_string(kctx->custom,
+                sizeof(kctx->custom), &kctx->custom_len,
                 p.custom->data, p.custom->data_size))
             return 0;
     }
@@ -501,156 +493,18 @@ static int kmac_set_ctx_params(void *vmacctx, const OSSL_PARAM *params)
     return 1;
 }

-/* Encoding/Padding Methods. */
-
-/* Returns the number of bytes required to store 'bits' into a byte array */
-static unsigned int get_encode_size(size_t bits)
-{
-    unsigned int cnt = 0, sz = sizeof(size_t);
-
-    while (bits && (cnt < sz)) {
-        ++cnt;
-        bits >>= 8;
-    }
-    /* If bits is zero 1 byte is required */
-    if (cnt == 0)
-        cnt = 1;
-    return cnt;
-}
-
-/*
- * Convert an integer into bytes . The number of bytes is appended
- * to the end of the buffer. Returns an array of bytes 'out' of size
- * *out_len.
- *
- * e.g if bits = 32, out[2] = { 0x20, 0x01 }
- */
-static int right_encode(unsigned char *out, size_t out_max_len, size_t *out_len,
-    size_t bits)
-{
-    unsigned int len = get_encode_size(bits);
-    int i;
-
-    if (len >= out_max_len) {
-        ERR_raise(ERR_LIB_PROV, PROV_R_LENGTH_TOO_LARGE);
-        return 0;
-    }
-
-    /* MSB's are at the start of the bytes array */
-    for (i = len - 1; i >= 0; --i) {
-        out[i] = (unsigned char)(bits & 0xFF);
-        bits >>= 8;
-    }
-    /* Tack the length onto the end */
-    out[len] = (unsigned char)len;
-
-    /* The Returned length includes the tacked on byte */
-    *out_len = len + 1;
-    return 1;
-}
-
-/*
- * Encodes a string with a left encoded length added. Note that the
- * in_len is converted to bits (*8).
- *
- * e.g- in="KMAC" gives out[6] = { 0x01, 0x20, 0x4B, 0x4D, 0x41, 0x43 }
- *                                 len   bits    K     M     A     C
- */
-static int encode_string(unsigned char *out, size_t out_max_len, size_t *out_len,
-    const unsigned char *in, size_t in_len)
-{
-    if (in == NULL) {
-        *out_len = 0;
-    } else {
-        size_t i, bits, len, sz;
-
-        bits = 8 * in_len;
-        len = get_encode_size(bits);
-        sz = 1 + len + in_len;
-
-        if (sz > out_max_len) {
-            ERR_raise(ERR_LIB_PROV, PROV_R_LENGTH_TOO_LARGE);
-            return 0;
-        }
-
-        out[0] = (unsigned char)len;
-        for (i = len; i > 0; --i) {
-            out[i] = (bits & 0xFF);
-            bits >>= 8;
-        }
-        memcpy(out + len + 1, in, in_len);
-        *out_len = sz;
-    }
-    return 1;
-}
-
-/*
- * Returns a zero padded encoding of the inputs in1 and an optional
- * in2 (can be NULL). The padded output must be a multiple of the blocksize 'w'.
- * The value of w is in bytes (< 256).
- *
- * The returned output is:
- *    zero_padded(multiple of w, (left_encode(w) || in1 [|| in2])
- */
-static int bytepad(unsigned char *out, size_t *out_len,
-    const unsigned char *in1, size_t in1_len,
-    const unsigned char *in2, size_t in2_len, size_t w)
-{
-    size_t len;
-    unsigned char *p = out;
-    size_t sz = w;
-
-    if (out == NULL) {
-        if (out_len == NULL) {
-            ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER);
-            return 0;
-        }
-        sz = 2 + in1_len + (in2 != NULL ? in2_len : 0);
-        *out_len = (sz + w - 1) / w * w;
-        return 1;
-    }
-
-    if (!ossl_assert(w <= 255))
-        return 0;
-
-    /* Left encoded w */
-    *p++ = 1;
-    *p++ = (unsigned char)w;
-    /* || in1 */
-    memcpy(p, in1, in1_len);
-    p += in1_len;
-    /* [ || in2 ] */
-    if (in2 != NULL && in2_len > 0) {
-        memcpy(p, in2, in2_len);
-        p += in2_len;
-    }
-    /* Figure out the pad size (divisible by w) */
-    len = p - out;
-    sz = (len + w - 1) / w * w;
-    /* zero pad the end of the buffer */
-    if (sz != len)
-        memset(p, 0, sz - len);
-    if (out_len != NULL)
-        *out_len = sz;
-    return 1;
-}
-
 /* Returns out = bytepad(encode_string(in), w) */
 static int kmac_bytepad_encode_key(unsigned char *out, size_t out_max_len,
-    size_t *out_len,
-    const unsigned char *in, size_t in_len,
-    size_t w)
+    size_t *out_len, const unsigned char *in, size_t in_len, size_t w)
 {
     unsigned char tmp[KMAC_MAX_KEY + KMAC_MAX_ENCODED_HEADER_LEN];
     size_t tmp_len;

-    if (!encode_string(tmp, sizeof(tmp), &tmp_len, in, in_len))
-        return 0;
-    if (!bytepad(NULL, out_len, tmp, tmp_len, NULL, 0, w))
+    if (!ossl_sp800_185_encode_string(tmp, sizeof(tmp), &tmp_len, in, in_len))
         return 0;
-    if (!ossl_assert(*out_len <= out_max_len))
+    if (!ossl_sp800_185_bytepad(NULL, out_max_len, out_len, tmp, tmp_len, NULL, 0, w))
         return 0;
-    return bytepad(out, NULL, tmp, tmp_len, NULL, 0, w);
+    return ossl_sp800_185_bytepad(out, out_max_len, NULL, tmp, tmp_len, NULL, 0, w);
 }

 #define IMPLEMENT_KMAC_TABLE(size, funcname, newname)                          \
diff --git a/test/evp_test.c b/test/evp_test.c
index 7ce3be9779..bd7ae80502 100644
--- a/test/evp_test.c
+++ b/test/evp_test.c
@@ -712,6 +712,7 @@ typedef struct digest_data_st {
     int xof;
     /* Size for variable output length but non-XOF */
     size_t digest_size;
+    STACK_OF(OPENSSL_STRING) *controls; /* collection of controls */
 } DIGEST_DATA;

 static int digest_test_init(EVP_TEST *t, const char *alg)
@@ -738,6 +739,7 @@ static int digest_test_init(EVP_TEST *t, const char *alg)
     mdat->fetched_digest = fetched_digest;
     mdat->pad_type = 0;
     mdat->xof = 0;
+    mdat->controls = sk_OPENSSL_STRING_new_null();
     if (fetched_digest != NULL)
         TEST_info("%s is fetched", alg);
     return 1;
@@ -750,6 +752,7 @@ static void digest_test_cleanup(EVP_TEST *t)
     sk_EVP_TEST_BUFFER_pop_free(mdat->input, evp_test_buffer_free);
     OPENSSL_free(mdat->output);
     EVP_MD_free(mdat->fetched_digest);
+    ctrlfree(mdat->controls);
 }

 static int digest_test_parse(EVP_TEST *t,
@@ -778,6 +781,8 @@ static int digest_test_parse(EVP_TEST *t,
         mdata->digest_size = sz;
         return 1;
     }
+    if (strcmp(keyword, "Ctrl") == 0)
+        return ctrladd(mdata->controls, value);
     return 0;
 }

@@ -815,7 +820,9 @@ static int digest_test_run(EVP_TEST *t)
     unsigned int got_len;
     size_t size = 0;
     int xof = 0;
-    OSSL_PARAM params[4], *p = &params[0];
+    OSSL_PARAM params[6], *p = &params[0];
+    size_t params_n = 0, params_allocated_n = 0;
+    const OSSL_PARAM *defined_params = EVP_MD_settable_ctx_params(expected->digest);

     t->err = "TEST_FAILURE";
     if (!TEST_ptr(mctx = EVP_MD_CTX_new()))
@@ -825,6 +832,13 @@ static int digest_test_run(EVP_TEST *t)
     if (!TEST_ptr(got))
         goto err;

+    if (sk_OPENSSL_STRING_num(expected->controls) > 0) {
+        if (!ctrl2params(t, expected->controls, defined_params,
+                params, OSSL_NELEM(params), &params_n))
+            return 0;
+        p = params + params_n;
+    }
+
     if (expected->xof > 0) {
         xof |= 1;
         *p++ = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_XOFLEN,
@@ -907,6 +921,7 @@ static int digest_test_run(EVP_TEST *t)
     }

 err:
+    ctrl2params_free(params, params_n, params_allocated_n);
     OPENSSL_free(got);
     EVP_MD_CTX_free(mctx);
     return 1;
diff --git a/test/evp_xof_test.c b/test/evp_xof_test.c
index 76eb3539dd..c4a87e2835 100644
--- a/test/evp_xof_test.c
+++ b/test/evp_xof_test.c
@@ -13,7 +13,7 @@
 #include "testutil.h"
 #include "internal/nelem.h"

-static const unsigned char shake256_input[] = {
+static const uint8_t shake256_input[] = {
     0x8d, 0x80, 0x01, 0xe2, 0xc0, 0x96, 0xf1, 0xb8,
     0x8e, 0x7c, 0x92, 0x24, 0xa0, 0x86, 0xef, 0xd4,
     0x79, 0x7f, 0xbf, 0x74, 0xa8, 0x03, 0x3a, 0x2d,
@@ -24,7 +24,7 @@ static const unsigned char shake256_input[] = {
  * This KAT output is 250 bytes, which is more than
  * the SHAKE256 block size (136 bytes).
  */
-static const unsigned char shake256_output[] = {
+static const uint8_t shake256_output[] = {
     0x2e, 0x97, 0x5f, 0x6a, 0x8a, 0x14, 0xf0, 0x70,
     0x4d, 0x51, 0xb1, 0x36, 0x67, 0xd8, 0x19, 0x5c,
     0x21, 0x9f, 0x71, 0xe6, 0x34, 0x56, 0x96, 0xc4,
@@ -59,6 +59,52 @@ static const unsigned char shake256_output[] = {
     0x66, 0x6c
 };

+static const uint8_t cshake256_output[] = {
+    0x30, 0xa6, 0x5f, 0xd5, 0xff, 0x3e, 0x49, 0xe8,
+    0xa9, 0xef, 0x06, 0xa3, 0x56, 0x4b, 0x4f, 0x55,
+    0x93, 0x0f, 0x4a, 0x9e, 0xe9, 0x74, 0x13, 0xf8,
+    0x4a, 0x80, 0x44, 0x65, 0xec, 0x62, 0x83, 0x7a,
+    0x21, 0xce, 0x96, 0x0e, 0x27, 0x1f, 0x81, 0x26,
+    0xcb, 0xd8, 0x42, 0x7b, 0x7d, 0x71, 0x6a, 0xdc,
+    0xaf, 0x4d, 0x13, 0x52, 0x28, 0x2b, 0xd9, 0x70,
+    0xfb, 0x90, 0x96, 0xfe, 0x24, 0xd2, 0x22, 0x48,
+    0x73, 0xae, 0x73, 0x1e, 0x10, 0x07, 0x4b, 0x92,
+    0x2a, 0xae, 0x1e, 0x7b, 0x7d, 0x06, 0xe2, 0x0f,
+    0x80, 0x08, 0xc3, 0xa5, 0x09, 0x71, 0x57, 0x84,
+    0x4a, 0xa8, 0x70, 0xe7, 0x61, 0x6b, 0x0c, 0x3c
+};
+
+typedef struct test_data_st {
+    const char *alg;
+    const uint8_t *in;
+    size_t inlen;
+    const uint8_t *out;
+    size_t outlen;
+    int default_xoflen;
+    const char *param_n;
+    const char *param_s;
+} TEST_DATA;
+
+static const TEST_DATA xof_test_data[] = {
+    {
+        "SHAKE256",
+        shake256_input,
+        sizeof(shake256_input),
+        shake256_output,
+        sizeof(shake256_output),
+    },
+    { "CSHAKE256",
+        shake256_input, sizeof(shake256_input),
+        shake256_output, sizeof(shake256_output),
+        64 },
+    { "CSHAKE256",
+        shake256_input, sizeof(shake256_input),
+        cshake256_output, sizeof(cshake256_output),
+        64,
+        "KMAC",
+        "Custom" },
+};
+
 static const unsigned char shake256_largemsg_input[] = {
     0xb2, 0xd2, 0x38, 0x65, 0xaf, 0x8f, 0x25, 0x6e,
     0x64, 0x40, 0xe2, 0x0d, 0x49, 0x8e, 0x3e, 0x64,
@@ -149,51 +195,39 @@ static const unsigned char shake256_largemsg_input[] = {
 };

 static const unsigned char shake256_largemsg_output[] = {
-    0x64,
-    0xea,
-    0x24,
-    0x6a,
-    0xab,
-    0x80,
-    0x37,
-    0x9e,
-    0x08,
-    0xe2,
-    0x19,
-    0x9e,
-    0x09,
-    0x69,
-    0xe2,
-    0xee,
-    0x1a,
-    0x5d,
-    0xd1,
-    0x68,
-    0x68,
-    0xec,
-    0x8d,
-    0x42,
-    0xd0,
-    0xf8,
-    0xb8,
-    0x44,
-    0x74,
-    0x54,
-    0x87,
-    0x3e,
+    0x64, 0xea, 0x24, 0x6a, 0xab, 0x80, 0x37, 0x9e,
+    0x08, 0xe2, 0x19, 0x9e, 0x09, 0x69, 0xe2, 0xee,
+    0x1a, 0x5d, 0xd1, 0x68, 0x68, 0xec, 0x8d, 0x42,
+    0xd0, 0xf8, 0xb8, 0x44, 0x74, 0x54, 0x87, 0x3e
 };

-static EVP_MD_CTX *shake_setup(const char *name)
+static const TEST_DATA large_msg_test_data[] = {
+    {
+        "SHAKE256",
+        shake256_largemsg_input,
+        sizeof(shake256_largemsg_input),
+        shake256_largemsg_output,
+        sizeof(shake256_largemsg_output),
+    },
+};
+
+static EVP_MD_CTX *xof_digest_setup(const TEST_DATA *td)
 {
     EVP_MD_CTX *ctx = NULL;
     EVP_MD *md = NULL;
+    OSSL_PARAM params[3], *p = params;

-    if (!TEST_ptr(md = EVP_MD_fetch(NULL, name, NULL)))
+    if (!TEST_ptr(md = EVP_MD_fetch(NULL, td->alg, NULL)))
         return NULL;

     if (!TEST_ptr(ctx = EVP_MD_CTX_new()))
         goto err;
-    if (!TEST_true(EVP_DigestInit_ex2(ctx, md, NULL)))
+    if (td->param_n != NULL)
+        *p++ = OSSL_PARAM_construct_utf8_string(OSSL_DIGEST_PARAM_FUNCTION_NAME, (char *)td->param_n, 0);
+    if (td->param_s != NULL)
+        *p++ = OSSL_PARAM_construct_utf8_string(OSSL_DIGEST_PARAM_CUSTOMIZATION, (char *)td->param_s, 0);
+    *p = OSSL_PARAM_construct_end();
+    if (!TEST_true(EVP_DigestInit_ex2(ctx, md, params)))
         goto err;
     EVP_MD_free(md);
     return ctx;
@@ -203,23 +237,24 @@ err:
     return NULL;
 }

-static int shake_kat_test(void)
+static int xof_kat_test(int tstid)
 {
+    const TEST_DATA *td = xof_test_data + tstid;
     int ret = 0;
     EVP_MD_CTX *ctx = NULL;
-    unsigned char out[sizeof(shake256_output)];
+    uint8_t out[2048];

-    if (!TEST_ptr(ctx = shake_setup("SHAKE256")))
+    if (!TEST_size_t_le(td->outlen, sizeof(out)))
         return 0;
-    if (!TEST_true(EVP_DigestUpdate(ctx, shake256_input,
-            sizeof(shake256_input)))
-        || !TEST_true(EVP_DigestFinalXOF(ctx, out, sizeof(out)))
-        || !TEST_mem_eq(out, sizeof(out),
-            shake256_output, sizeof(shake256_output))
+    if (!TEST_ptr(ctx = xof_digest_setup(td)))
+        return 0;
+    if (!TEST_true(EVP_DigestUpdate(ctx, td->in, td->inlen))
+        || !TEST_true(EVP_DigestFinalXOF(ctx, out, td->outlen))
+        || !TEST_mem_eq(out, td->outlen, td->out, td->outlen)
         /* Test that a second call to EVP_DigestFinalXOF fails */
-        || !TEST_false(EVP_DigestFinalXOF(ctx, out, sizeof(out)))
+        || !TEST_false(EVP_DigestFinalXOF(ctx, out, td->outlen))
         /* Test that a call to EVP_DigestSqueeze fails */
-        || !TEST_false(EVP_DigestSqueeze(ctx, out, sizeof(out))))
+        || !TEST_false(EVP_DigestSqueeze(ctx, out, td->outlen)))
         goto err;
     ret = 1;
 err:
@@ -227,37 +262,52 @@ err:
     return ret;
 }

-static int shake_kat_digestfinal_test(void)
+static int xof_kat_digestfinal_test(int tstid)
 {
+    const TEST_DATA *td = xof_test_data + tstid;
     int ret = 0;
     unsigned int digest_length = 0;
     EVP_MD_CTX *ctx = NULL;
-    unsigned char out[sizeof(shake256_output)];
+    uint8_t out[2048];

-    /* Test that EVP_DigestFinal without setting XOFLEN fails */
-    if (!TEST_ptr(ctx = shake_setup("SHAKE256")))
+    if (!TEST_size_t_le(td->outlen, sizeof(out)))
         return 0;
-    if (!TEST_true(EVP_DigestUpdate(ctx, shake256_input,
-            sizeof(shake256_input))))
-        return 0;
-    ERR_set_mark();
-    if (!TEST_false(EVP_DigestFinal(ctx, out, &digest_length))) {
-        ERR_clear_last_mark();
+    if (!TEST_ptr(ctx = xof_digest_setup(td)))
         return 0;
+    if (!TEST_true(EVP_DigestUpdate(ctx, td->in, td->inlen)))
+        goto err;
+    if (td->default_xoflen == 0) {
+        /*
+         * Test that EVP_DigestFinal without setting XOFLEN fails for SHAKE
+         * (The original code for SHAKE set the wrong default value which is
+         * why the XOF needs to be set for this).
+         */
+        ERR_set_mark();
+        if (!TEST_false(EVP_DigestFinal(ctx, out, &digest_length))) {
+            ERR_clear_last_mark();
+            goto err;
+        }
+        ERR_pop_to_mark();
+    } else {
+        /*
+         * Test that EVP_DigestFinal without setting XOFLEN passes for CSHAKE
+         * and correctly returns 2 * 256 = 512 bits (64 bytes) by default.
+         */
+        if (!TEST_true(EVP_DigestFinal(ctx, out, &digest_length))
+            || !TEST_uint_eq(digest_length, td->default_xoflen)
+            || !TEST_mem_eq(out, digest_length, td->out, digest_length))
+            goto err;
     }
-    ERR_pop_to_mark();
     EVP_MD_CTX_free(ctx);

-    /* However EVP_DigestFinalXOF must work */
-    if (!TEST_ptr(ctx = shake_setup("SHAKE256")))
-        return 0;
-    if (!TEST_true(EVP_DigestUpdate(ctx, shake256_input,
-            sizeof(shake256_input))))
+    /* EVP_DigestFinalXOF must work */
+    if (!TEST_ptr(ctx = xof_digest_setup(td)))
         return 0;
-    if (!TEST_true(EVP_DigestFinalXOF(ctx, out, sizeof(out)))
-        || !TEST_mem_eq(out, sizeof(out),
-            shake256_output, sizeof(shake256_output))
-        || !TEST_false(EVP_DigestFinalXOF(ctx, out, sizeof(out))))
+    if (!TEST_true(EVP_DigestUpdate(ctx, td->in, td->inlen)))
+        goto err;
+    if (!TEST_true(EVP_DigestFinalXOF(ctx, out, td->outlen))
+        || !TEST_mem_eq(out, td->outlen, td->out, td->outlen)
+        || !TEST_false(EVP_DigestFinalXOF(ctx, out, td->outlen)))
         goto err;
     ret = 1;
 err:
@@ -269,35 +319,37 @@ err:
  * Test that EVP_DigestFinal() returns the output length
  * set by the OSSL_DIGEST_PARAM_XOFLEN param.
  */
-static int shake_kat_digestfinal_xoflen_test(void)
+static int xof_kat_digestfinal_xoflen_test(int tstid)
 {
+    const TEST_DATA *td = xof_test_data + tstid;
     int ret = 0;
     unsigned int digest_length = 0;
     EVP_MD_CTX *ctx = NULL;
     const EVP_MD *md;
-    unsigned char out[sizeof(shake256_output)];
     OSSL_PARAM params[2];
     size_t sz = 12;
+    uint8_t out[2048];

-    if (!TEST_ptr(ctx = shake_setup("SHAKE256")))
+    if (!TEST_size_t_le(td->outlen, sizeof(out)))
         return 0;
+    if (!TEST_ptr(ctx = xof_digest_setup(td)))
+        return 0;
+
     md = EVP_MD_CTX_get0_md(ctx);

-    memset(out, 0, sizeof(out));
+    memset(out, 0, td->outlen);
     params[0] = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_XOFLEN, &sz);
     params[1] = OSSL_PARAM_construct_end();

-    if (!TEST_int_eq(EVP_MD_CTX_size(ctx), -1)
+    if (!TEST_int_eq(EVP_MD_CTX_size(ctx), td->default_xoflen == 0 ? -1 : td->default_xoflen)
         || !TEST_int_eq(EVP_MD_CTX_set_params(ctx, params), 1)
         || !TEST_int_eq(EVP_MD_CTX_size(ctx), (int)sz)
-        || !TEST_int_eq(EVP_MD_get_size(md), 0)
+        || !TEST_int_eq(EVP_MD_get_size(md), td->default_xoflen)
         || !TEST_true(EVP_MD_xof(md))
-        || !TEST_true(EVP_DigestUpdate(ctx, shake256_input,
-            sizeof(shake256_input)))
+        || !TEST_true(EVP_DigestUpdate(ctx, td->in, td->inlen))
         || !TEST_true(EVP_DigestFinal(ctx, out, &digest_length))
         || !TEST_uint_eq(digest_length, (unsigned int)sz)
-        || !TEST_mem_eq(out, digest_length,
-            shake256_output, digest_length)
+        || !TEST_mem_eq(out, digest_length, td->out, digest_length)
         || !TEST_uchar_eq(out[digest_length], 0))
         goto err;
     ret = 1;
@@ -310,15 +362,18 @@ err:
  * Test that multiple absorb calls gives the expected result.
  * This is a nested test that uses multiple strides for the input.
  */
-static int shake_absorb_test(void)
+static int xof_absorb_test(int tstid)
 {
+    const TEST_DATA *td = large_msg_test_data + tstid;
     int ret = 0;
     EVP_MD_CTX *ctx = NULL;
-    unsigned char out[sizeof(shake256_largemsg_output)];
-    size_t total = sizeof(shake256_largemsg_input);
+    unsigned char out[2048];
+    size_t total = td->inlen;
     size_t i, stride, sz;

-    if (!TEST_ptr(ctx = shake_setup("SHAKE256")))
+    if (!TEST_size_t_le(td->outlen, sizeof(out)))
+        return 0;
+    if (!TEST_ptr(ctx = xof_digest_setup(td)))
         return 0;

     for (stride = 1; stride < total; ++stride) {
@@ -327,14 +382,11 @@ static int shake_absorb_test(void)
             sz += stride;
             if ((i + sz) > total)
                 sz = total - i;
-            if (!TEST_true(EVP_DigestUpdate(ctx, shake256_largemsg_input + i,
-                    sz)))
+            if (!TEST_true(EVP_DigestUpdate(ctx, td->in + i, sz)))
                 goto err;
         }
-        if (!TEST_true(EVP_DigestFinalXOF(ctx, out, sizeof(out)))
-            || !TEST_mem_eq(out, sizeof(out),
-                shake256_largemsg_output,
-                sizeof(shake256_largemsg_output)))
+        if (!TEST_true(EVP_DigestFinalXOF(ctx, out, td->outlen))
+            || !TEST_mem_eq(out, td->outlen, td->out, td->outlen))
             goto err;
         if (!TEST_true(EVP_DigestInit_ex2(ctx, NULL, NULL)))
             goto err;
@@ -349,9 +401,11 @@ err:
  * Table containing the size of the output to squeeze for the
  * initially call, followed by a size for each subsequent call.
  */
-static const struct {
+typedef struct stride_test_data_st {
     size_t startsz, incsz;
-} stride_tests[] = {
+} STRIDE_TEST_DATA;
+
+static const STRIDE_TEST_DATA stride_test_data[] = {
     { 1, 1 },
     { 1, 136 },
     { 1, 136 / 2 },
@@ -394,17 +448,18 @@ static const struct {
  * in and inlen represent the input to absorb. expected_out and expected_outlen
  * represent the expected output.
  */
-static int do_shake_squeeze_test(int tst,
-    const unsigned char *in, size_t inlen,
-    const unsigned char *expected_out,
+static int do_xof_squeeze_test(const TEST_DATA *td,
+    const STRIDE_TEST_DATA *stride,
+    const uint8_t *in, size_t inlen,
+    const uint8_t *expected_out,
     size_t expected_outlen)
 {
     int ret = 0;
     EVP_MD_CTX *ctx = NULL;
     unsigned char *out = NULL;
-    size_t i = 0, sz = stride_tests[tst].startsz;
+    size_t i = 0, sz = stride->startsz;

-    if (!TEST_ptr(ctx = shake_setup("SHAKE256")))
+    if (!TEST_ptr(ctx = xof_digest_setup(td)))
         return 0;
     if (!TEST_ptr(out = OPENSSL_malloc(expected_outlen)))
         goto err;
@@ -417,7 +472,7 @@ static int do_shake_squeeze_test(int tst,
         if (!TEST_true(EVP_DigestSqueeze(ctx, out + i, sz)))
             goto err;
         i += sz;
-        sz = stride_tests[tst].incsz;
+        sz = stride->incsz;
     }
     if (!TEST_mem_eq(out, expected_outlen, expected_out, expected_outlen))
         goto err;
@@ -428,10 +483,12 @@ err:
     return ret;
 }

-static int shake_squeeze_kat_test(int tst)
+static int xof_squeeze_kat_test(int tstid)
 {
-    return do_shake_squeeze_test(tst, shake256_input, sizeof(shake256_input),
-        shake256_output, sizeof(shake256_output));
+    const STRIDE_TEST_DATA *sd = stride_test_data + tstid;
+    const TEST_DATA *td = xof_test_data + (tstid % (OSSL_NELEM(xof_test_data)));
+
+    return do_xof_squeeze_test(td, sd, td->in, td->inlen, td->out, td->outlen);
 }

 /*
@@ -440,42 +497,42 @@ static int shake_squeeze_kat_test(int tst)
  * output. Use this to test that multiple squeeze calls
  * on the same input gives the same output.
  */
-static int shake_squeeze_large_test(int tst)
+static int xof_squeeze_large_test(int tstid)
 {
+    const STRIDE_TEST_DATA *sd = stride_test_data + tstid;
+    const TEST_DATA *td = xof_test_data + (tstid % (OSSL_NELEM(xof_test_data)));
     int ret = 0;
     EVP_MD_CTX *ctx = NULL;
     unsigned char msg[16];
     unsigned char out[2000];

     if (!TEST_int_gt(RAND_bytes(msg, sizeof(msg)), 0)
-        || !TEST_ptr(ctx = shake_setup("SHAKE256"))
+        || !TEST_ptr(ctx = xof_digest_setup(td))
         || !TEST_true(EVP_DigestUpdate(ctx, msg, sizeof(msg)))
         || !TEST_true(EVP_DigestFinalXOF(ctx, out, sizeof(out))))
         goto err;

-    ret = do_shake_squeeze_test(tst, msg, sizeof(msg), out, sizeof(out));
+    ret = do_xof_squeeze_test(td, sd, msg, sizeof(msg), out, sizeof(out));
 err:
     EVP_MD_CTX_free(ctx);
     return ret;
 }

-static const size_t dupoffset_tests[] = {
+static const size_t dupoffset_test_data[] = {
     1, 135, 136, 137, 136 * 3 - 1, 136 * 3, 136 * 3 + 1
 };

 /* Helper function to test that EVP_MD_CTX_dup() copies the internal state */
-static int do_shake_squeeze_dup_test(int tst, const char *alg,
-    const unsigned char *in, size_t inlen,
-    const unsigned char *expected_out,
-    size_t expected_outlen)
+static int do_xof_squeeze_dup_test(const TEST_DATA *td, size_t dupoffset,
+    const uint8_t *in, size_t inlen,
+    const uint8_t *expected_out, size_t expected_outlen)
 {
     int ret = 0;
     EVP_MD_CTX *cur, *ctx = NULL, *dupctx = NULL;
     unsigned char *out = NULL;
     size_t i = 0, sz = 10;
-    size_t dupoffset = dupoffset_tests[tst];

-    if (!TEST_ptr(ctx = shake_setup(alg)))
+    if (!TEST_ptr(ctx = xof_digest_setup(td)))
         return 0;
     cur = ctx;
     if (!TEST_ptr(out = OPENSSL_malloc(expected_outlen)))
@@ -507,21 +564,22 @@ err:
 }

 /* Test that the internal state can be copied */
-static int shake_squeeze_dup_test(int tst)
+static int xof_squeeze_dup_test(int tstid)
 {
+    size_t dupoffset = dupoffset_test_data[tstid];
+    const TEST_DATA *td = xof_test_data + (tstid % (OSSL_NELEM(xof_test_data)));
     int ret = 0;
     EVP_MD_CTX *ctx = NULL;
     unsigned char msg[16];
     unsigned char out[1000];
-    const char *alg = "SHAKE128";

     if (!TEST_int_gt(RAND_bytes(msg, sizeof(msg)), 0)
-        || !TEST_ptr(ctx = shake_setup(alg))
+        || !TEST_ptr(ctx = xof_digest_setup(td))
         || !TEST_true(EVP_DigestUpdate(ctx, msg, sizeof(msg)))
         || !TEST_true(EVP_DigestFinalXOF(ctx, out, sizeof(out))))
         goto err;

-    ret = do_shake_squeeze_dup_test(tst, alg, msg, sizeof(msg),
+    ret = do_xof_squeeze_dup_test(td, dupoffset, msg, sizeof(msg),
         out, sizeof(out));
 err:
     EVP_MD_CTX_free(ctx);
@@ -529,30 +587,29 @@ err:
 }

 /* Test that a squeeze without a preceding absorb works */
-static int shake_squeeze_no_absorb_test(void)
+static int xof_squeeze_no_absorb_test(int tstid)
 {
+    const TEST_DATA *td = xof_test_data + tstid;
     int ret = 0;
-    EVP_MD_CTX *ctx = NULL;
+    EVP_MD_CTX *ctx = NULL, *ctx2 = NULL;
     unsigned char out[1000];
     unsigned char out2[1000];
-    const char *alg = "SHAKE128";

-    if (!TEST_ptr(ctx = shake_setup(alg))
-        || !TEST_true(EVP_DigestFinalXOF(ctx, out, sizeof(out))))
-        goto err;
-
-    if (!TEST_true(EVP_DigestInit_ex2(ctx, NULL, NULL))
-        || !TEST_true(EVP_DigestSqueeze(ctx, out2, sizeof(out2) / 2))
-        || !TEST_true(EVP_DigestSqueeze(ctx, out2 + sizeof(out2) / 2,
-            sizeof(out2) / 2)))
-        goto err;
-
-    if (!TEST_mem_eq(out2, sizeof(out2), out, sizeof(out)))
+    memset(out, 0, sizeof(out));
+    memset(out2, 0, sizeof(out2));
+    if (!TEST_ptr(ctx = xof_digest_setup(td))
+        || !TEST_ptr(ctx2 = EVP_MD_CTX_dup(ctx))
+        || !TEST_true(EVP_DigestFinalXOF(ctx, out, sizeof(out)))
+        || !TEST_true(EVP_DigestSqueeze(ctx2, out2, sizeof(out2) / 2))
+        || !TEST_true(EVP_DigestSqueeze(ctx2, out2 + sizeof(out2) / 2,
+            sizeof(out2) / 2))
+        || !TEST_mem_eq(out2, sizeof(out2), out, sizeof(out)))
         goto err;
     ret = 1;

 err:
     EVP_MD_CTX_free(ctx);
+    EVP_MD_CTX_free(ctx2);
     return ret;
 }

@@ -569,14 +626,14 @@ static int xof_fail_test(void)

 int setup_tests(void)
 {
-    ADD_TEST(shake_kat_test);
-    ADD_TEST(shake_kat_digestfinal_test);
-    ADD_TEST(shake_kat_digestfinal_xoflen_test);
-    ADD_TEST(shake_absorb_test);
-    ADD_ALL_TESTS(shake_squeeze_kat_test, OSSL_NELEM(stride_tests));
-    ADD_ALL_TESTS(shake_squeeze_large_test, OSSL_NELEM(stride_tests));
-    ADD_ALL_TESTS(shake_squeeze_dup_test, OSSL_NELEM(dupoffset_tests));
+    ADD_ALL_TESTS(xof_kat_test, OSSL_NELEM(xof_test_data));
+    ADD_ALL_TESTS(xof_kat_digestfinal_test, OSSL_NELEM(xof_test_data));
+    ADD_ALL_TESTS(xof_kat_digestfinal_xoflen_test, OSSL_NELEM(xof_test_data));
+    ADD_ALL_TESTS(xof_squeeze_no_absorb_test, OSSL_NELEM(xof_test_data));
+    ADD_ALL_TESTS(xof_absorb_test, OSSL_NELEM(large_msg_test_data));
+    ADD_ALL_TESTS(xof_squeeze_kat_test, OSSL_NELEM(stride_test_data));
+    ADD_ALL_TESTS(xof_squeeze_large_test, OSSL_NELEM(stride_test_data));
+    ADD_ALL_TESTS(xof_squeeze_dup_test, OSSL_NELEM(dupoffset_test_data));
     ADD_TEST(xof_fail_test);
-    ADD_TEST(shake_squeeze_no_absorb_test);
     return 1;
 }
diff --git a/test/recipes/30-test_evp_data/evpmd_sha.txt b/test/recipes/30-test_evp_data/evpmd_sha.txt
index b3b95ed76b..75393e5472 100644
--- a/test/recipes/30-test_evp_data/evpmd_sha.txt
+++ b/test/recipes/30-test_evp_data/evpmd_sha.txt
@@ -384,7 +384,93 @@ Digest = KECCAK-512
 Input = 4FBDC596508D24A2A0010E140980B809FB9C6D55EC75125891DD985D37665BD80F9BEB6A50207588ABF3CEEE8C77CD8A5AD48A9E0AA074ED388738362496D2FB2C87543BB3349EA64997CE3E7B424EA92D122F57DBB0855A803058437FE08AFB0C8B5E7179B9044BBF4D81A7163B3139E30888B536B0F957EFF99A7162F4CA5AA756A4A982DFADBF31EF255083C4B5C6C1B99A107D7D3AFFFDB89147C2CC4C9A2643F478E5E2D393AEA37B4C7CB4B5E97DADCF16B6B50AAE0F3B549ECE47746DB6CE6F67DD4406CD4E75595D5103D13F9DFA79372924D328F8DD1FCBEB5A8E2E8BF4C76DE08E3FC46AA021F989C49329C7ACAC5A688556D7BCBCB2A5D4BE69D3284E9C40EC4838EE8592120CE20A0B635ECADAA84FD5690509F54F77E35A417C584648BC9839B974E07BFAB0038E90295D0B13902530A830D1C2BDD53F1F9C9FAED43CA4EED0A8DD761BC7EDBDDA28A287C60CD42AF5F9C758E5C7250231C09A582563689AFC65E2B79A7A2B68200667752E9101746F03184E2399E4ED8835CB8E9AE90E296AF220AE234259FE0BD0BCC60F7A4A5FF3F70C5ED4DE9C8C519A10E962F673C82C5E9351786A8A3BFD570031857BD4C87F4FCA31ED4D50E14F2107DA02CB5058700B74EA241A8B41D78461658F1B2B90BFD84A4C2C9D6543861AB3C56451757DCFB9BA60333488DBDD02D601B41AAE317CA7474EB6E6DD
 Output = DEA56BDABBC6D24183CF7BDE1E1F78631B2B0230C76FF2F43075F2FDE77CF052769276CAD98DA62394EC62D77730F5761489585E093EA7315F3592717C485C84

+# Test vectors from https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/cSHAKE_samples.pdf
+FIPSversion = >=4.0.0
+Digest = CSHAKE-128
+Input = 00010203
+Output = C1C36925B6409A04F1B504FCBCA9D82B4017277CB5ED2B2065FC1D3814D5AAF5
+Ctrl = function-name:
+Ctrl = customization:Email Signature
+
+FIPSversion = >=4.0.0
+Digest = CSHAKE-128
+Input = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+Output = C5221D50E4F822D96A2E8881A961420F294B7B24FE3D2094BAED2C6524CC166B
+Ctrl = customization:Email Signature
+
+FIPSversion = >=4.0.0
+Digest = CSHAKE-256
+Input = 00010203
+Output = D008828E2B80AC9D2218FFEE1D070C48B8E4C87BFF32C9699D5B6896EEE0EDD164020E2BE0560858D9C00C037E34A96937C561A74C412BB4C746469527281C8C
+Ctrl = customization:Email Signature
+
+FIPSversion = >=4.0.0
+Digest = CSHAKE-256
+Input = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+Output = 07DC27B11E51FBAC75BC7B3C1D983E8B4B85FB1DEFAF218912AC86430273091727F42B17ED1DF63E8EC118F04B23633C1DFB1574C8FB55CB45DA8E25AFB092BB
+Ctrl = function-name:
+Ctrl = customization:Email Signature
+
+# These are SHAKE test vectors from (i.e where n = s = empty string)
+FIPSversion = >=4.0.0
+Digest = CSHAKE128
+Input = 49d81708d86cd59dea0ac2c1017a9712d6dffb754dde0b57a9023a39fc5f5b6be276fc176f59f6826610428fac3a0e85fcf71011db061b8fcf2bf085ccd45670effb6dc46f4e3f2ed08e981c5935187fc95b86cf46da675096b1cf9591a67842d6301116be93d8288e4d6b70f1b1db8aa5d203b774a21825665b8170351ee86801da91154570eaf80a1564945af7822df8232fd04ea65593a7f2ab1e9e84cf6ad6c494c9ec2d9d27aaad2b8f7e4f33f12a17b422bc2d4724c13ff8a8b62054d1bfb5c33b9c11183cd8df67694300165ca37637b5a781155f1c070d156339a0242374c6723b6584bffb71c02b935455f8cb086392f5e8e8cc2015956d8f19daeb6aca4476b27108387a2ce0dc5591154d0b94ddc090abe8f4363036b821062baffb7fe550ea7dcd30bfd86c84710081e1c9e450475e123c5ec41f98ff0149bbf6405b5207cad1fb2f313d0f2bcee9be3f6ebe623049640d9234ab644a172ab14ba02633a339b5b9bb38226fda5694f7ec63ebbb8238eb8219ec9c429f4bf0353383a72f2d21702f5e3c513499f04852710f33044512edc47a56bad90885e5713851a7efac694b869fa590076e844ff757d95de581c1b3fa3dd8ccd28cad4f8ae173ee1b28f98ee606dca89063fbef0f262b33053f2c854debdc9cd433ab77abb64f445aa9b981761c4761767f3b71c2646c7b0d873baae50bc9f0
+Output = c609be05458f7ab33e7b6b54bc6e8999
+
+FIPSversion = >=4.0.0
+Digest = CSHAKE256
+Input = dc5a100fa16df1583c79722a0d72833d3bf22c109b8889dbd35213c6bfce205813edae3242695cfd9f59b9a1c203c1b72ef1a5423147cb990b5316a85266675894e2644c3f9578cebe451a09e58c53788fe77a9e850943f8a275f830354b0593a762bac55e984db3e0661eca3cb83f67a6fb348e6177f7dee2df40c4322602f094953905681be3954fe44c4c902c8f6bba565a788b38f13411ba76ce0f9f6756a2a2687424c5435a51e62df7a8934b6e141f74c6ccf539e3782d22b5955d3baf1ab2cf7b5c3f74ec2f9447344e937957fd7f0bdfec56d5d25f61cde18c0986e244ecf780d6307e313117256948d4230ebb9ea62bb302cfe80d7dfebabc4a51d7687967ed5b416a139e974c005fff507a96
+Output = 2bac5716803a9cda8f9e84365ab0a681327b5ba34fdedfb1c12e6e807f45284b

+FIPSversion = >=4.0.0
+Digest = CSHAKE256
+Input = dc5a100fa16df1583c79722a0d72833d3bf22c109b8889dbd35213c6bfce205813edae3242695cfd9f59b9a1c203c1b72ef1a5423147cb990b5316a85266675894e2644c3f9578cebe451a09e58c53788fe77a9e850943f8a275f830354b0593a762bac55e984db3e0661eca3cb83f67a6fb348e6177f7dee2df40c4322602f094953905681be3954fe44c4c902c8f6bba565a788b38f13411ba76ce0f9f6756a2a2687424c5435a51e62df7a8934b6e141f74c6ccf539e3782d22b5955d3baf1ab2cf7b5c3f74ec2f9447344e937957fd7f0bdfec56d5d25f61cde18c0986e244ecf780d6307e313117256948d4230ebb9ea62bb302cfe80d7dfebabc4a51d7687967ed5b416a139e974c005fff507a96
+Output = 2bac5716803a9cda8f9e84365ab0a681327b5ba34fdedfb1c12e6e807f45284b
+Ctrl = function-name:
+Ctrl = customization:
+
+# A test from https://github.com/usnistgov/ACVP-Server/blob/master/gen-val/json-files/cSHAKE-128-1.0/internalProjection.json
+# where the encoding of the strings is exactly a multiple of the block size w. i.e. no zero padding is added.
+# The output length was modified to be on a byte boundary.
+FIPSversion = >=4.0.0
+Digest = CSHAKE-128
+Input = EA18
+Ctrl = customization:fmkctMwhBB[<Kta&RJ5r5ToA9N9~Y-,kin8y]xB}kviaDk_kPI^{o#N1|JIF5x.67pR]]fGX)6'=j.{MnLN1M0zf@'|3OzirhSJS9#.i#&rXz1FnM{WgI|g'tk=Ui5*-L4T6cH4k?d.H<Bk/`.dRC#HklD_LeV~mz
+Output = 2EEF41BD1680C16F36AE2B9C004805F7426AC9D4BB6BF7CFC78606A6E6F6F518EB6C0BE768
+
+# Tests from https://github.com/usnistgov/ACVP-Server/blob/master/gen-val/json-files/cSHAKE-128-1.0/internalProjection.json
+# and https://github.com/usnistgov/ACVP-Server/blob/master/gen-val/json-files/cSHAKE-256-1.0/internalProjection.json which have
+# an input length that is a multiple of 8 bits, that have different known function names.
+# Where the output was not a multiple of 8 the last byte has been modified.
+
+FIPSversion = >=4.0.0
+Digest = CSHAKE-128
+Input = CA88F708FA
+Ctrl = function-name:KMAC
+Ctrl = customization:`kiEF`&I))7]yq0?*sKa q)[jP`4R=)lV_9tyvT$kAbH$)1}p].bbeomb.
+Output = BEBB534CCFCCD300F731D2911FB4351D5FCC95AC2509E9ABAE8F9DC51106E28D7F25AE11738334
+
+FIPSversion = >=4.0.0
+Digest = CSHAKE-256
+Input = 13D101DA
+Ctrl = function-name:TupleHash
+Ctrl = customization:q8gN}O&V*VDU4Y.^5J13tG2,1^Lw~C2rw $AB3.SX)=@z
+Output = 43163A57FC1EE8F1C501A2ADD927698CA5A4B52C0D3EF3FD6D91D8D2386765E0AE
+
+FIPSversion = >=4.0.0
+Digest = CSHAKE-256
+Input = D5D7E7517F
+Ctrl = function-name:ParallelHash
+Ctrl = customization:vD-1>T,f.R*V%ZA<NtW0$3UZD[$X%QVQE,H6E;xqYQI4co^F#Sf:CU!dmQkbPRbZ{V1x3,v3{fTPiBvT}[UOk</o*dGrN7@(nm7,^d4v]R>[ OyJ
+Output = 442BE69B2AFD7C8282839920A8446AAF16A5049D3D018EAC87E04CF9225870EFCA6F88DB415829
+
+# Test that uses an unknown function name
+FIPSversion = >=4.0.0
+Digest = CSHAKE-128
+Input = CA88F708FA
+Ctrl = function-name:BadName
+Result = DIGESTINIT_ERROR
+Reason = invalid function name

 Title = Case insensitive digest tests

@@ -395,4 +481,3 @@ Output = A7FFC6F8BF1ED76651C14756A061D662F580FF4DE43B49FA82D80A4B80F8434A
 Digest = shA512
 Input = "abc"
 Output = ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f
-
diff --git a/util/perl/OpenSSL/paramnames.pm b/util/perl/OpenSSL/paramnames.pm
index cea9d2d068..a36f5dbe25 100644
--- a/util/perl/OpenSSL/paramnames.pm
+++ b/util/perl/OpenSSL/paramnames.pm
@@ -172,6 +172,10 @@ my %params = (
     'OSSL_DIGEST_PARAM_SIZE' =>         "size",         # size_t
     'OSSL_DIGEST_PARAM_XOF' =>          "xof",          # int, 0 or 1
     'OSSL_DIGEST_PARAM_ALGID_ABSENT' => "algid-absent", # int, 0 or 1
+    'OSSL_DIGEST_PARAM_FUNCTION_NAME' =>    "function-name", # utf8 string
+    'OSSL_DIGEST_PARAM_CUSTOMIZATION' =>    "customization", # utf8 string
+    'OSSL_DIGEST_PARAM_PROPERTIES' => '*OSSL_ALG_PARAM_PROPERTIES',# utf8 string
+
 # external mu digest parameters
     'OSSL_DIGEST_PARAM_MU_PUB_KEY' =>        "pub",                        # octet string
     'OSSL_DIGEST_PARAM_MU_CONTEXT_STRING' => "context-string",             # octet string