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)
This commit is contained in:
slontis 2025-09-03 17:48:30 +10:00 committed by Tomas Mraz
parent 3fa6bb2333
commit 9c73843141
29 changed files with 1272 additions and 428 deletions

1
.gitignore vendored
View file

@ -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

View file

@ -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

View file

@ -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]=\

View file

@ -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

View file

@ -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

158
crypto/sha/sha3_encode.c Normal file
View file

@ -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;
}

View file

@ -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:

View file

@ -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

View file

@ -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,20 +24,6 @@ provider, and includes the following varieties:
=over 4
=item KECCAK-KMAC-128
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
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".
@ -43,6 +32,28 @@ Known names are "SHAKE-128" and "SHAKE128".
Known names are "SHAKE-256" and "SHAKE256".
=item CSHAKE-128
Known names are "CSHAKE-128" and "CSHAKE128".
=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 CSHAKE-KECCAK-256
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).
=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, to ensure the maximum security strength of 256 bits, the output
length passed to EVP_DigestFinalXOF() should be at least 64.
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.
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.

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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),

View file

@ -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,

View file

@ -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 }
};

View file

@ -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

View file

@ -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)

View file

@ -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'],
)); -}

View file

@ -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)

View file

@ -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[];

View file

@ -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

View file

@ -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))
if (!ossl_sp800_185_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_bytepad(NULL, out_max_len, out_len, tmp, tmp_len, NULL, 0, w))
return 0;
if (!ossl_assert(*out_len <= out_max_len))
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) \

View file

@ -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;

View file

@ -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")))
/* EVP_DigestFinalXOF must work */
if (!TEST_ptr(ctx = xof_digest_setup(td)))
return 0;
if (!TEST_true(EVP_DigestUpdate(ctx, shake256_input,
sizeof(shake256_input))))
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;
}

View file

@ -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

View file

@ -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