From: slontis Date: Wed, 3 Sep 2025 07:48:30 +0000 (+1000) Subject: Add support for CSHAKE. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9c738431411e9f87d144793802b74e5ffd019403;p=thirdparty%2Fopenssl.git 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 Reviewed-by: Norbert Pocs MergeDate: Fri Jan 23 14:07:53 2026 (Merged from https://github.com/openssl/openssl/pull/28432) --- diff --git a/.gitignore b/.gitignore index ba7f69828b0..8cf5c16e430 100644 --- a/.gitignore +++ b/.gitignore @@ -163,6 +163,7 @@ providers/implementations/digests/mdc2_prov.inc providers/implementations/digests/sha2_prov.inc providers/implementations/digests/sha3_prov.inc providers/implementations/digests/ml_dsa_mu_prov.inc +providers/implementations/digests/cshake_prov.inc providers/implementations/include/prov/blake2_params.inc providers/implementations/kdfs/snmpkdf.inc providers/implementations/kdfs/srtpkdf.inc diff --git a/CHANGES.md b/CHANGES.md index 9901b34609c..fbf06a10294 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -32,6 +32,10 @@ OpenSSL 4.0 ### Changes between 3.6 and 4.0 [xx XXX xxxx] + * Added CSHAKE as per [SP 800-185] + + *Shane Lontis* + * Added configure options to disable KDF algorithms for hmac-drbg-kdf, kbkdf, krb5kdf, pvkkdf, snmpkdf, sskdf, sshkdf, x942kdf and x963kdf. @@ -21936,3 +21940,4 @@ ndif [ESV]: https://csrc.nist.gov/Projects/cryptographic-module-validation-program/entropy-validations [SP 800-132]: https://csrc.nist.gov/pubs/sp/800/132/final [SP 800-208]: https://csrc.nist.gov/pubs/sp/800/208/final +[SP 800-185]: https://csrc.nist.gov/pubs/sp/800/185/final diff --git a/build.info b/build.info index d6c4c2ba3ed..5e20a7ed7c4 100644 --- a/build.info +++ b/build.info @@ -120,6 +120,7 @@ DEPEND[]=include/openssl/asn1.h \ providers/implementations/digests/sha2_prov.inc \ providers/implementations/digests/sha3_prov.inc \ providers/implementations/digests/ml_dsa_mu_prov.inc \ + providers/implementations/digests/cshake_prov.inc \ providers/implementations/include/prov/blake2_params.inc \ providers/implementations/macs/cmac_prov.inc \ providers/implementations/macs/gmac_prov.inc \ @@ -242,6 +243,7 @@ DEPEND[providers/implementations/asymciphers/rsa_enc.inc \ providers/implementations/digests/mdc2_prov.inc \ providers/implementations/digests/sha2_prov.inc \ providers/implementations/digests/sha3_prov.inc \ + providers/implementations/digests/cshake_prov.inc \ providers/implementations/include/prov/blake2_params.inc \ providers/implementations/macs/cmac_prov.inc \ providers/implementations/macs/gmac_prov.inc \ @@ -257,6 +259,7 @@ DEPEND[providers/implementations/asymciphers/rsa_enc.inc \ providers/implementations/rands/seed_src_jitter.inc \ providers/implementations/rands/test_rng.inc \ include/openssl/core_names.h]=util/perl|OpenSSL/paramnames.pm + GENERATE[providers/implementations/asymciphers/rsa_enc.inc]=\ providers/implementations/asymciphers/rsa_enc.inc.in GENERATE[providers/implementations/asymciphers/sm2_enc.inc]=\ @@ -405,6 +408,8 @@ GENERATE[providers/implementations/digests/sha2_prov.inc]=\ providers/implementations/digests/sha2_prov.inc.in GENERATE[providers/implementations/digests/sha3_prov.inc]=\ providers/implementations/digests/sha3_prov.inc.in +GENERATE[providers/implementations/digests/cshake_prov.inc]=\ + providers/implementations/digests/cshake_prov.inc.in GENERATE[providers/implementations/include/prov/blake2_params.inc]=\ providers/implementations/include/prov/blake2_params.inc.in GENERATE[providers/implementations/digests/ml_dsa_mu_prov.inc]=\ diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index da6a2e70ecf..b3912877432 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -1073,6 +1073,7 @@ PROV_R_INVALID_DIGEST_LENGTH:166:invalid digest length PROV_R_INVALID_DIGEST_SIZE:218:invalid digest size PROV_R_INVALID_EDDSA_INSTANCE_FOR_ATTEMPTED_OPERATION:243:\ invalid eddsa instance for attempted operation +PROV_R_INVALID_FUNCTION_NAME:256:invalid function name PROV_R_INVALID_INPUT_LENGTH:230:invalid input length PROV_R_INVALID_ITERATION_COUNT:123:invalid iteration count PROV_R_INVALID_IV_LENGTH:109:invalid iv length @@ -1588,23 +1589,6 @@ SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES:362:srtp could not allocate profiles SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG:363:\ srtp protection profile list too long SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE:364:srtp unknown protection profile -SSL_R_TLS_EXT_INVALID_MAX_FRAGMENT_LENGTH:232:\ - ssl3 ext invalid max fragment length -SSL_R_TLS_EXT_INVALID_SERVERNAME:319:ssl3 ext invalid servername -SSL_R_TLS_EXT_INVALID_SERVERNAME_TYPE:320:ssl3 ext invalid servername type -SSL_R_TLS_SESSION_ID_TOO_LONG:300:ssl3 session id too long -SSL_R_TLS_ALERT_BAD_CERTIFICATE:1042:ssl/tls alert bad certificate -SSL_R_TLS_ALERT_BAD_RECORD_MAC:1020:ssl/tls alert bad record mac -SSL_R_TLS_ALERT_CERTIFICATE_EXPIRED:1045:ssl/tls alert certificate expired -SSL_R_TLS_ALERT_CERTIFICATE_REVOKED:1044:ssl/tls alert certificate revoked -SSL_R_TLS_ALERT_CERTIFICATE_UNKNOWN:1046:ssl/tls alert certificate unknown -SSL_R_TLS_ALERT_DECOMPRESSION_FAILURE:1030:ssl/tls alert decompression failure -SSL_R_TLS_ALERT_HANDSHAKE_FAILURE:1040:ssl/tls alert handshake failure -SSL_R_TLS_ALERT_ILLEGAL_PARAMETER:1047:ssl/tls alert illegal parameter -SSL_R_TLS_ALERT_NO_CERTIFICATE:1041:ssl/tls alert no certificate -SSL_R_TLS_ALERT_UNEXPECTED_MESSAGE:1010:ssl/tls alert unexpected message -SSL_R_TLS_ALERT_UNSUPPORTED_CERTIFICATE:1043:\ - ssl/tls alert unsupported certificate SSL_R_SSL_COMMAND_SECTION_EMPTY:117:ssl command section empty SSL_R_SSL_COMMAND_SECTION_NOT_FOUND:125:ssl command section not found SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION:228:ssl ctx has no default ssl version @@ -1649,8 +1633,25 @@ SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE:1113:\ SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE:1111:tlsv1 certificate unobtainable SSL_R_TLSV1_UNRECOGNIZED_NAME:1112:tlsv1 unrecognized name SSL_R_TLSV1_UNSUPPORTED_EXTENSION:1110:tlsv1 unsupported extension +SSL_R_TLS_ALERT_BAD_CERTIFICATE:1042:ssl/tls alert bad certificate +SSL_R_TLS_ALERT_BAD_RECORD_MAC:1020:ssl/tls alert bad record mac +SSL_R_TLS_ALERT_CERTIFICATE_EXPIRED:1045:ssl/tls alert certificate expired +SSL_R_TLS_ALERT_CERTIFICATE_REVOKED:1044:ssl/tls alert certificate revoked +SSL_R_TLS_ALERT_CERTIFICATE_UNKNOWN:1046:ssl/tls alert certificate unknown +SSL_R_TLS_ALERT_DECOMPRESSION_FAILURE:1030:ssl/tls alert decompression failure +SSL_R_TLS_ALERT_HANDSHAKE_FAILURE:1040:ssl/tls alert handshake failure +SSL_R_TLS_ALERT_ILLEGAL_PARAMETER:1047:ssl/tls alert illegal parameter +SSL_R_TLS_ALERT_NO_CERTIFICATE:1041:ssl/tls alert no certificate +SSL_R_TLS_ALERT_UNEXPECTED_MESSAGE:1010:ssl/tls alert unexpected message +SSL_R_TLS_ALERT_UNSUPPORTED_CERTIFICATE:1043:\ + ssl/tls alert unsupported certificate +SSL_R_TLS_EXT_INVALID_MAX_FRAGMENT_LENGTH:232:\ + ssl3 ext invalid max fragment length +SSL_R_TLS_EXT_INVALID_SERVERNAME:319:ssl3 ext invalid servername +SSL_R_TLS_EXT_INVALID_SERVERNAME_TYPE:320:ssl3 ext invalid servername type SSL_R_TLS_ILLEGAL_EXPORTER_LABEL:367:tls illegal exporter label SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST:157:tls invalid ecpointformat list +SSL_R_TLS_SESSION_ID_TOO_LONG:300:ssl3 session id too long SSL_R_TOO_MANY_KEY_UPDATES:132:too many key updates SSL_R_TOO_MANY_WARN_ALERTS:409:too many warn alerts SSL_R_TOO_MUCH_EARLY_DATA:164:too much early data diff --git a/crypto/sha/build.info b/crypto/sha/build.info index c3d927c85af..f495fa7072e 100644 --- a/crypto/sha/build.info +++ b/crypto/sha/build.info @@ -80,7 +80,7 @@ IF[{- !$disabled{asm} -}] ENDIF ENDIF -$COMMON=sha1dgst.c sha256.c sha512.c sha3.c $SHA1ASM $KECCAK1600ASM +$COMMON=sha1dgst.c sha256.c sha512.c sha3.c sha3_encode.c $SHA1ASM $KECCAK1600ASM SOURCE[../../libcrypto]=$COMMON sha1_one.c SOURCE[../../providers/libfips.a]= $COMMON diff --git a/crypto/sha/sha3_encode.c b/crypto/sha/sha3_encode.c new file mode 100644 index 00000000000..a1c042c0918 --- /dev/null +++ b/crypto/sha/sha3_encode.c @@ -0,0 +1,158 @@ +/* + * Copyright 2025 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* including crypto/sha.h requires this for SHA256_CTX */ +#include "internal/deprecated.h" + +/* + * NIST.SP.800-185 Encoding/Padding Methods used for SHA3 derived functions + * e.g. It is used by KMAC and cSHAKE + */ + +#include /* memcpy */ +#include +#include +#include "crypto/sha.h" +#include "internal/common.h" /* ossl_assert */ + +/* Returns the number of bytes required to store 'bits' into a byte array */ +static unsigned int get_encode_size(size_t bits) +{ + unsigned int cnt = 0, sz = sizeof(size_t); + + while (bits && (cnt < sz)) { + ++cnt; + bits >>= 8; + } + /* If bits is zero 1 byte is required */ + if (cnt == 0) + cnt = 1; + return cnt; +} + +/* + * Convert an integer into bytes. The number of bytes is appended + * to the end of the buffer. + * Returns an array of bytes 'out' of size *out_len. + * + * e.g if bits = 32, out[2] = { 0x20, 0x01 } + */ +int ossl_sp800_185_right_encode(unsigned char *out, + size_t out_max_len, size_t *out_len, + size_t bits) +{ + unsigned int len = get_encode_size(bits); + int i; + + if (len >= out_max_len) { + ERR_raise(ERR_LIB_PROV, PROV_R_LENGTH_TOO_LARGE); + return 0; + } + + /* MSB's are at the start of the bytes array */ + for (i = len - 1; i >= 0; --i) { + out[i] = (unsigned char)(bits & 0xFF); + bits >>= 8; + } + /* Tack the length onto the end */ + out[len] = (unsigned char)len; + + /* The Returned length includes the tacked on byte */ + *out_len = len + 1; + return 1; +} + +/* + * Encodes a string with a left encoded length added. Note that the + * in_len is converted to bits (* 8). + * + * e.g- in="KMAC" gives out[6] = { 0x01, 0x20, 0x4B, 0x4D, 0x41, 0x43 } + * len bits K M A C + */ +int ossl_sp800_185_encode_string(unsigned char *out, + size_t out_max_len, size_t *out_len, + const unsigned char *in, size_t in_len) +{ + if (in == NULL) { + *out_len = 0; + } else { + size_t i, bits, len, sz; + + bits = 8 * in_len; + len = get_encode_size(bits); + sz = 1 + len + in_len; + + if (sz > out_max_len) { + ERR_raise(ERR_LIB_PROV, PROV_R_LENGTH_TOO_LARGE); + return 0; + } + + out[0] = (unsigned char)len; + for (i = len; i > 0; --i) { + out[i] = (bits & 0xFF); + bits >>= 8; + } + memcpy(out + len + 1, in, in_len); + *out_len = sz; + } + return 1; +} + +/* + * Returns a zero padded encoding of the inputs in1 and an optional + * in2 (can be NULL). The padded output must be a multiple of the blocksize 'w'. + * The value of w is in bytes (< 256). + * + * The returned output is: + * zero_padded(multiple of w, (left_encode(w) || in1 [|| in2]) + */ +int ossl_sp800_185_bytepad(unsigned char *out, size_t out_len_max, size_t *out_len, + const unsigned char *in1, size_t in1_len, + const unsigned char *in2, size_t in2_len, + size_t w) +{ + size_t len; + unsigned char *p = out; + size_t sz; + + if (!ossl_assert(w <= 255)) + return 0; + sz = (2 + in1_len + (in2 != NULL ? in2_len : 0) + w - 1) / w * w; + if (out_len_max != 0 && sz > out_len_max) + return 0; + + if (out == NULL) { + if (out_len == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + *out_len = sz; + return 1; + } + + /* Left encoded w */ + *p++ = 1; + *p++ = (unsigned char)w; + /* || in1 */ + memcpy(p, in1, in1_len); + p += in1_len; + /* [ || in2 ] */ + if (in2 != NULL && in2_len > 0) { + memcpy(p, in2, in2_len); + p += in2_len; + } + /* Figure out the pad size (divisible by w) */ + len = p - out; + /* zero pad the end of the buffer */ + if (sz != len) + memset(p, 0, sz - len); + if (out_len != NULL) + *out_len = sz; + return 1; +} diff --git a/doc/man3/EVP_DigestInit.pod b/doc/man3/EVP_DigestInit.pod index 7178812f5b0..9c45af3cd61 100644 --- a/doc/man3/EVP_DigestInit.pod +++ b/doc/man3/EVP_DigestInit.pod @@ -150,8 +150,9 @@ Each Message digest algorithm (such as SHA256) produces a fixed size output length which is returned when EVP_DigestFinal_ex() is called. Extendable Output Functions (XOF) such as SHAKE256 have a variable sized output length I 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). +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). Note that EVP_MD_get_size() and EVP_MD_CTX_get_size_ex() behave differently for an XOF. @@ -386,7 +387,7 @@ L) will be considered. =item EVP_MD_xof() Returns 1 if I 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. -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) @@ -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) + +Sets the function name string. +It is used by L. + +=item "customization" (B) + +Sets a customisation string. +It is used by L. + +=item "properties" (B) + +Sets properties to be used when fetching algorithm implementations. + =back EVP_MD_CTX_get_params() can be used with the following OSSL_PARAM keys: diff --git a/doc/man7/EVP_MD-SHA3.pod b/doc/man7/EVP_MD-SHA3.pod index bc5c3508be7..7d7ce614edf 100644 --- a/doc/man7/EVP_MD-SHA3.pod +++ b/doc/man7/EVP_MD-SHA3.pod @@ -30,9 +30,18 @@ default provider, and includes the following varieties: This implementation supports the common gettable parameters described in L. +=head1 CONFORMING TO + +=over 4 + +=item FIPS 202 + +=back + =head1 SEE ALSO -L, L, L +L, L, L, +L =head1 COPYRIGHT diff --git a/doc/man7/EVP_MD-SHAKE.pod b/doc/man7/EVP_MD-SHAKE.pod index 343349d92ee..352f7751dca 100644 --- a/doc/man7/EVP_MD-SHAKE.pod +++ b/doc/man7/EVP_MD-SHAKE.pod @@ -2,17 +2,20 @@ =head1 NAME -EVP_MD-SHAKE, EVP_MD-KECCAK-KMAC +EVP_MD-SHAKE, EVP_MD-CSHAKE, EVP_MD-CSHAKE-KECCAK, - The SHAKE / KECCAK family EVP_MD implementations =head1 DESCRIPTION -Support for computing SHAKE or KECCAK-KMAC digests through the +Support for computing SHAKE, CSHAKE or CSHAKE-KECCAK digests through the B API. -KECCAK-KMAC is an Extendable Output Function (XOF), with a definition -similar to SHAKE, used by the KMAC EVP_MAC implementation (see -L). +CSHAKE is an Extendable Output Function (XOF), that allows custom strings +"n" and "s". If these strings are both empty then it is identical to SHAKE, +otherwise it uses CSHAKE-KECCAK. + +CSHAKE-KECCAK is an Extendable Output Function (XOF), with a definition +similar to SHAKE but appends 2 extra zero bits. It is used internally by CSHAKE. =head2 Identities @@ -21,28 +24,36 @@ provider, and includes the following varieties: =over 4 -=item KECCAK-KMAC-128 +=item SHAKE-128 + +Known names are "SHAKE-128" and "SHAKE128". + +=item SHAKE-256 + +Known names are "SHAKE-256" and "SHAKE256". + +=item CSHAKE-128 + +Known names are "CSHAKE-128" and "CSHAKE128". -Known names are "KECCAK-KMAC-128" and "KECCAK-KMAC128". This is used +=item CSHAKE-256 + +Known names are "CSHAKE-256" and "CSHAKE256". + +=item CSHAKE-KECCAK-128 + +Other known names are "KECCAK-KMAC-128" and "KECCAK-KMAC128". This is used by L. Using the notation from NIST FIPS 202 (Section 6.2), we have S = S (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. Using the notation from NIST FIPS 202 (Section 6.2), we have S = S (see the description of KMAC256 in Appendix A of NIST SP 800-185). -=item SHAKE-128 - -Known names are "SHAKE-128" and "SHAKE128". - -=item SHAKE-256 - -Known names are "SHAKE-256" and "SHAKE256". - =back =head2 Parameters @@ -59,26 +70,62 @@ The length of the "xoflen" parameter should not exceed that of a B. 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) An alias of "xoflen". +=item "function-name" (B) + +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) + +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) + +An optional property used internally by CSHAKE when fetching either +SHAKE or KECCAK algorithms. + =back See L for further information related to parameters =head1 NOTES -For SHAKE-128, to ensure the maximum security strength of 128 bits, the output -length passed to EVP_DigestFinalXOF() should be at least 32. +For SHAKE-128 and CSHAKE-128, to ensure the maximum security strength of +128 bits, the output length passed to EVP_DigestFinalXOF() should be at least 32. + +For SHAKE-256 and CSHAKE-256, to ensure the maximum security strength of +256 bits, the output length passed to EVP_DigestFinalXOF() should be at least 64. -For SHAKE-256, to ensure the maximum security strength of 256 bits, the output -length passed to EVP_DigestFinalXOF() should be at least 64. +The SHA3 specification allows bit strings to be used, but OpenSSL only allows +byte strings for inputs, and outputs. + +=head1 CONFORMING TO + +=over 4 + +=item FIPS 202 (SHA3 and SHAKE) + +=item SP800-185 Section 3 cSHAKE + +=item SP800-185 Section 4 KMAC + +=back =head1 SEE ALSO @@ -89,6 +136,8 @@ L, L, L Since OpenSSL 3.4 the SHAKE-128 and SHAKE-256 implementations have no default digest length. +CSHAKE-128 and CSHAKE-256 were added in OpenSSL 4.0 + =head1 COPYRIGHT Copyright 2020-2024 The OpenSSL Project Authors. All Rights Reserved. diff --git a/doc/man7/OSSL_PROVIDER-FIPS.pod b/doc/man7/OSSL_PROVIDER-FIPS.pod index 70fc2c597ee..befc9ad3c49 100644 --- a/doc/man7/OSSL_PROVIDER-FIPS.pod +++ b/doc/man7/OSSL_PROVIDER-FIPS.pod @@ -69,9 +69,11 @@ The OpenSSL FIPS provider supports these operations and algorithms: =item SHAKE, see L -=item KECCAK-KMAC, see L +=item CSHAKE, see L -KECCAK-KMAC is only used internally as a sub algorithm of KMAC. +=item CSHAKE-KECCAK, see L + +It is used internally as a sub algorithm of CSHAKE. =item ML-DSA-MU, see L @@ -612,6 +614,8 @@ L The HKDF-SHA256, HKDF-SHA384 and HKDF-SHA512 algorithms were added in OpenSSL 3.6. +The CSHAKE-128 and CSHAKE-256 algorithms were added in OpenSSL 4.0. + All other functionality was added in OpenSSL 3.0. =head1 COPYRIGHT diff --git a/doc/man7/OSSL_PROVIDER-default.pod b/doc/man7/OSSL_PROVIDER-default.pod index 207a46ce1e8..d49502b5fdb 100644 --- a/doc/man7/OSSL_PROVIDER-default.pod +++ b/doc/man7/OSSL_PROVIDER-default.pod @@ -59,10 +59,12 @@ The OpenSSL default provider supports these operations and algorithms: =item KECCAK, see L -=item KECCAK-KMAC, see L - =item SHAKE, see L +=item CSHAKE, see L + +=item CSHAKE-KECCAK, see L + =item BLAKE2, see L =item SM3, see L @@ -540,6 +542,8 @@ The RIPEMD160 digest was added to the default provider in OpenSSL 3.0.7. The HKDF-SHA256, HKDF-SHA384 and HKDF-SHA512 algorithms were added in OpenSSL 3.6. +The CSHAKE-128 and CSHAKE-256 algorithms were added in OpenSSL 4.0. + All other functionality was added in OpenSSL 3.0. =head1 COPYRIGHT diff --git a/include/crypto/sha.h b/include/crypto/sha.h index fed23f1a667..27112997bfd 100644 --- a/include/crypto/sha.h +++ b/include/crypto/sha.h @@ -14,10 +14,25 @@ #include +#ifndef OPENSSL_NO_DEPRECATED_3_0 +/* This is inside a deprecated block because SHA256_CTX was marked deprecated */ int ossl_sha256_192_init(SHA256_CTX *c); int sha512_224_init(SHA512_CTX *); int sha512_256_init(SHA512_CTX *); int ossl_sha1_ctrl(SHA_CTX *ctx, int cmd, int mslen, void *ms); +#endif + unsigned char *ossl_sha1(const unsigned char *d, size_t n, unsigned char *md); +int ossl_sp800_185_right_encode(unsigned char *out, + size_t out_max_len, size_t *out_len, + size_t bits); +int ossl_sp800_185_encode_string(unsigned char *out, + size_t out_max_len, size_t *out_len, + const unsigned char *in, size_t in_len); +int ossl_sp800_185_bytepad(unsigned char *out, size_t out_len_max, size_t *out_len, + const unsigned char *in1, size_t in1_len, + const unsigned char *in2, size_t in2_len, + size_t w); + #endif diff --git a/include/internal/sha3.h b/include/internal/sha3.h index d67aa1e19f5..d52780a660f 100644 --- a/include/internal/sha3.h +++ b/include/internal/sha3.h @@ -17,7 +17,7 @@ #define KECCAK1600_WIDTH 1600 #define SHA3_MDSIZE(bitlen) (bitlen / 8) -#define KMAC_MDSIZE(bitlen) 2 * (bitlen / 8) +#define CSHAKE_KECCAK_MDSIZE(bitlen) 2 * (bitlen / 8) #define SHA3_BLOCKSIZE(bitlen) (KECCAK1600_WIDTH - bitlen * 2) / 8 typedef struct keccak_st KECCAK1600_CTX; diff --git a/include/openssl/proverr.h b/include/openssl/proverr.h index e27048faed2..82e1e0fc658 100644 --- a/include/openssl/proverr.h +++ b/include/openssl/proverr.h @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -65,6 +65,7 @@ #define PROV_R_INVALID_DIGEST_LENGTH 166 #define PROV_R_INVALID_DIGEST_SIZE 218 #define PROV_R_INVALID_EDDSA_INSTANCE_FOR_ATTEMPTED_OPERATION 243 +#define PROV_R_INVALID_FUNCTION_NAME 256 #define PROV_R_INVALID_INPUT_LENGTH 230 #define PROV_R_INVALID_ITERATION_COUNT 123 #define PROV_R_INVALID_IV_LENGTH 109 diff --git a/providers/common/include/prov/proverr.h b/providers/common/include/prov/proverr.h index a2829caed0f..573bb212eb1 100644 --- a/providers/common/include/prov/proverr.h +++ b/providers/common/include/prov/proverr.h @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 2020-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2020-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy diff --git a/providers/common/provider_err.c b/providers/common/provider_err.c index f8fb4c16792..ed72958abf6 100644 --- a/providers/common/provider_err.c +++ b/providers/common/provider_err.c @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2026 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -93,6 +93,8 @@ static const ERR_STRING_DATA PROV_str_reasons[] = { "invalid digest size" }, { ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_EDDSA_INSTANCE_FOR_ATTEMPTED_OPERATION), "invalid eddsa instance for attempted operation" }, + { ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_FUNCTION_NAME), + "invalid function name" }, { ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_INPUT_LENGTH), "invalid input length" }, { ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_ITERATION_COUNT), diff --git a/providers/defltprov.c b/providers/defltprov.c index 87c53ca761f..6cc6d4bdc6d 100644 --- a/providers/defltprov.c +++ b/providers/defltprov.c @@ -124,15 +124,18 @@ static const OSSL_ALGORITHM deflt_digests[] = { * KECCAK-KMAC-128 and KECCAK-KMAC-256 as hashes are mostly useful for * the KMAC-128 and KMAC-256. */ - { PROV_NAMES_KECCAK_KMAC_128, "provider=default", - ossl_keccak_kmac_128_functions }, - { PROV_NAMES_KECCAK_KMAC_256, "provider=default", - ossl_keccak_kmac_256_functions }, + { PROV_NAMES_CSHAKE_KECCAK_128, "provider=default", + ossl_cshake_keccak_128_functions }, + { PROV_NAMES_CSHAKE_KECCAK_256, "provider=default", + ossl_cshake_keccak_256_functions }, /* Our primary name:NIST name */ { PROV_NAMES_SHAKE_128, "provider=default", ossl_shake_128_functions }, { PROV_NAMES_SHAKE_256, "provider=default", ossl_shake_256_functions }, + { PROV_NAMES_CSHAKE_128, "provider=default", ossl_cshake_128_functions }, + { PROV_NAMES_CSHAKE_256, "provider=default", ossl_cshake_256_functions }, + #ifndef OPENSSL_NO_BLAKE2 /* * https://blake2.net/ doesn't specify size variants, diff --git a/providers/fips/fipsprov.c b/providers/fips/fipsprov.c index f321990b622..924cb613a76 100644 --- a/providers/fips/fipsprov.c +++ b/providers/fips/fipsprov.c @@ -281,23 +281,25 @@ static int fips_self_test(void *provctx) * we have used historically. */ -#define FIPS_DIGESTS_COMMON() \ - { PROV_NAMES_SHA1, FIPS_DEFAULT_PROPERTIES, ossl_sha1_functions }, \ - { PROV_NAMES_SHA2_224, FIPS_DEFAULT_PROPERTIES, ossl_sha224_functions }, \ - { PROV_NAMES_SHA2_256, FIPS_DEFAULT_PROPERTIES, ossl_sha256_functions }, \ - { PROV_NAMES_SHA2_384, FIPS_DEFAULT_PROPERTIES, ossl_sha384_functions }, \ - { PROV_NAMES_SHA2_512, FIPS_DEFAULT_PROPERTIES, ossl_sha512_functions }, \ - { PROV_NAMES_SHA2_512_224, FIPS_DEFAULT_PROPERTIES, \ - ossl_sha512_224_functions }, \ - { PROV_NAMES_SHA2_512_256, FIPS_DEFAULT_PROPERTIES, \ - ossl_sha512_256_functions }, \ - { PROV_NAMES_SHA3_224, FIPS_DEFAULT_PROPERTIES, ossl_sha3_224_functions }, \ - { PROV_NAMES_SHA3_256, FIPS_DEFAULT_PROPERTIES, ossl_sha3_256_functions }, \ - { PROV_NAMES_SHA3_384, FIPS_DEFAULT_PROPERTIES, ossl_sha3_384_functions }, \ - { PROV_NAMES_SHA3_512, FIPS_DEFAULT_PROPERTIES, ossl_sha3_512_functions }, \ - { PROV_NAMES_SHAKE_128, FIPS_DEFAULT_PROPERTIES, ossl_shake_128_functions }, \ - { \ - PROV_NAMES_SHAKE_256, FIPS_DEFAULT_PROPERTIES, ossl_shake_256_functions \ +#define FIPS_DIGESTS_COMMON() \ + { PROV_NAMES_SHA1, FIPS_DEFAULT_PROPERTIES, ossl_sha1_functions }, \ + { PROV_NAMES_SHA2_224, FIPS_DEFAULT_PROPERTIES, ossl_sha224_functions }, \ + { PROV_NAMES_SHA2_256, FIPS_DEFAULT_PROPERTIES, ossl_sha256_functions }, \ + { PROV_NAMES_SHA2_384, FIPS_DEFAULT_PROPERTIES, ossl_sha384_functions }, \ + { PROV_NAMES_SHA2_512, FIPS_DEFAULT_PROPERTIES, ossl_sha512_functions }, \ + { PROV_NAMES_SHA2_512_224, FIPS_DEFAULT_PROPERTIES, \ + ossl_sha512_224_functions }, \ + { PROV_NAMES_SHA2_512_256, FIPS_DEFAULT_PROPERTIES, \ + ossl_sha512_256_functions }, \ + { PROV_NAMES_SHA3_224, FIPS_DEFAULT_PROPERTIES, ossl_sha3_224_functions }, \ + { PROV_NAMES_SHA3_256, FIPS_DEFAULT_PROPERTIES, ossl_sha3_256_functions }, \ + { PROV_NAMES_SHA3_384, FIPS_DEFAULT_PROPERTIES, ossl_sha3_384_functions }, \ + { PROV_NAMES_SHA3_512, FIPS_DEFAULT_PROPERTIES, ossl_sha3_512_functions }, \ + { PROV_NAMES_SHAKE_128, FIPS_DEFAULT_PROPERTIES, ossl_shake_128_functions }, \ + { PROV_NAMES_SHAKE_256, FIPS_DEFAULT_PROPERTIES, ossl_shake_256_functions }, \ + { PROV_NAMES_CSHAKE_128, FIPS_DEFAULT_PROPERTIES, ossl_cshake_128_functions }, \ + { \ + PROV_NAMES_CSHAKE_256, FIPS_DEFAULT_PROPERTIES, ossl_cshake_256_functions \ } static const OSSL_ALGORITHM fips_digests[] = { @@ -312,14 +314,10 @@ static const OSSL_ALGORITHM fips_digests_internal[] = { /* Used by LMS/HSS */ { PROV_NAMES_SHA2_256_192, FIPS_DEFAULT_PROPERTIES, ossl_sha256_192_internal_functions }, - /* - * KECCAK-KMAC-128 and KECCAK-KMAC-256 as hashes are mostly useful for - * KMAC128 and KMAC256. - */ - { PROV_NAMES_KECCAK_KMAC_128, FIPS_DEFAULT_PROPERTIES, - ossl_keccak_kmac_128_functions }, - { PROV_NAMES_KECCAK_KMAC_256, FIPS_DEFAULT_PROPERTIES, - ossl_keccak_kmac_256_functions }, + { PROV_NAMES_CSHAKE_KECCAK_128, FIPS_DEFAULT_PROPERTIES, + ossl_cshake_keccak_128_functions }, + { PROV_NAMES_CSHAKE_KECCAK_256, FIPS_DEFAULT_PROPERTIES, + ossl_cshake_keccak_256_functions }, { NULL, NULL, NULL } }; diff --git a/providers/implementations/digests/build.info b/providers/implementations/digests/build.info index ceaac9816df..8da0e80829a 100644 --- a/providers/implementations/digests/build.info +++ b/providers/implementations/digests/build.info @@ -26,7 +26,7 @@ ENDIF SOURCE[$COMMON_GOAL]=digestcommon.c SOURCE[$SHA2_GOAL]=sha2_prov.c -SOURCE[$SHA3_GOAL]=sha3_prov.c +SOURCE[$SHA3_GOAL]=sha3_prov.c cshake_prov.c SOURCE[$NULL_GOAL]=null_prov.c diff --git a/providers/implementations/digests/cshake_prov.c b/providers/implementations/digests/cshake_prov.c new file mode 100644 index 00000000000..b6a1e4daf7f --- /dev/null +++ b/providers/implementations/digests/cshake_prov.c @@ -0,0 +1,503 @@ +/* + * Copyright 2025-2026 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* including crypto/sha.h requires this for SHA256_CTX */ +#include "internal/deprecated.h" +/* + * NOTE: By default CSHAKE sets secure xof lengths (OSSL_DIGEST_PARAM_XOFLEN) + * that are used by EVP_DigestFinal_ex(). This differs from SHAKE where the + * xof length MUST be set (since the initial implementation shipped with BAD + * defaults - and the only safe way to fix it was to make the user set the value) + */ +#include +#include +#include +#include +#include +#include "crypto/sha.h" +#include "prov/provider_ctx.h" +#include "prov/digestcommon.h" +#include "prov/implementations.h" +#include "internal/common.h" +#include "internal/sha3.h" +#include "providers/implementations/digests/cshake_prov.inc" + +/* + * Length encoding will be a 1 byte size + length in bits (3 bytes max) + * This gives a range of 0..0XFFFFFF bits = 2097151 bytes). + */ +#define CSHAKE_MAX_ENCODED_HEADER_LEN (1 + 3) + +/* + * Restrict the maximum length of the custom strings N & S. + * This must not exceed 64 bits = 8k bytes. + */ +#define CSHAKE_MAX_STRING 512 + +/* Maximum size of both the encoded strings (N and S) */ +#define CSHAKE_MAX_ENCODED_STRING (CSHAKE_MAX_STRING + CSHAKE_MAX_ENCODED_HEADER_LEN) +#define CSHAKE_FLAGS (PROV_DIGEST_FLAG_XOF | PROV_DIGEST_FLAG_ALGID_ABSENT) + +typedef struct cshake_ctx_st { + OSSL_LIB_CTX *libctx; + char *propq; + EVP_MD_CTX *mdctx; + EVP_MD *md; + const uint8_t *func; /* encoded N */ + uint8_t custom[CSHAKE_MAX_ENCODED_STRING]; /* encoded S */ + size_t funclen; + size_t customlen; + size_t bitlen; + size_t xoflen; + int inited; +} CSHAKE_CTX; + +static OSSL_FUNC_digest_freectx_fn cshake_freectx; +static OSSL_FUNC_digest_dupctx_fn cshake_dupctx; +static OSSL_FUNC_digest_init_fn cshake_init; +static OSSL_FUNC_digest_update_fn cshake_update; +static OSSL_FUNC_digest_final_fn cshake_final; +static OSSL_FUNC_digest_squeeze_fn cshake_squeeze; +static OSSL_FUNC_digest_set_ctx_params_fn cshake_set_ctx_params; +static OSSL_FUNC_digest_settable_ctx_params_fn cshake_settable_ctx_params; +static OSSL_FUNC_digest_get_ctx_params_fn cshake_get_ctx_params; +static OSSL_FUNC_digest_gettable_ctx_params_fn cshake_gettable_ctx_params; + +typedef struct name_encode_map_st { + const char *name; + const uint8_t *encoding; + size_t encodinglen; +} NAME_ENCODE_MAP; + +/* Fixed value of encode_string("") */ +static const unsigned char empty_encoded_string[] = { + 0x01, 0x00 +}; + +/* Fixed value of encode_string("KMAC") */ +static const unsigned char kmac_encoded_string[] = { + 0x01, 0x20, 0x4B, 0x4D, 0x41, 0x43 +}; + +/* Fixed value of encode_string("TupleHash") */ +static const unsigned char tuplehash_encoded_string[] = { + 0x01, 0x48, 0x54, 0x75, 0x70, 0x6C, 0x65, 0x48, 0x61, 0x73, 0x68 +}; + +/* Fixed value of encode_string("ParallelHash") */ +static const unsigned char parallelhash_encoded_string[] = { + 0x01, 0x60, 0x50, 0x61, 0x72, 0x61, 0x6C, 0x6C, 0x65, 0x6C, 0x48, 0x61, 0x73, 0x68 +}; + +static int cshake_set_func_encode_string(const char *in, + const uint8_t **out, size_t *outlen) +{ + /* + * A list of valid function names to encoded string mappings + * See NIST SP800-185 Section 3.4 + */ + static NAME_ENCODE_MAP functionNameMap[] = { + { "", empty_encoded_string, sizeof(empty_encoded_string) }, + { "KMAC", kmac_encoded_string, sizeof(kmac_encoded_string) }, + { "TupleHash", tuplehash_encoded_string, sizeof(tuplehash_encoded_string) }, + { "ParallelHash", parallelhash_encoded_string, sizeof(parallelhash_encoded_string) }, + { NULL, NULL, 0 } + }; + + *out = NULL; + *outlen = 0; + /* + * Don't encode an empty string here - this is done manually later only when + * one of the strings is not empty. If both are empty then we don't want it + * to encode at all. + */ + if (in == NULL || in[0] == 0) + return 1; + for (int i = 1; functionNameMap[i].name != NULL; ++i) { + if (functionNameMap[i].name[0] == in[0]) { + if (OPENSSL_strcasecmp(functionNameMap[i].name, in) == 0) { + *out = functionNameMap[i].encoding; + *outlen = functionNameMap[i].encodinglen; + return 1; + } + return 0; /* Name does not match a known name */ + } + } + return 0; /* Name not found */ +} + +static int cshake_set_encode_string(const char *in, + uint8_t *out, size_t outmax, size_t *outlen) +{ + size_t inlen; + + if (*outlen != 0) + OPENSSL_cleanse(out, outmax); + *outlen = 0; + if (in == NULL) + return 1; + + inlen = strlen(in); + /* + * Don't encode an empty string here - this is done manually later only when + * one of the strings is not empty. If both are empty then we don't want it + * to encode at all. + */ + if (inlen == 0) + return 1; + if (inlen >= CSHAKE_MAX_STRING) + return 0; + return ossl_sp800_185_encode_string(out, outmax, outlen, + (const unsigned char *)in, inlen); +} + +/* + * Set the xof length, note that if the digest has not been fetched yet then + * it is just set into a variable and deferred to later. + */ +static int cshake_set_xoflen(CSHAKE_CTX *ctx, size_t xoflen) +{ + OSSL_PARAM params[2]; + + params[0] = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_XOFLEN, &xoflen); + params[1] = OSSL_PARAM_construct_end(); + + ctx->xoflen = xoflen; + if (ctx->md != NULL) + return EVP_MD_CTX_set_params(ctx->mdctx, params); + return 1; +} + +/* + * Fetch a digest for SHAKE or KECCAK, set its xof len and init it + * into an mdctx. + */ +static int cshake_set_shake_mode(CSHAKE_CTX *ctx, int shake) +{ + OSSL_PARAM params[2]; + const char *name; + + if (shake) + name = (ctx->bitlen == 128 ? "SHAKE128" : "SHAKE256"); + else + name = (ctx->bitlen == 128 ? "CSHAKE-KECCAK-128" : "CSHAKE-KECCAK-256"); + + if (ctx->md == NULL || !EVP_MD_is_a(ctx->md, name)) { + ctx->md = EVP_MD_fetch(ctx->libctx, name, ctx->propq); + if (ctx->md == NULL) + return 0; + } + params[0] = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_XOFLEN, + &ctx->xoflen); + params[1] = OSSL_PARAM_construct_end(); + return EVP_DigestInit_ex2(ctx->mdctx, ctx->md, params); +} + +static void *cshake_newctx(void *provctx, size_t bitlen) +{ + CSHAKE_CTX *ctx; + + if (ossl_unlikely(!ossl_prov_is_running())) + return NULL; + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx != NULL) { + ctx->mdctx = EVP_MD_CTX_create(); + if (ctx->mdctx == NULL) { + OPENSSL_free(ctx); + return NULL; + } + ctx->bitlen = bitlen; + ctx->libctx = PROV_LIBCTX_OF(provctx); + } + return ctx; +} + +static void cshake_freectx(void *vctx) +{ + CSHAKE_CTX *ctx = (CSHAKE_CTX *)vctx; + + EVP_MD_free(ctx->md); + EVP_MD_CTX_destroy(ctx->mdctx); + OPENSSL_clear_free(ctx, sizeof(*ctx)); +} + +static void *cshake_dupctx(void *ctx) +{ + CSHAKE_CTX *src = (CSHAKE_CTX *)ctx; + CSHAKE_CTX *ret = ossl_prov_is_running() ? OPENSSL_malloc(sizeof(*ret)) + : NULL; + + if (ret != NULL) { + *ret = *src; + ret->md = NULL; + ret->mdctx = NULL; + ret->propq = NULL; + + if (src->md != NULL && !EVP_MD_up_ref(src->md)) + goto err; + ret->md = src->md; + + if (src->mdctx != NULL) { + ret->mdctx = EVP_MD_CTX_new(); + if (ret->mdctx == NULL + || !EVP_MD_CTX_copy_ex(ret->mdctx, src->mdctx)) + goto err; + } + if (src->propq != NULL) { + ret->propq = OPENSSL_strdup(src->propq); + if (ret->propq == NULL) + goto err; + } + } + return ret; +err: + cshake_freectx(ret); + return NULL; +} + +static int cshake_init(void *vctx, const OSSL_PARAM params[]) +{ + CSHAKE_CTX *ctx = (CSHAKE_CTX *)vctx; + + if (ossl_unlikely(!ossl_prov_is_running())) + return 0; + ctx->inited = 0; + ctx->xoflen = (ctx->bitlen == 128) ? 32 : 64; /* Set default values here */ + cshake_set_func_encode_string(NULL, &ctx->func, &ctx->funclen); + cshake_set_encode_string(NULL, ctx->custom, sizeof(ctx->custom), &ctx->customlen); + return cshake_set_ctx_params(vctx, params); +} + +static const OSSL_PARAM *cshake_settable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + return cshake_set_ctx_params_list; +} + +static int set_property_query(CSHAKE_CTX *ctx, const char *propq) +{ + OPENSSL_free(ctx->propq); + ctx->propq = NULL; + if (propq != NULL) { + ctx->propq = OPENSSL_strdup(propq); + if (ctx->propq == NULL) + return 0; + } + return 1; +} + +static int cshake_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + CSHAKE_CTX *ctx = (CSHAKE_CTX *)vctx; + struct cshake_set_ctx_params_st p; + + if (ctx == NULL || !cshake_set_ctx_params_decoder(params, &p)) + return 0; + + if (p.xoflen != NULL) { + size_t xoflen; + + if (!OSSL_PARAM_get_size_t(p.xoflen, &xoflen) + || !cshake_set_xoflen(ctx, xoflen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + } + if (p.func != NULL) { + if (p.func->data_type != OSSL_PARAM_UTF8_STRING) + return 0; + if (!cshake_set_func_encode_string(p.func->data, &ctx->func, &ctx->funclen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_FUNCTION_NAME); + return 0; + } + } + if (p.custom != NULL) { + if (p.custom->data_type != OSSL_PARAM_UTF8_STRING) + return 0; + if (!cshake_set_encode_string(p.custom->data, ctx->custom, sizeof(ctx->custom), &ctx->customlen)) + return 0; + } + if (p.propq != NULL) { + if (p.propq->data_type != OSSL_PARAM_UTF8_STRING + || !set_property_query(ctx, p.propq->data)) + return 0; + } + return 1; +} + +/* + * bytepad(encode_string(N) || encode_string(S), w) + * See SP800-185 Section 2.3.3 Padding. + * + * Rather than build an array and do a single keccak operation, we use the + * internal keccak buffer to simplify the process. + * Note that if the strings are large enough to fill the buffer, it will handle + * this internally by absorbing full blocks. The zero padding is also simple + * as we just fill the buffer with zeros to make it a multiple of the blocksize. + */ +static int cshake_absorb_bytepad_strings(CSHAKE_CTX *ctx) +{ + const uint8_t zeros[SHA3_BLOCKSIZE(128)] = { 0 }; + uint8_t bytepad_header[2] = { 0x01, 0x00 }; + const uint8_t *n = ctx->func, *s = ctx->custom; + size_t nlen = ctx->funclen, slen = ctx->customlen; + size_t zlen; + size_t w = SHA3_BLOCKSIZE(ctx->bitlen); /* w = 168 or 136 */ + + bytepad_header[1] = (uint8_t)w; + + /* Empty strings are still encoded */ + if (nlen == 0) { + n = empty_encoded_string; + nlen = sizeof(empty_encoded_string); + } + if (slen == 0) { + s = empty_encoded_string; + slen = sizeof(empty_encoded_string); + } + /* Calculate the number of padding zeros to fill up the block */ + zlen = ((sizeof(bytepad_header) + nlen + slen) % w); + if (zlen != 0) + zlen = w - zlen; + + /* left encoded(w) || encodestring(n) || encodestring(s) || zero_padding */ + return EVP_DigestUpdate(ctx->mdctx, bytepad_header, sizeof(bytepad_header)) + && EVP_DigestUpdate(ctx->mdctx, n, nlen) + && EVP_DigestUpdate(ctx->mdctx, s, slen) + && EVP_DigestUpdate(ctx->mdctx, zeros, zlen); +} + +/* + * The setup of the EVP_MD gets deferred until after the set_ctx_params + * which means that we need to defer to the functions that may be called + * afterwards (i.e. The update(), final() or squeeze()). + * + */ +static int check_init(CSHAKE_CTX *ctx) +{ + /* + * We have to defer choosing the mode EVP_MD object (SHAKE or KECCAK) + * until the first call to either update(), final() or squeeze() + * since the strings can be set at any time before this point. + */ + if (ctx->inited == 0) { + if (ctx->funclen != 0 || ctx->customlen != 0) { + if (!cshake_set_shake_mode(ctx, 0) + || !cshake_absorb_bytepad_strings(ctx)) + return 0; + } else { + /* Use SHAKE if N and S are both empty strings */ + if (!cshake_set_shake_mode(ctx, 1)) + return 0; + } + ctx->inited = 1; + } + return 1; +} + +static int cshake_update(void *vctx, const unsigned char *in, size_t inlen) +{ + CSHAKE_CTX *ctx = (CSHAKE_CTX *)vctx; + + return check_init(ctx) + && EVP_DigestUpdate(ctx->mdctx, in, inlen); +} + +static int cshake_final(void *vctx, uint8_t *out, size_t *outl, size_t outsz) +{ + CSHAKE_CTX *ctx = (CSHAKE_CTX *)vctx; + unsigned int der = (unsigned int)(*outl); + int ret = 1; + + if (ossl_unlikely(!ossl_prov_is_running())) + return 0; + + if (outsz > 0) + ret = check_init(ctx) && EVP_DigestFinal_ex(ctx->mdctx, out, &der); + *outl = der; + return ret; +} + +static int cshake_squeeze(void *vctx, uint8_t *out, size_t *outl, size_t outsz) +{ + CSHAKE_CTX *ctx = (CSHAKE_CTX *)vctx; + int ret = 1; + + if (ossl_unlikely(!ossl_prov_is_running())) + return 0; + + if (outsz > 0) + ret = check_init(ctx) && EVP_DigestSqueeze(ctx->mdctx, out, outsz); + if (ret && outl != NULL) + *outl = outsz; + return ret; +} + +static const OSSL_PARAM *cshake_gettable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + return cshake_get_ctx_params_list; +} + +static int cshake_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + CSHAKE_CTX *ctx = (CSHAKE_CTX *)vctx; + struct cshake_get_ctx_params_st p; + + if (ctx == NULL || !cshake_get_ctx_params_decoder(params, &p)) + return 0; + + /* Size is an alias of xoflen */ + if (p.xoflen != NULL || p.size != NULL) { + size_t xoflen = ctx->xoflen; + + if (ctx->md != NULL) + xoflen = EVP_MD_CTX_get_size_ex(ctx->mdctx); + + if (p.size != NULL && !OSSL_PARAM_set_size_t(p.size, xoflen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + if (p.xoflen != NULL && !OSSL_PARAM_set_size_t(p.xoflen, xoflen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + } + return 1; +} + +#define IMPLEMENT_CSHAKE_functions(bitlen) \ + static OSSL_FUNC_digest_newctx_fn cshake_##bitlen##_newctx; \ + static void *cshake_##bitlen##_newctx(void *provctx) \ + { \ + return cshake_newctx(provctx, bitlen); \ + } \ + PROV_FUNC_DIGEST_GET_PARAM(cshake_##bitlen, SHA3_BLOCKSIZE(bitlen), \ + CSHAKE_KECCAK_MDSIZE(bitlen), CSHAKE_FLAGS) \ + const OSSL_DISPATCH ossl_cshake_##bitlen##_functions[] = { \ + { OSSL_FUNC_DIGEST_NEWCTX, (void (*)(void))cshake_##bitlen##_newctx }, \ + { OSSL_FUNC_DIGEST_INIT, (void (*)(void))cshake_init }, \ + { OSSL_FUNC_DIGEST_UPDATE, (void (*)(void))cshake_update }, \ + { OSSL_FUNC_DIGEST_FINAL, (void (*)(void))cshake_final }, \ + { OSSL_FUNC_DIGEST_SQUEEZE, (void (*)(void))cshake_squeeze }, \ + { OSSL_FUNC_DIGEST_FREECTX, (void (*)(void))cshake_freectx }, \ + { OSSL_FUNC_DIGEST_DUPCTX, (void (*)(void))cshake_dupctx }, \ + { OSSL_FUNC_DIGEST_SET_CTX_PARAMS, (void (*)(void))cshake_set_ctx_params }, \ + { OSSL_FUNC_DIGEST_SETTABLE_CTX_PARAMS, \ + (void (*)(void))cshake_settable_ctx_params }, \ + { OSSL_FUNC_DIGEST_GET_CTX_PARAMS, (void (*)(void))cshake_get_ctx_params }, \ + { OSSL_FUNC_DIGEST_GETTABLE_CTX_PARAMS, \ + (void (*)(void))cshake_gettable_ctx_params }, \ + PROV_DISPATCH_FUNC_DIGEST_GET_PARAMS(cshake_##bitlen), \ + PROV_DISPATCH_FUNC_DIGEST_CONSTRUCT_END + +/* ossl_cshake_128_functions */ +IMPLEMENT_CSHAKE_functions(128) + /* ossl_cshake_256_functions */ + IMPLEMENT_CSHAKE_functions(256) diff --git a/providers/implementations/digests/cshake_prov.inc.in b/providers/implementations/digests/cshake_prov.inc.in new file mode 100644 index 00000000000..42ed97f2c3a --- /dev/null +++ b/providers/implementations/digests/cshake_prov.inc.in @@ -0,0 +1,24 @@ +/* + * Copyright 2025-2026 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ +{- +use OpenSSL::paramnames qw(produce_param_decoder); +-} + +{- produce_param_decoder('cshake_set_ctx_params', + (['OSSL_DIGEST_PARAM_XOFLEN', 'xoflen', 'size_t'], + ['OSSL_DIGEST_PARAM_SIZE', 'xoflen', 'size_t'], + ['OSSL_DIGEST_PARAM_FUNCTION_NAME', 'func', 'utf8_string'], + ['OSSL_DIGEST_PARAM_CUSTOMIZATION', 'custom', 'utf8_string'], + ['OSSL_DIGEST_PARAM_PROPERTIES', 'propq', 'utf8_string'], + )); -} + +{- produce_param_decoder('cshake_get_ctx_params', + (['OSSL_DIGEST_PARAM_XOFLEN', 'xoflen', 'size_t'], + ['OSSL_DIGEST_PARAM_SIZE', 'size', 'size_t'], + )); -} diff --git a/providers/implementations/digests/sha3_prov.c b/providers/implementations/digests/sha3_prov.c index 5072cd8e79d..67cc6917080 100644 --- a/providers/implementations/digests/sha3_prov.c +++ b/providers/implementations/digests/sha3_prov.c @@ -25,7 +25,35 @@ #define SHA3_FLAGS PROV_DIGEST_FLAG_ALGID_ABSENT #define SHAKE_FLAGS (PROV_DIGEST_FLAG_XOF | PROV_DIGEST_FLAG_ALGID_ABSENT) -#define KMAC_FLAGS PROV_DIGEST_FLAG_XOF +#define CSHAKE_KECCAK_FLAGS PROV_DIGEST_FLAG_XOF + +/* + * FIPS 202 Section 5.1 Specifies a padding mode that is added to the last + * block that consists of a 1 bit followed by padding zero bits and a trailing + * 1 bit (where the bits are in LSB order) + * + * For a given input message special algorithm context bits are appended: + * i.e. + * KECCAK[c] = (No tag is used) + * SHA3 = 01 + * SHAKE = 1111 + * CSHAKE_KECCAK = 00 (See NIST SP800-185 3.3 : i.e. it has 2 trailing zero bits) + * Note that KMAC and TupleHash use CSHAKE_KECCAK. + * The OpenSSL implementation only allows input messages that are in bytes, + * so the above concatenated bits will start on a byte boundary. + * Following these bits will be a 1 bit then the padding zeros which gives + * + * KECCAK[c] = 1000 + * SHA3 = 0110 + * SHAKE = 11111000 + * CSHAKE_KECCAK = 0010 (See NIST SP800-185 3.3 : i.e. KMAC uses cSHAKE with a fixed string) + * + * Which gives the following padding values as bytes. + */ +#define KECCAK_PADDING 0x01 +#define SHA3_PADDING 0x06 +#define SHAKE_PADDING 0x1f +#define CSHAKE_KECCAK_PADDING 0x04 /* * Forward declaration of any unique methods implemented here. This is not strictly @@ -56,7 +84,6 @@ static sha3_squeeze_fn generic_sha3_squeeze; #define S390_SHA3 1 #define S390_SHA3_CAPABLE(name) \ ((OPENSSL_s390xcap_P.kimd[0] & S390X_CAPBIT(S390X_##name)) && (OPENSSL_s390xcap_P.klmd[0] & S390X_CAPBIT(S390X_##name))) - #endif static int keccak_init(void *vctx, ossl_unused const OSSL_PARAM params[]) @@ -320,7 +347,7 @@ static int s390x_keccak_final(void *vctx, unsigned char *out, size_t outlen) return s390x_keccakc_final(vctx, out, outlen, 0x01); } -static int s390x_kmac_final(void *vctx, unsigned char *out, size_t outlen) +static int s390x_cshake_keccak_final(void *vctx, unsigned char *out, size_t outlen) { return s390x_keccakc_final(vctx, out, outlen, 0x04); } @@ -374,12 +401,12 @@ static int s390x_keccakc_squeeze(void *vctx, unsigned char *out, size_t outlen, static int s390x_keccak_squeeze(void *vctx, unsigned char *out, size_t outlen) { - return s390x_keccakc_squeeze(vctx, out, outlen, 0x01); + return s390x_keccakc_squeeze(vctx, out, outlen, KECCAK_PADDING); } -static int s390x_kmac_squeeze(void *vctx, unsigned char *out, size_t outlen) +static int s390x_cshake_keccak_squeeze(void *vctx, unsigned char *out, size_t outlen) { - return s390x_keccakc_squeeze(vctx, out, outlen, 0x04); + return s390x_keccakc_squeeze(vctx, out, outlen, CSHAKE_KECCAK_PADDING); } static PROV_SHA3_METHOD sha3_s390x_md = { @@ -400,10 +427,10 @@ static PROV_SHA3_METHOD shake_s390x_md = { s390x_shake_squeeze, }; -static PROV_SHA3_METHOD kmac_s390x_md = { +static PROV_SHA3_METHOD cshake_keccak_s390x_md = { s390x_sha3_absorb, - s390x_kmac_final, - s390x_kmac_squeeze, + s390x_cshake_keccak_final, + s390x_cshake_keccak_squeeze, }; #define SHAKE_SET_MD(uname, typ) \ @@ -421,12 +448,12 @@ static PROV_SHA3_METHOD kmac_s390x_md = { } else { \ ctx->meth = sha3_generic_md; \ } -#define KMAC_SET_MD(bitlen) \ +#define CSHAKE_KECCAK_SET_MD(bitlen) \ if (S390_SHA3_CAPABLE(SHAKE_##bitlen)) { \ ctx->pad = S390X_SHAKE_##bitlen; \ - ctx->meth = kmac_s390x_md; \ + ctx->meth = cshake_keccak_s390x_md; \ } else { \ - ctx->meth = sha3_generic_md; \ + ctx->meth = shake_generic_md; \ } #elif defined(__aarch64__) && defined(KECCAK1600_ASM) #include "arm_arch.h" @@ -467,15 +494,15 @@ static PROV_SHA3_METHOD shake_ARMSHA3_md = { } else { \ ctx->meth = sha3_generic_md; \ } -#define KMAC_SET_MD(bitlen) \ +#define CSHAKE_KECCAK_SET_MD(bitlen) \ if (OPENSSL_armcap_P & ARMV8_HAVE_SHA3_AND_WORTH_USING) { \ - ctx->meth = sha3_ARMSHA3_md; \ + ctx->meth = shake_ARMSHA3_md; \ } else { \ - ctx->meth = sha3_generic_md; \ + ctx->meth = shake_generic_md; \ } #else #define SHA3_SET_MD(uname, typ) ctx->meth = sha3_generic_md; -#define KMAC_SET_MD(bitlen) ctx->meth = sha3_generic_md; +#define CSHAKE_KECCAK_SET_MD(bitlen) ctx->meth = shake_generic_md; #define SHAKE_SET_MD(uname, typ) ctx->meth = shake_generic_md; #endif /* S390_SHA3 */ @@ -509,7 +536,7 @@ static PROV_SHA3_METHOD shake_ARMSHA3_md = { return ctx; \ } -#define KMAC_newctx(uname, bitlen, pad) \ +#define CSHAKE_KECCAK_newctx(uname, bitlen, pad) \ static OSSL_FUNC_digest_newctx_fn uname##_newctx; \ static void *uname##_newctx(void *provctx) \ { \ @@ -519,7 +546,7 @@ static PROV_SHA3_METHOD shake_ARMSHA3_md = { if (ctx == NULL) \ return NULL; \ ossl_keccak_init(ctx, pad, bitlen, 2 * bitlen); \ - KMAC_SET_MD(bitlen) \ + CSHAKE_KECCAK_SET_MD(bitlen) \ return ctx; \ } @@ -761,36 +788,37 @@ static int shake_set_ctx_params(void *vctx, const OSSL_PARAM params[]) #define KECCAK_SER_ID 0x010000 #define SHAKE_SER_ID 0x020000 #define SHA3_SER_ID 0x040000 -#define KMAK_SER_ID 0x080000 +#define CSHAKE_KECCAK_SER_ID 0x080000 -#define IMPLEMENT_SHA3_functions(bitlen) \ - SHA3_newctx(sha3, SHA3_##bitlen, sha3_##bitlen, bitlen, '\x06') \ - IMPLEMENT_SERIALIZE_FNS(sha3_##bitlen, SHA3_SER_ID + bitlen) \ - PROV_FUNC_SHA3_DIGEST(sha3_##bitlen, bitlen, \ - SHA3_BLOCKSIZE(bitlen), SHA3_MDSIZE(bitlen), \ +#define IMPLEMENT_SHA3_functions(bitlen) \ + SHA3_newctx(sha3, SHA3_##bitlen, sha3_##bitlen, bitlen, (uint8_t)SHA3_PADDING) \ + IMPLEMENT_SERIALIZE_FNS(sha3_##bitlen, SHA3_SER_ID + bitlen) \ + PROV_FUNC_SHA3_DIGEST(sha3_##bitlen, bitlen, \ + SHA3_BLOCKSIZE(bitlen), SHA3_MDSIZE(bitlen), \ SHA3_FLAGS) -#define IMPLEMENT_KECCAK_functions(bitlen) \ - SHA3_newctx(keccak, KECCAK_##bitlen, keccak_##bitlen, bitlen, '\x01') \ - IMPLEMENT_SERIALIZE_FNS(keccak_##bitlen, KECCAK_SER_ID + bitlen) \ - PROV_FUNC_SHA3_DIGEST(keccak_##bitlen, bitlen, \ - SHA3_BLOCKSIZE(bitlen), SHA3_MDSIZE(bitlen), \ +#define IMPLEMENT_KECCAK_functions(bitlen) \ + SHA3_newctx(keccak, KECCAK_##bitlen, keccak_##bitlen, bitlen, (uint8_t)KECCAK_PADDING) \ + IMPLEMENT_SERIALIZE_FNS(keccak_##bitlen, KECCAK_SER_ID + bitlen) \ + PROV_FUNC_SHA3_DIGEST(keccak_##bitlen, bitlen, \ + SHA3_BLOCKSIZE(bitlen), SHA3_MDSIZE(bitlen), \ SHA3_FLAGS) #define IMPLEMENT_SHAKE_functions(bitlen) \ SHAKE_newctx(shake, SHAKE_##bitlen, shake_##bitlen, bitlen, \ - 0 /* no default md length */, '\x1f') \ + 0 /* no default md length */, (uint8_t)SHAKE_PADDING) \ IMPLEMENT_SERIALIZE_FNS(shake_##bitlen, SHAKE_SER_ID + bitlen) \ PROV_FUNC_SHAKE_DIGEST(shake_##bitlen, bitlen, \ SHA3_BLOCKSIZE(bitlen), 0, \ SHAKE_FLAGS) -#define IMPLEMENT_KMAC_functions(bitlen) \ - KMAC_newctx(keccak_kmac_##bitlen, bitlen, '\x04') \ - IMPLEMENT_SERIALIZE_FNS(keccak_kmac_##bitlen, KMAK_SER_ID + bitlen) \ - PROV_FUNC_SHAKE_DIGEST(keccak_kmac_##bitlen, bitlen, \ - SHA3_BLOCKSIZE(bitlen), KMAC_MDSIZE(bitlen), \ - KMAC_FLAGS) +#define IMPLEMENT_CSHAKE_KECCAK_functions(bitlen) \ + CSHAKE_KECCAK_newctx(cshake_keccak_##bitlen, bitlen, (uint8_t)CSHAKE_KECCAK_PADDING) \ + IMPLEMENT_SERIALIZE_FNS(cshake_keccak_##bitlen, CSHAKE_KECCAK_SER_ID + bitlen) \ + PROV_FUNC_SHAKE_DIGEST(cshake_keccak_##bitlen, bitlen, \ + SHA3_BLOCKSIZE(bitlen), \ + CSHAKE_KECCAK_MDSIZE(bitlen), \ + CSHAKE_KECCAK_FLAGS) /* ossl_sha3_224_functions */ IMPLEMENT_SHA3_functions(224) @@ -812,7 +840,7 @@ IMPLEMENT_KECCAK_functions(512) IMPLEMENT_SHAKE_functions(128) /* ossl_shake_256_functions */ IMPLEMENT_SHAKE_functions(256) -/* ossl_keccak_kmac_128_functions */ -IMPLEMENT_KMAC_functions(128) -/* ossl_keccak_kmac_256_functions */ -IMPLEMENT_KMAC_functions(256) +/* ossl_cshake_keccak_128_functions */ +IMPLEMENT_CSHAKE_KECCAK_functions(128) + /* ossl_cshake_keccak_256_functions */ + IMPLEMENT_CSHAKE_KECCAK_functions(256) diff --git a/providers/implementations/include/prov/implementations.h b/providers/implementations/include/prov/implementations.h index 990dd258643..a3b0187b80f 100644 --- a/providers/implementations/include/prov/implementations.h +++ b/providers/implementations/include/prov/implementations.h @@ -27,10 +27,12 @@ extern const OSSL_DISPATCH ossl_keccak_224_functions[]; extern const OSSL_DISPATCH ossl_keccak_256_functions[]; extern const OSSL_DISPATCH ossl_keccak_384_functions[]; extern const OSSL_DISPATCH ossl_keccak_512_functions[]; -extern const OSSL_DISPATCH ossl_keccak_kmac_128_functions[]; -extern const OSSL_DISPATCH ossl_keccak_kmac_256_functions[]; extern const OSSL_DISPATCH ossl_shake_128_functions[]; extern const OSSL_DISPATCH ossl_shake_256_functions[]; +extern const OSSL_DISPATCH ossl_cshake_keccak_128_functions[]; +extern const OSSL_DISPATCH ossl_cshake_keccak_256_functions[]; +extern const OSSL_DISPATCH ossl_cshake_128_functions[]; +extern const OSSL_DISPATCH ossl_cshake_256_functions[]; extern const OSSL_DISPATCH ossl_blake2s256_functions[]; extern const OSSL_DISPATCH ossl_blake2b512_functions[]; extern const OSSL_DISPATCH ossl_md5_functions[]; diff --git a/providers/implementations/include/prov/names.h b/providers/implementations/include/prov/names.h index 04b41d53c84..70c4eb03733 100644 --- a/providers/implementations/include/prov/names.h +++ b/providers/implementations/include/prov/names.h @@ -248,12 +248,14 @@ #define PROV_NAMES_SHAKE_128 "SHAKE-128:SHAKE128:2.16.840.1.101.3.4.2.11" #define PROV_NAMES_SHAKE_256 "SHAKE-256:SHAKE256:2.16.840.1.101.3.4.2.12" -/* - * KECCAK-KMAC-128 and KECCAK-KMAC-256 as hashes are mostly useful for - * KMAC128 and KMAC256. - */ -#define PROV_NAMES_KECCAK_KMAC_128 "KECCAK-KMAC-128:KECCAK-KMAC128" -#define PROV_NAMES_KECCAK_KMAC_256 "KECCAK-KMAC-256:KECCAK-KMAC256" +#define PROV_NAMES_CSHAKE_128 "CSHAKE-128:CSHAKE128" +#define PROV_NAMES_CSHAKE_256 "CSHAKE-256:CSHAKE256" + +/* Internal algorithms used by CSHAKE variants */ +#define PROV_NAMES_CSHAKE_KECCAK_128 "CSHAKE-KECCAK-128:KECCAK-KMAC-128:KECCAK-KMAC128" +#define PROV_NAMES_CSHAKE_KECCAK_256 "CSHAKE-KECCAK-256:KECCAK-KMAC-256:KECCAK-KMAC256" +#define PROV_NAMES_KECCAK_KMAC_128 PROV_NAMES_CSHAKE_KECCAK_128 +#define PROV_NAMES_KECCAK_KMAC_256 PROV_NAMES_CSHAKE_KECCAK_256 /* * https://blake2.net/ doesn't specify size variants, but mentions that * Bouncy Castle uses the names BLAKE2b-160, BLAKE2b-256, BLAKE2b-384, and diff --git a/providers/implementations/macs/kmac_prov.c b/providers/implementations/macs/kmac_prov.c index f4726e88ab3..68d1083799e 100644 --- a/providers/implementations/macs/kmac_prov.c +++ b/providers/implementations/macs/kmac_prov.c @@ -62,6 +62,7 @@ #include "prov/providercommon.h" #include "internal/cryptlib.h" /* ossl_assert */ #include "providers/implementations/macs/kmac_prov.inc" +#include "crypto/sha.h" /* * Forward declaration of everything implemented here. This is not strictly @@ -139,18 +140,8 @@ struct kmac_data_st { OSSL_FIPS_IND_DECLARE }; -static int encode_string(unsigned char *out, size_t out_max_len, size_t *out_len, - const unsigned char *in, size_t in_len); -static int right_encode(unsigned char *out, size_t out_max_len, size_t *out_len, - size_t bits); -static int bytepad(unsigned char *out, size_t *out_len, - const unsigned char *in1, size_t in1_len, - const unsigned char *in2, size_t in2_len, - size_t w); static int kmac_bytepad_encode_key(unsigned char *out, size_t out_max_len, - size_t *out_len, - const unsigned char *in, size_t in_len, - size_t w); + size_t *out_len, const unsigned char *in, size_t in_len, size_t w); static void kmac_free(void *vmacctx) { @@ -349,7 +340,7 @@ static int kmac_init(void *vmacctx, const unsigned char *key, (void)kmac_set_ctx_params(kctx, cparams); } - if (!bytepad(NULL, &out_len, kmac_string, sizeof(kmac_string), + if (!ossl_sp800_185_bytepad(NULL, 0, &out_len, kmac_string, sizeof(kmac_string), kctx->custom, kctx->custom_len, block_len)) { ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); return 0; @@ -357,7 +348,7 @@ static int kmac_init(void *vmacctx, const unsigned char *key, out = OPENSSL_malloc(out_len); if (out == NULL) return 0; - res = bytepad(out, NULL, kmac_string, sizeof(kmac_string), + res = ossl_sp800_185_bytepad(out, out_len, NULL, kmac_string, sizeof(kmac_string), kctx->custom, kctx->custom_len, block_len) && EVP_DigestUpdate(ctx, out, out_len) && EVP_DigestUpdate(ctx, kctx->key, kctx->key_len); @@ -388,7 +379,7 @@ static int kmac_final(void *vmacctx, unsigned char *out, size_t *outl, /* KMAC XOF mode sets the encoded length to 0 */ lbits = (kctx->xof_mode ? 0 : (kctx->out_len * 8)); - ok = right_encode(encoded_outlen, sizeof(encoded_outlen), &len, lbits) + ok = ossl_sp800_185_right_encode(encoded_outlen, sizeof(encoded_outlen), &len, lbits) && EVP_DigestUpdate(ctx, encoded_outlen, len) && EVP_DigestFinalXOF(ctx, out, kctx->out_len); *outl = kctx->out_len; @@ -493,7 +484,8 @@ static int kmac_set_ctx_params(void *vmacctx, const OSSL_PARAM *params) ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_CUSTOM_LENGTH); return 0; } - if (!encode_string(kctx->custom, sizeof(kctx->custom), &kctx->custom_len, + if (!ossl_sp800_185_encode_string(kctx->custom, + sizeof(kctx->custom), &kctx->custom_len, p.custom->data, p.custom->data_size)) return 0; } @@ -501,156 +493,18 @@ static int kmac_set_ctx_params(void *vmacctx, const OSSL_PARAM *params) return 1; } -/* Encoding/Padding Methods. */ - -/* Returns the number of bytes required to store 'bits' into a byte array */ -static unsigned int get_encode_size(size_t bits) -{ - unsigned int cnt = 0, sz = sizeof(size_t); - - while (bits && (cnt < sz)) { - ++cnt; - bits >>= 8; - } - /* If bits is zero 1 byte is required */ - if (cnt == 0) - cnt = 1; - return cnt; -} - -/* - * Convert an integer into bytes . The number of bytes is appended - * to the end of the buffer. Returns an array of bytes 'out' of size - * *out_len. - * - * e.g if bits = 32, out[2] = { 0x20, 0x01 } - */ -static int right_encode(unsigned char *out, size_t out_max_len, size_t *out_len, - size_t bits) -{ - unsigned int len = get_encode_size(bits); - int i; - - if (len >= out_max_len) { - ERR_raise(ERR_LIB_PROV, PROV_R_LENGTH_TOO_LARGE); - return 0; - } - - /* MSB's are at the start of the bytes array */ - for (i = len - 1; i >= 0; --i) { - out[i] = (unsigned char)(bits & 0xFF); - bits >>= 8; - } - /* Tack the length onto the end */ - out[len] = (unsigned char)len; - - /* The Returned length includes the tacked on byte */ - *out_len = len + 1; - return 1; -} - -/* - * Encodes a string with a left encoded length added. Note that the - * in_len is converted to bits (*8). - * - * e.g- in="KMAC" gives out[6] = { 0x01, 0x20, 0x4B, 0x4D, 0x41, 0x43 } - * len bits K M A C - */ -static int encode_string(unsigned char *out, size_t out_max_len, size_t *out_len, - const unsigned char *in, size_t in_len) -{ - if (in == NULL) { - *out_len = 0; - } else { - size_t i, bits, len, sz; - - bits = 8 * in_len; - len = get_encode_size(bits); - sz = 1 + len + in_len; - - if (sz > out_max_len) { - ERR_raise(ERR_LIB_PROV, PROV_R_LENGTH_TOO_LARGE); - return 0; - } - - out[0] = (unsigned char)len; - for (i = len; i > 0; --i) { - out[i] = (bits & 0xFF); - bits >>= 8; - } - memcpy(out + len + 1, in, in_len); - *out_len = sz; - } - return 1; -} - -/* - * Returns a zero padded encoding of the inputs in1 and an optional - * in2 (can be NULL). The padded output must be a multiple of the blocksize 'w'. - * The value of w is in bytes (< 256). - * - * The returned output is: - * zero_padded(multiple of w, (left_encode(w) || in1 [|| in2]) - */ -static int bytepad(unsigned char *out, size_t *out_len, - const unsigned char *in1, size_t in1_len, - const unsigned char *in2, size_t in2_len, size_t w) -{ - size_t len; - unsigned char *p = out; - size_t sz = w; - - if (out == NULL) { - if (out_len == NULL) { - ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER); - return 0; - } - sz = 2 + in1_len + (in2 != NULL ? in2_len : 0); - *out_len = (sz + w - 1) / w * w; - return 1; - } - - if (!ossl_assert(w <= 255)) - return 0; - - /* Left encoded w */ - *p++ = 1; - *p++ = (unsigned char)w; - /* || in1 */ - memcpy(p, in1, in1_len); - p += in1_len; - /* [ || in2 ] */ - if (in2 != NULL && in2_len > 0) { - memcpy(p, in2, in2_len); - p += in2_len; - } - /* Figure out the pad size (divisible by w) */ - len = p - out; - sz = (len + w - 1) / w * w; - /* zero pad the end of the buffer */ - if (sz != len) - memset(p, 0, sz - len); - if (out_len != NULL) - *out_len = sz; - return 1; -} - /* Returns out = bytepad(encode_string(in), w) */ static int kmac_bytepad_encode_key(unsigned char *out, size_t out_max_len, - size_t *out_len, - const unsigned char *in, size_t in_len, - size_t w) + size_t *out_len, const unsigned char *in, size_t in_len, size_t w) { unsigned char tmp[KMAC_MAX_KEY + KMAC_MAX_ENCODED_HEADER_LEN]; size_t tmp_len; - if (!encode_string(tmp, sizeof(tmp), &tmp_len, in, in_len)) - return 0; - if (!bytepad(NULL, out_len, tmp, tmp_len, NULL, 0, w)) + if (!ossl_sp800_185_encode_string(tmp, sizeof(tmp), &tmp_len, in, in_len)) return 0; - if (!ossl_assert(*out_len <= out_max_len)) + if (!ossl_sp800_185_bytepad(NULL, out_max_len, out_len, tmp, tmp_len, NULL, 0, w)) return 0; - return bytepad(out, NULL, tmp, tmp_len, NULL, 0, w); + return ossl_sp800_185_bytepad(out, out_max_len, NULL, tmp, tmp_len, NULL, 0, w); } #define IMPLEMENT_KMAC_TABLE(size, funcname, newname) \ diff --git a/test/evp_test.c b/test/evp_test.c index 7ce3be97798..bd7ae805026 100644 --- a/test/evp_test.c +++ b/test/evp_test.c @@ -712,6 +712,7 @@ typedef struct digest_data_st { int xof; /* Size for variable output length but non-XOF */ size_t digest_size; + STACK_OF(OPENSSL_STRING) *controls; /* collection of controls */ } DIGEST_DATA; static int digest_test_init(EVP_TEST *t, const char *alg) @@ -738,6 +739,7 @@ static int digest_test_init(EVP_TEST *t, const char *alg) mdat->fetched_digest = fetched_digest; mdat->pad_type = 0; mdat->xof = 0; + mdat->controls = sk_OPENSSL_STRING_new_null(); if (fetched_digest != NULL) TEST_info("%s is fetched", alg); return 1; @@ -750,6 +752,7 @@ static void digest_test_cleanup(EVP_TEST *t) sk_EVP_TEST_BUFFER_pop_free(mdat->input, evp_test_buffer_free); OPENSSL_free(mdat->output); EVP_MD_free(mdat->fetched_digest); + ctrlfree(mdat->controls); } static int digest_test_parse(EVP_TEST *t, @@ -778,6 +781,8 @@ static int digest_test_parse(EVP_TEST *t, mdata->digest_size = sz; return 1; } + if (strcmp(keyword, "Ctrl") == 0) + return ctrladd(mdata->controls, value); return 0; } @@ -815,7 +820,9 @@ static int digest_test_run(EVP_TEST *t) unsigned int got_len; size_t size = 0; int xof = 0; - OSSL_PARAM params[4], *p = ¶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())) @@ -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), ¶ms_n)) + return 0; + p = params + params_n; + } + if (expected->xof > 0) { xof |= 1; *p++ = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_XOFLEN, @@ -907,6 +921,7 @@ static int digest_test_run(EVP_TEST *t) } err: + ctrl2params_free(params, params_n, params_allocated_n); OPENSSL_free(got); EVP_MD_CTX_free(mctx); return 1; diff --git a/test/evp_xof_test.c b/test/evp_xof_test.c index 76eb3539ddd..c4a87e28354 100644 --- a/test/evp_xof_test.c +++ b/test/evp_xof_test.c @@ -13,7 +13,7 @@ #include "testutil.h" #include "internal/nelem.h" -static const unsigned char shake256_input[] = { +static const uint8_t shake256_input[] = { 0x8d, 0x80, 0x01, 0xe2, 0xc0, 0x96, 0xf1, 0xb8, 0x8e, 0x7c, 0x92, 0x24, 0xa0, 0x86, 0xef, 0xd4, 0x79, 0x7f, 0xbf, 0x74, 0xa8, 0x03, 0x3a, 0x2d, @@ -24,7 +24,7 @@ static const unsigned char shake256_input[] = { * This KAT output is 250 bytes, which is more than * the SHAKE256 block size (136 bytes). */ -static const unsigned char shake256_output[] = { +static const uint8_t shake256_output[] = { 0x2e, 0x97, 0x5f, 0x6a, 0x8a, 0x14, 0xf0, 0x70, 0x4d, 0x51, 0xb1, 0x36, 0x67, 0xd8, 0x19, 0x5c, 0x21, 0x9f, 0x71, 0xe6, 0x34, 0x56, 0x96, 0xc4, @@ -59,6 +59,52 @@ static const unsigned char shake256_output[] = { 0x66, 0x6c }; +static const uint8_t cshake256_output[] = { + 0x30, 0xa6, 0x5f, 0xd5, 0xff, 0x3e, 0x49, 0xe8, + 0xa9, 0xef, 0x06, 0xa3, 0x56, 0x4b, 0x4f, 0x55, + 0x93, 0x0f, 0x4a, 0x9e, 0xe9, 0x74, 0x13, 0xf8, + 0x4a, 0x80, 0x44, 0x65, 0xec, 0x62, 0x83, 0x7a, + 0x21, 0xce, 0x96, 0x0e, 0x27, 0x1f, 0x81, 0x26, + 0xcb, 0xd8, 0x42, 0x7b, 0x7d, 0x71, 0x6a, 0xdc, + 0xaf, 0x4d, 0x13, 0x52, 0x28, 0x2b, 0xd9, 0x70, + 0xfb, 0x90, 0x96, 0xfe, 0x24, 0xd2, 0x22, 0x48, + 0x73, 0xae, 0x73, 0x1e, 0x10, 0x07, 0x4b, 0x92, + 0x2a, 0xae, 0x1e, 0x7b, 0x7d, 0x06, 0xe2, 0x0f, + 0x80, 0x08, 0xc3, 0xa5, 0x09, 0x71, 0x57, 0x84, + 0x4a, 0xa8, 0x70, 0xe7, 0x61, 0x6b, 0x0c, 0x3c +}; + +typedef struct test_data_st { + const char *alg; + const uint8_t *in; + size_t inlen; + const uint8_t *out; + size_t outlen; + int default_xoflen; + const char *param_n; + const char *param_s; +} TEST_DATA; + +static const TEST_DATA xof_test_data[] = { + { + "SHAKE256", + shake256_input, + sizeof(shake256_input), + shake256_output, + sizeof(shake256_output), + }, + { "CSHAKE256", + shake256_input, sizeof(shake256_input), + shake256_output, sizeof(shake256_output), + 64 }, + { "CSHAKE256", + shake256_input, sizeof(shake256_input), + cshake256_output, sizeof(cshake256_output), + 64, + "KMAC", + "Custom" }, +}; + static const unsigned char shake256_largemsg_input[] = { 0xb2, 0xd2, 0x38, 0x65, 0xaf, 0x8f, 0x25, 0x6e, 0x64, 0x40, 0xe2, 0x0d, 0x49, 0x8e, 0x3e, 0x64, @@ -149,51 +195,39 @@ static const unsigned char shake256_largemsg_input[] = { }; static const unsigned char shake256_largemsg_output[] = { - 0x64, - 0xea, - 0x24, - 0x6a, - 0xab, - 0x80, - 0x37, - 0x9e, - 0x08, - 0xe2, - 0x19, - 0x9e, - 0x09, - 0x69, - 0xe2, - 0xee, - 0x1a, - 0x5d, - 0xd1, - 0x68, - 0x68, - 0xec, - 0x8d, - 0x42, - 0xd0, - 0xf8, - 0xb8, - 0x44, - 0x74, - 0x54, - 0x87, - 0x3e, + 0x64, 0xea, 0x24, 0x6a, 0xab, 0x80, 0x37, 0x9e, + 0x08, 0xe2, 0x19, 0x9e, 0x09, 0x69, 0xe2, 0xee, + 0x1a, 0x5d, 0xd1, 0x68, 0x68, 0xec, 0x8d, 0x42, + 0xd0, 0xf8, 0xb8, 0x44, 0x74, 0x54, 0x87, 0x3e }; -static EVP_MD_CTX *shake_setup(const char *name) +static const TEST_DATA large_msg_test_data[] = { + { + "SHAKE256", + shake256_largemsg_input, + sizeof(shake256_largemsg_input), + shake256_largemsg_output, + sizeof(shake256_largemsg_output), + }, +}; + +static EVP_MD_CTX *xof_digest_setup(const TEST_DATA *td) { EVP_MD_CTX *ctx = NULL; EVP_MD *md = NULL; + OSSL_PARAM params[3], *p = params; - if (!TEST_ptr(md = EVP_MD_fetch(NULL, name, NULL))) + if (!TEST_ptr(md = EVP_MD_fetch(NULL, td->alg, NULL))) return NULL; if (!TEST_ptr(ctx = EVP_MD_CTX_new())) goto err; - if (!TEST_true(EVP_DigestInit_ex2(ctx, md, NULL))) + if (td->param_n != NULL) + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_DIGEST_PARAM_FUNCTION_NAME, (char *)td->param_n, 0); + if (td->param_s != NULL) + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_DIGEST_PARAM_CUSTOMIZATION, (char *)td->param_s, 0); + *p = OSSL_PARAM_construct_end(); + if (!TEST_true(EVP_DigestInit_ex2(ctx, md, params))) goto err; EVP_MD_free(md); return ctx; @@ -203,23 +237,24 @@ err: return NULL; } -static int shake_kat_test(void) +static int xof_kat_test(int tstid) { + const TEST_DATA *td = xof_test_data + tstid; int ret = 0; EVP_MD_CTX *ctx = NULL; - unsigned char out[sizeof(shake256_output)]; + uint8_t out[2048]; - if (!TEST_ptr(ctx = shake_setup("SHAKE256"))) + if (!TEST_size_t_le(td->outlen, sizeof(out))) return 0; - if (!TEST_true(EVP_DigestUpdate(ctx, shake256_input, - sizeof(shake256_input))) - || !TEST_true(EVP_DigestFinalXOF(ctx, out, sizeof(out))) - || !TEST_mem_eq(out, sizeof(out), - shake256_output, sizeof(shake256_output)) + if (!TEST_ptr(ctx = xof_digest_setup(td))) + return 0; + if (!TEST_true(EVP_DigestUpdate(ctx, td->in, td->inlen)) + || !TEST_true(EVP_DigestFinalXOF(ctx, out, td->outlen)) + || !TEST_mem_eq(out, td->outlen, td->out, td->outlen) /* Test that a second call to EVP_DigestFinalXOF fails */ - || !TEST_false(EVP_DigestFinalXOF(ctx, out, sizeof(out))) + || !TEST_false(EVP_DigestFinalXOF(ctx, out, td->outlen)) /* Test that a call to EVP_DigestSqueeze fails */ - || !TEST_false(EVP_DigestSqueeze(ctx, out, sizeof(out)))) + || !TEST_false(EVP_DigestSqueeze(ctx, out, td->outlen))) goto err; ret = 1; err: @@ -227,37 +262,52 @@ err: return ret; } -static int shake_kat_digestfinal_test(void) +static int xof_kat_digestfinal_test(int tstid) { + const TEST_DATA *td = xof_test_data + tstid; int ret = 0; unsigned int digest_length = 0; EVP_MD_CTX *ctx = NULL; - unsigned char out[sizeof(shake256_output)]; + uint8_t out[2048]; - /* Test that EVP_DigestFinal without setting XOFLEN fails */ - if (!TEST_ptr(ctx = shake_setup("SHAKE256"))) + if (!TEST_size_t_le(td->outlen, sizeof(out))) return 0; - if (!TEST_true(EVP_DigestUpdate(ctx, shake256_input, - sizeof(shake256_input)))) - return 0; - ERR_set_mark(); - if (!TEST_false(EVP_DigestFinal(ctx, out, &digest_length))) { - ERR_clear_last_mark(); + if (!TEST_ptr(ctx = xof_digest_setup(td))) return 0; + if (!TEST_true(EVP_DigestUpdate(ctx, td->in, td->inlen))) + goto err; + if (td->default_xoflen == 0) { + /* + * Test that EVP_DigestFinal without setting XOFLEN fails for SHAKE + * (The original code for SHAKE set the wrong default value which is + * why the XOF needs to be set for this). + */ + ERR_set_mark(); + if (!TEST_false(EVP_DigestFinal(ctx, out, &digest_length))) { + ERR_clear_last_mark(); + goto err; + } + ERR_pop_to_mark(); + } else { + /* + * Test that EVP_DigestFinal without setting XOFLEN passes for CSHAKE + * and correctly returns 2 * 256 = 512 bits (64 bytes) by default. + */ + if (!TEST_true(EVP_DigestFinal(ctx, out, &digest_length)) + || !TEST_uint_eq(digest_length, td->default_xoflen) + || !TEST_mem_eq(out, digest_length, td->out, digest_length)) + goto err; } - ERR_pop_to_mark(); EVP_MD_CTX_free(ctx); - /* However EVP_DigestFinalXOF must work */ - if (!TEST_ptr(ctx = shake_setup("SHAKE256"))) - return 0; - if (!TEST_true(EVP_DigestUpdate(ctx, shake256_input, - sizeof(shake256_input)))) + /* EVP_DigestFinalXOF must work */ + if (!TEST_ptr(ctx = xof_digest_setup(td))) return 0; - if (!TEST_true(EVP_DigestFinalXOF(ctx, out, sizeof(out))) - || !TEST_mem_eq(out, sizeof(out), - shake256_output, sizeof(shake256_output)) - || !TEST_false(EVP_DigestFinalXOF(ctx, out, sizeof(out)))) + if (!TEST_true(EVP_DigestUpdate(ctx, td->in, td->inlen))) + goto err; + if (!TEST_true(EVP_DigestFinalXOF(ctx, out, td->outlen)) + || !TEST_mem_eq(out, td->outlen, td->out, td->outlen) + || !TEST_false(EVP_DigestFinalXOF(ctx, out, td->outlen))) goto err; ret = 1; err: @@ -269,35 +319,37 @@ err: * Test that EVP_DigestFinal() returns the output length * set by the OSSL_DIGEST_PARAM_XOFLEN param. */ -static int shake_kat_digestfinal_xoflen_test(void) +static int xof_kat_digestfinal_xoflen_test(int tstid) { + const TEST_DATA *td = xof_test_data + tstid; int ret = 0; unsigned int digest_length = 0; EVP_MD_CTX *ctx = NULL; const EVP_MD *md; - unsigned char out[sizeof(shake256_output)]; OSSL_PARAM params[2]; size_t sz = 12; + uint8_t out[2048]; - if (!TEST_ptr(ctx = shake_setup("SHAKE256"))) + if (!TEST_size_t_le(td->outlen, sizeof(out))) return 0; + if (!TEST_ptr(ctx = xof_digest_setup(td))) + return 0; + md = EVP_MD_CTX_get0_md(ctx); - memset(out, 0, sizeof(out)); + memset(out, 0, td->outlen); params[0] = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_XOFLEN, &sz); params[1] = OSSL_PARAM_construct_end(); - if (!TEST_int_eq(EVP_MD_CTX_size(ctx), -1) + if (!TEST_int_eq(EVP_MD_CTX_size(ctx), td->default_xoflen == 0 ? -1 : td->default_xoflen) || !TEST_int_eq(EVP_MD_CTX_set_params(ctx, params), 1) || !TEST_int_eq(EVP_MD_CTX_size(ctx), (int)sz) - || !TEST_int_eq(EVP_MD_get_size(md), 0) + || !TEST_int_eq(EVP_MD_get_size(md), td->default_xoflen) || !TEST_true(EVP_MD_xof(md)) - || !TEST_true(EVP_DigestUpdate(ctx, shake256_input, - sizeof(shake256_input))) + || !TEST_true(EVP_DigestUpdate(ctx, td->in, td->inlen)) || !TEST_true(EVP_DigestFinal(ctx, out, &digest_length)) || !TEST_uint_eq(digest_length, (unsigned int)sz) - || !TEST_mem_eq(out, digest_length, - shake256_output, digest_length) + || !TEST_mem_eq(out, digest_length, td->out, digest_length) || !TEST_uchar_eq(out[digest_length], 0)) goto err; ret = 1; @@ -310,15 +362,18 @@ err: * Test that multiple absorb calls gives the expected result. * This is a nested test that uses multiple strides for the input. */ -static int shake_absorb_test(void) +static int xof_absorb_test(int tstid) { + const TEST_DATA *td = large_msg_test_data + tstid; int ret = 0; EVP_MD_CTX *ctx = NULL; - unsigned char out[sizeof(shake256_largemsg_output)]; - size_t total = sizeof(shake256_largemsg_input); + unsigned char out[2048]; + size_t total = td->inlen; size_t i, stride, sz; - if (!TEST_ptr(ctx = shake_setup("SHAKE256"))) + if (!TEST_size_t_le(td->outlen, sizeof(out))) + return 0; + if (!TEST_ptr(ctx = xof_digest_setup(td))) return 0; for (stride = 1; stride < total; ++stride) { @@ -327,14 +382,11 @@ static int shake_absorb_test(void) sz += stride; if ((i + sz) > total) sz = total - i; - if (!TEST_true(EVP_DigestUpdate(ctx, shake256_largemsg_input + i, - sz))) + if (!TEST_true(EVP_DigestUpdate(ctx, td->in + i, sz))) goto err; } - if (!TEST_true(EVP_DigestFinalXOF(ctx, out, sizeof(out))) - || !TEST_mem_eq(out, sizeof(out), - shake256_largemsg_output, - sizeof(shake256_largemsg_output))) + if (!TEST_true(EVP_DigestFinalXOF(ctx, out, td->outlen)) + || !TEST_mem_eq(out, td->outlen, td->out, td->outlen)) goto err; if (!TEST_true(EVP_DigestInit_ex2(ctx, NULL, NULL))) goto err; @@ -349,9 +401,11 @@ err: * Table containing the size of the output to squeeze for the * initially call, followed by a size for each subsequent call. */ -static const struct { +typedef struct stride_test_data_st { size_t startsz, incsz; -} stride_tests[] = { +} STRIDE_TEST_DATA; + +static const STRIDE_TEST_DATA stride_test_data[] = { { 1, 1 }, { 1, 136 }, { 1, 136 / 2 }, @@ -394,17 +448,18 @@ static const struct { * in and inlen represent the input to absorb. expected_out and expected_outlen * represent the expected output. */ -static int do_shake_squeeze_test(int tst, - const unsigned char *in, size_t inlen, - const unsigned char *expected_out, +static int do_xof_squeeze_test(const TEST_DATA *td, + const STRIDE_TEST_DATA *stride, + const uint8_t *in, size_t inlen, + const uint8_t *expected_out, size_t expected_outlen) { int ret = 0; EVP_MD_CTX *ctx = NULL; unsigned char *out = NULL; - size_t i = 0, sz = stride_tests[tst].startsz; + size_t i = 0, sz = stride->startsz; - if (!TEST_ptr(ctx = shake_setup("SHAKE256"))) + if (!TEST_ptr(ctx = xof_digest_setup(td))) return 0; if (!TEST_ptr(out = OPENSSL_malloc(expected_outlen))) goto err; @@ -417,7 +472,7 @@ static int do_shake_squeeze_test(int tst, if (!TEST_true(EVP_DigestSqueeze(ctx, out + i, sz))) goto err; i += sz; - sz = stride_tests[tst].incsz; + sz = stride->incsz; } if (!TEST_mem_eq(out, expected_outlen, expected_out, expected_outlen)) goto err; @@ -428,10 +483,12 @@ err: return ret; } -static int shake_squeeze_kat_test(int tst) +static int xof_squeeze_kat_test(int tstid) { - return do_shake_squeeze_test(tst, shake256_input, sizeof(shake256_input), - shake256_output, sizeof(shake256_output)); + const STRIDE_TEST_DATA *sd = stride_test_data + tstid; + const TEST_DATA *td = xof_test_data + (tstid % (OSSL_NELEM(xof_test_data))); + + return do_xof_squeeze_test(td, sd, td->in, td->inlen, td->out, td->outlen); } /* @@ -440,42 +497,42 @@ static int shake_squeeze_kat_test(int tst) * output. Use this to test that multiple squeeze calls * on the same input gives the same output. */ -static int shake_squeeze_large_test(int tst) +static int xof_squeeze_large_test(int tstid) { + const STRIDE_TEST_DATA *sd = stride_test_data + tstid; + const TEST_DATA *td = xof_test_data + (tstid % (OSSL_NELEM(xof_test_data))); int ret = 0; EVP_MD_CTX *ctx = NULL; unsigned char msg[16]; unsigned char out[2000]; if (!TEST_int_gt(RAND_bytes(msg, sizeof(msg)), 0) - || !TEST_ptr(ctx = shake_setup("SHAKE256")) + || !TEST_ptr(ctx = xof_digest_setup(td)) || !TEST_true(EVP_DigestUpdate(ctx, msg, sizeof(msg))) || !TEST_true(EVP_DigestFinalXOF(ctx, out, sizeof(out)))) goto err; - ret = do_shake_squeeze_test(tst, msg, sizeof(msg), out, sizeof(out)); + ret = do_xof_squeeze_test(td, sd, msg, sizeof(msg), out, sizeof(out)); err: EVP_MD_CTX_free(ctx); return ret; } -static const size_t dupoffset_tests[] = { +static const size_t dupoffset_test_data[] = { 1, 135, 136, 137, 136 * 3 - 1, 136 * 3, 136 * 3 + 1 }; /* Helper function to test that EVP_MD_CTX_dup() copies the internal state */ -static int do_shake_squeeze_dup_test(int tst, const char *alg, - const unsigned char *in, size_t inlen, - const unsigned char *expected_out, - size_t expected_outlen) +static int do_xof_squeeze_dup_test(const TEST_DATA *td, size_t dupoffset, + const uint8_t *in, size_t inlen, + const uint8_t *expected_out, size_t expected_outlen) { int ret = 0; EVP_MD_CTX *cur, *ctx = NULL, *dupctx = NULL; unsigned char *out = NULL; size_t i = 0, sz = 10; - size_t dupoffset = dupoffset_tests[tst]; - if (!TEST_ptr(ctx = shake_setup(alg))) + if (!TEST_ptr(ctx = xof_digest_setup(td))) return 0; cur = ctx; if (!TEST_ptr(out = OPENSSL_malloc(expected_outlen))) @@ -507,21 +564,22 @@ err: } /* Test that the internal state can be copied */ -static int shake_squeeze_dup_test(int tst) +static int xof_squeeze_dup_test(int tstid) { + size_t dupoffset = dupoffset_test_data[tstid]; + const TEST_DATA *td = xof_test_data + (tstid % (OSSL_NELEM(xof_test_data))); int ret = 0; EVP_MD_CTX *ctx = NULL; unsigned char msg[16]; unsigned char out[1000]; - const char *alg = "SHAKE128"; if (!TEST_int_gt(RAND_bytes(msg, sizeof(msg)), 0) - || !TEST_ptr(ctx = shake_setup(alg)) + || !TEST_ptr(ctx = xof_digest_setup(td)) || !TEST_true(EVP_DigestUpdate(ctx, msg, sizeof(msg))) || !TEST_true(EVP_DigestFinalXOF(ctx, out, sizeof(out)))) goto err; - ret = do_shake_squeeze_dup_test(tst, alg, msg, sizeof(msg), + ret = do_xof_squeeze_dup_test(td, dupoffset, msg, sizeof(msg), out, sizeof(out)); err: EVP_MD_CTX_free(ctx); @@ -529,30 +587,29 @@ err: } /* Test that a squeeze without a preceding absorb works */ -static int shake_squeeze_no_absorb_test(void) +static int xof_squeeze_no_absorb_test(int tstid) { + const TEST_DATA *td = xof_test_data + tstid; int ret = 0; - EVP_MD_CTX *ctx = NULL; + EVP_MD_CTX *ctx = NULL, *ctx2 = NULL; unsigned char out[1000]; unsigned char out2[1000]; - const char *alg = "SHAKE128"; - if (!TEST_ptr(ctx = shake_setup(alg)) - || !TEST_true(EVP_DigestFinalXOF(ctx, out, sizeof(out)))) - goto err; - - if (!TEST_true(EVP_DigestInit_ex2(ctx, NULL, NULL)) - || !TEST_true(EVP_DigestSqueeze(ctx, out2, sizeof(out2) / 2)) - || !TEST_true(EVP_DigestSqueeze(ctx, out2 + sizeof(out2) / 2, - sizeof(out2) / 2))) - goto err; - - if (!TEST_mem_eq(out2, sizeof(out2), out, sizeof(out))) + memset(out, 0, sizeof(out)); + memset(out2, 0, sizeof(out2)); + if (!TEST_ptr(ctx = xof_digest_setup(td)) + || !TEST_ptr(ctx2 = EVP_MD_CTX_dup(ctx)) + || !TEST_true(EVP_DigestFinalXOF(ctx, out, sizeof(out))) + || !TEST_true(EVP_DigestSqueeze(ctx2, out2, sizeof(out2) / 2)) + || !TEST_true(EVP_DigestSqueeze(ctx2, out2 + sizeof(out2) / 2, + sizeof(out2) / 2)) + || !TEST_mem_eq(out2, sizeof(out2), out, sizeof(out))) goto err; ret = 1; err: EVP_MD_CTX_free(ctx); + EVP_MD_CTX_free(ctx2); return ret; } @@ -569,14 +626,14 @@ static int xof_fail_test(void) int setup_tests(void) { - ADD_TEST(shake_kat_test); - ADD_TEST(shake_kat_digestfinal_test); - ADD_TEST(shake_kat_digestfinal_xoflen_test); - ADD_TEST(shake_absorb_test); - ADD_ALL_TESTS(shake_squeeze_kat_test, OSSL_NELEM(stride_tests)); - ADD_ALL_TESTS(shake_squeeze_large_test, OSSL_NELEM(stride_tests)); - ADD_ALL_TESTS(shake_squeeze_dup_test, OSSL_NELEM(dupoffset_tests)); + ADD_ALL_TESTS(xof_kat_test, OSSL_NELEM(xof_test_data)); + ADD_ALL_TESTS(xof_kat_digestfinal_test, OSSL_NELEM(xof_test_data)); + ADD_ALL_TESTS(xof_kat_digestfinal_xoflen_test, OSSL_NELEM(xof_test_data)); + ADD_ALL_TESTS(xof_squeeze_no_absorb_test, OSSL_NELEM(xof_test_data)); + ADD_ALL_TESTS(xof_absorb_test, OSSL_NELEM(large_msg_test_data)); + ADD_ALL_TESTS(xof_squeeze_kat_test, OSSL_NELEM(stride_test_data)); + ADD_ALL_TESTS(xof_squeeze_large_test, OSSL_NELEM(stride_test_data)); + ADD_ALL_TESTS(xof_squeeze_dup_test, OSSL_NELEM(dupoffset_test_data)); ADD_TEST(xof_fail_test); - ADD_TEST(shake_squeeze_no_absorb_test); return 1; } diff --git a/test/recipes/30-test_evp_data/evpmd_sha.txt b/test/recipes/30-test_evp_data/evpmd_sha.txt index b3b95ed76b5..75393e5472b 100644 --- a/test/recipes/30-test_evp_data/evpmd_sha.txt +++ b/test/recipes/30-test_evp_data/evpmd_sha.txt @@ -384,7 +384,93 @@ Digest = KECCAK-512 Input = 4FBDC596508D24A2A0010E140980B809FB9C6D55EC75125891DD985D37665BD80F9BEB6A50207588ABF3CEEE8C77CD8A5AD48A9E0AA074ED388738362496D2FB2C87543BB3349EA64997CE3E7B424EA92D122F57DBB0855A803058437FE08AFB0C8B5E7179B9044BBF4D81A7163B3139E30888B536B0F957EFF99A7162F4CA5AA756A4A982DFADBF31EF255083C4B5C6C1B99A107D7D3AFFFDB89147C2CC4C9A2643F478E5E2D393AEA37B4C7CB4B5E97DADCF16B6B50AAE0F3B549ECE47746DB6CE6F67DD4406CD4E75595D5103D13F9DFA79372924D328F8DD1FCBEB5A8E2E8BF4C76DE08E3FC46AA021F989C49329C7ACAC5A688556D7BCBCB2A5D4BE69D3284E9C40EC4838EE8592120CE20A0B635ECADAA84FD5690509F54F77E35A417C584648BC9839B974E07BFAB0038E90295D0B13902530A830D1C2BDD53F1F9C9FAED43CA4EED0A8DD761BC7EDBDDA28A287C60CD42AF5F9C758E5C7250231C09A582563689AFC65E2B79A7A2B68200667752E9101746F03184E2399E4ED8835CB8E9AE90E296AF220AE234259FE0BD0BCC60F7A4A5FF3F70C5ED4DE9C8C519A10E962F673C82C5E9351786A8A3BFD570031857BD4C87F4FCA31ED4D50E14F2107DA02CB5058700B74EA241A8B41D78461658F1B2B90BFD84A4C2C9D6543861AB3C56451757DCFB9BA60333488DBDD02D601B41AAE317CA7474EB6E6DD Output = DEA56BDABBC6D24183CF7BDE1E1F78631B2B0230C76FF2F43075F2FDE77CF052769276CAD98DA62394EC62D77730F5761489585E093EA7315F3592717C485C84 +# Test vectors from https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/cSHAKE_samples.pdf +FIPSversion = >=4.0.0 +Digest = CSHAKE-128 +Input = 00010203 +Output = C1C36925B6409A04F1B504FCBCA9D82B4017277CB5ED2B2065FC1D3814D5AAF5 +Ctrl = function-name: +Ctrl = customization:Email Signature + +FIPSversion = >=4.0.0 +Digest = CSHAKE-128 +Input = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7 +Output = C5221D50E4F822D96A2E8881A961420F294B7B24FE3D2094BAED2C6524CC166B +Ctrl = customization:Email Signature + +FIPSversion = >=4.0.0 +Digest = CSHAKE-256 +Input = 00010203 +Output = D008828E2B80AC9D2218FFEE1D070C48B8E4C87BFF32C9699D5B6896EEE0EDD164020E2BE0560858D9C00C037E34A96937C561A74C412BB4C746469527281C8C +Ctrl = customization:Email Signature + +FIPSversion = >=4.0.0 +Digest = CSHAKE-256 +Input = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7 +Output = 07DC27B11E51FBAC75BC7B3C1D983E8B4B85FB1DEFAF218912AC86430273091727F42B17ED1DF63E8EC118F04B23633C1DFB1574C8FB55CB45DA8E25AFB092BB +Ctrl = function-name: +Ctrl = customization:Email Signature + +# These are SHAKE test vectors from (i.e where n = s = empty string) +FIPSversion = >=4.0.0 +Digest = CSHAKE128 +Input = 49d81708d86cd59dea0ac2c1017a9712d6dffb754dde0b57a9023a39fc5f5b6be276fc176f59f6826610428fac3a0e85fcf71011db061b8fcf2bf085ccd45670effb6dc46f4e3f2ed08e981c5935187fc95b86cf46da675096b1cf9591a67842d6301116be93d8288e4d6b70f1b1db8aa5d203b774a21825665b8170351ee86801da91154570eaf80a1564945af7822df8232fd04ea65593a7f2ab1e9e84cf6ad6c494c9ec2d9d27aaad2b8f7e4f33f12a17b422bc2d4724c13ff8a8b62054d1bfb5c33b9c11183cd8df67694300165ca37637b5a781155f1c070d156339a0242374c6723b6584bffb71c02b935455f8cb086392f5e8e8cc2015956d8f19daeb6aca4476b27108387a2ce0dc5591154d0b94ddc090abe8f4363036b821062baffb7fe550ea7dcd30bfd86c84710081e1c9e450475e123c5ec41f98ff0149bbf6405b5207cad1fb2f313d0f2bcee9be3f6ebe623049640d9234ab644a172ab14ba02633a339b5b9bb38226fda5694f7ec63ebbb8238eb8219ec9c429f4bf0353383a72f2d21702f5e3c513499f04852710f33044512edc47a56bad90885e5713851a7efac694b869fa590076e844ff757d95de581c1b3fa3dd8ccd28cad4f8ae173ee1b28f98ee606dca89063fbef0f262b33053f2c854debdc9cd433ab77abb64f445aa9b981761c4761767f3b71c2646c7b0d873baae50bc9f0 +Output = c609be05458f7ab33e7b6b54bc6e8999 + +FIPSversion = >=4.0.0 +Digest = CSHAKE256 +Input = dc5a100fa16df1583c79722a0d72833d3bf22c109b8889dbd35213c6bfce205813edae3242695cfd9f59b9a1c203c1b72ef1a5423147cb990b5316a85266675894e2644c3f9578cebe451a09e58c53788fe77a9e850943f8a275f830354b0593a762bac55e984db3e0661eca3cb83f67a6fb348e6177f7dee2df40c4322602f094953905681be3954fe44c4c902c8f6bba565a788b38f13411ba76ce0f9f6756a2a2687424c5435a51e62df7a8934b6e141f74c6ccf539e3782d22b5955d3baf1ab2cf7b5c3f74ec2f9447344e937957fd7f0bdfec56d5d25f61cde18c0986e244ecf780d6307e313117256948d4230ebb9ea62bb302cfe80d7dfebabc4a51d7687967ed5b416a139e974c005fff507a96 +Output = 2bac5716803a9cda8f9e84365ab0a681327b5ba34fdedfb1c12e6e807f45284b +FIPSversion = >=4.0.0 +Digest = CSHAKE256 +Input = dc5a100fa16df1583c79722a0d72833d3bf22c109b8889dbd35213c6bfce205813edae3242695cfd9f59b9a1c203c1b72ef1a5423147cb990b5316a85266675894e2644c3f9578cebe451a09e58c53788fe77a9e850943f8a275f830354b0593a762bac55e984db3e0661eca3cb83f67a6fb348e6177f7dee2df40c4322602f094953905681be3954fe44c4c902c8f6bba565a788b38f13411ba76ce0f9f6756a2a2687424c5435a51e62df7a8934b6e141f74c6ccf539e3782d22b5955d3baf1ab2cf7b5c3f74ec2f9447344e937957fd7f0bdfec56d5d25f61cde18c0986e244ecf780d6307e313117256948d4230ebb9ea62bb302cfe80d7dfebabc4a51d7687967ed5b416a139e974c005fff507a96 +Output = 2bac5716803a9cda8f9e84365ab0a681327b5ba34fdedfb1c12e6e807f45284b +Ctrl = function-name: +Ctrl = customization: + +# A test from https://github.com/usnistgov/ACVP-Server/blob/master/gen-val/json-files/cSHAKE-128-1.0/internalProjection.json +# where the encoding of the strings is exactly a multiple of the block size w. i.e. no zero padding is added. +# The output length was modified to be on a byte boundary. +FIPSversion = >=4.0.0 +Digest = CSHAKE-128 +Input = EA18 +Ctrl = customization:fmkctMwhBB[=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[ OyJ +Output = 442BE69B2AFD7C8282839920A8446AAF16A5049D3D018EAC87E04CF9225870EFCA6F88DB415829 + +# Test that uses an unknown function name +FIPSversion = >=4.0.0 +Digest = CSHAKE-128 +Input = CA88F708FA +Ctrl = function-name:BadName +Result = DIGESTINIT_ERROR +Reason = invalid function name Title = Case insensitive digest tests @@ -395,4 +481,3 @@ Output = A7FFC6F8BF1ED76651C14756A061D662F580FF4DE43B49FA82D80A4B80F8434A Digest = shA512 Input = "abc" Output = ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f - diff --git a/util/perl/OpenSSL/paramnames.pm b/util/perl/OpenSSL/paramnames.pm index cea9d2d0686..a36f5dbe25e 100644 --- a/util/perl/OpenSSL/paramnames.pm +++ b/util/perl/OpenSSL/paramnames.pm @@ -172,6 +172,10 @@ my %params = ( 'OSSL_DIGEST_PARAM_SIZE' => "size", # size_t 'OSSL_DIGEST_PARAM_XOF' => "xof", # int, 0 or 1 'OSSL_DIGEST_PARAM_ALGID_ABSENT' => "algid-absent", # int, 0 or 1 + 'OSSL_DIGEST_PARAM_FUNCTION_NAME' => "function-name", # utf8 string + 'OSSL_DIGEST_PARAM_CUSTOMIZATION' => "customization", # utf8 string + 'OSSL_DIGEST_PARAM_PROPERTIES' => '*OSSL_ALG_PARAM_PROPERTIES',# utf8 string + # external mu digest parameters 'OSSL_DIGEST_PARAM_MU_PUB_KEY' => "pub", # octet string 'OSSL_DIGEST_PARAM_MU_CONTEXT_STRING' => "context-string", # octet string