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)
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
### 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.
[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
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 \
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 \
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]=\
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]=\
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
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
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
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
--- /dev/null
+/*
+ * 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;
+}
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.
=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(),
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>
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:
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
=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
=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
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
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.
=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)>
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
=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)>
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
#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
#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;
/*
* 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
#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
/*
* 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
/*
* 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
"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),
* 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,
* 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[] = {
/* 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 }
};
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
--- /dev/null
+/*
+ * 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)
--- /dev/null
+/*
+ * 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'],
+ )); -}
#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
#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[])
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);
}
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 = {
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) \
} 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"
} 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 */
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) \
{ \
if (ctx == NULL) \
return NULL; \
ossl_keccak_init(ctx, pad, bitlen, 2 * bitlen); \
- KMAC_SET_MD(bitlen) \
+ CSHAKE_KECCAK_SET_MD(bitlen) \
return ctx; \
}
#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)
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)
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[];
#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
#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
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)
{
(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;
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);
/* 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;
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;
}
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) \
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)
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;
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,
mdata->digest_size = sz;
return 1;
}
+ if (strcmp(keyword, "Ctrl") == 0)
+ return ctrladd(mdata->controls, value);
return 0;
}
unsigned int got_len;
size_t size = 0;
int xof = 0;
- OSSL_PARAM params[4], *p = ¶ms[0];
+ OSSL_PARAM params[6], *p = ¶ms[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()))
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), ¶ms_n))
+ return 0;
+ p = params + params_n;
+ }
+
if (expected->xof > 0) {
xof |= 1;
*p++ = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_XOFLEN,
}
err:
+ ctrl2params_free(params, params_n, params_allocated_n);
OPENSSL_free(got);
EVP_MD_CTX_free(mctx);
return 1;
#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,
* 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,
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,
};
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;
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:
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:
* 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;
* 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) {
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;
* 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 },
* 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;
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;
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);
}
/*
* 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)))
}
/* 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);
}
/* 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;
}
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;
}
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
Digest = shA512
Input = "abc"
Output = ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f
-
'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