diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 50d4cb7c435..b23b8406791 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -728,6 +728,7 @@ WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC_A WOLFSSL_DILITHIUM_SMALL_MEM_POLY64 WOLFSSL_DISABLE_EARLY_SANITY_CHECKS +WOLFSSL_DRBG_SHA256 WOLFSSL_DTLS_DISALLOW_FUTURE WOLFSSL_DTLS_RECORDS_CAN_SPAN_DATAGRAMS WOLFSSL_DTLS_RESEND_ONLY_TIMEOUT diff --git a/IDE/WIN10/wolfssl-fips.vcxproj b/IDE/WIN10/wolfssl-fips.vcxproj index eac076eb3ae..31149cfec0d 100644 --- a/IDE/WIN10/wolfssl-fips.vcxproj +++ b/IDE/WIN10/wolfssl-fips.vcxproj @@ -318,6 +318,13 @@ + + + + + + + diff --git a/configure.ac b/configure.ac index 938ceddb4dd..91580eff0c7 100644 --- a/configure.ac +++ b/configure.ac @@ -624,21 +624,31 @@ AS_CASE([$ENABLED_FIPS], DEF_SP_MATH="yes" DEF_FAST_MATH="no" ], + [v7],[ + FIPS_VERSION="v7" + HAVE_FIPS_VERSION=7 + HAVE_FIPS_VERSION_MAJOR=7 + HAVE_FIPS_VERSION_MINOR=0 + HAVE_FIPS_VERSION_PATCH=0 + ENABLED_FIPS="yes" + DEF_SP_MATH="yes" + DEF_FAST_MATH="no" + ], # Should always remain one ahead of the latest so as not to be confused with # the latest - [ready|v6-ready],[ + [ready|v7-ready],[ FIPS_VERSION="ready" - HAVE_FIPS_VERSION=7 - HAVE_FIPS_VERSION_MAJOR=7 + HAVE_FIPS_VERSION=8 + HAVE_FIPS_VERSION_MAJOR=8 HAVE_FIPS_VERSION_MINOR=0 HAVE_FIPS_VERSION_PATCH=0 ENABLED_FIPS="yes" DEF_SP_MATH="yes" DEF_FAST_MATH="no" ], - [dev|v6-dev],[ + [dev|v7-dev],[ FIPS_VERSION="dev" - HAVE_FIPS_VERSION_MAJOR=7 + HAVE_FIPS_VERSION_MAJOR=8 HAVE_FIPS_VERSION_MINOR=0 HAVE_FIPS_VERSION_PATCH=0 ENABLED_FIPS="yes" @@ -646,14 +656,14 @@ AS_CASE([$ENABLED_FIPS], ], [lean-aesgcm|lean-aesgcm-ready|lean-aesgcm-dev],[ FIPS_VERSION="$ENABLED_FIPS" - HAVE_FIPS_VERSION_MAJOR=7 + HAVE_FIPS_VERSION_MAJOR=8 HAVE_FIPS_VERSION_MINOR=0 HAVE_FIPS_VERSION_PATCH=0 ENABLED_FIPS="yes" ], [ AS_IF([test "$ENABLED_FIPS" = "yes"],[ENABLED_FIPS="(unset)"],[ENABLED_FIPS=\"$ENABLED_FIPS\"]) - AC_MSG_ERROR([Invalid value for --enable-fips $ENABLED_FIPS (main options: v1, v2, v5, v6, ready, dev, rand, lean-aesgcm, no, disabled)]) + AC_MSG_ERROR([Invalid value for --enable-fips $ENABLED_FIPS (main options: v1, v2, v5, v6, v7, ready, dev, rand, lean-aesgcm, no, disabled)]) ]) if test -z "$HAVE_FIPS_VERSION_MAJOR" @@ -1795,118 +1805,6 @@ do esac done -if test "$ENABLED_MLKEM" != "no" -then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_MLKEM" - # Use liboqs if specified. - if test "$ENABLED_LIBOQS" = "no"; then - ENABLED_WC_MLKEM=yes - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_MLKEM" - AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_WC_MLKEM" - fi - - if test "$ENABLED_ORIGINAL" = "yes"; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_MLKEM_KYBER" - if test "$ENABLED_MLKEM512" = ""; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_KYBER512" - fi - if test "$ENABLED_MLKEM768" = ""; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_KYBER768" - fi - if test "$ENABLED_MLKEM1024" = ""; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_KYBER1024" - fi - if test "$ENABLED_ML_KEM" = "unset"; then - ENABLED_ML_KEM=no - fi - fi - if test "$ENABLED_ML_KEM" = "unset"; then - ENABLED_ML_KEM=yes - fi - if test "$ENABLED_ML_KEM" = "yes"; then - if test "$ENABLED_MLKEM512" = ""; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_KEM_512" - fi - if test "$ENABLED_MLKEM768" = ""; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_KEM_768" - fi - if test "$ENABLED_MLKEM1024" = ""; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_KEM_1024" - fi - else - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_KEM" - fi - if test "$ENABLED_MLKEM_MAKE_KEY" = "no"; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_MLKEM_NO_MAKE_KEY" - fi - if test "$ENABLED_MLKEM_ENCAPSULATE" = "no"; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_MLKEM_NO_ENCAPSULATE" - fi - if test "$ENABLED_MLKEM_DECAPSULATE" = "no"; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_MLKEM_NO_DECAPSULATE" - fi - - if test "$ENABLED_WC_MLKEM" = "yes" - then - test "$enable_sha3" = "" && enable_sha3=yes - test "$enable_shake128" = "" && enable_shake128=yes - test "$enable_shake256" = "" && enable_shake256=yes - fi -fi - -AC_ARG_ENABLE([tls-mlkem-standalone], - [AS_HELP_STRING([--enable-tls-mlkem-standalone],[Enable ML-KEM as standalone TLS key exchange (non-hybrid) (default: disabled)])], - [ ENABLED_MLKEM_STANDALONE=$enableval ], - [ ENABLED_MLKEM_STANDALONE=no ] - ) - -AS_IF([ test "$ENABLED_MLKEM_STANDALONE" = "yes" && test "$ENABLED_ML_KEM" = "no" ],[AC_MSG_ERROR([ML-KEM as standalone TLS key exchange (non-hybrid) requires ML-KEM.])]) -if test "$ENABLED_MLKEM_STANDALONE" != "yes" -then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_TLS_NO_MLKEM_STANDALONE" -fi - -AC_ARG_ENABLE([pqc-hybrids], - [AS_HELP_STRING([--enable-pqc-hybrids],[Enable PQ/T hybrid combinations (default: enabled)])], - [ ENABLED_PQC_HYBRIDS=$enableval ], - [ ENABLED_PQC_HYBRIDS=yes ] - ) - -if test "$ENABLED_PQC_HYBRIDS" = "yes" -then - if test "$ENABLED_ML_KEM" = "no" || test "$ENABLED_MLKEM" = "no" - then - ENABLED_PQC_HYBRIDS=no - elif test "$ENABLED_MLKEM768" = "" && test "$ENABLED_MLKEM1024" = ""; then - AC_MSG_NOTICE([PQC hybrid combinations require either ML-KEM 768 or ML-KEM 1024, but both disabled.]) - ENABLED_PQC_HYBRIDS=no - else - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_PQC_HYBRIDS" - fi -fi - -if test "$ENABLED_ML_KEM" != "no" && test "$ENABLED_MLKEM" != "no" -then - if test "$ENABLED_PQC_HYBRIDS" = "no" && test "$ENABLED_MLKEM_STANDALONE" = "no" && test "$ENABLED_CRYPTONLY" = "no" - then - AC_MSG_ERROR([Both hybrid PQ/T and standalone ML-KEM are disabled, so no PQC hybrid combinations will be available.]) - fi -fi - -# Extra PQ/T Hybrid combinations -AC_ARG_ENABLE([extra-pqc-hybrids], - [AS_HELP_STRING([--enable-extra-pqc-hybrids],[Enable extra PQ/T hybrid combinations (default: disabled)])], - [ ENABLED_EXTRA_PQC_HYBRIDS=$enableval ], - [ ENABLED_EXTRA_PQC_HYBRIDS=no ] - ) - -if test "$ENABLED_EXTRA_PQC_HYBRIDS" = "yes" -then - AS_IF([ test "$ENABLED_EXPERIMENTAL" != "yes" ],[ AC_MSG_ERROR([extra-pqc-hybrids requires --enable-experimental.]) ]) - AS_IF([ test "$ENABLED_ML_KEM" = "no" ],[ AC_MSG_ERROR([extra-pqc-hybrids requires ML-KEM.]) ]) - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_EXTRA_PQC_HYBRIDS" -fi - # Dilithium # - SHA3, Shake128 and Shake256 AC_ARG_ENABLE([mldsa], @@ -1978,39 +1876,6 @@ do esac done -if test "$ENABLED_DILITHIUM" != "no" -then - AM_CFLAGS="$AM_CFLAGS -DHAVE_DILITHIUM" - - if test "$ENABLED_MLDSA44" = ""; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_DSA_44" - fi - if test "$ENABLED_MLDSA65" = ""; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_DSA_65" - fi - if test "$ENABLED_MLDSA87" = ""; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_DSA_87" - fi - if test "$ENABLED_DILITHIUM_MAKE_KEY" = "no"; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DILITHIUM_NO_MAKE_KEY" - fi - if test "$ENABLED_DILITHIUM_SIGN" = "no"; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DILITHIUM_NO_SIGN" - fi - if test "$ENABLED_DILITHIUM_VERIFY" = "no"; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DILITHIUM_NO_VERIFY" - fi - - if test "$ENABLED_LIBOQS" = "no"; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_DILITHIUM" - AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_WC_DILITHIUM" - test "$enable_sha3" = "" && enable_sha3=yes - test "$enable_shake128" = "" && enable_shake128=yes - test "$enable_shake256" = "" && enable_shake256=yes - fi - ENABLED_CERTS=yes -fi - # XMSS ENABLED_WC_XMSS=no AC_ARG_ENABLE([xmss], @@ -2090,19 +1955,6 @@ AC_ARG_WITH([libxmss], [XMSS_ROOT=""] ) -if test "$ENABLED_XMSS" != "no" -then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_XMSS" - - # Use hash-sigs XMSS lib if enabled. - if test "$ENABLED_LIBXMSS" = "yes"; then - ENABLED_WC_XMSS=no - else - ENABLED_WC_XMSS=yes - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_XMSS" - fi -fi - # LMS ENABLED_WC_LMS=no AC_ARG_ENABLE([lms], @@ -2130,6 +1982,9 @@ do sha256-192) AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_LMS_SHA256_192" ;; + shake256) + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_LMS_SHAKE256" + ;; *) AC_MSG_ERROR([Invalid choice for LMS []: $ENABLED_LMS.]) break;; @@ -2204,19 +2059,6 @@ AC_ARG_WITH([liblms], ] ) -if test "$ENABLED_LMS" != "no" -then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_LMS" - - # Use hash-sigs LMS lib if enabled. - if test "$ENABLED_LIBLMS" = "yes"; then - ENABLED_WC_LMS=no - else - ENABLED_WC_LMS=yes - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_LMS" - fi -fi - # SLH-DSA ENABLED_SLHDSA=yes AC_ARG_ENABLE([slhdsa], @@ -2271,59 +2113,50 @@ do no-f) AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_FAST" ;; + sha2) + SLHDSA_SHA2=yes + SLHDSA_PARAM_SHA2_128S=yes + SLHDSA_PARAM_SHA2_128F=yes + SLHDSA_PARAM_SHA2_192S=yes + SLHDSA_PARAM_SHA2_192F=yes + SLHDSA_PARAM_SHA2_256S=yes + SLHDSA_PARAM_SHA2_256F=yes + ;; + sha2-128s) + SLHDSA_SHA2=yes + SLHDSA_PARAM_SHA2_128S=yes + ;; + sha2-128f) + SLHDSA_SHA2=yes + SLHDSA_PARAM_SHA2_128F=yes + ;; + sha2-192s) + SLHDSA_SHA2=yes + SLHDSA_PARAM_SHA2_192S=yes + ;; + sha2-192f) + SLHDSA_SHA2=yes + SLHDSA_PARAM_SHA2_192F=yes + ;; + sha2-256s) + SLHDSA_SHA2=yes + SLHDSA_PARAM_SHA2_256S=yes + ;; + sha2-256f) + SLHDSA_SHA2=yes + SLHDSA_PARAM_SHA2_256F=yes + ;; + no-sha2-s) + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL" + ;; + no-sha2-f) + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST" + ;; *) AC_MSG_ERROR([Invalid choice for SLH-DSA []: $ENABLED_SLHDSA.]) break;; esac done - -if test "$ENABLED_SLHDSA" != "no" -then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_SLHDSA" - AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_HAVE_SLHDSA" - - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_SLHDSA" - - if test "$SLHDSA_PARAM_128S" = "yes" - then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_128S" - else - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_128S" - fi - if test "$SLHDSA_PARAM_128F" = "yes" - then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_128F" - else - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_128F" - fi - if test "$SLHDSA_PARAM_192S" = "yes" - then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_192S" - else - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_192S" - fi - if test "$SLHDSA_PARAM_192F" = "yes" - then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_192F" - else - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_192F" - fi - if test "$SLHDSA_PARAM_256S" = "yes" - then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_256S" - else - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_256S" - fi - if test "$SLHDSA_PARAM_256F" = "yes" - then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_256F" - else - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_256F" - fi - - enable_shake256=yes -fi - # SINGLE THREADED AC_ARG_ENABLE([singlethreaded], [AS_HELP_STRING([--enable-singlethreaded],[Enable wolfSSL single threaded (default: disabled)])], @@ -4711,7 +4544,7 @@ if test "$ENABLED_MLKEM" != "no" then if test "$ENABLED_SHAKE128" = "no" then - AC_MSG_WARN([MLKEM enabled (not explicitly disabled); overriding --disable-shake128 to enable SHAKE128]) + AC_MSG_NOTICE([MLKEM enabled (not explicitly disabled); overriding --disable-shake128 to enable SHAKE128]) ENABLED_SHAKE128=yes enable_shake128=yes fi @@ -4729,7 +4562,7 @@ if test "$ENABLED_MLKEM" != "no" then if test "$ENABLED_SHAKE256" = "no" then - AC_MSG_WARN([MLKEM enabled (not explicitly disabled); overriding --disable-shake256 to enable SHAKE256]) + AC_MSG_NOTICE([MLKEM enabled (not explicitly disabled); overriding --disable-shake256 to enable SHAKE256]) ENABLED_SHAKE256=yes enable_shake256=yes fi @@ -4760,6 +4593,25 @@ then AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHA512" fi +# SHA-256 Hash DRBG (SP 800-90A) -- sub-option of hashdrbg +AC_ARG_ENABLE([sha256-drbg], + [AS_HELP_STRING([--enable-sha256-drbg],[Enable SHA-256 Hash DRBG (default: enabled)])], + [ ENABLED_SHA256_DRBG=$enableval ], + [ ENABLED_SHA256_DRBG=yes ] + ) + +# SHA-512 Hash DRBG (SP 800-90A) -- sub-option of hashdrbg +AC_ARG_ENABLE([sha512-drbg], + [AS_HELP_STRING([--enable-sha512-drbg],[Enable SHA-512 Hash DRBG (default: enabled)])], + [ ENABLED_SHA512_DRBG=$enableval ], + [ ENABLED_SHA512_DRBG=yes ] + ) + +# SHA-512 DRBG requires SHA-512 +if test "$ENABLED_SHA512" != "yes" +then + ENABLED_SHA512_DRBG=no +fi # SHA384 AC_ARG_ENABLE([sha384], @@ -6257,11 +6109,11 @@ AC_ARG_ENABLE([aeskeywrap], # FIPS feature and macro setup AS_CASE([$FIPS_VERSION], - [v6|ready|dev],[ # FIPS 140-3 SRTP-KDF + [v7|ready|dev],[ # FIPS 140-3 PQ-FS AS_IF([test "$FIPS_VERSION" = "dev"], [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_FIPS_DEV"]) - AS_IF([test "$FIPS_VERSION" = "ready"], + AS_IF([test "$FIPS_VERSION" = "ready" || test "$FIPS_VERSION" = "v7"], [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_FIPS_READY"]) AM_CFLAGS="$AM_CFLAGS \ @@ -6376,8 +6228,8 @@ AS_CASE([$FIPS_VERSION], (test "$FIPS_VERSION" != "dev" || test "$enable_sha512" != "no")], [ENABLED_SHA512="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHA512 -DWOLFSSL_SHA384"]) - # SHA512-224 and SHA512-256 are SHA-2 algorithms not in our FIPS algorithm list - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NOSHA512_224 -DWOLFSSL_NOSHA512_256" + # SHA512-224 and SHA512-256 enabled for FIPS v7+ (needed for ML-DSA + # HashML-DSA ACVP test vectors with SHA2-512/224 and SHA2-512/256) # Shake128 because we're testing SHAKE256 AS_IF([test "x$ENABLED_SHAKE128" = "xno" && @@ -6438,6 +6290,64 @@ AS_CASE([$FIPS_VERSION], (test "$FIPS_VERSION" != "dev" || test "$enable_aeskeywrap" != "no")], [ENABLED_AESKEYWRAP="yes"; AM_CFLAGS="$AM_CFLAGS -DHAVE_AES_KEYWRAP"]) +# Post-Quantum section + AS_IF([test "$ENABLED_MLKEM" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_mlkem" != "no")], + [ENABLED_MLKEM="yes" + ENABLED_MLKEM512="yes" + ENABLED_MLKEM768="yes" + ENABLED_MLKEM1024="yes" + ENABLED_MLKEM_MAKE_KEY="yes" + ENABLED_MLKEM_ENCAPSULATE="yes" + ENABLED_MLKEM_DECAPSULATE="yes"]) + + AS_IF([test "$ENABLED_DILITHIUM" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_dilithium" != "no")], + [ENABLED_DILITHIUM="yes" + ENABLED_MLDSA44="yes" + ENABLED_MLDSA65="yes" + ENABLED_MLDSA87="yes" + ENABLED_DILITHIUM_MAKE_KEY="yes" + ENABLED_DILITHIUM_SIGN="yes" + ENABLED_DILITHIUM_VERIFY="yes"]) + + AS_IF([test "$ENABLED_XMSS" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_xmss" != "no")], + [ENABLED_XMSS="yes"]) + + AS_IF([test "$ENABLED_LMS" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_lms" != "no")], + [ENABLED_LMS="yes"]) + # LMS: enable SHA-256/192 and SHAKE256 parameter sets for FIPS v7 + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_LMS_SHA256_192 -DWOLFSSL_LMS_SHAKE256" + + AS_IF([test "$ENABLED_SLHDSA" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_slhdsa" != "no")], + [ENABLED_SLHDSA="yes" + SLHDSA_PARAM_128S="yes" + SLHDSA_PARAM_128F="yes" + SLHDSA_PARAM_192S="yes" + SLHDSA_PARAM_192F="yes" + SLHDSA_PARAM_256S="yes" + SLHDSA_PARAM_256F="yes" + SLHDSA_SHA2="yes" + SLHDSA_PARAM_SHA2_128S="yes" + SLHDSA_PARAM_SHA2_128F="yes" + SLHDSA_PARAM_SHA2_192S="yes" + SLHDSA_PARAM_SHA2_192F="yes" + SLHDSA_PARAM_SHA2_256S="yes" + SLHDSA_PARAM_SHA2_256F="yes"]) + +# SHA-256 DRBG -- cannot be disabled at build time in FIPS mode + AS_IF([test "$enable_sha256_drbg" = "no"], + [AC_MSG_WARN([Can not disable SHA256-DRBG at build time in FIPS mode, disable at run-time with wc_Sha256Drbg_Disable() or wc_Sha256Drbg_Disable_fips()])]) + ENABLED_SHA256_DRBG="yes" + +# SHA-512 DRBG -- cannot be disabled at build time in FIPS mode + AS_IF([test "$enable_sha512_drbg" = "no"], + [AC_MSG_WARN([Can not disable SHA512-DRBG at build time in FIPS mode, disable it at run-time with wc_Sha512Drbg_Disable() or wc_Sha512Drbg_Disable_fips()])]) + ENABLED_SHA512_DRBG="yes" + # Old TLS requires MD5 + HMAC, which is not allowed under FIPS 140-3 AS_IF([test "$ENABLED_OLD_TLS" != "no"], [AC_MSG_WARN([Forcing off oldtls for FIPS ${FIPS_VERSION}.]) @@ -6445,12 +6355,7 @@ AS_CASE([$FIPS_VERSION], ], - [lean-aesgcm|lean-aesgcm-ready|lean-aesgcm-dev],[ - - AS_IF([test "$FIPS_VERSION" = "lean-aesgcm-dev"], - [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_FIPS_DEV"]) - AS_IF([test "$FIPS_VERSION" = "lean-aesgcm-ready"], - [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_FIPS_READY"]) + [v6],[ # FIPS 140-3 SRTP-KDF (frozen) AM_CFLAGS="$AM_CFLAGS \ -DHAVE_FIPS \ @@ -6458,7 +6363,194 @@ AS_CASE([$FIPS_VERSION], -DHAVE_FIPS_VERSION_MAJOR=$HAVE_FIPS_VERSION_MAJOR \ -DHAVE_FIPS_VERSION_MINOR=$HAVE_FIPS_VERSION_MINOR \ -DHAVE_FIPS_VERSION_PATCH=$HAVE_FIPS_VERSION_PATCH \ - -DNO_BIG_INT \ + -DHAVE_ECC_CDH \ + -DWC_RSA_NO_PADDING \ + -DECC_USER_CURVES \ + -DHAVE_ECC384 \ + -DHAVE_ECC521 \ + -DWOLFSSL_VALIDATE_FFC_IMPORT \ + -DHAVE_FFDHE_Q \ + -DHAVE_FFDHE_3072 \ + -DHAVE_FFDHE_4096 \ + -DHAVE_FFDHE_6144 \ + -DHAVE_FFDHE_8192" + + # KCAPI API does not support custom k for sign, don't force enable ECC key sizes and don't use seed callback + AS_IF([test "x$ENABLED_KCAPI_ECC" = "xno"], + [AM_CFLAGS="$AM_CFLAGS \ + -DWC_RNG_SEED_CB \ + -DWOLFSSL_ECDSA_SET_K \ + -DWOLFSSL_VALIDATE_ECC_IMPORT \ + -DWOLFSSL_VALIDATE_ECC_KEYGEN \ + -DHAVE_ECC192 \ + -DHAVE_ECC224 \ + -DHAVE_ECC256"]) + + DEFAULT_MAX_CLASSIC_ASYM_KEY_BITS=8192 +# optimizations section + +# protocol section + AS_IF([test "$ENABLED_WOLFSSH" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_ssh" != "no")], + [enable_ssh="yes"]) + + AS_IF([test "$ENABLED_HKDF" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_hkdf" != "no")], + [ENABLED_HKDF="yes"; AM_CFLAGS="$AM_CFLAGS -DHAVE_HKDF"]) + + AS_IF([test "x$ENABLED_PWDBASED" = "xno" && + (test "$FIPS_VERSION" != "dev" || test "$enable_pwdbased" != "no")], + [ENABLED_PWDBASED="yes"; AM_CFLAGS="$AM_CFLAGS -DHAVE_PBKDF2 -DHAVE_AESGCM"]) + + AS_IF([test "x$ENABLED_SRTP" = "xno" && + (test "$FIPS_VERSION" != "dev" || test "$enable_srtp" != "no")], + [ENABLED_SRTP="yes"]) + AS_IF([test "x$ENABLED_SRTP_KDF" = "xno" && + (test "$FIPS_VERSION" != "dev" || test "$enable_srtp_kdf" != "no")], + [ENABLED_SRTP_KDF="yes"]) + +# public key section + AS_IF([test "$ENABLED_KEYGEN" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_keygen" != "no")], + [ENABLED_KEYGEN="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_KEY_GEN"]) + +# AS_IF([test "$ENABLED_COMPKEY" != "yes" && +# (test "$FIPS_VERSION" != "dev" || test "$enable_compkey" != "yes")], +# [ENABLED_COMPKEY="yes"]) + + AS_IF([test "$ENABLED_RSAPSS" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_rsapss" != "no")], + [ENABLED_RSAPSS="yes"; AM_CFLAGS="$AM_CFLAGS -DWC_RSA_PSS"]) + + AS_IF([test "$ENABLED_ECC" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_ecc" != "no")], + [ENABLED_ECC="yes"; AM_CFLAGS="$AM_CFLAGS -DHAVE_ECC -DTFM_ECC256" + AS_IF([test "$ENABLED_ECC_SHAMIR" = "yes"], + [AM_CFLAGS="$AM_CFLAGS -DECC_SHAMIR"])]) + + AS_IF([test "$ENABLED_ED25519" = "no" && + (test "$FIPS_VERSION" != "dev" || test "$enable_ed25519" != "no")], + [ENABLED_ED25519="yes"; AM_CFLAGS="$AM_CFLAGS -DHAVE_ED25519 -DHAVE_ED25519_KEY_IMPORT"]) + + AS_IF([test "$ENABLED_CURVE25519" != "no" && + (test "$FIPS_VERSION" != "dev" || test "$enable_curve25519" = "")], + [ENABLED_CURVE25519="no"; AM_CFLAGS="$AM_CFLAGS"]) + + AS_IF([test "x$ENABLED_ED448" != "xyes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_ed448" != "no")], + [ENABLED_ED448="yes"; AM_CFLAGS="$AM_CFLAGS -DHAVE_ED448 -DHAVE_ED448_KEY_IMPORT"]) + + AS_IF([test "$ENABLED_CURVE448" != "no" && + (test "$FIPS_VERSION" != "dev" || test "$enable_curve448" = "")], + [ENABLED_CURVE448="no"; AM_CFLAGS="$AM_CFLAGS"]) + + AS_IF([test "x$ENABLED_ED25519_STREAM" != "xyes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_ed25519_stream" != "no")], + [ENABLED_ED25519_STREAM="yes"]) + AS_IF([test "x$ENABLED_ED448_STREAM" != "xyes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_ed448_stream" != "no")], + [ENABLED_ED448_STREAM="yes"]) + + AS_IF([test "x$ENABLED_ECCCUSTCURVES" != "xno" && + test "$FIPS_VERSION" != "dev"], + [AC_MSG_WARN([Forcing off ecccustcurves for FIPS ${FIPS_VERSION}.]) + ENABLED_ECCCUSTCURVES="no"]) + +# Hashing section + AS_IF([test "x$ENABLED_SHA3" != "xyes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_sha3" != "no")], + [ENABLED_SHA3="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHA3"]) + + AS_IF([test "$ENABLED_SHA224" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_sha224" != "no")], + [ENABLED_SHA224="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHA224"]) + + AS_IF([test "$ENABLED_SHA512" = "no" && + (test "$FIPS_VERSION" != "dev" || test "$enable_sha512" != "no")], + [ENABLED_SHA512="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHA512 -DWOLFSSL_SHA384"]) + + # SHA512-224 and SHA512-256 are needed for HashML-DSA (FIPS 204) + + # Shake128 because we're testing SHAKE256 + AS_IF([test "x$ENABLED_SHAKE128" = "xno" && + (test "$FIPS_VERSION" != "dev" || test "$enable_shake128" != "no")], + [ENABLED_SHAKE128="yes"]) + + # Shake256 mandated for ED448 + AS_IF([test "x$ENABLED_SHAKE256" = "xno" && + (test "$FIPS_VERSION" != "dev" || test "$enable_shake256" != "no")], + [ENABLED_SHAKE256="yes"]) + +# Aes section + AS_IF([test "$ENABLED_AESCCM" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_aesccm" != "no")], + [ENABLED_AESCCM="yes"; AM_CFLAGS="$AM_CFLAGS -DHAVE_AESCCM"]) + + AS_IF([test "$ENABLED_AESCTR" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_aesctr" != "no")], + [ENABLED_AESCTR="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_AES_COUNTER"]) + + AS_IF([test "$ENABLED_CMAC" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_cmac" != "no")], + [ENABLED_CMAC="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_CMAC"]) + + AS_IF([test "$ENABLED_AESGCM" = "no" && + (test "$FIPS_VERSION" != "dev" || test "$enable_aesgcm" != "no")], + [ENABLED_AESGCM="yes"; AM_CFLAGS="$AM_CFLAGS -DHAVE_AESGCM"; AM_CCASFLAGS="$AM_CCASFLAGS -DHAVE_AESGCM"]) + + AS_IF([test "$ENABLED_AESGCM_STREAM" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_aesgcm_stream" != "no")], + [ENABLED_AESGCM_STREAM="yes"]) + + AS_IF([test "x$ENABLED_AESOFB" = "xno" && + (test "$FIPS_VERSION" != "dev" || test "$enable_aesofb" != "no")], + [ENABLED_AESOFB="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_AES_OFB"]) + + AS_IF([test "x$ENABLED_AESCFB" = "xno" && + (test "$FIPS_VERSION" != "dev" || test "$enable_aescfb" != "no")], + [ENABLED_AESCFB="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_AES_CFB"]) + + AS_IF([test "x$ENABLED_AESXTS" = "xno" && + (test "$FIPS_VERSION" != "dev" || test "$enable_aesxts" != "no")], + [ENABLED_AESXTS="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_AES_XTS"]) + AS_IF([test "x$ENABLED_AESXTS" = "xyes" && test "x$ENABLED_AESNI" = "xyes"], + [AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_AES_XTS"]) + + AS_IF([test "x$ENABLED_AESXTS_STREAM" = "xno" && + (test "$FIPS_VERSION" != "dev" || test "$enable_aesxts_stream" != "no")], + [ENABLED_AESXTS_STREAM="yes"]) + + AS_IF([(test "$ENABLED_AESCCM" != "no" && test "$HAVE_AESCCM_PORT" != "yes") || + (test "$ENABLED_AESCTR" != "no" && test "$HAVE_AESCTR_PORT" != "yes") || + (test "$ENABLED_AESGCM" != "no" && test "$HAVE_AESGCM_PORT" != "yes") || + (test "$ENABLED_AESOFB" != "no" && test "$HAVE_AESOFB_PORT" != "yes")], + [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_AES_DIRECT -DHAVE_AES_ECB"]) + + AS_IF([test "x$ENABLED_AESKEYWRAP" != "xyes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_aeskeywrap" != "no")], + [ENABLED_AESKEYWRAP="yes"; AM_CFLAGS="$AM_CFLAGS -DHAVE_AES_KEYWRAP"]) + +# Old TLS requires MD5 + HMAC, which is not allowed under FIPS 140-3 + AS_IF([test "$ENABLED_OLD_TLS" != "no"], + [AC_MSG_WARN([Forcing off oldtls for FIPS ${FIPS_VERSION}.]) + ENABLED_OLD_TLS="no"; AM_CFLAGS="$AM_CFLAGS -DNO_OLD_TLS"]) + + ], + + [lean-aesgcm|lean-aesgcm-ready|lean-aesgcm-dev],[ + + AS_IF([test "$FIPS_VERSION" = "lean-aesgcm-dev"], + [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_FIPS_DEV"]) + AS_IF([test "$FIPS_VERSION" = "lean-aesgcm-ready"], + [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_FIPS_READY"]) + + AM_CFLAGS="$AM_CFLAGS \ + -DHAVE_FIPS \ + -DHAVE_FIPS_VERSION=$HAVE_FIPS_VERSION \ + -DHAVE_FIPS_VERSION_MAJOR=$HAVE_FIPS_VERSION_MAJOR \ + -DHAVE_FIPS_VERSION_MINOR=$HAVE_FIPS_VERSION_MINOR \ + -DHAVE_FIPS_VERSION_PATCH=$HAVE_FIPS_VERSION_PATCH \ + -DNO_BIG_INT \ -DWC_RNG_SEED_CB \ -DNO_PBKDF2" @@ -6922,6 +7014,11 @@ AS_CASE([$SELFTEST_VERSION], AM_CFLAGS="$AM_CFLAGS -DHAVE_SELFTEST -DHAVE_PUBLIC_FFDHE" ]) +# Selftest uses its own random.c which doesn't support SHA-512 DRBG +# or runtime DRBG disable/enable APIs +AS_IF([test "x$ENABLED_SELFTEST" = "xyes"], + [ENABLED_SHA512_DRBG=no]) + AS_IF([test "x$ENABLED_AESXTS" = "xyes"], [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_AES_XTS -DWOLFSSL_AES_DIRECT"]) AS_IF([test "x$ENABLED_AESXTS" = "xyes" && test "x$ENABLED_INTELASM" = "xyes"], @@ -7027,6 +7124,21 @@ then AM_CFLAGS="$AM_CFLAGS -DWC_SRTP_KDF -DHAVE_AES_ECB -DWOLFSSL_AES_DIRECT" fi +# ML-KEM and Dilithium require SHA-3 and SHAKE -- force them on before flag +# processing so that the correct -D flags are emitted. +if test "$ENABLED_MLKEM" != "no" && test "$ENABLED_LIBOQS" = "no" +then + ENABLED_SHA3=yes + ENABLED_SHAKE128=yes + ENABLED_SHAKE256=yes +fi +if test "$ENABLED_DILITHIUM" != "no" && test "$ENABLED_LIBOQS" = "no" +then + ENABLED_SHA3=yes + ENABLED_SHAKE128=yes + ENABLED_SHAKE256=yes +fi + # Set SHA-3 flags if test "$ENABLED_SHA3" != "no" then @@ -7065,6 +7177,301 @@ else AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_SHAKE256" fi +# MLKEM CFLAG processing (after FIPS section for sandwich pattern) +if test "$ENABLED_MLKEM" != "no" +then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_MLKEM" + # Use liboqs if specified. + if test "$ENABLED_LIBOQS" = "no"; then + ENABLED_WC_MLKEM=yes + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_MLKEM" + AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_WC_MLKEM" + fi + + if test "$ENABLED_ORIGINAL" = "yes"; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_MLKEM_KYBER" + if test "$ENABLED_MLKEM512" = ""; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_KYBER512" + fi + if test "$ENABLED_MLKEM768" = ""; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_KYBER768" + fi + if test "$ENABLED_MLKEM1024" = ""; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_KYBER1024" + fi + if test "$ENABLED_ML_KEM" = "unset"; then + ENABLED_ML_KEM=no + fi + fi + if test "$ENABLED_ML_KEM" = "unset"; then + ENABLED_ML_KEM=yes + fi + if test "$ENABLED_ML_KEM" = "yes"; then + if test "$ENABLED_MLKEM512" = ""; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_KEM_512" + fi + if test "$ENABLED_MLKEM768" = ""; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_KEM_768" + fi + if test "$ENABLED_MLKEM1024" = ""; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_KEM_1024" + fi + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_KEM" + fi + if test "$ENABLED_MLKEM_MAKE_KEY" = "no"; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_MLKEM_NO_MAKE_KEY" + fi + if test "$ENABLED_MLKEM_ENCAPSULATE" = "no"; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_MLKEM_NO_ENCAPSULATE" + fi + if test "$ENABLED_MLKEM_DECAPSULATE" = "no"; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_MLKEM_NO_DECAPSULATE" + fi + + if test "$ENABLED_WC_MLKEM" = "yes" + then + test "$enable_sha3" = "" && enable_sha3=yes + test "$enable_shake128" = "" && enable_shake128=yes + test "$enable_shake256" = "" && enable_shake256=yes + fi +fi + +AC_ARG_ENABLE([tls-mlkem-standalone], + [AS_HELP_STRING([--enable-tls-mlkem-standalone],[Enable ML-KEM as standalone TLS key exchange (non-hybrid) (default: disabled)])], + [ ENABLED_MLKEM_STANDALONE=$enableval ], + [ ENABLED_MLKEM_STANDALONE=no ] + ) + +AS_IF([ test "$ENABLED_MLKEM_STANDALONE" = "yes" && test "$ENABLED_ML_KEM" = "no" ],[AC_MSG_ERROR([ML-KEM as standalone TLS key exchange (non-hybrid) requires ML-KEM.])]) +if test "$ENABLED_MLKEM_STANDALONE" != "yes" +then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_TLS_NO_MLKEM_STANDALONE" +fi + +AC_ARG_ENABLE([pqc-hybrids], + [AS_HELP_STRING([--enable-pqc-hybrids],[Enable PQ/T hybrid combinations (default: enabled)])], + [ ENABLED_PQC_HYBRIDS=$enableval ], + [ ENABLED_PQC_HYBRIDS=yes ] + ) + +if test "$ENABLED_PQC_HYBRIDS" = "yes" +then + if test "$ENABLED_ML_KEM" = "no" || test "$ENABLED_MLKEM" = "no" + then + ENABLED_PQC_HYBRIDS=no + elif test "$ENABLED_MLKEM768" = "" && test "$ENABLED_MLKEM1024" = ""; then + AC_MSG_NOTICE([PQC hybrid combinations require either ML-KEM 768 or ML-KEM 1024, but both disabled.]) + ENABLED_PQC_HYBRIDS=no + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_PQC_HYBRIDS" + fi +fi + +if test "$ENABLED_ML_KEM" != "no" && test "$ENABLED_MLKEM" != "no" +then + if test "$ENABLED_PQC_HYBRIDS" = "no" && test "$ENABLED_MLKEM_STANDALONE" = "no" && test "$ENABLED_CRYPTONLY" = "no" + then + AC_MSG_ERROR([Both hybrid PQ/T and standalone ML-KEM are disabled, so no PQC hybrid combinations will be available.]) + fi +fi + +# Extra PQ/T Hybrid combinations +AC_ARG_ENABLE([extra-pqc-hybrids], + [AS_HELP_STRING([--enable-extra-pqc-hybrids],[Enable extra PQ/T hybrid combinations (default: disabled)])], + [ ENABLED_EXTRA_PQC_HYBRIDS=$enableval ], + [ ENABLED_EXTRA_PQC_HYBRIDS=no ] + ) + +if test "$ENABLED_EXTRA_PQC_HYBRIDS" = "yes" +then + AS_IF([ test "$ENABLED_EXPERIMENTAL" != "yes" ],[ AC_MSG_ERROR([extra-pqc-hybrids requires --enable-experimental.]) ]) + AS_IF([ test "$ENABLED_ML_KEM" = "no" ],[ AC_MSG_ERROR([extra-pqc-hybrids requires ML-KEM.]) ]) + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_EXTRA_PQC_HYBRIDS" +fi + +# Dilithium CFLAG processing (after FIPS section for sandwich pattern) +if test "$ENABLED_DILITHIUM" != "no" +then + AM_CFLAGS="$AM_CFLAGS -DHAVE_DILITHIUM" + + if test "$ENABLED_MLDSA44" = ""; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_DSA_44" + fi + if test "$ENABLED_MLDSA65" = ""; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_DSA_65" + fi + if test "$ENABLED_MLDSA87" = ""; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_DSA_87" + fi + if test "$ENABLED_DILITHIUM_MAKE_KEY" = "no"; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DILITHIUM_NO_MAKE_KEY" + fi + if test "$ENABLED_DILITHIUM_SIGN" = "no"; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DILITHIUM_NO_SIGN" + fi + if test "$ENABLED_DILITHIUM_VERIFY" = "no"; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DILITHIUM_NO_VERIFY" + fi + + if test "$ENABLED_LIBOQS" = "no"; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_DILITHIUM" + AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_WC_DILITHIUM" + test "$enable_sha3" = "" && enable_sha3=yes + test "$enable_shake128" = "" && enable_shake128=yes + test "$enable_shake256" = "" && enable_shake256=yes + fi + ENABLED_CERTS=yes +fi + +# XMSS CFLAG processing (after FIPS section for sandwich pattern) +if test "$ENABLED_XMSS" != "no" +then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_XMSS" + + # Use hash-sigs XMSS lib if enabled. + if test "$ENABLED_LIBXMSS" = "yes"; then + ENABLED_WC_XMSS=no + else + ENABLED_WC_XMSS=yes + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_XMSS" + fi +fi + +# LMS CFLAG processing (after FIPS section for sandwich pattern) +if test "$ENABLED_LMS" != "no" +then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_LMS" + + # Use hash-sigs LMS lib if enabled. + if test "$ENABLED_LIBLMS" = "yes"; then + ENABLED_WC_LMS=no + else + ENABLED_WC_LMS=yes + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_LMS" + fi +fi + +# SLH-DSA CFLAG processing (after FIPS section for sandwich pattern) +if test "$ENABLED_SLHDSA" != "no" +then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_SLHDSA" + AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_HAVE_SLHDSA" + + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_SLHDSA" + + if test "$SLHDSA_PARAM_128S" = "yes" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_128S" + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_128S" + fi + if test "$SLHDSA_PARAM_128F" = "yes" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_128F" + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_128F" + fi + if test "$SLHDSA_PARAM_192S" = "yes" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_192S" + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_192S" + fi + if test "$SLHDSA_PARAM_192F" = "yes" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_192F" + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_192F" + fi + if test "$SLHDSA_PARAM_256S" = "yes" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_256S" + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_256S" + fi + if test "$SLHDSA_PARAM_256F" = "yes" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_256F" + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_256F" + fi + + # SHA2 parameter set support + if test "$SLHDSA_SHA2" = "yes" + then + # Dependency checks for SHA2 SLH-DSA + if test "$ENABLED_SHA256" = "no" + then + AC_MSG_ERROR([SLH-DSA SHA2 requires SHA-256 (--enable-sha256)]) + fi + if test "$ENABLED_SHA512" = "no" + then + AC_MSG_ERROR([SLH-DSA SHA2 requires SHA-512 (--enable-sha512)]) + fi + if test "$ENABLED_HMAC" = "no" + then + AC_MSG_ERROR([SLH-DSA SHA2 requires HMAC (--enable-hmac)]) + fi + + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_SHA2" + + if test "$SLHDSA_PARAM_SHA2_128S" = "yes" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_SHA2_128S" + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_SHA2_128S" + fi + if test "$SLHDSA_PARAM_SHA2_128F" = "yes" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_SHA2_128F" + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_SHA2_128F" + fi + if test "$SLHDSA_PARAM_SHA2_192S" = "yes" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_SHA2_192S" + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_SHA2_192S" + fi + if test "$SLHDSA_PARAM_SHA2_192F" = "yes" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_SHA2_192F" + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_SHA2_192F" + fi + if test "$SLHDSA_PARAM_SHA2_256S" = "yes" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_SHA2_256S" + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_SHA2_256S" + fi + if test "$SLHDSA_PARAM_SHA2_256F" = "yes" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_SHA2_256F" + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_SHA2_256F" + fi + fi + + # SLH-DSA requires SHAKE-256 (and SHA-3 as its dependency). + # This runs after the SHAKE256 flags section, so we must set both the + # ENABLED variable and emit the CFLAGS ourselves. + if test "$ENABLED_SHAKE256" = "no" || test "$ENABLED_SHAKE256" = "" + then + ENABLED_SHAKE256=yes + if test "$ENABLED_SHA3" = "no" + then + ENABLED_SHA3=yes + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHA3" + fi + # Remove -DWOLFSSL_NO_SHAKE256 if it was already added and add the + # positive define. + AM_CFLAGS=$(echo "$AM_CFLAGS" | sed 's/-DWOLFSSL_NO_SHAKE256//g') + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHAKE256" + fi +fi + # set POLY1305 default POLY1305_DEFAULT=yes @@ -7153,27 +7560,60 @@ then AM_CFLAGS="$AM_CFLAGS -DHAVE_ASCON" fi -# Hash DRBG +# Hash DRBG (master switch for all Hash DRBGs) AC_ARG_ENABLE([hashdrbg], [AS_HELP_STRING([--enable-hashdrbg],[Enable Hash DRBG support (default: enabled)])], [ ENABLED_HASHDRBG=$enableval ], [ ENABLED_HASHDRBG=yes ] ) +# If hashdrbg is explicitly disabled, force both sub-options off +if test "x$ENABLED_HASHDRBG" = "xno" +then + ENABLED_SHA256_DRBG=no + ENABLED_SHA512_DRBG=no +fi + +# If both sub-options are off, treat hashdrbg as off +if test "x$ENABLED_SHA256_DRBG" != "xyes" && test "x$ENABLED_SHA512_DRBG" != "xyes" +then + ENABLED_HASHDRBG=no +fi + +# FIPS override: Hash DRBG is mandatory +if test "x$ENABLED_HASHDRBG" != "xyes" && test "x$ENABLED_FIPS" = "xyes" && test "x$ENABLED_KCAPI" = "xno" +then + if test "$enable_hashdrbg" = "no" + then + AC_MSG_WARN([SHA256-DRBG required in FIPS build]) + fi + ENABLED_HASHDRBG=yes + ENABLED_SHA256_DRBG=yes +fi + +# SHA-512 DRBG and runtime DRBG disable/enable APIs are v7+ only +if test "x$ENABLED_FIPS" = "xyes" && test $HAVE_FIPS_VERSION -lt 7 +then + ENABLED_SHA512_DRBG=no +fi + +# Set Hash DRBG compiler flags if test "x$ENABLED_HASHDRBG" = "xyes" then AM_CFLAGS="$AM_CFLAGS -DHAVE_HASHDRBG" -else - # turn on Hash DRBG if FIPS is on (don't force on for KCAPI) - if test "x$ENABLED_FIPS" = "xyes" && test "x$ENABLED_KCAPI" = "xno" + if test "x$ENABLED_SHA256_DRBG" != "xyes" then - AM_CFLAGS="$AM_CFLAGS -DHAVE_HASHDRBG" - ENABLED_HASHDRBG=yes - else - AM_CFLAGS="$AM_CFLAGS -DWC_NO_HASHDRBG" + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_SHA256_DRBG" + fi + if test "x$ENABLED_SHA512_DRBG" = "xyes" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DRBG_SHA512" fi +else + AM_CFLAGS="$AM_CFLAGS -DWC_NO_HASHDRBG" fi + # MemUse Entropy (AKA wolfEntropy) if test "x$ENABLED_ENTROPY_MEMUSE" != "xno" then @@ -10754,6 +11194,11 @@ AS_IF([test "x$ENABLED_MAXSTRENGTH" = "xyes" && \ test "x$ENABLED_LEANPSK" = "xyes"], [AC_MSG_ERROR([Cannot use Max Strength and Lean PSK at the same time.])]) +AS_IF([test "x$ENABLED_CRYPTONLY" = "xno" && \ + test "x$ENABLED_PSK" = "xno" && \ + test "x$ENABLED_ASN" = "xno"], + [AC_MSG_ERROR([please enable psk if disabling asn.])]) + AS_IF([test "x$ENABLED_OCSP" = "xyes" && \ test "x$ENABLED_ASN" = "xno"], [AC_MSG_ERROR([please enable asn if enabling ocsp.])]) @@ -11506,6 +11951,8 @@ AM_CONDITIONAL([BUILD_FIPS_V5],[test "$HAVE_FIPS_VERSION" = 5]) AM_CONDITIONAL([BUILD_FIPS_V5_PLUS],[test "$HAVE_FIPS_VERSION" -ge 5]) AM_CONDITIONAL([BUILD_FIPS_V6],[test $HAVE_FIPS_VERSION = 6]) AM_CONDITIONAL([BUILD_FIPS_V6_PLUS],[test $HAVE_FIPS_VERSION -ge 6]) +AM_CONDITIONAL([BUILD_FIPS_V7],[test $HAVE_FIPS_VERSION = 7]) +AM_CONDITIONAL([BUILD_FIPS_V7_PLUS],[test $HAVE_FIPS_VERSION -ge 7]) AM_CONDITIONAL([BUILD_SIPHASH],[test "x$ENABLED_SIPHASH" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_CMAC],[test "x$ENABLED_CMAC" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_SELFTEST],[test "x$ENABLED_SELFTEST" = "xyes"]) @@ -11994,6 +12441,8 @@ echo " * certgencache: $ENABLED_certgencache" echo " * CHACHA: $ENABLED_CHACHA" echo " * XCHACHA: $ENABLED_XCHACHA" echo " * Hash DRBG: $ENABLED_HASHDRBG" +echo " * SHA-256 Hash DRBG: $ENABLED_SHA256_DRBG" +echo " * SHA-512 Hash DRBG: $ENABLED_SHA512_DRBG" echo " * MmemUse Entropy:" echo " * (AKA: wolfEntropy): $ENABLED_ENTROPY_MEMUSE" echo " * PWDBASED: $ENABLED_PWDBASED" diff --git a/doc/dox_comments/header_files/random.h b/doc/dox_comments/header_files/random.h index ead9011d468..f6961b99427 100644 --- a/doc/dox_comments/header_files/random.h +++ b/doc/dox_comments/header_files/random.h @@ -583,3 +583,241 @@ int wc_Entropy_Get(int bits, unsigned char* entropy, word32 len); \sa wc_Entropy_Get */ int wc_Entropy_OnDemandTest(void); + +/*! + \ingroup Random + + \brief Runs the SHA-512 Hash_DRBG Known Answer Test (KAT) per + SP 800-90A. Instantiates a SHA-512 DRBG with seedA, optionally + reseeds with seedB, generates output, and compares against known + test vectors. Available when WOLFSSL_DRBG_SHA512 is defined. + + \return 0 On success + \return BAD_FUNC_ARG If seedA or output is NULL, or if reseed is + set and seedB is NULL + \return -1 Test failed + + \param reseed Non-zero to test reseeding + \param seedA Initial entropy seed + \param seedASz Size of seedA in bytes + \param seedB Reseed entropy (required if reseed is set) + \param seedBSz Size of seedB in bytes + \param output Buffer to receive generated output + \param outputSz Size of output in bytes + + _Example_ + \code + byte output[WC_SHA512_DIGEST_SIZE * 4]; + const byte seedA[] = { ... }; + const byte seedB[] = { ... }; + + ret = wc_RNG_HealthTest_SHA512(0, seedA, sizeof(seedA), NULL, 0, + output, sizeof(output)); + if (ret != 0) + return -1; + + ret = wc_RNG_HealthTest_SHA512(1, seedA, sizeof(seedA), + seedB, sizeof(seedB), + output, sizeof(output)); + if (ret != 0) + return -1; + \endcode + + \sa wc_RNG_HealthTest + \sa wc_RNG_HealthTest_SHA512_ex +*/ +int wc_RNG_HealthTest_SHA512(int reseed, const byte* seedA, word32 seedASz, + const byte* seedB, word32 seedBSz, + byte* output, word32 outputSz); + +/*! + \ingroup Random + + \brief Extended SHA-512 Hash_DRBG health test with nonce, + personalization string, and additional input support. Suitable + for full ACVP / CAVP test vector validation. Available when + WOLFSSL_DRBG_SHA512 is defined. + + \return 0 On success + \return BAD_FUNC_ARG If required params are NULL + \return -1 Test failed + + \param reseed Non-zero to test reseeding + \param nonce Nonce buffer (can be NULL) + \param nonceSz Nonce size + \param persoString Personalization string (can be NULL) + \param persoStringSz Personalization string size + \param seedA Initial entropy seed + \param seedASz Initial seed size + \param seedB Reseed entropy (required if reseed is set) + \param seedBSz Reseed size + \param additionalA Additional input for first generate (can be NULL) + \param additionalASz Additional input A size + \param additionalB Additional input for second generate (can be NULL) + \param additionalBSz Additional input B size + \param output Output buffer + \param outputSz Output size + \param heap Heap hint (can be NULL) + \param devId Device ID (INVALID_DEVID for software) + + _Example_ + \code + byte output[WC_SHA512_DIGEST_SIZE * 4]; + const byte seedA[] = { ... }; + const byte nonce[] = { ... }; + + int ret = wc_RNG_HealthTest_SHA512_ex(0, nonce, sizeof(nonce), + NULL, 0, + seedA, sizeof(seedA), + NULL, 0, + NULL, 0, NULL, 0, + output, sizeof(output), + NULL, INVALID_DEVID); + \endcode + + \sa wc_RNG_HealthTest_SHA512 + \sa wc_RNG_HealthTest_ex +*/ +int wc_RNG_HealthTest_SHA512_ex(int reseed, const byte* nonce, word32 nonceSz, + const byte* persoString, word32 persoStringSz, + const byte* seedA, word32 seedASz, + const byte* seedB, word32 seedBSz, + const byte* additionalA, word32 additionalASz, + const byte* additionalB, word32 additionalBSz, + byte* output, word32 outputSz, + void* heap, int devId); + +/*! + \ingroup Random + + \brief Disables the SHA-256 Hash_DRBG at runtime. When disabled, + newly initialized WC_RNG instances will not use the SHA-256 DRBG. + If the SHA-512 DRBG is enabled (WOLFSSL_DRBG_SHA512), new RNG + instances will use SHA-512 instead. Requires HAVE_HASHDRBG. + + \return 0 On success + + _Example_ + \code + wc_Sha256Drbg_Disable(); + // New WC_RNG instances will now use SHA-512 DRBG if available + WC_RNG rng; + wc_InitRng(&rng); + \endcode + + \sa wc_Sha256Drbg_Enable + \sa wc_Sha256Drbg_GetStatus + \sa wc_Sha512Drbg_Disable +*/ +int wc_Sha256Drbg_Disable(void); + +/*! + \ingroup Random + + \brief Re-enables the SHA-256 Hash_DRBG at runtime after a prior + call to wc_Sha256Drbg_Disable(). Requires HAVE_HASHDRBG. + + \return 0 On success + + _Example_ + \code + wc_Sha256Drbg_Disable(); + // ... use SHA-512 DRBG only ... + wc_Sha256Drbg_Enable(); + // New WC_RNG instances can use SHA-256 DRBG again + \endcode + + \sa wc_Sha256Drbg_Disable + \sa wc_Sha256Drbg_GetStatus +*/ +int wc_Sha256Drbg_Enable(void); + +/*! + \ingroup Random + + \brief Returns the current status of the SHA-256 Hash_DRBG + (disabled or enabled). Requires HAVE_HASHDRBG. + + \return 1 SHA-256 DRBG is disabled + \return 0 SHA-256 DRBG is enabled + + _Example_ + \code + if (wc_Sha256Drbg_GetStatus()) { + printf("SHA-256 DRBG is off\n"); + } + \endcode + + \sa wc_Sha256Drbg_Disable + \sa wc_Sha256Drbg_Enable +*/ +int wc_Sha256Drbg_GetStatus(void); + +/*! + \ingroup Random + + \brief Disables the SHA-512 Hash_DRBG at runtime. When disabled, + newly initialized WC_RNG instances will not use the SHA-512 DRBG. + If the SHA-256 DRBG is still enabled, new RNG instances will fall + back to SHA-256. Available when WOLFSSL_DRBG_SHA512 is defined. + Requires HAVE_HASHDRBG. + + \return 0 On success + + _Example_ + \code + wc_Sha512Drbg_Disable(); + // New WC_RNG instances will now use SHA-256 DRBG + WC_RNG rng; + wc_InitRng(&rng); + \endcode + + \sa wc_Sha512Drbg_Enable + \sa wc_Sha512Drbg_GetStatus + \sa wc_Sha256Drbg_Disable +*/ +int wc_Sha512Drbg_Disable(void); + +/*! + \ingroup Random + + \brief Re-enables the SHA-512 Hash_DRBG at runtime after a prior + call to wc_Sha512Drbg_Disable(). Available when WOLFSSL_DRBG_SHA512 + is defined. Requires HAVE_HASHDRBG. + + \return 0 On success + + _Example_ + \code + wc_Sha512Drbg_Disable(); + // ... use SHA-256 DRBG only ... + wc_Sha512Drbg_Enable(); + // New WC_RNG instances can use SHA-512 DRBG again + \endcode + + \sa wc_Sha512Drbg_Disable + \sa wc_Sha512Drbg_GetStatus +*/ +int wc_Sha512Drbg_Enable(void); + +/*! + \ingroup Random + + \brief Returns the current status of the SHA-512 Hash_DRBG + (disabled or enabled). Available when WOLFSSL_DRBG_SHA512 is + defined. Requires HAVE_HASHDRBG. + + \return 1 SHA-512 DRBG is disabled + \return 0 SHA-512 DRBG is enabled + + _Example_ + \code + if (wc_Sha512Drbg_GetStatus()) { + printf("SHA-512 DRBG is off\n"); + } + \endcode + + \sa wc_Sha512Drbg_Disable + \sa wc_Sha512Drbg_Enable +*/ +int wc_Sha512Drbg_GetStatus(void); diff --git a/doc/dox_comments/header_files/wc_slhdsa.h b/doc/dox_comments/header_files/wc_slhdsa.h new file mode 100644 index 00000000000..a520d153b2c --- /dev/null +++ b/doc/dox_comments/header_files/wc_slhdsa.h @@ -0,0 +1,793 @@ +/*! + \ingroup SLH_DSA + + \brief Initializes an SLH-DSA key object with the specified parameter set. + Must be called before any other SLH-DSA operation. Use wc_SlhDsaKey_Free() + to release resources when done. + + SLH-DSA (FIPS 205) is a stateless hash-based digital signature algorithm. + Parameter sets control the hash function (SHAKE or SHA2), security level + (128, 192, 256), and speed/size tradeoff (s = small signatures, + f = fast signing). + + \return 0 on success. + \return BAD_FUNC_ARG if key is NULL or param is invalid. + + \param [in,out] key Pointer to the SlhDsaKey to initialize. + \param [in] param Parameter set to use. One of: SLHDSA_SHAKE128S, + SLHDSA_SHAKE128F, SLHDSA_SHAKE192S, SLHDSA_SHAKE192F, SLHDSA_SHAKE256S, + SLHDSA_SHAKE256F, SLHDSA_SHA2_128S, SLHDSA_SHA2_128F, SLHDSA_SHA2_192S, + SLHDSA_SHA2_192F, SLHDSA_SHA2_256S, SLHDSA_SHA2_256F. + \param [in] heap Pointer to heap hint for dynamic memory allocation. + May be NULL. + \param [in] devId Device identifier for hardware crypto callbacks. + Use INVALID_DEVID for software-only. + + _Example_ + \code + SlhDsaKey key; + int ret; + + ret = wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID); + if (ret != 0) { + // error initializing key + } + // ... use key ... + wc_SlhDsaKey_Free(&key); + \endcode + + \sa wc_SlhDsaKey_Free + \sa wc_SlhDsaKey_MakeKey +*/ +int wc_SlhDsaKey_Init(SlhDsaKey* key, enum SlhDsaParam param, + void* heap, int devId); + +/*! + \ingroup SLH_DSA + + \brief Frees resources associated with an SLH-DSA key object. + + \param [in,out] key Pointer to the SlhDsaKey to free. May be NULL. + + _Example_ + \code + SlhDsaKey key; + wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID); + // ... use key ... + wc_SlhDsaKey_Free(&key); + \endcode + + \sa wc_SlhDsaKey_Init +*/ +void wc_SlhDsaKey_Free(SlhDsaKey* key); + +/*! + \ingroup SLH_DSA + + \brief Generates a new SLH-DSA key pair using the RNG for randomness. + The key must have been initialized with wc_SlhDsaKey_Init() first. + + \return 0 on success. + \return BAD_FUNC_ARG if key or rng is NULL, or key is not initialized. + + \param [in,out] key Pointer to an initialized SlhDsaKey. + \param [in] rng Pointer to an initialized WC_RNG. + + _Example_ + \code + SlhDsaKey key; + WC_RNG rng; + int ret; + + wc_InitRng(&rng); + wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID); + ret = wc_SlhDsaKey_MakeKey(&key, &rng); + if (ret != 0) { + // error generating key + } + \endcode + + \sa wc_SlhDsaKey_Init + \sa wc_SlhDsaKey_MakeKeyWithRandom +*/ +int wc_SlhDsaKey_MakeKey(SlhDsaKey* key, WC_RNG* rng); + +/*! + \ingroup SLH_DSA + + \brief Generates an SLH-DSA key pair from caller-provided seed material. + This is the deterministic key generation interface — given the same seeds, + the same key pair is produced. + + \return 0 on success. + \return BAD_FUNC_ARG if key or any seed pointer is NULL, or lengths + do not match the parameter set's n value. + + \param [in,out] key Pointer to an initialized SlhDsaKey. + \param [in] sk_seed Secret key seed (n bytes). + \param [in] sk_seed_len Length of sk_seed. + \param [in] sk_prf Secret key PRF seed (n bytes). + \param [in] sk_prf_len Length of sk_prf. + \param [in] pk_seed Public key seed (n bytes). + \param [in] pk_seed_len Length of pk_seed. + + _Example_ + \code + SlhDsaKey key; + byte sk_seed[16], sk_prf[16], pk_seed[16]; // n=16 for 128-bit params + int ret; + + // fill seeds with known values (e.g. from NIST test vectors) + wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID); + ret = wc_SlhDsaKey_MakeKeyWithRandom(&key, + sk_seed, sizeof(sk_seed), + sk_prf, sizeof(sk_prf), + pk_seed, sizeof(pk_seed)); + \endcode + + \sa wc_SlhDsaKey_MakeKey +*/ +int wc_SlhDsaKey_MakeKeyWithRandom(SlhDsaKey* key, + const byte* sk_seed, word32 sk_seed_len, + const byte* sk_prf, word32 sk_prf_len, + const byte* pk_seed, word32 pk_seed_len); + +/*! + \ingroup SLH_DSA + + \brief Signs a message using the SLH-DSA external (pure) interface with + deterministic randomness. This is FIPS 205 Algorithm 22 with opt_rand set + to PK.seed. The message M is wrapped internally as + M' = 0x00 || len(ctx) || ctx || M before signing. + + \return 0 on success. + \return BAD_FUNC_ARG if key, msg, sig, or sigSz is NULL. + \return BUFFER_E if the output buffer is too small. + + \param [in] key Pointer to a private SlhDsaKey. + \param [in] ctx Context string for domain separation. May be NULL if + ctxSz is 0. + \param [in] ctxSz Length of the context string (0-255). + \param [in] msg Pointer to the message to sign. + \param [in] msgSz Length of the message. + \param [out] sig Buffer to receive the signature. + \param [in,out] sigSz On input, size of sig buffer. On output, actual + signature length. + + _Example_ + \code + SlhDsaKey key; + byte sig[WC_SLHDSA_MAX_SIG_LEN]; + word32 sigSz = sizeof(sig); + byte msg[] = "Hello World!"; + int ret; + + // key already generated via wc_SlhDsaKey_MakeKey() + ret = wc_SlhDsaKey_SignDeterministic(&key, NULL, 0, + msg, sizeof(msg), sig, &sigSz); + \endcode + + \sa wc_SlhDsaKey_SignWithRandom + \sa wc_SlhDsaKey_Sign + \sa wc_SlhDsaKey_Verify +*/ +int wc_SlhDsaKey_SignDeterministic(SlhDsaKey* key, const byte* ctx, + byte ctxSz, const byte* msg, word32 msgSz, byte* sig, word32* sigSz); + +/*! + \ingroup SLH_DSA + + \brief Signs a message using the SLH-DSA external (pure) interface with + caller-provided additional randomness. This is FIPS 205 Algorithm 22 with + an explicit opt_rand value. + + \return 0 on success. + \return BAD_FUNC_ARG if key, msg, sig, sigSz, or addRnd is NULL. + + \param [in] key Pointer to a private SlhDsaKey. + \param [in] ctx Context string. May be NULL if ctxSz is 0. + \param [in] ctxSz Length of the context string (0-255). + \param [in] msg Pointer to the message to sign. + \param [in] msgSz Length of the message. + \param [out] sig Buffer to receive the signature. + \param [in,out] sigSz On input, size of sig buffer. On output, actual + signature length. + \param [in] addRnd Additional randomness (n bytes, where n is the + parameter set's security parameter). + + _Example_ + \code + SlhDsaKey key; + byte sig[WC_SLHDSA_MAX_SIG_LEN]; + word32 sigSz = sizeof(sig); + byte msg[] = "Hello World!"; + byte addRnd[16]; // n=16 for 128-bit params + int ret; + + wc_RNG_GenerateBlock(&rng, addRnd, sizeof(addRnd)); + ret = wc_SlhDsaKey_SignWithRandom(&key, NULL, 0, + msg, sizeof(msg), sig, &sigSz, addRnd); + \endcode + + \sa wc_SlhDsaKey_SignDeterministic + \sa wc_SlhDsaKey_Sign +*/ +int wc_SlhDsaKey_SignWithRandom(SlhDsaKey* key, const byte* ctx, + byte ctxSz, const byte* msg, word32 msgSz, byte* sig, word32* sigSz, + const byte* addRnd); + +/*! + \ingroup SLH_DSA + + \brief Signs a message using the SLH-DSA external (pure) interface with + RNG-provided randomness. This is the general-purpose signing function + that uses the WC_RNG for opt_rand. + + \return 0 on success. + \return BAD_FUNC_ARG if key, msg, sig, sigSz, or rng is NULL. + + \param [in] key Pointer to a private SlhDsaKey. + \param [in] ctx Context string. May be NULL if ctxSz is 0. + \param [in] ctxSz Length of the context string (0-255). + \param [in] msg Pointer to the message to sign. + \param [in] msgSz Length of the message. + \param [out] sig Buffer to receive the signature. + \param [in,out] sigSz On input, size of sig buffer. On output, actual + signature length. + \param [in] rng Pointer to an initialized WC_RNG. + + _Example_ + \code + SlhDsaKey key; + WC_RNG rng; + byte sig[WC_SLHDSA_MAX_SIG_LEN]; + word32 sigSz = sizeof(sig); + byte msg[] = "Hello World!"; + int ret; + + ret = wc_SlhDsaKey_Sign(&key, NULL, 0, + msg, sizeof(msg), sig, &sigSz, &rng); + \endcode + + \sa wc_SlhDsaKey_SignDeterministic + \sa wc_SlhDsaKey_Verify +*/ +int wc_SlhDsaKey_Sign(SlhDsaKey* key, const byte* ctx, + byte ctxSz, const byte* msg, word32 msgSz, byte* sig, word32* sigSz, + WC_RNG* rng); + +/*! + \ingroup SLH_DSA + + \brief Verifies an SLH-DSA signature over a message using the external + (pure) interface. This is FIPS 205 Algorithm 23. The message is wrapped + internally as M' = 0x00 || len(ctx) || ctx || M before verification. + + \return 0 on success (signature valid). + \return BAD_FUNC_ARG if key, msg, or sig is NULL. + \return SIG_VERIFY_E if the signature is invalid. + + \param [in] key Pointer to a public SlhDsaKey. + \param [in] ctx Context string. May be NULL if ctxSz is 0. + \param [in] ctxSz Length of the context string (0-255). + \param [in] msg Pointer to the message to verify. + \param [in] msgSz Length of the message. + \param [in] sig Pointer to the signature to verify. + \param [in] sigSz Length of the signature. + + _Example_ + \code + SlhDsaKey key; + byte sig[...]; // previously generated signature + word32 sigSz; + byte msg[] = "Hello World!"; + int ret; + + ret = wc_SlhDsaKey_Verify(&key, NULL, 0, + msg, sizeof(msg), sig, sigSz); + if (ret == 0) { + // signature is valid + } + \endcode + + \sa wc_SlhDsaKey_Sign + \sa wc_SlhDsaKey_SignDeterministic +*/ +int wc_SlhDsaKey_Verify(SlhDsaKey* key, const byte* ctx, + byte ctxSz, const byte* msg, word32 msgSz, const byte* sig, + word32 sigSz); + +/*! + \ingroup SLH_DSA + + \brief Signs using the SLH-DSA internal interface with deterministic + randomness. Unlike the external interface, M' is provided directly by + the caller — no 0x00||len(ctx)||ctx||M wrapping is performed. This + corresponds to FIPS 205 Algorithm 19 (slh_sign_internal) with opt_rand + set to PK.seed. + + Use this when the CAVP test framework or protocol layer has already + constructed M'. + + \return 0 on success. + \return BAD_FUNC_ARG if key, mprime, sig, or sigSz is NULL. + + \param [in] key Pointer to a private SlhDsaKey. + \param [in] mprime Pointer to the pre-constructed M' message. + \param [in] mprimeSz Length of M'. + \param [out] sig Buffer to receive the signature. + \param [in,out] sigSz On input, size of sig buffer. On output, actual + signature length. + + _Example_ + \code + SlhDsaKey key; + byte sig[WC_SLHDSA_MAX_SIG_LEN]; + word32 sigSz = sizeof(sig); + byte mprime[] = { ... }; // pre-constructed M' + int ret; + + ret = wc_SlhDsaKey_SignMsgDeterministic(&key, + mprime, sizeof(mprime), sig, &sigSz); + \endcode + + \sa wc_SlhDsaKey_SignMsgWithRandom + \sa wc_SlhDsaKey_VerifyMsg + \sa wc_SlhDsaKey_SignDeterministic +*/ +int wc_SlhDsaKey_SignMsgDeterministic(SlhDsaKey* key, + const byte* mprime, word32 mprimeSz, byte* sig, word32* sigSz); + +/*! + \ingroup SLH_DSA + + \brief Signs using the SLH-DSA internal interface with caller-provided + additional randomness. M' is provided directly — no wrapping is performed. + This corresponds to FIPS 205 Algorithm 19 (slh_sign_internal) with an + explicit opt_rand value. + + \return 0 on success. + \return BAD_FUNC_ARG if key, mprime, sig, sigSz, or addRnd is NULL. + + \param [in] key Pointer to a private SlhDsaKey. + \param [in] mprime Pointer to the pre-constructed M' message. + \param [in] mprimeSz Length of M'. + \param [out] sig Buffer to receive the signature. + \param [in,out] sigSz On input, size of sig buffer. On output, actual + signature length. + \param [in] addRnd Additional randomness (n bytes). + + _Example_ + \code + SlhDsaKey key; + byte sig[WC_SLHDSA_MAX_SIG_LEN]; + word32 sigSz = sizeof(sig); + byte mprime[] = { ... }; + byte addRnd[16]; + int ret; + + wc_RNG_GenerateBlock(&rng, addRnd, sizeof(addRnd)); + ret = wc_SlhDsaKey_SignMsgWithRandom(&key, + mprime, sizeof(mprime), sig, &sigSz, addRnd); + \endcode + + \sa wc_SlhDsaKey_SignMsgDeterministic + \sa wc_SlhDsaKey_VerifyMsg +*/ +int wc_SlhDsaKey_SignMsgWithRandom(SlhDsaKey* key, + const byte* mprime, word32 mprimeSz, byte* sig, word32* sigSz, + const byte* addRnd); + +/*! + \ingroup SLH_DSA + + \brief Verifies an SLH-DSA signature using the internal interface. M' is + provided directly — no wrapping is performed. This corresponds to FIPS 205 + Algorithm 20 (slh_verify_internal). + + \return 0 on success (signature valid). + \return BAD_FUNC_ARG if key, mprime, or sig is NULL. + \return SIG_VERIFY_E if the signature is invalid. + + \param [in] key Pointer to a public SlhDsaKey. + \param [in] mprime Pointer to the pre-constructed M' message. + \param [in] mprimeSz Length of M'. + \param [in] sig Pointer to the signature to verify. + \param [in] sigSz Length of the signature. + + _Example_ + \code + SlhDsaKey key; + byte sig[...]; // previously generated signature + word32 sigSz; + byte mprime[] = { ... }; + int ret; + + ret = wc_SlhDsaKey_VerifyMsg(&key, + mprime, sizeof(mprime), sig, sigSz); + if (ret == 0) { + // signature is valid + } + \endcode + + \sa wc_SlhDsaKey_SignMsgDeterministic + \sa wc_SlhDsaKey_Verify +*/ +int wc_SlhDsaKey_VerifyMsg(SlhDsaKey* key, const byte* mprime, + word32 mprimeSz, const byte* sig, word32 sigSz); + +/*! + \ingroup SLH_DSA + + \brief Signs a pre-hashed message using the SLH-DSA external (HashSLH-DSA) + interface with deterministic randomness. The message is hashed with the + specified hash algorithm, then signed per FIPS 205 Algorithm 22 with the + pre-hash domain separator (0x01). + + \return 0 on success. + \return BAD_FUNC_ARG if key, msg, sig, or sigSz is NULL, or hashType + is unsupported. + + \param [in] key Pointer to a private SlhDsaKey. + \param [in] ctx Context string. May be NULL if ctxSz is 0. + \param [in] ctxSz Length of the context string (0-255). + \param [in] msg Pointer to the message to hash and sign. + \param [in] msgSz Length of the message. + \param [in] hashType Hash algorithm to use for pre-hashing. Supported: + WC_HASH_TYPE_SHA256, WC_HASH_TYPE_SHA384, WC_HASH_TYPE_SHA512, + WC_HASH_TYPE_SHAKE128, WC_HASH_TYPE_SHAKE256, WC_HASH_TYPE_SHA3_224, + WC_HASH_TYPE_SHA3_256, WC_HASH_TYPE_SHA3_384, WC_HASH_TYPE_SHA3_512. + \param [out] sig Buffer to receive the signature. + \param [in,out] sigSz On input, size of sig buffer. On output, actual + signature length. + + _Example_ + \code + SlhDsaKey key; + byte sig[WC_SLHDSA_MAX_SIG_LEN]; + word32 sigSz = sizeof(sig); + byte msg[] = "Hello World!"; + int ret; + + ret = wc_SlhDsaKey_SignHashDeterministic(&key, NULL, 0, + msg, sizeof(msg), WC_HASH_TYPE_SHA256, sig, &sigSz); + \endcode + + \sa wc_SlhDsaKey_SignHashWithRandom + \sa wc_SlhDsaKey_SignHash + \sa wc_SlhDsaKey_VerifyHash +*/ +int wc_SlhDsaKey_SignHashDeterministic(SlhDsaKey* key, + const byte* ctx, byte ctxSz, const byte* msg, word32 msgSz, + enum wc_HashType hashType, byte* sig, word32* sigSz); + +/*! + \ingroup SLH_DSA + + \brief Signs a pre-hashed message using the SLH-DSA external (HashSLH-DSA) + interface with caller-provided additional randomness. + + \return 0 on success. + \return BAD_FUNC_ARG if key, msg, sig, sigSz, or addRnd is NULL. + + \param [in] key Pointer to a private SlhDsaKey. + \param [in] ctx Context string. May be NULL if ctxSz is 0. + \param [in] ctxSz Length of the context string (0-255). + \param [in] msg Pointer to the message to hash and sign. + \param [in] msgSz Length of the message. + \param [in] hashType Hash algorithm to use for pre-hashing. + \param [out] sig Buffer to receive the signature. + \param [in,out] sigSz On input, size of sig buffer. On output, actual + signature length. + \param [in] addRnd Additional randomness (n bytes). + + \sa wc_SlhDsaKey_SignHashDeterministic + \sa wc_SlhDsaKey_VerifyHash +*/ +int wc_SlhDsaKey_SignHashWithRandom(SlhDsaKey* key, + const byte* ctx, byte ctxSz, const byte* msg, word32 msgSz, + enum wc_HashType hashType, byte* sig, word32* sigSz, byte* addRnd); + +/*! + \ingroup SLH_DSA + + \brief Signs a pre-hashed message using the SLH-DSA external (HashSLH-DSA) + interface with RNG-provided randomness. + + \return 0 on success. + \return BAD_FUNC_ARG if key, msg, sig, sigSz, or rng is NULL. + + \param [in] key Pointer to a private SlhDsaKey. + \param [in] ctx Context string. May be NULL if ctxSz is 0. + \param [in] ctxSz Length of the context string (0-255). + \param [in] msg Pointer to the message to hash and sign. + \param [in] msgSz Length of the message. + \param [in] hashType Hash algorithm to use for pre-hashing. + \param [out] sig Buffer to receive the signature. + \param [in,out] sigSz On input, size of sig buffer. On output, actual + signature length. + \param [in] rng Pointer to an initialized WC_RNG. + + \sa wc_SlhDsaKey_SignHashDeterministic + \sa wc_SlhDsaKey_VerifyHash +*/ +int wc_SlhDsaKey_SignHash(SlhDsaKey* key, const byte* ctx, + byte ctxSz, const byte* msg, word32 msgSz, enum wc_HashType hashType, + byte* sig, word32* sigSz, WC_RNG* rng); + +/*! + \ingroup SLH_DSA + + \brief Verifies an SLH-DSA signature over a pre-hashed message + (HashSLH-DSA). The message is hashed with the specified hash algorithm + before verification. + + \return 0 on success (signature valid). + \return BAD_FUNC_ARG if key, msg, or sig is NULL. + \return SIG_VERIFY_E if the signature is invalid. + + \param [in] key Pointer to a public SlhDsaKey. + \param [in] ctx Context string. May be NULL if ctxSz is 0. + \param [in] ctxSz Length of the context string (0-255). + \param [in] msg Pointer to the message to hash and verify. + \param [in] msgSz Length of the message. + \param [in] hashType Hash algorithm used for pre-hashing. Must match the + hash used during signing. + \param [in] sig Pointer to the signature to verify. + \param [in] sigSz Length of the signature. + + _Example_ + \code + SlhDsaKey key; + byte sig[...]; + word32 sigSz; + byte msg[] = "Hello World!"; + int ret; + + ret = wc_SlhDsaKey_VerifyHash(&key, NULL, 0, + msg, sizeof(msg), WC_HASH_TYPE_SHA256, sig, sigSz); + if (ret == 0) { + // signature is valid + } + \endcode + + \sa wc_SlhDsaKey_SignHashDeterministic + \sa wc_SlhDsaKey_Verify +*/ +int wc_SlhDsaKey_VerifyHash(SlhDsaKey* key, const byte* ctx, + byte ctxSz, const byte* msg, word32 msgSz, enum wc_HashType hashType, + const byte* sig, word32 sigSz); + +/*! + \ingroup SLH_DSA + + \brief Imports an SLH-DSA private key from a raw byte buffer. The buffer + must contain the full private key (4*n bytes: SK.seed || SK.prf || + PK.seed || PK.root). After import, the key can be used for signing. + + \return 0 on success. + \return BAD_FUNC_ARG if key or in is NULL, or inLen does not match the + expected private key size for the parameter set. + + \param [in,out] key Pointer to an initialized SlhDsaKey. + \param [in] in Buffer containing the raw private key bytes. + \param [in] inLen Length of the input buffer. + + _Example_ + \code + SlhDsaKey key; + byte privKey[...]; // 4*n bytes + int ret; + + wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID); + ret = wc_SlhDsaKey_ImportPrivate(&key, privKey, sizeof(privKey)); + \endcode + + \sa wc_SlhDsaKey_ExportPrivate + \sa wc_SlhDsaKey_ImportPublic +*/ +int wc_SlhDsaKey_ImportPrivate(SlhDsaKey* key, const byte* in, + word32 inLen); + +/*! + \ingroup SLH_DSA + + \brief Imports an SLH-DSA public key from a raw byte buffer. The buffer + must contain PK.seed || PK.root (2*n bytes). After import, the key can + be used for verification. + + \return 0 on success. + \return BAD_FUNC_ARG if key or in is NULL, or inLen does not match the + expected public key size. + + \param [in,out] key Pointer to an initialized SlhDsaKey. + \param [in] in Buffer containing the raw public key bytes. + \param [in] inLen Length of the input buffer. + + _Example_ + \code + SlhDsaKey key; + byte pubKey[...]; // 2*n bytes + int ret; + + wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID); + ret = wc_SlhDsaKey_ImportPublic(&key, pubKey, sizeof(pubKey)); + \endcode + + \sa wc_SlhDsaKey_ExportPublic + \sa wc_SlhDsaKey_ImportPrivate +*/ +int wc_SlhDsaKey_ImportPublic(SlhDsaKey* key, const byte* in, + word32 inLen); + +/*! + \ingroup SLH_DSA + + \brief Checks the consistency of an SLH-DSA key. For a key with both + private and public components, verifies that the public key matches the + private key. + + \return 0 on success (key is valid). + \return BAD_FUNC_ARG if key is NULL. + + \param [in] key Pointer to the SlhDsaKey to check. + + \sa wc_SlhDsaKey_MakeKey + \sa wc_SlhDsaKey_ImportPrivate +*/ +int wc_SlhDsaKey_CheckKey(SlhDsaKey* key); + +/*! + \ingroup SLH_DSA + + \brief Exports the private key from an SLH-DSA key object into a raw + byte buffer (4*n bytes). + + \return 0 on success. + \return BAD_FUNC_ARG if key, out, or outLen is NULL. + \return BUFFER_E if the output buffer is too small. + + \param [in] key Pointer to the SlhDsaKey containing a private key. + \param [out] out Buffer to receive the raw private key bytes. + \param [in,out] outLen On input, size of out buffer. On output, bytes + written. + + _Example_ + \code + SlhDsaKey key; + byte privKey[4 * 32]; // 4*n for 256-bit params + word32 privKeySz = sizeof(privKey); + int ret; + + ret = wc_SlhDsaKey_ExportPrivate(&key, privKey, &privKeySz); + \endcode + + \sa wc_SlhDsaKey_ImportPrivate + \sa wc_SlhDsaKey_ExportPublic +*/ +int wc_SlhDsaKey_ExportPrivate(SlhDsaKey* key, byte* out, + word32* outLen); + +/*! + \ingroup SLH_DSA + + \brief Exports the public key from an SLH-DSA key object into a raw + byte buffer (2*n bytes: PK.seed || PK.root). + + \return 0 on success. + \return BAD_FUNC_ARG if key, out, or outLen is NULL. + \return BUFFER_E if the output buffer is too small. + + \param [in] key Pointer to the SlhDsaKey containing a public key. + \param [out] out Buffer to receive the raw public key bytes. + \param [in,out] outLen On input, size of out buffer. On output, bytes + written. + + _Example_ + \code + SlhDsaKey key; + byte pubKey[2 * 32]; + word32 pubKeySz = sizeof(pubKey); + int ret; + + ret = wc_SlhDsaKey_ExportPublic(&key, pubKey, &pubKeySz); + \endcode + + \sa wc_SlhDsaKey_ImportPublic + \sa wc_SlhDsaKey_ExportPrivate +*/ +int wc_SlhDsaKey_ExportPublic(SlhDsaKey* key, byte* out, + word32* outLen); + +/*! + \ingroup SLH_DSA + + \brief Returns the private key size in bytes for the key's parameter set. + + \return Private key size in bytes (4*n) on success. + \return BAD_FUNC_ARG if key is NULL or not initialized. + + \param [in] key Pointer to an initialized SlhDsaKey. + + \sa wc_SlhDsaKey_PublicSize + \sa wc_SlhDsaKey_SigSize + \sa wc_SlhDsaKey_PrivateSizeFromParam +*/ +int wc_SlhDsaKey_PrivateSize(SlhDsaKey* key); + +/*! + \ingroup SLH_DSA + + \brief Returns the public key size in bytes for the key's parameter set. + + \return Public key size in bytes (2*n) on success. + \return BAD_FUNC_ARG if key is NULL or not initialized. + + \param [in] key Pointer to an initialized SlhDsaKey. + + \sa wc_SlhDsaKey_PrivateSize + \sa wc_SlhDsaKey_SigSize + \sa wc_SlhDsaKey_PublicSizeFromParam +*/ +int wc_SlhDsaKey_PublicSize(SlhDsaKey* key); + +/*! + \ingroup SLH_DSA + + \brief Returns the signature size in bytes for the key's parameter set. + + \return Signature size in bytes on success. + \return BAD_FUNC_ARG if key is NULL or not initialized. + + \param [in] key Pointer to an initialized SlhDsaKey. + + \sa wc_SlhDsaKey_PrivateSize + \sa wc_SlhDsaKey_PublicSize + \sa wc_SlhDsaKey_SigSizeFromParam +*/ +int wc_SlhDsaKey_SigSize(SlhDsaKey* key); + +/*! + \ingroup SLH_DSA + + \brief Returns the private key size in bytes for the given parameter set + without needing an initialized key object. + + \return Private key size in bytes (4*n) on success. + \return BAD_FUNC_ARG if param is invalid. + + \param [in] param The SLH-DSA parameter set. + + \sa wc_SlhDsaKey_PrivateSize +*/ +int wc_SlhDsaKey_PrivateSizeFromParam(enum SlhDsaParam param); + +/*! + \ingroup SLH_DSA + + \brief Returns the public key size in bytes for the given parameter set + without needing an initialized key object. + + \return Public key size in bytes (2*n) on success. + \return BAD_FUNC_ARG if param is invalid. + + \param [in] param The SLH-DSA parameter set. + + \sa wc_SlhDsaKey_PublicSize +*/ +int wc_SlhDsaKey_PublicSizeFromParam(enum SlhDsaParam param); + +/*! + \ingroup SLH_DSA + + \brief Returns the signature size in bytes for the given parameter set + without needing an initialized key object. + + \return Signature size in bytes on success. + \return BAD_FUNC_ARG if param is invalid. + + \param [in] param The SLH-DSA parameter set. + + \sa wc_SlhDsaKey_SigSize +*/ +int wc_SlhDsaKey_SigSizeFromParam(enum SlhDsaParam param); diff --git a/src/include.am b/src/include.am index cb91fe84cc5..3dc8c76da8b 100644 --- a/src/include.am +++ b/src/include.am @@ -431,7 +431,7 @@ src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/fips.c \ src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wolfcrypt_last.c endif BUILD_FIPS_V5 -if BUILD_FIPS_V6_PLUS +if BUILD_FIPS_V6 # FIPS 140-3 SRTP-KDF first file src_libwolfssl@LIBSUFFIX@_la_SOURCES += \ wolfcrypt/src/wolfcrypt_first.c @@ -766,7 +766,390 @@ src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/fips.c \ # fips last file src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wolfcrypt_last.c -endif BUILD_FIPS_V6_PLUS +endif BUILD_FIPS_V6 + +if BUILD_FIPS_V7_PLUS +# FIPS 140-3 v7.0.0+ first file +src_libwolfssl@LIBSUFFIX@_la_SOURCES += \ + wolfcrypt/src/wolfcrypt_first.c + +src_libwolfssl@LIBSUFFIX@_la_SOURCES += \ + wolfcrypt/src/hmac.c \ + wolfcrypt/src/random.c + +if BUILD_MEMUSE +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wolfentropy.c +endif + +if BUILD_RNG_BANK +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/rng_bank.c +endif + +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/kdf.c + +if BUILD_RSA +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/rsa.c +endif + +if BUILD_ECC +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/ecc.c +endif + +if BUILD_AES +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/aes.c + +if BUILD_ARMASM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(LEGACY_ARMASM_AES_C) +endif BUILD_ARMASM + +if BUILD_ARMASM_NEON +if BUILD_ARMASM_INLINE +src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(NEW_ARMASM_AES_ASM_C) +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-aes-asm_c.c +else +src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(NEW_ARMASM_AES_ASM_S) +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-aes-asm.S +endif !BUILD_ARMASM_INLINE +else +if BUILD_ARMASM +if BUILD_ARMASM_INLINE +if BUILD_ARM_NONTHUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-aes-asm_c.c +endif +if BUILD_ARM_THUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-aes-asm_c.c +endif +else +if BUILD_ARM_NONTHUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-aes-asm.S +endif +if BUILD_ARM_THUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-aes-asm.S +endif +endif !BUILD_ARMASM_INLINE +endif BUILD_ARMASM +endif !BUILD_ARMASM_NEON +endif BUILD_AES + +if BUILD_AESNI +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/aes_asm.S +if BUILD_X86_ASM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/aes_gcm_x86_asm.S +else +if BUILD_AESGCM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/aes_gcm_asm.S +endif +if BUILD_AESXTS +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/aes_xts_asm.S +endif +endif +endif + +if BUILD_SHA +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sha.c +endif + +if BUILD_ARMASM_NEON +src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(ARMASM_SHA256_C) +src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(LEGACY_ARMASM_SHA256_C) +if BUILD_ARMASM_INLINE +src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(NEW_ARMASM_SHA256_ASM_C) +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha256-asm_c.c +else +src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(NEW_ARMASM_SHA256_ASM_S) +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha256-asm.S +endif !BUILD_ARMASM_INLINE +else +if BUILD_ARMASM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(ARMASM_SHA256_C) +src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(LEGACY_ARMASM_SHA256_C) +if BUILD_ARMASM_INLINE +if BUILD_ARM_NONTHUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha256-asm_c.c +endif +if BUILD_ARM_THUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-sha256-asm_c.c +endif +else +if BUILD_ARM_NONTHUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha256-asm.S +endif +if BUILD_ARM_THUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-sha256-asm.S +endif +endif !BUILD_ARMASM_INLINE +else +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sha256.c +if BUILD_INTELASM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sha256_asm.S +endif BUILD_INTELASM +endif !BUILD_ARMASM +endif !BUILD_ARMASM_NEON + +if BUILD_RISCV_ASM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/riscv/riscv-64-sha256.c +endif BUILD_RISCV_ASM + +if BUILD_PPC32_ASM +if BUILD_PPC32_ASM_INLINE +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/ppc32/ppc32-sha256-asm_c.c +else +if BUILD_PPC32_ASM_INLINE_REG +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/ppc32/ppc32-sha256-asm_cr.c +else +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/ppc32/ppc32-sha256-asm.S +endif !BUILD_PPC32_ASM_INLINE_REG +endif !BUILD_PPC32_ASM_INLINE +endif BUILD_PPC32_ASM + +if BUILD_SHA512 +if BUILD_RISCV_ASM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/riscv/riscv-64-sha512.c +else + +if !BUILD_FIPS_V5 +if !BUILD_FIPS_V6 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sha512.c +endif !BUILD_FIPS_V6 +endif !BUILD_FIPS_V5 + +if BUILD_ARMASM_NEON +src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(LEGACY_ARMASM_SHA512_C) +if BUILD_ARMASM_INLINE +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-sha512-asm_c.c +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha512-asm_c.c +else +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-sha512-asm.S +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha512-asm.S +endif !BUILD_ARMASM_INLINE +else +if BUILD_ARMASM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(LEGACY_ARMASM_SHA512_C) +if BUILD_ARMASM_INLINE +if BUILD_ARM_NONTHUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha512-asm_c.c +endif +if BUILD_ARM_THUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-sha512-asm_c.c +endif +else +if BUILD_ARM_NONTHUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha512-asm.S +endif +if BUILD_ARM_THUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-sha512-asm.S +endif +endif !BUILD_ARMASM_INLINE +else + +if BUILD_FIPS_V5 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sha512.c +else +if BUILD_FIPS_V6 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sha512.c +endif BUILD_FIPS_V6 +endif !BUILD_FIPS_V5 + +if BUILD_INTELASM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sha512_asm.S +endif BUILD_INTELASM +endif !BUILD_ARMASM +endif !BUILD_ARMASM_NEON +endif !BUILD_RISCV_ASM +endif BUILD_SHA512 + +if BUILD_SHA3 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sha3.c +if BUILD_ARMASM_NEON +if BUILD_ARMASM_INLINE +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-sha3-asm_c.c +else +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-sha3-asm.S +endif !BUILD_ARMASM_INLINE +endif BUILD_ARMASM_NEON +if BUILD_ARMASM +if BUILD_ARMASM_INLINE +if BUILD_ARM_NONTHUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha3-asm_c.c +endif +if BUILD_ARM_THUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-sha3-asm_c.c +endif +else +if BUILD_ARM_NONTHUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha3-asm.S +endif +if BUILD_ARM_THUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-sha3-asm.S +endif +endif !BUILD_ARMASM_INLINE +endif BUILD_ARMASM +if BUILD_RISCV_ASM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/riscv/riscv-64-sha3.c +endif BUILD_RISCV_ASM +if BUILD_INTELASM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sha3_asm.S +endif +endif + +if BUILD_DH +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/dh.c +endif + +if BUILD_CMAC +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/cmac.c +endif + +if BUILD_CURVE448 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/curve448.c +endif + +if BUILD_ED448 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/ed448.c +endif + +if BUILD_CURVE25519 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/curve25519.c +endif + +if BUILD_ED25519 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/ed25519.c +endif + +if BUILD_ARMASM +if BUILD_ARMASM_NEON +if BUILD_ARMASM_INLINE +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-curve25519_c.c +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-curve25519_c.c +else +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-curve25519.S +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-curve25519.S +endif !BUILD_ARMASM_INLINE +else +if BUILD_ARMASM_INLINE +if BUILD_ARM_NONTHUMB +if BUILD_ARM_32 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-curve25519_c.c +endif +if BUILD_ARM_64 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-curve25519_c.c +endif +endif +if BUILD_ARM_THUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-curve25519_c.c +endif +else +if BUILD_ARM_NONTHUMB +if BUILD_ARM_32 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-curve25519.S +endif +if BUILD_ARM_64 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-curve25519.S +endif +endif +if BUILD_ARM_THUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-curve25519.S +endif +endif !BUILD_ARMASM_INLINE +endif !BUILD_ARMASM_NEON +endif BUILD_ARMASM + +if BUILD_PWDBASED +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/pwdbased.c +endif BUILD_PWDBASED + +if BUILD_SP +if BUILD_SP_C32 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sp_c32.c +endif +if BUILD_SP_C64 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sp_c64.c +endif + +if BUILD_SP_X86_64 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sp_x86_64.c +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sp_x86_64_asm.S +endif +if !BUILD_FIPS_V2 +if BUILD_SP_ARM32 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sp_arm32.c +endif +endif +if BUILD_SP_ARM_THUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sp_armthumb.c +endif +if !BUILD_FIPS_V2 +if BUILD_SP_ARM64 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sp_arm64.c +endif +endif +if BUILD_SP_ARM_CORTEX +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sp_cortexm.c +endif +endif BUILD_SP + +# PQ Algorithms (FIPS v7.0.0+) +if BUILD_WC_MLKEM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_mlkem.c +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_mlkem_poly.c +if BUILD_ARMASM +if BUILD_ARM_THUMB +if BUILD_ARMASM_INLINE +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-mlkem-asm_c.c +else +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-mlkem-asm.S +endif !BUILD_ARMASM_INLINE +else +if BUILD_ARMASM_INLINE +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-mlkem-asm_c.c +else +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-mlkem-asm.S +endif !BUILD_ARMASM_INLINE +endif !BUILD_ARM_THUMB +endif BUILD_ARMASM +if !BUILD_X86_ASM +if BUILD_INTELASM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_mlkem_asm.S +endif +endif +if BUILD_ARMASM_NEON +if BUILD_ARMASM_INLINE +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-mlkem-asm_c.c +else +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-mlkem-asm.S +endif !BUILD_ARMASM_INLINE +endif BUILD_ARMASM_NEON +endif + +if BUILD_DILITHIUM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/dilithium.c +if !BUILD_X86_ASM +if BUILD_INTELASM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_mldsa_asm.S +endif BUILD_INTELASM +endif !BUILD_X86_ASM +endif + +if BUILD_WC_LMS +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_lms.c +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_lms_impl.c +endif + +if BUILD_WC_XMSS +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_xmss.c +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_xmss_impl.c +endif + +if BUILD_WC_SLHDSA +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_slhdsa.c +endif + +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/fips.c \ + wolfcrypt/src/fips_test.c + +# fips last file +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wolfcrypt_last.c +endif BUILD_FIPS_V7_PLUS endif BUILD_FIPS @@ -1377,6 +1760,7 @@ if BUILD_SAKKE src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sakke.c endif +if !BUILD_FIPS_V7_PLUS if BUILD_WC_MLKEM src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_mlkem.c src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_mlkem_poly.c @@ -1427,10 +1811,13 @@ if BUILD_WC_XMSS src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_xmss.c src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_xmss_impl.c endif +endif !BUILD_FIPS_V7_PLUS +if !BUILD_FIPS_V7_PLUS if BUILD_WC_SLHDSA src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_slhdsa.c endif +endif !BUILD_FIPS_V7_PLUS if !BUILD_FIPS_V6_PLUS if BUILD_CURVE25519 diff --git a/tests/api.c b/tests/api.c index 8687213f42b..863cbfcb2fa 100644 --- a/tests/api.c +++ b/tests/api.c @@ -27168,8 +27168,6 @@ static int error_test(void) {27, 26 }, #endif { -9, WC_SPAN1_FIRST_E + 1 }, - { -124, -124 }, - { -167, -169 }, { -300, -300 }, { -335, -336 }, { -346, -349 }, diff --git a/tests/api/test_hash.c b/tests/api/test_hash.c index 1fe2e84098d..be5b1be38f4 100644 --- a/tests/api/test_hash.c +++ b/tests/api/test_hash.c @@ -68,6 +68,12 @@ static const enum wc_HashType supportedHash[] = { WC_HASH_TYPE_SHA3_256, WC_HASH_TYPE_SHA3_384, WC_HASH_TYPE_SHA3_512, +#if defined(WOLFSSL_SHAKE128) + WC_HASH_TYPE_SHAKE128, +#endif +#if defined(WOLFSSL_SHAKE256) + WC_HASH_TYPE_SHAKE256, +#endif #endif #ifdef WOLFSSL_SM3 WC_HASH_TYPE_SM3, @@ -101,6 +107,12 @@ static const enum wc_HashType notCompiledHash[] = { WC_HASH_TYPE_SHA3_256, WC_HASH_TYPE_SHA3_384, WC_HASH_TYPE_SHA3_512, +#endif +#if defined(WOLFSSL_SHAKE128) && !defined(WOLFSSL_SHA3) + WC_HASH_TYPE_SHAKE128, +#endif +#if defined(WOLFSSL_SHAKE256) && !defined(WOLFSSL_SHA3) + WC_HASH_TYPE_SHAKE256, #endif WC_HASH_TYPE_NONE /* Dummy value to ensure list is non-zero. */ }; @@ -108,12 +120,6 @@ static const int notCompiledHashLen = (sizeof(notCompiledHash) / sizeof(enum wc_HashType)) - 1; static const enum wc_HashType notSupportedHash[] = { -#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128) - WC_HASH_TYPE_SHAKE128, -#endif -#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256) - WC_HASH_TYPE_SHAKE256, -#endif WC_HASH_TYPE_MD5_SHA, WC_HASH_TYPE_MD2, WC_HASH_TYPE_MD4, @@ -137,6 +143,12 @@ static const enum wc_HashType sizeSupportedHash[] = { #if defined(HAVE_BLAKE2) || defined(HAVE_BLAKE2S) WC_HASH_TYPE_BLAKE2B, WC_HASH_TYPE_BLAKE2S, +#endif +#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128) + WC_HASH_TYPE_SHAKE128, +#endif +#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256) + WC_HASH_TYPE_SHAKE256, #endif WC_HASH_TYPE_NONE /* Dummy value to ensure list is non-zero. */ }; @@ -155,18 +167,18 @@ static const enum wc_HashType sizeNotCompiledHash[] = { #if !defined(HAVE_BLAKE2) && !defined(HAVE_BLAKE2S) WC_HASH_TYPE_BLAKE2B, WC_HASH_TYPE_BLAKE2S, +#endif +#if defined(WOLFSSL_SHAKE128) && !defined(WOLFSSL_SHA3) + WC_HASH_TYPE_SHAKE128, +#endif +#if defined(WOLFSSL_SHAKE256) && !defined(WOLFSSL_SHA3) + WC_HASH_TYPE_SHAKE256, #endif WC_HASH_TYPE_NONE /* Dummy value to ensure list is non-zero. */ }; static const int sizeNotCompiledHashLen = (sizeof(sizeNotCompiledHash) / sizeof(enum wc_HashType)) - 1; static const enum wc_HashType sizeNotSupportedHash[] = { -#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128) - WC_HASH_TYPE_SHAKE128, -#endif -#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256) - WC_HASH_TYPE_SHAKE256, -#endif WC_HASH_TYPE_NONE }; static const int sizeNotSupportedHashLen = (sizeof(sizeNotSupportedHash) / diff --git a/tests/api/test_mldsa.c b/tests/api/test_mldsa.c index 2aa788e8615..19c24a73e60 100644 --- a/tests/api/test_mldsa.c +++ b/tests/api/test_mldsa.c @@ -553,6 +553,8 @@ int test_wc_dilithium(void) ExpectIntEQ(wc_InitRng(&rng), 0); #endif + PRIVATE_KEY_UNLOCK(); + ExpectIntEQ(wc_dilithium_init(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_dilithium_init_ex(NULL, NULL, INVALID_DEVID), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); wc_dilithium_free(NULL); @@ -673,6 +675,8 @@ int test_wc_dilithium(void) WC_NO_ERR_TRACE(BAD_FUNC_ARG)); #endif + PRIVATE_KEY_LOCK(); + wc_dilithium_free(key); #if !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) || \ !defined(WOLFSSL_DILITHIUM_NO_SIGN) @@ -765,6 +769,8 @@ int test_wc_dilithium_sign(void) ExpectIntEQ(wc_InitRng(&rng), 0); ExpectIntEQ(wc_dilithium_init(key), 0); + PRIVATE_KEY_UNLOCK(); + #ifndef WOLFSSL_NO_ML_DSA_44 ExpectIntEQ(wc_dilithium_set_level(key, WC_ML_DSA_44), 0); #elif !defined(WOLFSSL_NO_ML_DSA_65) @@ -878,6 +884,8 @@ int test_wc_dilithium_sign(void) #endif wc_dilithium_free(importKey); + PRIVATE_KEY_LOCK(); + wc_dilithium_free(key); wc_FreeRng(&rng); @@ -1251,6 +1259,8 @@ int test_wc_dilithium_check_key(void) ExpectIntEQ(wc_InitRng(&rng), 0); + PRIVATE_KEY_UNLOCK(); + ExpectIntEQ(wc_dilithium_check_key(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_dilithium_init(checkKey), 0); @@ -1337,6 +1347,8 @@ int test_wc_dilithium_check_key(void) pubCheckKey[48] ^= 0x80; } + PRIVATE_KEY_LOCK(); + wc_dilithium_free(checkKey); wc_FreeRng(&rng); @@ -2940,6 +2952,8 @@ int test_wc_dilithium_der(void) ExpectIntEQ(wc_InitRng(&rng), 0); ExpectIntEQ(wc_dilithium_init(key), 0); + PRIVATE_KEY_UNLOCK(); + ExpectIntEQ(wc_Dilithium_PublicKeyToDer(key, der, DILITHIUM_MAX_DER_SIZE, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_Dilithium_PublicKeyToDer(key, der, DILITHIUM_MAX_DER_SIZE, @@ -3091,6 +3105,7 @@ int test_wc_dilithium_der(void) idx = 0; ExpectIntEQ(wc_Dilithium_PrivateKeyDecode(der, &idx, key, len), 0); + PRIVATE_KEY_LOCK(); wc_dilithium_free(key); wc_FreeRng(&rng); @@ -12346,6 +12361,9 @@ int test_wc_dilithium_sig_kats(void) } ExpectIntEQ(wc_dilithium_init_ex(key, NULL, INVALID_DEVID), 0); + + PRIVATE_KEY_UNLOCK(); + #ifndef WOLFSSL_NO_ML_DSA_44 ExpectIntEQ(wc_dilithium_set_level(key, WC_ML_DSA_44), 0); ExpectIntEQ(wc_dilithium_import_private(sk_44, (word32)sizeof(sk_44), key), @@ -12377,6 +12395,8 @@ int test_wc_dilithium_sig_kats(void) ExpectIntEQ(XMEMCMP(sig, sig_87, sizeof(sig_87)), 0); #endif + PRIVATE_KEY_LOCK(); + wc_dilithium_free(key); XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif @@ -16745,6 +16765,8 @@ int test_wc_Dilithium_PrivateKeyDecode_OpenSSL_form(void) ExpectNotNull(der = (byte*) XMALLOC(derMaxSz, NULL, DYNAMIC_TYPE_TMP_BUFFER)); + PRIVATE_KEY_UNLOCK(); + for (size_t i = 0; i < sizeof(ossl_form) / sizeof(ossl_form[0]); ++i) { ExpectNotNull(fp = XFOPEN(ossl_form[i].fileName, "rb")); ExpectIntGT(derSz = XFREAD(der, 1, derMaxSz, fp), 0); @@ -16811,6 +16833,8 @@ int test_wc_Dilithium_PrivateKeyDecode_OpenSSL_form(void) wc_dilithium_free(&key); } + PRIVATE_KEY_LOCK(); + XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return EXPECT_RESULT(); diff --git a/tests/api/test_mlkem.c b/tests/api/test_mlkem.c index c727194fbe1..c42ab186a49 100644 --- a/tests/api/test_mlkem.c +++ b/tests/api/test_mlkem.c @@ -1451,6 +1451,8 @@ int test_wc_mlkem_make_key_kats(void) XMEMSET(key, 0, sizeof(MlKemKey)); } + PRIVATE_KEY_UNLOCK(); + #ifndef WOLFSSL_NO_ML_KEM_512 ExpectIntEQ(wc_MlKemKey_Init(key, WC_ML_KEM_512, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_MlKemKey_MakeKeyWithRandom(key, seed_512, sizeof(seed_512)), @@ -1488,6 +1490,8 @@ int test_wc_mlkem_make_key_kats(void) wc_MlKemKey_Free(key); #endif + PRIVATE_KEY_LOCK(); + XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return EXPECT_RESULT(); @@ -3845,6 +3849,8 @@ int test_wc_mlkem_decapsulate_kats(void) XMEMSET(key, 0, sizeof(MlKemKey)); } + PRIVATE_KEY_UNLOCK(); + #ifndef WOLFSSL_NO_ML_KEM_512 ExpectIntEQ(wc_MlKemKey_Init(key, WC_ML_KEM_512, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_MlKemKey_DecodePrivateKey(key, dk_512, sizeof(dk_512)), 0); @@ -3867,6 +3873,8 @@ int test_wc_mlkem_decapsulate_kats(void) wc_MlKemKey_Free(key); #endif + PRIVATE_KEY_LOCK(); + XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return EXPECT_RESULT(); diff --git a/tests/api/test_random.c b/tests/api/test_random.c index fe8aaf0ee15..79f8c27b5ee 100644 --- a/tests/api/test_random.c +++ b/tests/api/test_random.c @@ -530,3 +530,146 @@ int test_wc_RNG_HealthTest(void) return EXPECT_RESULT(); } +/* + * Testing wc_RNG_HealthTest_SHA512() + * Test vectors from NIST CAVP drbgtestvectors.zip, Hash_DRBG.rsp, [SHA-512]. + * Source: https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm- + * Validation-Program/documents/drbg/drbgtestvectors.zip + */ +int test_wc_RNG_HealthTest_SHA512(void) +{ + EXPECT_DECLS; +#if defined(HAVE_HASHDRBG) && defined(WOLFSSL_DRBG_SHA512) && \ + !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + + /* No-reseed test: drbgvectors_no_reseed/Hash_DRBG.rsp, [SHA-512], + * COUNT=0 */ + const byte test1Seed[] = + { + /* EntropyInput (32 bytes) */ + 0x6b, 0x50, 0xa7, 0xd8, 0xf8, 0xa5, 0x5d, 0x7a, + 0x3d, 0xf8, 0xbb, 0x40, 0xbc, 0xc3, 0xb7, 0x22, + 0xd8, 0x70, 0x8d, 0xe6, 0x7f, 0xda, 0x01, 0x0b, + 0x03, 0xc4, 0xc8, 0x4d, 0x72, 0x09, 0x6f, 0x8c, + /* Nonce (16 bytes) */ + 0x3e, 0xc6, 0x49, 0xcc, 0x62, 0x56, 0xd9, 0xfa, + 0x31, 0xdb, 0x7a, 0x29, 0x04, 0xaa, 0xf0, 0x25 + }; + const byte test1Output[] = + { + 0x95, 0xb7, 0xf1, 0x7e, 0x98, 0x02, 0xd3, 0x57, + 0x73, 0x92, 0xc6, 0xa9, 0xc0, 0x80, 0x83, 0xb6, + 0x7d, 0xd1, 0x29, 0x22, 0x65, 0xb5, 0xf4, 0x2d, + 0x23, 0x7f, 0x1c, 0x55, 0xbb, 0x9b, 0x10, 0xbf, + 0xcf, 0xd8, 0x2c, 0x77, 0xa3, 0x78, 0xb8, 0x26, + 0x6a, 0x00, 0x99, 0x14, 0x3b, 0x3c, 0x2d, 0x64, + 0x61, 0x1e, 0xee, 0xb6, 0x9a, 0xcd, 0xc0, 0x55, + 0x95, 0x7c, 0x13, 0x9e, 0x8b, 0x19, 0x0c, 0x7a, + 0x06, 0x95, 0x5f, 0x2c, 0x79, 0x7c, 0x27, 0x78, + 0xde, 0x94, 0x03, 0x96, 0xa5, 0x01, 0xf4, 0x0e, + 0x91, 0x39, 0x6a, 0xcf, 0x8d, 0x7e, 0x45, 0xeb, + 0xdb, 0xb5, 0x3b, 0xbf, 0x8c, 0x97, 0x52, 0x30, + 0xd2, 0xf0, 0xff, 0x91, 0x06, 0xc7, 0x61, 0x19, + 0xae, 0x49, 0x8e, 0x7f, 0xbc, 0x03, 0xd9, 0x0f, + 0x8e, 0x4c, 0x51, 0x62, 0x7a, 0xed, 0x5c, 0x8d, + 0x42, 0x63, 0xd5, 0xd2, 0xb9, 0x78, 0x87, 0x3a, + 0x0d, 0xe5, 0x96, 0xee, 0x6d, 0xc7, 0xf7, 0xc2, + 0x9e, 0x37, 0xee, 0xe8, 0xb3, 0x4c, 0x90, 0xdd, + 0x1c, 0xf6, 0xa9, 0xdd, 0xb2, 0x2b, 0x4c, 0xbd, + 0x08, 0x6b, 0x14, 0xb3, 0x5d, 0xe9, 0x3d, 0xa2, + 0xd5, 0xcb, 0x18, 0x06, 0x69, 0x8c, 0xbd, 0x7b, + 0xbb, 0x67, 0xbf, 0xe3, 0xd3, 0x1f, 0xd2, 0xd1, + 0xdb, 0xd2, 0xa1, 0xe0, 0x58, 0xa3, 0xeb, 0x99, + 0xd7, 0xe5, 0x1f, 0x1a, 0x93, 0x8e, 0xed, 0x5e, + 0x1c, 0x1d, 0xe2, 0x3a, 0x6b, 0x43, 0x45, 0xd3, + 0x19, 0x14, 0x09, 0xf9, 0x2f, 0x39, 0xb3, 0x67, + 0x0d, 0x8d, 0xbf, 0xb6, 0x35, 0xd8, 0xe6, 0xa3, + 0x69, 0x32, 0xd8, 0x10, 0x33, 0xd1, 0x44, 0x8d, + 0x63, 0xb4, 0x03, 0xdd, 0xf8, 0x8e, 0x12, 0x1b, + 0x6e, 0x81, 0x9a, 0xc3, 0x81, 0x22, 0x6c, 0x13, + 0x21, 0xe4, 0xb0, 0x86, 0x44, 0xf6, 0x72, 0x7c, + 0x36, 0x8c, 0x5a, 0x9f, 0x7a, 0x4b, 0x3e, 0xe2 + }; + + /* Reseed test: drbgvectors_pr_false/Hash_DRBG.rsp, [SHA-512], COUNT=0 */ + const byte test2SeedA[] = + { + /* EntropyInput (32 bytes) */ + 0x31, 0x44, 0xe1, 0x7a, 0x10, 0xc8, 0x56, 0x12, + 0x97, 0x64, 0xf5, 0x8f, 0xd8, 0xe4, 0x23, 0x10, + 0x20, 0x54, 0x69, 0x96, 0xc0, 0xbf, 0x6c, 0xff, + 0x8e, 0x91, 0xc2, 0x4e, 0xe0, 0x9b, 0xe3, 0x33, + /* Nonce (16 bytes) */ + 0xb1, 0x6f, 0xcb, 0x1c, 0xf0, 0xc0, 0x10, 0xf3, + 0x1f, 0xea, 0xb7, 0x33, 0x58, 0x8b, 0x8e, 0x04 + }; + const byte test2SeedB[] = + { + /* EntropyInputReseed (32 bytes) */ + 0xa0, 0xb3, 0x58, 0x4c, 0x2c, 0x84, 0x12, 0xf6, + 0x18, 0x40, 0x68, 0x34, 0x40, 0x4d, 0x1e, 0xb0, + 0xce, 0x99, 0x9b, 0xa2, 0x89, 0x66, 0x05, 0x4d, + 0x7e, 0x49, 0x7e, 0x0d, 0xb6, 0x08, 0xb9, 0x67 + }; + const byte test2Output[] = + { + 0xef, 0xa3, 0x5d, 0xd0, 0x36, 0x2a, 0xdb, 0x76, + 0x26, 0x45, 0x6b, 0x36, 0xfa, 0xc7, 0x4d, 0x3c, + 0x28, 0xd0, 0x1d, 0x92, 0x64, 0x20, 0x27, 0x5a, + 0x28, 0xbe, 0xa9, 0xc9, 0xdd, 0x75, 0x47, 0xc1, + 0x5e, 0x79, 0x31, 0x85, 0x2a, 0xc1, 0x27, 0x70, + 0x76, 0x56, 0x75, 0x35, 0x23, 0x9c, 0x1f, 0x42, + 0x9c, 0x7f, 0x75, 0xcf, 0x74, 0xc2, 0x26, 0x7d, + 0xeb, 0x6a, 0x3e, 0x59, 0x6c, 0xf3, 0x26, 0x15, + 0x6c, 0x79, 0x69, 0x41, 0x28, 0x3b, 0x8d, 0x58, + 0x3f, 0x17, 0x1c, 0x2f, 0x6e, 0x33, 0x23, 0xf7, + 0x55, 0x5e, 0x1b, 0x18, 0x1f, 0xfd, 0xa3, 0x05, + 0x07, 0x21, 0x0c, 0xb1, 0xf5, 0x89, 0xb2, 0x3c, + 0xd7, 0x18, 0x80, 0xfd, 0x44, 0x37, 0x0c, 0xac, + 0xf4, 0x33, 0x75, 0xb0, 0xdb, 0x7e, 0x33, 0x6f, + 0x12, 0xb3, 0x09, 0xbf, 0xd4, 0xf6, 0x10, 0xbb, + 0x8f, 0x20, 0xe1, 0xa1, 0x5e, 0x25, 0x3a, 0x4f, + 0xe5, 0x11, 0xa0, 0x27, 0x96, 0x8d, 0xf0, 0xb1, + 0x05, 0xa1, 0xd7, 0x3a, 0xff, 0x7c, 0x7a, 0x82, + 0x6d, 0x39, 0xf6, 0x40, 0xdf, 0xb8, 0xf5, 0x22, + 0x25, 0x9e, 0xd4, 0x02, 0x28, 0x2e, 0x2c, 0x2e, + 0x9d, 0x3a, 0x49, 0x8f, 0x51, 0x72, 0x5f, 0xe4, + 0x14, 0x1b, 0x06, 0xda, 0x55, 0x98, 0xa4, 0x2a, + 0xc1, 0xe0, 0x49, 0x4e, 0x99, 0x7d, 0x56, 0x6a, + 0x1a, 0x39, 0xb6, 0x76, 0xb9, 0x6a, 0x60, 0x03, + 0xa4, 0xc5, 0xdb, 0x84, 0xf2, 0x46, 0x58, 0x4e, + 0xe6, 0x5a, 0xf7, 0x0f, 0xf2, 0x16, 0x02, 0x78, + 0x16, 0x6d, 0xa1, 0x6d, 0x91, 0xc9, 0xb8, 0xf2, + 0xde, 0xb0, 0x27, 0x51, 0xa1, 0x08, 0x8a, 0xd6, + 0xbe, 0x4e, 0x80, 0xef, 0x96, 0x6e, 0xb7, 0x3e, + 0x66, 0xbc, 0x87, 0xca, 0xd8, 0x7c, 0x77, 0xc0, + 0xb3, 0x4a, 0x21, 0xba, 0x1d, 0xa0, 0xba, 0x6d, + 0x16, 0xca, 0x50, 0x46, 0xdc, 0x4a, 0xbd, 0xa0 + }; + + byte output[WC_SHA512_DIGEST_SIZE * 4]; /* 256 bytes */ + + /* Bad parameter tests */ + ExpectIntNE(wc_RNG_HealthTest_SHA512(0, NULL, sizeof(test1Seed), + NULL, 0, output, sizeof(output)), 0); + ExpectIntNE(wc_RNG_HealthTest_SHA512(0, test1Seed, sizeof(test1Seed), + NULL, 0, NULL, sizeof(output)), 0); + ExpectIntNE(wc_RNG_HealthTest_SHA512(0, test1Seed, sizeof(test1Seed), + NULL, 0, output, 42), 0); /* wrong output size */ + + /* Good parameter tests */ + /* No-reseed */ + ExpectIntEQ(wc_RNG_HealthTest_SHA512(0, test1Seed, sizeof(test1Seed), + NULL, 0, output, sizeof(output)), 0); + ExpectBufEQ(test1Output, output, sizeof(output)); + + /* With reseed */ + ExpectIntEQ(wc_RNG_HealthTest_SHA512(1, test2SeedA, sizeof(test2SeedA), + test2SeedB, sizeof(test2SeedB), output, sizeof(output)), 0); + ExpectBufEQ(test2Output, output, sizeof(output)); + +#endif /* HAVE_HASHDRBG && WOLFSSL_DRBG_SHA512 && !HAVE_SELFTEST && FIPS v7+ */ + return EXPECT_RESULT(); +} + diff --git a/tests/api/test_random.h b/tests/api/test_random.h index a6478b38df9..0454e14c703 100644 --- a/tests/api/test_random.h +++ b/tests/api/test_random.h @@ -35,6 +35,7 @@ int test_wc_rng_new(void); int test_wc_RNG_DRBG_Reseed(void); int test_wc_RNG_TestSeed(void); int test_wc_RNG_HealthTest(void); +int test_wc_RNG_HealthTest_SHA512(void); #define TEST_RANDOM_DECLS \ TEST_DECL_GROUP("random", test_wc_InitRng), \ @@ -47,6 +48,7 @@ int test_wc_RNG_HealthTest(void); TEST_DECL_GROUP("random", test_wc_rng_new), \ TEST_DECL_GROUP("random", test_wc_RNG_DRBG_Reseed), \ TEST_DECL_GROUP("random", test_wc_RNG_TestSeed), \ - TEST_DECL_GROUP("random", test_wc_RNG_HealthTest) + TEST_DECL_GROUP("random", test_wc_RNG_HealthTest), \ + TEST_DECL_GROUP("random", test_wc_RNG_HealthTest_SHA512) #endif /* WOLFCRYPT_TEST_RANDOM_H */ diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index 354e5a68004..5c9e7ed608c 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -975,16 +975,37 @@ static WC_INLINE void bench_append_memory_info(char* buffer, size_t size, #define BENCH_SLHDSA_SHAKE192F 0x00000100 #define BENCH_SLHDSA_SHAKE256S 0x00000200 #define BENCH_SLHDSA_SHAKE256F 0x00000400 +#define BENCH_SLHDSA_SHA2_128S 0x00000800 +#define BENCH_SLHDSA_SHA2_128F 0x00001000 +#define BENCH_SLHDSA_SHA2_192S 0x00002000 +#define BENCH_SLHDSA_SHA2_192F 0x00004000 +#define BENCH_SLHDSA_SHA2_256S 0x00008000 +#define BENCH_SLHDSA_SHA2_256F 0x00010000 #define BENCH_SLHDSA (BENCH_SLHDSA_SHAKE128S | \ BENCH_SLHDSA_SHAKE128F | \ BENCH_SLHDSA_SHAKE192S | \ BENCH_SLHDSA_SHAKE192F | \ BENCH_SLHDSA_SHAKE256S | \ - BENCH_SLHDSA_SHAKE256F) + BENCH_SLHDSA_SHAKE256F | \ + BENCH_SLHDSA_SHA2_128S | \ + BENCH_SLHDSA_SHA2_128F | \ + BENCH_SLHDSA_SHA2_192S | \ + BENCH_SLHDSA_SHA2_192F | \ + BENCH_SLHDSA_SHA2_256S | \ + BENCH_SLHDSA_SHA2_256F) /* Other */ #define BENCH_RNG 0x00000001 #define BENCH_SCRYPT 0x00000002 +#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + #define BENCH_RNG_SHA512 0x00000004 +#endif +#define BENCH_RNG_INIT 0x00000008 +#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + #define BENCH_RNG_SHA512_INIT 0x00000010 +#endif #if defined(HAVE_AESGCM) || defined(HAVE_AESCCM) || \ (defined(HAVE_CHACHA) && defined(HAVE_POLY1305)) @@ -1292,6 +1313,17 @@ static const bench_alg bench_other_opt[] = { #ifndef WC_NO_RNG { "-rng", BENCH_RNG }, #endif +#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + { "-rng-sha512", BENCH_RNG_SHA512 }, +#endif +#ifndef WC_NO_RNG + { "-rng-init", BENCH_RNG_INIT }, +#endif +#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + { "-rng-sha512-init", BENCH_RNG_SHA512_INIT }, +#endif #ifdef HAVE_SCRYPT { "-scrypt", BENCH_SCRYPT }, #endif @@ -1340,6 +1372,12 @@ static const bench_pq_hash_sig_alg bench_pq_hash_sig_opt[] = { { "-slhdsa-shake192f", BENCH_SLHDSA_SHAKE192F}, { "-slhdsa-shake256s", BENCH_SLHDSA_SHAKE256S}, { "-slhdsa-shake256f", BENCH_SLHDSA_SHAKE256F}, + { "-slhdsa-sha2-128s", BENCH_SLHDSA_SHA2_128S}, + { "-slhdsa-sha2-128f", BENCH_SLHDSA_SHA2_128F}, + { "-slhdsa-sha2-192s", BENCH_SLHDSA_SHA2_192S}, + { "-slhdsa-sha2-192f", BENCH_SLHDSA_SHA2_192F}, + { "-slhdsa-sha2-256s", BENCH_SLHDSA_SHA2_256S}, + { "-slhdsa-sha2-256f", BENCH_SLHDSA_SHA2_256F}, { "-slhdsa", BENCH_SLHDSA }, #endif { NULL, 0} @@ -2056,12 +2094,7 @@ static const char* bench_result_words3[][5] = { #define BENCH_ASYM #endif -#if defined(BENCH_ASYM) -#if defined(HAVE_ECC) || !defined(NO_RSA) || !defined(NO_DH) || \ - defined(HAVE_CURVE25519) || defined(HAVE_ED25519) || \ - defined(HAVE_CURVE448) || defined(HAVE_ED448) || \ - defined(WOLFSSL_HAVE_MLKEM) || defined(HAVE_DILITHIUM) || \ - defined(WOLFSSL_HAVE_LMS) +#if defined(BENCH_ASYM) || !defined(WC_NO_RNG) static const char* bench_result_words2[][6] = { #ifdef BENCH_MICROSECOND { "ops took", "μsec" , "avg" , "ops/μsec", "cycles/op", @@ -2075,8 +2108,7 @@ static const char* bench_result_words2[][6] = { NULL }, /* 1 Japanese */ #endif }; -#endif -#endif +#endif /* BENCH_ASYM || !WC_NO_RNG */ #ifdef WOLFSSL_CAAM #include @@ -3200,6 +3232,102 @@ static void bench_stats_sym_finish(const char* desc, int useDeviceID, TEST_SLEEP(); } /* bench_stats_sym_finish */ +#ifndef WC_NO_RNG +/* Report ops/sec in the same format as bench_stats_asym_finish, but without + * requiring BENCH_ASYM to be defined. Used for benchmarks like RNG init/free + * that measure operation counts rather than byte throughput. */ +static void bench_stats_ops_finish(const char* algo, int strength, + const char* desc, int count, double start, int ret) +{ + double total, each = 0, opsSec, milliEach; + const char **word = bench_result_words2[lng_index]; + char msg[256]; +#ifdef BENCH_MICROSECOND + const int digits = 5; +#else + const int digits = 3; +#endif + + XMEMSET(msg, 0, sizeof(msg)); + + total = current_time(0) - start; + +#ifdef WOLFSSL_ESPIDF + END_ESP_CYCLES +#else + END_CYCLES +#endif + + if (count > 0) + each = total / count; + if (total > 0) + opsSec = count / total; + else + opsSec = 0; + +#ifdef BENCH_MICROSECOND + milliEach = each / 1000; +#else + milliEach = each * 1000; +#endif + + SLEEP_ON_ERROR(ret); + + if (csv_format == 1) { + (void)XSNPRINTF(msg, sizeof(msg), "%s,%d,%s," FLT_FMT_PREC "," + FLT_FMT_PREC "," STATS_CLAUSE_SEPARATOR, + algo, strength, desc, + FLT_FMT_PREC_ARGS(3, milliEach), + FLT_FMT_PREC_ARGS(digits, opsSec)); + } + else { +#ifdef HAVE_GET_CYCLES + (void)XSNPRINTF(msg, sizeof(msg), + "%-6s %5d %8s %6d %s " FLT_FMT_PREC2 " %s, %s " + FLT_FMT_PREC2 " ms, " FLT_FMT_PREC2 " %s, %lu cycles", + algo, strength, desc, + count, word[0], + FLT_FMT_PREC2_ARGS(5, 3, total), word[1], word[2], + FLT_FMT_PREC2_ARGS(5, 3, milliEach), + FLT_FMT_PREC2_ARGS(digits + 6, digits, opsSec), + word[3], (unsigned long)total_cycles); +#else + (void)XSNPRINTF(msg, sizeof(msg), + "%-6s %5d %8s %6d %s " FLT_FMT_PREC2 " %s, %s " + FLT_FMT_PREC2 " ms, " FLT_FMT_PREC2 " %s", + algo, strength, desc, + count, word[0], + FLT_FMT_PREC2_ARGS(5, 3, total), word[1], word[2], + FLT_FMT_PREC2_ARGS(5, 3, milliEach), + FLT_FMT_PREC2_ARGS(digits + 6, digits, opsSec), + word[3]); +#endif + +#ifdef WOLFSSL_ESPIDF + SHOW_ESP_CYCLES_OPS(msg, sizeof(msg)); +#else + SHOW_CYCLES_OPS(msg, sizeof(msg)); +#endif + } + + printf("%s", msg); + + if (ret < 0) { + printf("%sBenchmark %s %s %d failed: %d\n", + err_prefix, algo, desc, strength, ret); + } + +#ifndef WOLFSSL_SGX + XFFLUSH(stdout); +#endif + + (void)ret; + + bench_stats_prepare(); + TEST_SLEEP(); +} /* bench_stats_ops_finish */ +#endif /* !WC_NO_RNG */ + #ifdef BENCH_ASYM #if defined(HAVE_ECC) || !defined(NO_RSA) || !defined(NO_DH) || \ defined(HAVE_CURVE25519) || defined(HAVE_ED25519) || \ @@ -3837,6 +3965,12 @@ static void* benchmarks_do(void* args) if (bench_all || (bench_other_algs & BENCH_RNG)) bench_rng(); #endif /* WC_NO_RNG */ +#if defined(WOLFSSL_DRBG_SHA512) && !defined(WC_NO_RNG) && \ + !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + if (bench_all || (bench_other_algs & BENCH_RNG_SHA512)) + bench_rng_sha512(); +#endif #ifndef NO_AES #ifdef HAVE_AES_CBC if (bench_all || (bench_cipher_algs & BENCH_AES_CBC)) { @@ -4397,6 +4531,36 @@ static void* benchmarks_do(void* args) bench_slhdsa(SLHDSA_SHAKE256F); } #endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128S + if (bench_pq_hash_sig_algs & BENCH_SLHDSA_SHA2_128S) { + bench_slhdsa(SLHDSA_SHA2_128S); + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128F + if (bench_pq_hash_sig_algs & BENCH_SLHDSA_SHA2_128F) { + bench_slhdsa(SLHDSA_SHA2_128F); + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192S + if (bench_pq_hash_sig_algs & BENCH_SLHDSA_SHA2_192S) { + bench_slhdsa(SLHDSA_SHA2_192S); + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192F + if (bench_pq_hash_sig_algs & BENCH_SLHDSA_SHA2_192F) { + bench_slhdsa(SLHDSA_SHA2_192F); + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256S + if (bench_pq_hash_sig_algs & BENCH_SLHDSA_SHA2_256S) { + bench_slhdsa(SLHDSA_SHA2_256S); + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256F + if (bench_pq_hash_sig_algs & BENCH_SLHDSA_SHA2_256F) { + bench_slhdsa(SLHDSA_SHA2_256F); + } +#endif #endif #if defined(HAVE_ECC) && !defined(WC_NO_RNG) @@ -4596,6 +4760,16 @@ static void* benchmarks_do(void* args) bench_sphincsKeySign(5, SMALL_VARIANT); #endif +#ifndef WC_NO_RNG + if (bench_all || (bench_other_algs & BENCH_RNG_INIT)) + bench_rng_init(); +#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + if (bench_all || (bench_other_algs & BENCH_RNG_SHA512_INIT)) + bench_rng_sha512_init(); +#endif +#endif + exit: /* free benchmark buffers */ XFREE(bench_plain, HEAP_HINT, DYNAMIC_TYPE_WOLF_BIGINT); @@ -4728,6 +4902,19 @@ int benchmark_init(void) wc_SetSeed_Cb(WC_GENERATE_SEED_DEFAULT); #endif +#if defined(HAVE_FIPS) && FIPS_VERSION3_GE(7,0,0) + /* Pre-run all CASTs so their overhead is not captured in benchmark + * metrics. Without this, the first use of each algorithm triggers + * its CAST on-demand, inflating that algorithm's benchmark numbers. */ + { + int castRet = wc_RunAllCast_fips(); + if (castRet != 0) { + printf("%swc_RunAllCast_fips: %d CAST(s) failed, module in " + "DEGRADED mode\n", err_prefix, castRet); + } + } +#endif + bench_stats_init(); #if defined(DEBUG_WOLFSSL) && !defined(HAVE_VALGRIND) @@ -4942,6 +5129,21 @@ void bench_rng(void) WC_RNG myrng; DECLARE_MULTI_VALUE_STATS_VARS() + /* Force SHA-256 DRBG by temporarily disabling SHA-512 DRBG */ +#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + #if !defined(NO_SHA256) + ret = wc_Sha512Drbg_Disable(); + if (ret != 0) { + printf("wc_Sha512Drbg_Disable failed %d\n", ret); + return; + } + #else + printf("RNG SHA-256 DRBG (Skipped: Disabled)\n"); + return; + #endif +#endif + bench_stats_prepare(); #ifndef HAVE_FIPS @@ -4950,7 +5152,11 @@ void bench_rng(void) ret = wc_InitRng(&myrng); #endif if (ret < 0) { - printf("InitRNG failed %d\n", ret); + printf("InitRNG (SHA-256) failed %d\n", ret); +#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + wc_Sha512Drbg_Enable(); +#endif return; } @@ -4981,15 +5187,204 @@ void bench_rng(void) #endif ); exit_rng: - bench_stats_sym_finish("RNG", 0, count, bench_size, start, ret); + bench_stats_sym_finish("RNG SHA-256 DRBG", 0, count, bench_size, start, + ret); #ifdef MULTI_VALUE_STATISTICS bench_multi_value_stats(max, min, sum, squareSum, runs); #endif wc_FreeRng(&myrng); + + /* Restore SHA-512 DRBG */ +#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + wc_Sha512Drbg_Enable(); +#endif } #endif /* WC_NO_RNG */ +#if defined(WOLFSSL_DRBG_SHA512) && !defined(WC_NO_RNG) && \ + !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) +void bench_rng_sha512(void) +{ + int ret, i, count; + double start; + long pos, len, remain; + WC_RNG myrng; + DECLARE_MULTI_VALUE_STATS_VARS() + + /* Force SHA-512 DRBG by temporarily disabling SHA-256 DRBG */ +#ifndef NO_SHA256 + ret = wc_Sha256Drbg_Disable(); + if (ret != 0) { + printf("wc_Sha256Drbg_Disable failed %d\n", ret); + return; + } +#endif + + bench_stats_prepare(); + +#ifndef HAVE_FIPS + ret = wc_InitRng_ex(&myrng, HEAP_HINT, devId); +#else + ret = wc_InitRng(&myrng); +#endif + if (ret < 0) { + printf("InitRNG (SHA-512) failed %d\n", ret); +#ifndef NO_SHA256 + wc_Sha256Drbg_Enable(); +#endif + return; + } + + bench_stats_start(&count, &start); + do { + for (i = 0; i < numBlocks; i++) { + /* Split request to handle large RNG request */ + pos = 0; + remain = (int)bench_size; + while (remain > 0) { + len = remain; + if (len > RNG_MAX_BLOCK_LEN) + len = RNG_MAX_BLOCK_LEN; + ret = wc_RNG_GenerateBlock(&myrng, &bench_plain[pos], + (word32)len); + if (ret < 0) + goto exit_rng_sha512; + + remain -= len; + pos += len; + } + RECORD_MULTI_VALUE_STATS(); + } + count += i; + } while (bench_stats_check(start) +#ifdef MULTI_VALUE_STATISTICS + || runs < minimum_runs +#endif + ); +exit_rng_sha512: + bench_stats_sym_finish("RNG SHA-512 DRBG", 0, count, bench_size, start, + ret); +#ifdef MULTI_VALUE_STATISTICS + bench_multi_value_stats(max, min, sum, squareSum, runs); +#endif + + wc_FreeRng(&myrng); + + /* Restore SHA-256 DRBG */ +#ifndef NO_SHA256 + wc_Sha256Drbg_Enable(); +#endif +} +#endif /* WOLFSSL_DRBG_SHA512 && !WC_NO_RNG && !HAVE_SELFTEST && FIPS v7+ */ + +#ifndef WC_NO_RNG +void bench_rng_init(void) +{ + int ret, count; + double start; + WC_RNG myrng; + DECLARE_MULTI_VALUE_STATS_VARS() + + /* Force SHA-256 DRBG by temporarily disabling SHA-512 DRBG */ +#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + #if !defined(NO_SHA256) + ret = wc_Sha512Drbg_Disable(); + if (ret != 0) { + printf("wc_Sha512Drbg_Disable failed %d\n", ret); + return; + } + #else + printf("RNG SHA-256 Init/Free (Skipped: Disabled)\n"); + return; + #endif +#endif + + bench_stats_start(&count, &start); + do { + #ifndef HAVE_FIPS + ret = wc_InitRng_ex(&myrng, HEAP_HINT, devId); + #else + ret = wc_InitRng(&myrng); + #endif + if (ret < 0) { + printf("InitRNG (SHA-256 init bench) failed %d\n", ret); + goto exit_rng_init; + } + wc_FreeRng(&myrng); + count++; + RECORD_MULTI_VALUE_STATS(); + } while (bench_stats_check(start) +#ifdef MULTI_VALUE_STATISTICS + || runs < minimum_runs +#endif + ); +exit_rng_init: + bench_stats_ops_finish("RNG", 256, "SHA256 Init/Free", count, start, ret); +#ifdef MULTI_VALUE_STATISTICS + bench_multi_value_stats(max, min, sum, squareSum, runs); +#endif + + /* Restore SHA-512 DRBG */ +#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + wc_Sha512Drbg_Enable(); +#endif +} + +#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) +void bench_rng_sha512_init(void) +{ + int ret, count; + double start; + WC_RNG myrng; + DECLARE_MULTI_VALUE_STATS_VARS() + + /* Force SHA-512 DRBG by temporarily disabling SHA-256 DRBG */ +#ifndef NO_SHA256 + ret = wc_Sha256Drbg_Disable(); + if (ret != 0) { + printf("wc_Sha256Drbg_Disable failed %d\n", ret); + return; + } +#endif + + bench_stats_start(&count, &start); + do { + #ifndef HAVE_FIPS + ret = wc_InitRng_ex(&myrng, HEAP_HINT, devId); + #else + ret = wc_InitRng(&myrng); + #endif + if (ret < 0) { + printf("InitRNG (SHA-512 init bench) failed %d\n", ret); + goto exit_rng_sha512_init; + } + wc_FreeRng(&myrng); + count++; + RECORD_MULTI_VALUE_STATS(); + } while (bench_stats_check(start) +#ifdef MULTI_VALUE_STATISTICS + || runs < minimum_runs +#endif + ); +exit_rng_sha512_init: + bench_stats_ops_finish("RNG", 512, "SHA512 Init/Free", count, start, ret); +#ifdef MULTI_VALUE_STATISTICS + bench_multi_value_stats(max, min, sum, squareSum, runs); +#endif + + /* Restore SHA-256 DRBG */ +#ifndef NO_SHA256 + wc_Sha256Drbg_Enable(); +#endif +} +#endif /* WOLFSSL_DRBG_SHA512 && !HAVE_SELFTEST && FIPS v7+ */ +#endif /* !WC_NO_RNG */ #ifndef NO_AES @@ -10704,6 +11099,7 @@ static void bench_mlkem_encap(int type, const char* name, int keySize, RESET_MULTI_VALUE_STATS_VARS(); /* MLKEM Decapsulate */ + PRIVATE_KEY_UNLOCK(); bench_stats_start(&count, &start); do { /* while free pending slots in queue, submit ops */ @@ -10721,6 +11117,7 @@ static void bench_mlkem_encap(int type, const char* name, int keySize, ); exit_decap: + PRIVATE_KEY_LOCK(); bench_stats_asym_finish(name, keySize, desc[13], 0, count, start, ret); #ifdef MULTI_VALUE_STATISTICS bench_multi_value_stats(max, min, sum, squareSum, runs); @@ -11213,6 +11610,13 @@ static void bench_lms_sign_verify(enum wc_LmsParm parm, byte* pub) case WC_LMS_PARM_L4_H5_W4: case WC_LMS_PARM_L4_H10_W4: case WC_LMS_PARM_L4_H10_W8: + case WC_LMS_PARM_L1_H25_W1: + case WC_LMS_PARM_L1_H25_W2: + case WC_LMS_PARM_L1_H25_W4: + case WC_LMS_PARM_L1_H25_W8: + case WC_LMS_PARM_L1_H10_W1: + case WC_LMS_PARM_L1_H15_W1: + case WC_LMS_PARM_L1_H20_W1: #endif #ifdef WOLFSSL_LMS_SHA256_192 @@ -11236,6 +11640,57 @@ static void bench_lms_sign_verify(enum wc_LmsParm parm, byte* pub) case WC_LMS_PARM_SHA256_192_L3_H5_W8: case WC_LMS_PARM_SHA256_192_L3_H10_W4: case WC_LMS_PARM_SHA256_192_L4_H5_W8: + case WC_LMS_PARM_SHA256_192_L1_H25_W1: + case WC_LMS_PARM_SHA256_192_L1_H25_W2: + case WC_LMS_PARM_SHA256_192_L1_H25_W4: + case WC_LMS_PARM_SHA256_192_L1_H25_W8: + case WC_LMS_PARM_SHA256_192_L1_H10_W1: + case WC_LMS_PARM_SHA256_192_L1_H15_W1: + case WC_LMS_PARM_SHA256_192_L1_H20_W1: + case WC_LMS_PARM_SHA256_192_L1_H15_W8: +#endif + +#ifdef WOLFSSL_LMS_SHAKE256 + case WC_LMS_PARM_SHAKE_L1_H5_W1: + case WC_LMS_PARM_SHAKE_L1_H5_W2: + case WC_LMS_PARM_SHAKE_L1_H5_W4: + case WC_LMS_PARM_SHAKE_L1_H5_W8: + case WC_LMS_PARM_SHAKE_L1_H10_W1: + case WC_LMS_PARM_SHAKE_L1_H10_W2: + case WC_LMS_PARM_SHAKE_L1_H10_W4: + case WC_LMS_PARM_SHAKE_L1_H10_W8: + case WC_LMS_PARM_SHAKE_L1_H15_W1: + case WC_LMS_PARM_SHAKE_L1_H15_W2: + case WC_LMS_PARM_SHAKE_L1_H15_W4: + case WC_LMS_PARM_SHAKE_L1_H15_W8: + case WC_LMS_PARM_SHAKE_L1_H20_W1: + case WC_LMS_PARM_SHAKE_L1_H20_W2: + case WC_LMS_PARM_SHAKE_L1_H20_W4: + case WC_LMS_PARM_SHAKE_L1_H20_W8: + case WC_LMS_PARM_SHAKE_L1_H25_W1: + case WC_LMS_PARM_SHAKE_L1_H25_W2: + case WC_LMS_PARM_SHAKE_L1_H25_W4: + case WC_LMS_PARM_SHAKE_L1_H25_W8: + case WC_LMS_PARM_SHAKE192_L1_H5_W1: + case WC_LMS_PARM_SHAKE192_L1_H5_W2: + case WC_LMS_PARM_SHAKE192_L1_H5_W4: + case WC_LMS_PARM_SHAKE192_L1_H5_W8: + case WC_LMS_PARM_SHAKE192_L1_H10_W1: + case WC_LMS_PARM_SHAKE192_L1_H10_W2: + case WC_LMS_PARM_SHAKE192_L1_H10_W4: + case WC_LMS_PARM_SHAKE192_L1_H10_W8: + case WC_LMS_PARM_SHAKE192_L1_H15_W1: + case WC_LMS_PARM_SHAKE192_L1_H15_W2: + case WC_LMS_PARM_SHAKE192_L1_H15_W4: + case WC_LMS_PARM_SHAKE192_L1_H15_W8: + case WC_LMS_PARM_SHAKE192_L1_H20_W1: + case WC_LMS_PARM_SHAKE192_L1_H20_W2: + case WC_LMS_PARM_SHAKE192_L1_H20_W4: + case WC_LMS_PARM_SHAKE192_L1_H20_W8: + case WC_LMS_PARM_SHAKE192_L1_H25_W1: + case WC_LMS_PARM_SHAKE192_L1_H25_W2: + case WC_LMS_PARM_SHAKE192_L1_H25_W4: + case WC_LMS_PARM_SHAKE192_L1_H25_W8: #endif default: @@ -12060,9 +12515,17 @@ void bench_slhdsa(enum SlhDsaParam param) } len = wc_SlhDsaKey_PublicSize(key) / 2 * 8; - XMEMCPY(name, "SLH-DSA-S", 10); - if ((param & 1) == 1) { - name[8] = 'F'; + if (SLHDSA_IS_SHA2(param)) { + XMEMCPY(name, "SLH-DSA-SHA2-S", 15); + if ((param & 1) == 1) { + name[13] = 'F'; + } + } + else { + XMEMCPY(name, "SLH-DSA-S", 10); + if ((param & 1) == 1) { + name[8] = 'F'; + } } bench_stats_start(&count, &start); @@ -12080,6 +12543,7 @@ void bench_slhdsa(enum SlhDsaParam param) ); bench_stats_asym_finish(name, len, "gen", 0, count, start, ret); + PRIVATE_KEY_UNLOCK(); bench_stats_start(&count, &start); do { sigLen = WC_SLHDSA_MAX_SIG_LEN; @@ -12095,6 +12559,7 @@ void bench_slhdsa(enum SlhDsaParam param) || runs < minimum_runs #endif ); + PRIVATE_KEY_LOCK(); bench_stats_asym_finish(name, len, "sign", 0, count, start, ret); outLen = (word32)sizeof(pk); @@ -12127,6 +12592,78 @@ void bench_slhdsa(enum SlhDsaParam param) ); bench_stats_asym_finish(name, len, "verify", 0, count, start, ret); + /* Internal interface: sign M' directly (no M' construction). */ + PRIVATE_KEY_UNLOCK(); + bench_stats_start(&count, &start); + do { + sigLen = WC_SLHDSA_MAX_SIG_LEN; + ret = wc_SlhDsaKey_SignMsgDeterministic(key, msg, + (word32)sizeof(msg), sig, &sigLen); + if (ret != 0) { + goto exit; + } + count++; + RECORD_MULTI_VALUE_STATS(); + } while (bench_stats_check(start) +#ifdef MULTI_VALUE_STATISTICS + || runs < minimum_runs +#endif + ); + PRIVATE_KEY_LOCK(); + bench_stats_asym_finish(name, len, "sign-msg", 0, count, start, ret); + + bench_stats_start(&count, &start); + do { + ret = wc_SlhDsaKey_VerifyMsg(key_vfy, msg, (word32)sizeof(msg), + sig, sigLen); + if (ret != 0) { + goto exit; + } + count++; + RECORD_MULTI_VALUE_STATS(); + } while (bench_stats_check(start) +#ifdef MULTI_VALUE_STATISTICS + || runs < minimum_runs +#endif + ); + bench_stats_asym_finish(name, len, "vrfy-msg", 0, count, start, ret); + + /* Pre-hash interface: hash message, then sign the hash. */ + PRIVATE_KEY_UNLOCK(); + bench_stats_start(&count, &start); + do { + sigLen = WC_SLHDSA_MAX_SIG_LEN; + ret = wc_SlhDsaKey_SignHashDeterministic(key, ctx, 0, msg, + (word32)sizeof(msg), WC_HASH_TYPE_SHA256, sig, &sigLen); + if (ret != 0) { + goto exit; + } + count++; + RECORD_MULTI_VALUE_STATS(); + } while (bench_stats_check(start) +#ifdef MULTI_VALUE_STATISTICS + || runs < minimum_runs +#endif + ); + PRIVATE_KEY_LOCK(); + bench_stats_asym_finish(name, len, "sign-pre", 0, count, start, ret); + + bench_stats_start(&count, &start); + do { + ret = wc_SlhDsaKey_VerifyHash(key_vfy, ctx, 0, msg, + (word32)sizeof(msg), WC_HASH_TYPE_SHA256, sig, sigLen); + if (ret != 0) { + goto exit; + } + count++; + RECORD_MULTI_VALUE_STATS(); + } while (bench_stats_check(start) +#ifdef MULTI_VALUE_STATISTICS + || runs < minimum_runs +#endif + ); + bench_stats_asym_finish(name, len, "vrfy-pre", 0, count, start, ret); + exit: #ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC if (key_vfy) @@ -15515,6 +16052,7 @@ void bench_dilithiumKeySign(byte level) #elif !defined WOLFSSL_DILITHIUM_NO_SIGN + PRIVATE_KEY_UNLOCK(); #ifndef WOLFSSL_NO_ML_DSA_44 if (level == 2) { ret = wc_dilithium_import_private(bench_dilithium_level2_key, @@ -15533,6 +16071,7 @@ void bench_dilithiumKeySign(byte level) sizeof_bench_dilithium_level5_key, key); } #endif + PRIVATE_KEY_LOCK(); if (ret != 0) { printf("Failed to load private key\n"); goto out; diff --git a/wolfcrypt/benchmark/benchmark.h b/wolfcrypt/benchmark/benchmark.h index dc97fe68379..7b291b25885 100644 --- a/wolfcrypt/benchmark/benchmark.h +++ b/wolfcrypt/benchmark/benchmark.h @@ -130,6 +130,13 @@ void bench_sakkeRskGen(void); void bench_sakkeValidate(void); void bench_sakke(void); void bench_rng(void); +void bench_rng_init(void); +#if defined(WOLFSSL_DRBG_SHA512) && !defined(WC_NO_RNG) && \ + !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) +void bench_rng_sha512(void); +void bench_rng_sha512_init(void); +#endif void bench_blake2b(void); void bench_blake2s(void); void bench_ascon_hash(void); diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 8d8de5a2cd9..6413dc3ab0a 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -4379,6 +4379,12 @@ static word32 SetBitString16Bit(word16 val, byte* output) #ifndef WOLFSSL_NOSHA3_512 static const byte hashSha3_512hOid[] = {96, 134, 72, 1, 101, 3, 4, 2, 10}; #endif /* WOLFSSL_NOSHA3_512 */ +#ifdef WOLFSSL_SHAKE128 + static const byte hashShake128hOid[] = {96, 134, 72, 1, 101, 3, 4, 2, 11}; +#endif /* WOLFSSL_SHAKE128 */ +#ifdef WOLFSSL_SHAKE256 + static const byte hashShake256hOid[] = {96, 134, 72, 1, 101, 3, 4, 2, 12}; +#endif /* WOLFSSL_SHAKE256 */ #endif /* WOLFSSL_SHA3 */ /* hmacType */ @@ -5252,6 +5258,18 @@ const byte* OidFromId(word32 id, word32 type, word32* oidSz) *oidSz = sizeof(hashSha3_512hOid); break; #endif /* WOLFSSL_NOSHA3_512 */ + #ifdef WOLFSSL_SHAKE128 + case SHAKE128h: + oid = hashShake128hOid; + *oidSz = sizeof(hashShake128hOid); + break; + #endif /* WOLFSSL_SHAKE128 */ + #ifdef WOLFSSL_SHAKE256 + case SHAKE256h: + oid = hashShake256hOid; + *oidSz = sizeof(hashShake256hOid); + break; + #endif /* WOLFSSL_SHAKE256 */ #endif /* WOLFSSL_SHA3 */ default: break; diff --git a/wolfcrypt/src/dh.c b/wolfcrypt/src/dh.c index 69fa1152a91..87c2794a7f3 100644 --- a/wolfcrypt/src/dh.c +++ b/wolfcrypt/src/dh.c @@ -1063,6 +1063,11 @@ static int CheckDhLN(word32 modLen, word32 divLen) if (divLen == 224 || divLen == 256) ret = 0; break; + /* Per SP 800-56Ar3 Table 2 */ + case 3072: + if (divLen == 256) + ret = 0; + break; default: break; } diff --git a/wolfcrypt/src/dilithium.c b/wolfcrypt/src/dilithium.c index 17a2dd8eb50..2dfcba8e414 100644 --- a/wolfcrypt/src/dilithium.c +++ b/wolfcrypt/src/dilithium.c @@ -132,6 +132,11 @@ #include +#if FIPS_VERSION3_GE(2,0,0) + /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */ + #define FIPS_NO_WRAPPERS +#endif + #ifndef WOLFSSL_DILITHIUM_NO_ASN1 #include #endif @@ -734,6 +739,15 @@ static int dilithium_get_hash_oid(int hash, byte* oidBuffer, word32* oidLen) oid = sha512Oid; } else +#ifndef WOLFSSL_NOSHA512_224 + if (hash == WC_HASH_TYPE_SHA512_224) { + static byte sha512_224Oid[DILITHIUM_HASH_OID_LEN] = { + 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05 + }; + oid = sha512_224Oid; + } + else +#endif #ifndef WOLFSSL_NOSHA512_256 if (hash == WC_HASH_TYPE_SHA512_256) { static byte sha512_256Oid[DILITHIUM_HASH_OID_LEN] = { @@ -9360,7 +9374,7 @@ static void dilithium_make_pub_vec(dilithium_key* key, sword32* t1) * @return MEMORY_E when memory allocation fails. * @return Other negative when an error occurs. */ -static int dilithium_verify_mu(dilithium_key* key, const byte* mu, +static int dilithium_verify_with_mu(dilithium_key* key, const byte* mu, const byte* sig, word32 sigLen, int* res) { #ifndef WOLFSSL_DILITHIUM_VERIFY_SMALL_MEM @@ -9819,7 +9833,7 @@ static int dilithium_verify_ctx_msg(dilithium_key* key, const byte* ctx, ctx, (byte)ctxLen, msg, msgLen, mu, DILITHIUM_MU_SZ); } if (ret == 0) { - ret = dilithium_verify_mu(key, mu, sig, sigLen, res); + ret = dilithium_verify_with_mu(key, mu, sig, sigLen, res); } return ret; @@ -9862,7 +9876,7 @@ static int dilithium_verify_msg(dilithium_key* key, const byte* msg, mu, DILITHIUM_MU_SZ); } if (ret == 0) { - ret = dilithium_verify_mu(key, mu, sig, sigLen, res); + ret = dilithium_verify_with_mu(key, mu, sig, sigLen, res); } return ret; @@ -9917,7 +9931,7 @@ static int dilithium_verify_ctx_hash(dilithium_key* key, const byte* ctx, ctx, (byte)ctxLen, oidMsgHash, oidMsgHashLen, mu, DILITHIUM_MU_SZ); } if (ret == 0) { - ret = dilithium_verify_mu(key, mu, sig, sigLen, res); + ret = dilithium_verify_with_mu(key, mu, sig, sigLen, res); } return ret; @@ -10132,6 +10146,30 @@ int wc_dilithium_make_key(dilithium_key* key, WC_RNG* rng) #endif } +#ifdef HAVE_FIPS + /* Pairwise Consistency Test (PCT) per FIPS 140-3 / ISO 19790:2012 + * Section 7.10.3.3 (TE10.35.02): sign with new sk, verify with pk. + * Runs on every key generation. */ + if (ret == 0) { + static const byte pct_msg[] = "wolfSSL ML-DSA PCT"; + byte pct_sig[DILITHIUM_MAX_SIG_SIZE]; + word32 pct_sigSz = DILITHIUM_MAX_SIG_SIZE; + int pct_res = 0; + + ret = wc_dilithium_sign_msg(pct_msg, sizeof(pct_msg), + pct_sig, &pct_sigSz, key, rng); + + if (ret == 0) + ret = wc_dilithium_verify_msg(pct_sig, pct_sigSz, + pct_msg, sizeof(pct_msg), &pct_res, key); + + if (ret == 0 && pct_res != 1) + ret = ML_DSA_PCT_E; + + ForceZero(pct_sig, sizeof(pct_sig)); + } +#endif /* HAVE_FIPS */ + return ret; } @@ -10160,6 +10198,9 @@ int wc_dilithium_make_key_from_seed(dilithium_key* key, const byte* seed) #endif } + /* Note: PCT is performed in wc_dilithium_make_key() which calls this + * function and has the RNG parameter needed for signing. */ + return ret; } #endif @@ -10461,6 +10502,53 @@ int wc_dilithium_sign_ctx_hash_with_seed(const byte* ctx, byte ctxLen, return ret; } + +/* Sign using the ML-DSA internal interface with a pre-computed mu value. + * + * This implements ML-DSA.Sign_internal from FIPS 204 Section 6.2. + * The caller provides mu directly (already computed from tr||M'), bypassing + * the external message hashing step. Used by ACVP internal interface tests. + * + * mu [in] Pre-computed mu value (64 bytes). + * muLen [in] Length of mu in bytes (must be 64). + * sig [out] Buffer to write signature into. + * sigLen [in/out] On in, size of buffer. + * On out, the length of the signature in bytes. + * key [in] Dilithium key to use when signing. + * seed [in] 32-byte random seed (rnd). + * returns BAD_FUNC_ARG when a parameter is NULL or muLen is not 64, + * BUFFER_E when sigLen is too small, + * 0 otherwise. + */ +int wc_dilithium_sign_mu_with_seed(const byte* mu, word32 muLen, + byte* sig, word32 *sigLen, dilithium_key* key, const byte* seed) +{ + int ret = 0; + + /* Validate parameters. */ + if ((mu == NULL) || (sig == NULL) || (sigLen == NULL) || (key == NULL) || + (seed == NULL)) { + ret = BAD_FUNC_ARG; + } + if ((ret == 0) && (muLen != DILITHIUM_MU_SZ)) { + ret = BAD_FUNC_ARG; + } + + if (ret == 0) { + #ifdef WOLFSSL_WC_DILITHIUM + /* Build [seed||mu] buffer and call internal sign function. */ + byte seedMu[DILITHIUM_RND_SZ + DILITHIUM_MU_SZ]; + XMEMCPY(seedMu, seed, DILITHIUM_RND_SZ); + XMEMCPY(seedMu + DILITHIUM_RND_SZ, mu, DILITHIUM_MU_SZ); + ret = dilithium_sign_with_seed_mu(key, seedMu, sig, sigLen); + #elif defined(HAVE_LIBOQS) + ret = NOT_COMPILED_IN; + (void)muLen; + #endif + } + + return ret; +} #endif /* !WOLFSSL_DILITHIUM_NO_SIGN */ #ifndef WOLFSSL_DILITHIUM_NO_VERIFY @@ -10636,6 +10724,47 @@ int wc_dilithium_verify_ctx_hash(const byte* sig, word32 sigLen, return ret; } + +/* Verify using the ML-DSA internal interface with a pre-computed mu value. + * + * This implements ML-DSA.Verify_internal from FIPS 204 Section 6.3. + * The caller provides mu directly (already computed from tr||M'), bypassing + * the external message hashing step. Used by ACVP internal interface tests. + * + * sig [in] Signature to verify. + * sigLen [in] Size of signature in bytes. + * mu [in] Pre-computed mu value (64 bytes). + * muLen [in] Length of mu in bytes (must be 64). + * res [out] *res is set to 1 on successful verification. + * key [in] Dilithium key to use to verify. + * returns BAD_FUNC_ARG when a parameter is NULL or muLen is not 64, + * 0 otherwise. + */ +int wc_dilithium_verify_mu(const byte* sig, word32 sigLen, const byte* mu, + word32 muLen, int* res, dilithium_key* key) +{ + int ret = 0; + + /* Validate parameters. */ + if ((key == NULL) || (sig == NULL) || (mu == NULL) || (res == NULL)) { + ret = BAD_FUNC_ARG; + } + if ((ret == 0) && (muLen != DILITHIUM_MU_SZ)) { + ret = BAD_FUNC_ARG; + } + + if (ret == 0) { + #ifdef WOLFSSL_WC_DILITHIUM + ret = dilithium_verify_with_mu(key, mu, sig, sigLen, res); + #elif defined(HAVE_LIBOQS) + ret = NOT_COMPILED_IN; + (void)sigLen; + (void)muLen; + #endif + } + + return ret; +} #endif /* WOLFSSL_DILITHIUM_NO_VERIFY */ #ifndef WC_NO_CONSTRUCTORS diff --git a/wolfcrypt/src/error.c b/wolfcrypt/src/error.c index 431a3c996c0..edc6a43e303 100644 --- a/wolfcrypt/src/error.c +++ b/wolfcrypt/src/error.c @@ -665,6 +665,30 @@ const char* wc_GetErrorString(int error) case ALREADY_E: return "Operation was redundant or preempted"; + case ML_KEM_KAT_FIPS_E: + return "wolfCrypt FIPS ML-KEM Known Answer Test Failure"; + + case ML_DSA_KAT_FIPS_E: + return "wolfCrypt FIPS ML-DSA Known Answer Test Failure"; + + case LMS_KAT_FIPS_E: + return "wolfCrypt FIPS LMS Known Answer Test Failure"; + + case XMSS_KAT_FIPS_E: + return "wolfCrypt FIPS XMSS Known Answer Test Failure"; + + case ML_KEM_PCT_E: + return "wolfcrypt ML-KEM Pairwise Consistency Test Failure"; + + case ML_DSA_PCT_E: + return "wolfcrypt ML-DSA Pairwise Consistency Test Failure"; + + case DRBG_SHA512_KAT_FIPS_E: + return "SHA-512 DRBG Known Answer Test check FIPS error"; + + case SLH_DSA_KAT_FIPS_E: + return "SLH-DSA Known Answer Test check FIPS error"; + case SEQ_OVERFLOW_E: return "Sequence counter would overflow"; diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 02fe3fa49bc..0d88776767c 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -5764,8 +5764,8 @@ void wolfSSL_EVP_init(void) break; #ifndef WOLFSSL_NOSHA512_224 case WC_HASH_TYPE_SHA512_224: - #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) + #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) ret = wc_Sha512_224Copy((wc_Sha512*)&src->hash.digest, (wc_Sha512*)&des->hash.digest); #else @@ -5775,8 +5775,8 @@ void wolfSSL_EVP_init(void) #endif /* !WOLFSSL_NOSHA512_224 */ #ifndef WOLFSSL_NOSHA512_256 case WC_HASH_TYPE_SHA512_256: - #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) + #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) ret = wc_Sha512_256Copy((wc_Sha512*)&src->hash.digest, (wc_Sha512*)&des->hash.digest); #else @@ -10702,16 +10702,16 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type) break; #ifndef WOLFSSL_NOSHA512_224 case WC_HASH_TYPE_SHA512_224: - #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) + #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) wc_Sha512_224Free((wc_Sha512*)&ctx->hash.digest); #endif break; #endif /* !WOLFSSL_NOSHA512_224 */ #ifndef WOLFSSL_NOSHA512_256 case WC_HASH_TYPE_SHA512_256: - #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) + #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) wc_Sha512_256Free((wc_Sha512*)&ctx->hash.digest); #endif break; @@ -10812,13 +10812,15 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type) ret = wolfSSL_SHA384_Init(&(ctx->hash.digest.sha384)); } else #endif - #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ + #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && \ defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224) if (XSTRCMP(md, WC_SN_sha512_224) == 0) { ret = wolfSSL_SHA512_224_Init(&(ctx->hash.digest.sha512)); } else #endif - #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ + #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && \ defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_256) if (XSTRCMP(md, WC_SN_sha512_256) == 0) { ret = wolfSSL_SHA512_256_Init(&(ctx->hash.digest.sha512)); @@ -10969,8 +10971,8 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type) #ifndef WOLFSSL_NOSHA512_224 case WC_HASH_TYPE_SHA512_224: - #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) + #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) ret = wolfSSL_SHA512_224_Update((WOLFSSL_SHA512_CTX*)&ctx->hash, data, (unsigned long)sz); #endif @@ -10979,8 +10981,8 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type) #ifndef WOLFSSL_NOSHA512_256 case WC_HASH_TYPE_SHA512_256: - #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) + #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) ret = wolfSSL_SHA512_256_Update((WOLFSSL_SHA512_CTX*)&ctx->hash, data, (unsigned long)sz); #endif /* WOLFSSL_SHA512 */ @@ -11123,8 +11125,8 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type) break; #ifndef WOLFSSL_NOSHA512_224 case WC_HASH_TYPE_SHA512_224: - #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) + #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) ret = wolfSSL_SHA512_224_Final(md, (WOLFSSL_SHA512_CTX*)&ctx->hash); if (s) *s = WC_SHA512_224_DIGEST_SIZE; #endif @@ -11132,8 +11134,8 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type) #endif /* !WOLFSSL_NOSHA512_224 */ #ifndef WOLFSSL_NOSHA512_256 case WC_HASH_TYPE_SHA512_256: - #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) + #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) ret = wolfSSL_SHA512_256_Final(md, (WOLFSSL_SHA512_CTX*)&ctx->hash); if (s) *s = WC_SHA512_256_DIGEST_SIZE; #endif diff --git a/wolfcrypt/src/ext_mlkem.c b/wolfcrypt/src/ext_mlkem.c index 91634f494f2..90ffbb1662d 100644 --- a/wolfcrypt/src/ext_mlkem.c +++ b/wolfcrypt/src/ext_mlkem.c @@ -22,6 +22,12 @@ #include #if defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_WC_MLKEM) + +#if FIPS_VERSION3_GE(2,0,0) + /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */ + #define FIPS_NO_WRAPPERS +#endif + #include #ifdef NO_INLINE diff --git a/wolfcrypt/src/hash.c b/wolfcrypt/src/hash.c index 61f7aacd632..cf345c8a28f 100644 --- a/wolfcrypt/src/hash.c +++ b/wolfcrypt/src/hash.c @@ -335,20 +335,20 @@ int wc_HashGetDigestSize(enum wc_HashType hash_type) break; #ifndef WOLFSSL_NOSHA512_224 case WC_HASH_TYPE_SHA512_224: -#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) +#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0) #if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224) dig_size = WC_SHA512_224_DIGEST_SIZE; #endif -#endif /* !HAVE_FIPS && !HAVE_SELFTEST */ +#endif break; #endif #ifndef WOLFSSL_NOSHA512_256 case WC_HASH_TYPE_SHA512_256: -#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) +#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0) #if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_256) dig_size = WC_SHA512_256_DIGEST_SIZE; #endif -#endif /* !HAVE_FIPS && !HAVE_SELFTEST */ +#endif break; #endif case WC_HASH_TYPE_MD5_SHA: /* Old TLS Specific */ @@ -390,13 +390,18 @@ int wc_HashGetDigestSize(enum wc_HashType hash_type) break; #endif - /* Not Supported */ #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128) case WC_HASH_TYPE_SHAKE128: + dig_size = 32; /* SHAKE-128: 256-bit output */ + break; #endif #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256) case WC_HASH_TYPE_SHAKE256: + dig_size = 64; /* SHAKE-256: 512-bit output */ + break; #endif + + /* Not Supported */ case WC_HASH_TYPE_NONE: default: dig_size = BAD_FUNC_ARG; @@ -454,20 +459,20 @@ int wc_HashGetBlockSize(enum wc_HashType hash_type) break; #ifndef WOLFSSL_NOSHA512_224 case WC_HASH_TYPE_SHA512_224: -#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) +#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0) #if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224) block_size = WC_SHA512_224_BLOCK_SIZE; #endif -#endif /* !HAVE_FIPS && !HAVE_SELFTEST */ +#endif break; #endif #ifndef WOLFSSL_NOSHA512_256 case WC_HASH_TYPE_SHA512_256: -#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) +#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0) #if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_256) block_size = WC_SHA512_256_BLOCK_SIZE; #endif -#endif /* !HAVE_FIPS && !HAVE_SELFTEST */ +#endif break; #endif case WC_HASH_TYPE_MD5_SHA: /* Old TLS Specific */ @@ -509,13 +514,18 @@ int wc_HashGetBlockSize(enum wc_HashType hash_type) break; #endif - /* Not Supported */ #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128) case WC_HASH_TYPE_SHAKE128: + block_size = WC_SHA3_128_BLOCK_SIZE; + break; #endif #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256) case WC_HASH_TYPE_SHAKE256: + block_size = WC_SHA3_256_BLOCK_SIZE; + break; #endif + + /* Not Supported */ case WC_HASH_TYPE_NONE: default: block_size = BAD_FUNC_ARG; @@ -581,20 +591,20 @@ int wc_Hash_ex(enum wc_HashType hash_type, const byte* data, break; #ifndef WOLFSSL_NOSHA512_224 case WC_HASH_TYPE_SHA512_224: -#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) +#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0) #if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224) ret = wc_Sha512_224Hash_ex(data, data_len, hash, heap, devId); #endif -#endif /* !HAVE_FIPS && !HAVE_SELFTEST */ +#endif break; #endif #ifndef WOLFSSL_NOSHA512_256 case WC_HASH_TYPE_SHA512_256: -#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) -#if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224) +#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0) +#if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_256) ret = wc_Sha512_256Hash_ex(data, data_len, hash, heap, devId); #endif -#endif /* !HAVE_FIPS && !HAVE_SELFTEST */ +#endif break; #endif case WC_HASH_TYPE_MD5_SHA: @@ -634,17 +644,40 @@ int wc_Hash_ex(enum wc_HashType hash_type, const byte* data, break; #endif - /* Not Supported */ - case WC_HASH_TYPE_MD2: - case WC_HASH_TYPE_MD4: - case WC_HASH_TYPE_BLAKE2B: - case WC_HASH_TYPE_BLAKE2S: #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128) case WC_HASH_TYPE_SHAKE128: + { + wc_Shake shake; + ret = wc_InitShake128(&shake, heap, devId); + if (ret == 0) { + ret = wc_Shake128_Update(&shake, data, data_len); + if (ret == 0) + ret = wc_Shake128_Final(&shake, hash, 32); + wc_Shake128_Free(&shake); + } + break; + } #endif #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256) case WC_HASH_TYPE_SHAKE256: + { + wc_Shake shake; + ret = wc_InitShake256(&shake, heap, devId); + if (ret == 0) { + ret = wc_Shake256_Update(&shake, data, data_len); + if (ret == 0) + ret = wc_Shake256_Final(&shake, hash, 64); + wc_Shake256_Free(&shake); + } + break; + } #endif + + /* Not Supported */ + case WC_HASH_TYPE_MD2: + case WC_HASH_TYPE_MD4: + case WC_HASH_TYPE_BLAKE2B: + case WC_HASH_TYPE_BLAKE2S: case WC_HASH_TYPE_NONE: default: ret = BAD_FUNC_ARG; @@ -746,20 +779,20 @@ int wc_HashInit_ex(wc_HashAlg* hash, enum wc_HashType type, void* heap, break; #ifndef WOLFSSL_NOSHA512_224 case WC_HASH_TYPE_SHA512_224: -#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) +#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0) #if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224) ret = wc_InitSha512_224_ex(&hash->alg.sha512, heap, devId); #endif -#endif /* !HAVE_FIPS && !HAVE_SELFTEST */ +#endif break; #endif #ifndef WOLFSSL_NOSHA512_256 case WC_HASH_TYPE_SHA512_256: -#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) +#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0) #if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_256) ret = wc_InitSha512_256_ex(&hash->alg.sha512, heap, devId); #endif -#endif /* !HAVE_FIPS && !HAVE_SELFTEST */ +#endif break; #endif case WC_HASH_TYPE_SHA3_224: @@ -789,18 +822,23 @@ int wc_HashInit_ex(wc_HashAlg* hash, enum wc_HashType type, void* heap, break; #endif - /* not supported */ - case WC_HASH_TYPE_MD5_SHA: - case WC_HASH_TYPE_MD2: - case WC_HASH_TYPE_MD4: - case WC_HASH_TYPE_BLAKE2B: - case WC_HASH_TYPE_BLAKE2S: #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128) case WC_HASH_TYPE_SHAKE128: + ret = wc_InitShake128(&hash->alg.sha3, heap, devId); + break; #endif #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256) case WC_HASH_TYPE_SHAKE256: + ret = wc_InitShake256(&hash->alg.sha3, heap, devId); + break; #endif + + /* not supported */ + case WC_HASH_TYPE_MD5_SHA: + case WC_HASH_TYPE_MD2: + case WC_HASH_TYPE_MD4: + case WC_HASH_TYPE_BLAKE2B: + case WC_HASH_TYPE_BLAKE2S: case WC_HASH_TYPE_NONE: default: ret = BAD_FUNC_ARG; @@ -864,20 +902,20 @@ int wc_HashUpdate(wc_HashAlg* hash, enum wc_HashType type, const byte* data, break; #ifndef WOLFSSL_NOSHA512_224 case WC_HASH_TYPE_SHA512_224: -#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) +#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0) #if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224) ret = wc_Sha512_224Update(&hash->alg.sha512, data, dataSz); #endif -#endif /* !HAVE_FIPS && !HAVE_SELFTEST */ +#endif break; #endif #ifndef WOLFSSL_NOSHA512_256 case WC_HASH_TYPE_SHA512_256: -#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) +#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0) #if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_256) ret = wc_Sha512_256Update(&hash->alg.sha512, data, dataSz); #endif -#endif /* !HAVE_FIPS && !HAVE_SELFTEST */ +#endif break; #endif case WC_HASH_TYPE_SHA3_224: @@ -907,18 +945,23 @@ int wc_HashUpdate(wc_HashAlg* hash, enum wc_HashType type, const byte* data, break; #endif - /* not supported */ - case WC_HASH_TYPE_MD5_SHA: - case WC_HASH_TYPE_MD2: - case WC_HASH_TYPE_MD4: - case WC_HASH_TYPE_BLAKE2B: - case WC_HASH_TYPE_BLAKE2S: #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128) case WC_HASH_TYPE_SHAKE128: + ret = wc_Shake128_Update(&hash->alg.sha3, data, dataSz); + break; #endif #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256) case WC_HASH_TYPE_SHAKE256: + ret = wc_Shake256_Update(&hash->alg.sha3, data, dataSz); + break; #endif + + /* not supported */ + case WC_HASH_TYPE_MD5_SHA: + case WC_HASH_TYPE_MD2: + case WC_HASH_TYPE_MD4: + case WC_HASH_TYPE_BLAKE2B: + case WC_HASH_TYPE_BLAKE2S: case WC_HASH_TYPE_NONE: default: ret = BAD_FUNC_ARG; @@ -974,20 +1017,20 @@ int wc_HashFinal(wc_HashAlg* hash, enum wc_HashType type, byte* out) break; #ifndef WOLFSSL_NOSHA512_224 case WC_HASH_TYPE_SHA512_224: -#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) +#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0) #if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224) ret = wc_Sha512_224Final(&hash->alg.sha512, out); #endif -#endif /* !HAVE_FIPS && !HAVE_SELFTEST */ +#endif break; #endif #ifndef WOLFSSL_NOSHA512_256 case WC_HASH_TYPE_SHA512_256: -#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) +#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0) #if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_256) ret = wc_Sha512_256Final(&hash->alg.sha512, out); #endif -#endif /* !HAVE_FIPS && !HAVE_SELFTEST */ +#endif break; #endif case WC_HASH_TYPE_SHA3_224: @@ -1017,18 +1060,23 @@ int wc_HashFinal(wc_HashAlg* hash, enum wc_HashType type, byte* out) break; #endif - /* not supported */ - case WC_HASH_TYPE_MD5_SHA: - case WC_HASH_TYPE_MD2: - case WC_HASH_TYPE_MD4: - case WC_HASH_TYPE_BLAKE2B: - case WC_HASH_TYPE_BLAKE2S: #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128) case WC_HASH_TYPE_SHAKE128: + ret = wc_Shake128_Final(&hash->alg.sha3, out, 32); + break; #endif #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256) case WC_HASH_TYPE_SHAKE256: + ret = wc_Shake256_Final(&hash->alg.sha3, out, 64); + break; #endif + + /* not supported */ + case WC_HASH_TYPE_MD5_SHA: + case WC_HASH_TYPE_MD2: + case WC_HASH_TYPE_MD4: + case WC_HASH_TYPE_BLAKE2B: + case WC_HASH_TYPE_BLAKE2S: case WC_HASH_TYPE_NONE: default: ret = BAD_FUNC_ARG; @@ -1090,22 +1138,22 @@ int wc_HashFree(wc_HashAlg* hash, enum wc_HashType type) break; #ifndef WOLFSSL_NOSHA512_224 case WC_HASH_TYPE_SHA512_224: -#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) +#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0) #if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224) wc_Sha512_224Free(&hash->alg.sha512); ret = 0; #endif -#endif /* !HAVE_FIPS && !HAVE_SELFTEST */ +#endif break; #endif #ifndef WOLFSSL_NOSHA512_256 case WC_HASH_TYPE_SHA512_256: -#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) +#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0) #if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_256) wc_Sha512_256Free(&hash->alg.sha512); ret = 0; #endif -#endif /* !HAVE_FIPS && !HAVE_SELFTEST */ +#endif break; #endif case WC_HASH_TYPE_SHA3_224: @@ -1140,18 +1188,25 @@ int wc_HashFree(wc_HashAlg* hash, enum wc_HashType type) break; #endif - /* not supported */ - case WC_HASH_TYPE_MD5_SHA: - case WC_HASH_TYPE_MD2: - case WC_HASH_TYPE_MD4: - case WC_HASH_TYPE_BLAKE2B: - case WC_HASH_TYPE_BLAKE2S: #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128) case WC_HASH_TYPE_SHAKE128: + wc_Shake128_Free(&hash->alg.sha3); + ret = 0; + break; #endif #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256) case WC_HASH_TYPE_SHAKE256: + wc_Shake256_Free(&hash->alg.sha3); + ret = 0; + break; #endif + + /* not supported */ + case WC_HASH_TYPE_MD5_SHA: + case WC_HASH_TYPE_MD2: + case WC_HASH_TYPE_MD4: + case WC_HASH_TYPE_BLAKE2B: + case WC_HASH_TYPE_BLAKE2S: case WC_HASH_TYPE_NONE: default: ret = BAD_FUNC_ARG; @@ -1210,6 +1265,12 @@ int wc_HashSetFlags(wc_HashAlg* hash, enum wc_HashType type, word32 flags) case WC_HASH_TYPE_SHA3_256: case WC_HASH_TYPE_SHA3_384: case WC_HASH_TYPE_SHA3_512: + #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128) + case WC_HASH_TYPE_SHAKE128: + #endif + #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256) + case WC_HASH_TYPE_SHAKE256: + #endif #ifdef WOLFSSL_SHA3 ret = wc_Sha3_SetFlags(&hash->alg.sha3, flags); #endif @@ -1228,12 +1289,6 @@ int wc_HashSetFlags(wc_HashAlg* hash, enum wc_HashType type, word32 flags) case WC_HASH_TYPE_BLAKE2B: case WC_HASH_TYPE_BLAKE2S: case WC_HASH_TYPE_NONE: - #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128) - case WC_HASH_TYPE_SHAKE128: - #endif - #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256) - case WC_HASH_TYPE_SHAKE256: - #endif default: ret = BAD_FUNC_ARG; }; @@ -1289,6 +1344,12 @@ int wc_HashGetFlags(wc_HashAlg* hash, enum wc_HashType type, word32* flags) case WC_HASH_TYPE_SHA3_256: case WC_HASH_TYPE_SHA3_384: case WC_HASH_TYPE_SHA3_512: + #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128) + case WC_HASH_TYPE_SHAKE128: + #endif + #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256) + case WC_HASH_TYPE_SHAKE256: + #endif #ifdef WOLFSSL_SHA3 ret = wc_Sha3_GetFlags(&hash->alg.sha3, flags); #endif @@ -1306,12 +1367,6 @@ int wc_HashGetFlags(wc_HashAlg* hash, enum wc_HashType type, word32* flags) case WC_HASH_TYPE_MD4: case WC_HASH_TYPE_BLAKE2B: case WC_HASH_TYPE_BLAKE2S: - #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128) - case WC_HASH_TYPE_SHAKE128: - #endif - #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256) - case WC_HASH_TYPE_SHAKE256: - #endif case WC_HASH_TYPE_NONE: default: ret = BAD_FUNC_ARG; @@ -1536,7 +1591,7 @@ int wc_HashGetFlags(wc_HashAlg* hash, enum wc_HashType type, word32* flags) #endif return wc_Sha512Hash_ex(data, len, hash, NULL, devId); } -#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) +#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0) #ifndef WOLFSSL_NOSHA512_224 int wc_Sha512_224Hash_ex(const byte* data, word32 len, byte* hash, void* heap, int devId) @@ -1576,9 +1631,9 @@ int wc_HashGetFlags(wc_HashAlg* hash, enum wc_HashType type, word32* flags) return wc_Sha512_224Hash_ex(data, len, hash, NULL, devId); } #endif /* !WOLFSSL_NOSHA512_224 */ -#endif /* !HAVE_FIPS && !HAVE_SELFTEST */ +#endif /* !HAVE_FIPS || FIPS v7+ */ -#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) +#if !defined(HAVE_SELFTEST) || !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0) #ifndef WOLFSSL_NOSHA512_256 int wc_Sha512_256Hash_ex(const byte* data, word32 len, byte* hash, void* heap, int devId) @@ -1618,7 +1673,7 @@ int wc_HashGetFlags(wc_HashAlg* hash, enum wc_HashType type, word32* flags) return wc_Sha512_256Hash_ex(data, len, hash, NULL, devId); } #endif /* !WOLFSSL_NOSHA512_256 */ -#endif /* !HAVE_FIPS && !HAVE_SELFTEST */ +#endif /* !HAVE_FIPS || FIPS v7+ */ #endif /* WOLFSSL_SHA512 */ diff --git a/wolfcrypt/src/hmac.c b/wolfcrypt/src/hmac.c index 4b3cfd15890..5489a490aa4 100644 --- a/wolfcrypt/src/hmac.c +++ b/wolfcrypt/src/hmac.c @@ -87,6 +87,12 @@ int wc_HmacSizeByType(int type) if (!(type == WC_MD5 || type == WC_SHA || #ifdef WOLFSSL_SM3 type == WC_SM3 || + #endif + #ifndef WOLFSSL_NOSHA512_224 + type == WC_SHA512_224 || + #endif + #ifndef WOLFSSL_NOSHA512_256 + type == WC_SHA512_256 || #endif type == WC_SHA224 || type == WC_SHA256 || type == WC_SHA384 || type == WC_SHA512 || @@ -129,6 +135,16 @@ int wc_HmacSizeByType(int type) case WC_SHA512: ret = WC_SHA512_DIGEST_SIZE; break; + #ifndef WOLFSSL_NOSHA512_224 + case WC_SHA512_224: + ret = WC_SHA512_224_DIGEST_SIZE; + break; + #endif + #ifndef WOLFSSL_NOSHA512_256 + case WC_SHA512_256: + ret = WC_SHA512_256_DIGEST_SIZE; + break; + #endif #endif /* WOLFSSL_SHA512 */ #ifdef WOLFSSL_SHA3 @@ -201,6 +217,16 @@ static int HmacKeyInitHash(wc_HmacHash* hash, int type, void* heap, int devId) case WC_SHA512: ret = wc_InitSha512_ex(&hash->sha512, heap, devId); break; + #ifndef WOLFSSL_NOSHA512_224 + case WC_SHA512_224: + ret = wc_InitSha512_224_ex(&hash->sha512, heap, devId); + break; + #endif + #ifndef WOLFSSL_NOSHA512_256 + case WC_SHA512_256: + ret = wc_InitSha512_256_ex(&hash->sha512, heap, devId); + break; + #endif #endif /* WOLFSSL_SHA512 */ #ifdef WOLFSSL_SHA3 @@ -300,6 +326,16 @@ static int HmacKeyCopyHash(byte macType, wc_HmacHash* src, wc_HmacHash* dst) case WC_SHA512: ret = wc_Sha512Copy(&src->sha512, &dst->sha512); break; + #ifndef WOLFSSL_NOSHA512_224 + case WC_SHA512_224: + ret = wc_Sha512_224Copy(&src->sha512, &dst->sha512); + break; + #endif + #ifndef WOLFSSL_NOSHA512_256 + case WC_SHA512_256: + ret = wc_Sha512_256Copy(&src->sha512, &dst->sha512); + break; + #endif #endif /* WOLFSSL_SHA512 */ #ifdef WOLFSSL_SHA3 @@ -395,6 +431,18 @@ static int HmacKeyHashUpdate(byte macType, wc_HmacHash* hash, byte* pad) case WC_SHA512: ret = wc_Sha512Update(&hash->sha512, pad, WC_SHA512_BLOCK_SIZE); break; + #ifndef WOLFSSL_NOSHA512_224 + case WC_SHA512_224: + ret = wc_Sha512_224Update(&hash->sha512, pad, + WC_SHA512_224_BLOCK_SIZE); + break; + #endif + #ifndef WOLFSSL_NOSHA512_256 + case WC_SHA512_256: + ret = wc_Sha512_256Update(&hash->sha512, pad, + WC_SHA512_256_BLOCK_SIZE); + break; + #endif #endif /* WOLFSSL_SHA512 */ #ifdef WOLFSSL_SHA3 @@ -475,6 +523,12 @@ int wc_HmacSetKey_ex(Hmac* hmac, int type, const byte* key, word32 length, !(type == WC_MD5 || type == WC_SHA || #ifdef WOLFSSL_SM3 type == WC_SM3 || + #endif + #ifndef WOLFSSL_NOSHA512_224 + type == WC_SHA512_224 || + #endif + #ifndef WOLFSSL_NOSHA512_256 + type == WC_SHA512_256 || #endif type == WC_SHA224 || type == WC_SHA256 || type == WC_SHA384 || type == WC_SHA512 || @@ -731,6 +785,46 @@ int wc_HmacSetKey_ex(Hmac* hmac, int type, const byte* key, word32 length, length = WC_SHA512_DIGEST_SIZE; } break; + #ifndef WOLFSSL_NOSHA512_224 + case WC_SHA512_224: + hmac_block_size = WC_SHA512_224_BLOCK_SIZE; + if (length <= WC_SHA512_224_BLOCK_SIZE) { + if (key != NULL) { + XMEMCPY(ip, key, length); + } + } + else { + ret = wc_Sha512_224Update(&hmac->hash.sha512, key, length); + if (ret != 0) + break; + ret = wc_Sha512_224Final(&hmac->hash.sha512, ip); + if (ret != 0) + break; + + length = WC_SHA512_224_DIGEST_SIZE; + } + break; + #endif + #ifndef WOLFSSL_NOSHA512_256 + case WC_SHA512_256: + hmac_block_size = WC_SHA512_256_BLOCK_SIZE; + if (length <= WC_SHA512_256_BLOCK_SIZE) { + if (key != NULL) { + XMEMCPY(ip, key, length); + } + } + else { + ret = wc_Sha512_256Update(&hmac->hash.sha512, key, length); + if (ret != 0) + break; + ret = wc_Sha512_256Final(&hmac->hash.sha512, ip); + if (ret != 0) + break; + + length = WC_SHA512_256_DIGEST_SIZE; + } + break; + #endif #endif /* WOLFSSL_SHA512 */ #ifdef WOLFSSL_SHA3 @@ -983,6 +1077,16 @@ int wc_HmacUpdate(Hmac* hmac, const byte* msg, word32 length) case WC_SHA512: ret = wc_Sha512Update(&hmac->hash.sha512, msg, length); break; + #ifndef WOLFSSL_NOSHA512_224 + case WC_SHA512_224: + ret = wc_Sha512_224Update(&hmac->hash.sha512, msg, length); + break; + #endif + #ifndef WOLFSSL_NOSHA512_256 + case WC_SHA512_256: + ret = wc_Sha512_256Update(&hmac->hash.sha512, msg, length); + break; + #endif #endif /* WOLFSSL_SHA512 */ #ifdef WOLFSSL_SHA3 @@ -1210,6 +1314,48 @@ int wc_HmacFinal(Hmac* hmac, byte* hash) break; ret = wc_Sha512Final(&hmac->hash.sha512, hash); break; + #ifndef WOLFSSL_NOSHA512_224 + case WC_SHA512_224: + ret = wc_Sha512_224Final(&hmac->hash.sha512, + (byte*)hmac->innerHash); + if (ret != 0) + break; + #ifndef WOLFSSL_HMAC_COPY_HASH + ret = wc_Sha512_224Update(&hmac->hash.sha512, (byte*)hmac->opad, + WC_SHA512_224_BLOCK_SIZE); + #else + ret = HmacKeyCopyHash(WC_SHA512_224, &hmac->o_hash, &hmac->hash); + #endif + if (ret != 0) + break; + ret = wc_Sha512_224Update(&hmac->hash.sha512, + (byte*)hmac->innerHash, WC_SHA512_224_DIGEST_SIZE); + if (ret != 0) + break; + ret = wc_Sha512_224Final(&hmac->hash.sha512, hash); + break; + #endif + #ifndef WOLFSSL_NOSHA512_256 + case WC_SHA512_256: + ret = wc_Sha512_256Final(&hmac->hash.sha512, + (byte*)hmac->innerHash); + if (ret != 0) + break; + #ifndef WOLFSSL_HMAC_COPY_HASH + ret = wc_Sha512_256Update(&hmac->hash.sha512, (byte*)hmac->opad, + WC_SHA512_256_BLOCK_SIZE); + #else + ret = HmacKeyCopyHash(WC_SHA512_256, &hmac->o_hash, &hmac->hash); + #endif + if (ret != 0) + break; + ret = wc_Sha512_256Update(&hmac->hash.sha512, + (byte*)hmac->innerHash, WC_SHA512_256_DIGEST_SIZE); + if (ret != 0) + break; + ret = wc_Sha512_256Final(&hmac->hash.sha512, hash); + break; + #endif #endif /* WOLFSSL_SHA512 */ #ifdef WOLFSSL_SHA3 @@ -1489,6 +1635,24 @@ void wc_HmacFree(Hmac* hmac) wc_Sha512Free(&hmac->o_hash.sha512); #endif break; + #ifndef WOLFSSL_NOSHA512_224 + case WC_SHA512_224: + wc_Sha512_224Free(&hmac->hash.sha512); + #ifdef WOLFSSL_HMAC_COPY_HASH + wc_Sha512_224Free(&hmac->i_hash.sha512); + wc_Sha512_224Free(&hmac->o_hash.sha512); + #endif + break; + #endif + #ifndef WOLFSSL_NOSHA512_256 + case WC_SHA512_256: + wc_Sha512_256Free(&hmac->hash.sha512); + #ifdef WOLFSSL_HMAC_COPY_HASH + wc_Sha512_256Free(&hmac->i_hash.sha512); + wc_Sha512_256Free(&hmac->o_hash.sha512); + #endif + break; + #endif #endif /* WOLFSSL_SHA512 */ #ifdef WOLFSSL_SHA3 diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index 9fa318c7608..c75f89a5060 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -133,7 +133,12 @@ This library contains implementation for the random number generator. #ifndef WC_NO_RNG /* if not FIPS and RNG is disabled then do not compile */ -#include +#ifndef NO_SHA256 + #include +#endif +#ifdef WOLFSSL_DRBG_SHA512 + #include +#endif #ifdef WOLF_CRYPTO_CB #include @@ -332,16 +337,60 @@ enum { drbgInitV = 4 }; +#ifndef NO_SHA256 typedef struct DRBG_internal DRBG_internal; +#endif + +#ifdef WOLFSSL_DRBG_SHA512 +typedef struct DRBG_SHA512_internal DRBG_SHA512_internal; + +static int Hash512_DRBG_Reseed(DRBG_SHA512_internal* drbg, const byte* seed, + word32 seedSz, + const byte* additional, word32 additionalSz); +static int Hash512_DRBG_Generate(DRBG_SHA512_internal* drbg, byte* out, + word32 outSz, + const byte* additional, word32 additionalSz); +static int Hash512_DRBG_Instantiate(DRBG_SHA512_internal* drbg, + const byte* seed, word32 seedSz, + const byte* nonce, word32 nonceSz, + const byte* perso, word32 persoSz, + void* heap, int devId); +static int Hash512_DRBG_Uninstantiate(DRBG_SHA512_internal* drbg); +#endif + +/* Runtime DRBG disable state */ +#ifndef NO_SHA256 +#ifdef WOLFSSL_NO_SHA256_DRBG +static int sha256DrbgDisabled = 1; +#else +static int sha256DrbgDisabled = 0; +#endif +#endif +#ifdef WOLFSSL_DRBG_SHA512 +static int sha512DrbgDisabled = 0; +#endif static int wc_RNG_HealthTestLocal(WC_RNG* rng, int reseed, void* heap, int devId); +#ifdef WOLFSSL_DRBG_SHA512 +static int wc_RNG_HealthTest_SHA512_ex_internal(DRBG_SHA512_internal* drbg, + int reseed, const byte* nonce, word32 nonceSz, + const byte* perso, word32 persoSz, + const byte* seedA, word32 seedASz, + const byte* seedB, word32 seedBSz, + const byte* additionalA, word32 additionalASz, + const byte* additionalB, word32 additionalBSz, + byte* output, word32 outputSz, + void* heap, int devId); +#endif + /* Hash Derivation Function */ /* Returns: DRBG_SUCCESS or DRBG_FAILURE */ static int Hash_df(DRBG_internal* drbg, byte* out, word32 outSz, byte type, const byte* inA, word32 inASz, - const byte* inB, word32 inBSz) + const byte* inB, word32 inBSz, + const byte* inC, word32 inCSz) { int ret = DRBG_FAILURE; byte ctr; @@ -406,6 +455,10 @@ static int Hash_df(DRBG_internal* drbg, byte* out, word32 outSz, byte type, if (inB != NULL && inBSz > 0) ret = wc_Sha256Update(sha, inB, inBSz); } + if (ret == 0) { + if (inC != NULL && inCSz > 0) + ret = wc_Sha256Update(sha, inC, inCSz); + } if (ret == 0) ret = wc_Sha256Final(sha, digest); @@ -440,7 +493,8 @@ static int Hash_df(DRBG_internal* drbg, byte* out, word32 outSz, byte type, } /* Returns: DRBG_SUCCESS or DRBG_FAILURE */ -static int Hash_DRBG_Reseed(DRBG_internal* drbg, const byte* seed, word32 seedSz) +static int Hash_DRBG_Reseed(DRBG_internal* drbg, const byte* seed, word32 seedSz, + const byte* additional, word32 additionalSz) { int ret; WC_DECLARE_VAR(newV, byte, DRBG_SEED_LEN, 0); @@ -458,13 +512,14 @@ static int Hash_DRBG_Reseed(DRBG_internal* drbg, const byte* seed, word32 seedSz XMEMSET(newV, 0, DRBG_SEED_LEN); ret = Hash_df(drbg, newV, DRBG_SEED_LEN, drbgReseed, - drbg->V, sizeof(drbg->V), seed, seedSz); + drbg->V, sizeof(drbg->V), seed, seedSz, + additional, additionalSz); if (ret == DRBG_SUCCESS) { XMEMCPY(drbg->V, newV, sizeof(drbg->V)); ForceZero(newV, DRBG_SEED_LEN); ret = Hash_df(drbg, drbg->C, sizeof(drbg->C), drbgInitC, drbg->V, - sizeof(drbg->V), NULL, 0); + sizeof(drbg->V), NULL, 0, NULL, 0); } if (ret == DRBG_SUCCESS) { drbg->reseedCtr = 1; @@ -490,17 +545,31 @@ int wc_RNG_DRBG_Reseed(WC_RNG* rng, const byte* seed, word32 seedSz) return BAD_FUNC_ARG; } - if (rng->drbg == NULL) { - #if defined(HAVE_INTEL_RDSEED) || defined(HAVE_INTEL_RDRAND) - if (IS_INTEL_RDRAND(intel_flags)) { - /* using RDRAND not DRBG, so return success */ - return 0; - } - return BAD_FUNC_ARG; - #endif +#ifdef HAVE_INTEL_RDRAND + if (IS_INTEL_RDRAND(intel_flags)) { + /* using RDRAND not DRBG, so return success */ + return 0; } +#endif - return Hash_DRBG_Reseed((DRBG_internal *)rng->drbg, seed, seedSz); +#ifndef NO_SHA256 + if (rng->drbgType == WC_DRBG_SHA256) { + if (rng->drbg == NULL) + return BAD_FUNC_ARG; + return Hash_DRBG_Reseed((DRBG_internal *)rng->drbg, seed, seedSz, + NULL, 0); + } +#endif +#ifdef WOLFSSL_DRBG_SHA512 + if (rng->drbgType == WC_DRBG_SHA512) { + if (rng->drbg512 == NULL) + return BAD_FUNC_ARG; + return Hash512_DRBG_Reseed((DRBG_SHA512_internal *)rng->drbg512, + seed, seedSz, NULL, 0); + } +#endif + + return BAD_FUNC_ARG; } static WC_INLINE void array_add_one(byte* data, word32 dataSz) @@ -638,7 +707,8 @@ static WC_INLINE void array_add(byte* d, word32 dLen, const byte* s, word32 sLen } /* Returns: DRBG_SUCCESS, DRBG_NEED_RESEED, or DRBG_FAILURE */ -static int Hash_DRBG_Generate(DRBG_internal* drbg, byte* out, word32 outSz) +static int Hash_DRBG_Generate(DRBG_internal* drbg, byte* out, word32 outSz, + const byte* additional, word32 additionalSz) { int ret; #ifdef WOLFSSL_SMALL_STACK_CACHE @@ -680,6 +750,49 @@ static int Hash_DRBG_Generate(DRBG_internal* drbg, byte* out, word32 outSz) type = drbgGenerateH; reseedCtr = drbg->reseedCtr; + /* SP 800-90A 10.1.1.4 step 2: if additional_input != Null, + * w = Hash(0x02 || V || additional_input), V = (V + w) mod 2^seedlen */ + if (additional != NULL && additionalSz > 0) { + byte addType = drbgGenerateW; +#ifndef WOLFSSL_SMALL_STACK_CACHE + #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) + ret = wc_InitSha256_ex(sha, drbg->heap, drbg->devId); + #else + ret = wc_InitSha256(sha); + #endif + if (ret != 0) { + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE) + XFREE(digest, drbg->heap, DYNAMIC_TYPE_DIGEST); + #endif + return DRBG_FAILURE; + } +#else + ret = 0; +#endif + if (ret == 0) + ret = wc_Sha256Update(sha, &addType, sizeof(addType)); + if (ret == 0) + ret = wc_Sha256Update(sha, drbg->V, sizeof(drbg->V)); + if (ret == 0) + ret = wc_Sha256Update(sha, additional, additionalSz); + if (ret == 0) + ret = wc_Sha256Final(sha, digest); +#ifndef WOLFSSL_SMALL_STACK_CACHE + wc_Sha256Free(sha); +#endif + if (ret == 0) { + array_add(drbg->V, sizeof(drbg->V), digest, + WC_SHA256_DIGEST_SIZE); + } + else { + ForceZero(digest, WC_SHA256_DIGEST_SIZE); + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE) + XFREE(digest, drbg->heap, DYNAMIC_TYPE_DIGEST); + #endif + return DRBG_FAILURE; + } + } + ret = Hash_gen(drbg, out, outSz, drbg->V); if (ret == DRBG_SUCCESS) { #ifndef WOLFSSL_SMALL_STACK_CACHE @@ -735,15 +848,18 @@ static int Hash_DRBG_Generate(DRBG_internal* drbg, byte* out, word32 outSz) /* Returns: DRBG_SUCCESS or DRBG_FAILURE */ static int Hash_DRBG_Init(DRBG_internal* drbg, const byte* seed, word32 seedSz, - const byte* nonce, word32 nonceSz) + const byte* nonce, word32 nonceSz, + const byte* perso, word32 persoSz) { if (seed == NULL) return DRBG_FAILURE; if (Hash_df(drbg, drbg->V, sizeof(drbg->V), drbgInitV, seed, seedSz, - nonce, nonceSz) == DRBG_SUCCESS && + nonce, nonceSz, + perso, persoSz) == DRBG_SUCCESS && Hash_df(drbg, drbg->C, sizeof(drbg->C), drbgInitC, drbg->V, - sizeof(drbg->V), NULL, 0) == DRBG_SUCCESS) { + sizeof(drbg->V), NULL, 0, + NULL, 0) == DRBG_SUCCESS) { drbg->reseedCtr = 1; return DRBG_SUCCESS; @@ -754,9 +870,10 @@ static int Hash_DRBG_Init(DRBG_internal* drbg, const byte* seed, word32 seedSz, } /* Returns: DRBG_SUCCESS or DRBG_FAILURE */ -static int Hash_DRBG_Instantiate(DRBG_internal* drbg, const byte* seed, word32 seedSz, - const byte* nonce, word32 nonceSz, - void* heap, int devId) +static int Hash_DRBG_Instantiate(DRBG_internal* drbg, const byte* seed, + word32 seedSz, const byte* nonce, + word32 nonceSz, const byte* perso, + word32 persoSz, void* heap, int devId) { int ret = DRBG_FAILURE; @@ -779,7 +896,8 @@ static int Hash_DRBG_Instantiate(DRBG_internal* drbg, const byte* seed, word32 s #endif if (seed != NULL) - ret = Hash_DRBG_Init(drbg, seed, seedSz, nonce, nonceSz); + ret = Hash_DRBG_Init(drbg, seed, seedSz, nonce, nonceSz, + perso, persoSz); return ret; } @@ -803,6 +921,443 @@ static int Hash_DRBG_Uninstantiate(DRBG_internal* drbg) return (compareSum == 0) ? DRBG_SUCCESS : DRBG_FAILURE; } +/* ====================================================================== */ +/* SHA-512 Hash_DRBG (SP 800-90A Rev 1, Table 2) */ +/* */ +/* Internal state (V, C): seedlen = 888 bits = 111 bytes each */ +/* Output block length: 512 bits = 64 bytes (WC_SHA512_DIGEST_SIZE) */ +/* Security strength: 256 bits */ +/* */ +/* NOTE: The raw entropy seed gathered at instantiation / reseed is */ +/* WC_DRBG_SEED_SZ (1024 bits in FIPS builds), NOT seedlen. We overseed */ +/* to tolerate weak entropy sources. Hash_df then compresses the seed */ +/* material down to the 888-bit V and derives C from V. See random.h. */ +/* ====================================================================== */ +#ifdef WOLFSSL_DRBG_SHA512 + +#define OUTPUT_BLOCK_LEN_SHA512 (WC_SHA512_DIGEST_SIZE) /* 64 bytes */ + +/* Hash Derivation Function using SHA-512 */ +/* Returns: DRBG_SUCCESS or DRBG_FAILURE */ +static int Hash512_df(DRBG_SHA512_internal* drbg, byte* out, word32 outSz, + byte type, + const byte* inA, word32 inASz, + const byte* inB, word32 inBSz, + const byte* inC, word32 inCSz) +{ + int ret = DRBG_FAILURE; + byte ctr; + word32 i; + word32 len; + word32 bits = (outSz * 8); +#ifdef WOLFSSL_SMALL_STACK_CACHE + wc_Sha512* sha = &drbg->sha512; +#else + wc_Sha512 sha[1]; +#endif +#if defined(WOLFSSL_SMALL_STACK_CACHE) + byte* digest = drbg->digest_scratch; +#elif defined(WOLFSSL_SMALL_STACK) + byte* digest; +#else + byte digest[WC_SHA512_DIGEST_SIZE]; +#endif + + if (drbg == NULL) { + return DRBG_FAILURE; + } + +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE) + digest = (byte*)XMALLOC(WC_SHA512_DIGEST_SIZE, drbg->heap, + DYNAMIC_TYPE_DIGEST); + if (digest == NULL) + return DRBG_FAILURE; +#endif + +#ifdef LITTLE_ENDIAN_ORDER + bits = ByteReverseWord32(bits); +#endif + len = (outSz / OUTPUT_BLOCK_LEN_SHA512) + + ((outSz % OUTPUT_BLOCK_LEN_SHA512) ? 1 : 0); + + ctr = 1; + for (i = 0; i < len; i++) { +#ifndef WOLFSSL_SMALL_STACK_CACHE + #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) + ret = wc_InitSha512_ex(sha, drbg->heap, drbg->devId); + #else + ret = wc_InitSha512(sha); + #endif + if (ret != 0) + break; +#endif + ret = wc_Sha512Update(sha, &ctr, sizeof(ctr)); + if (ret == 0) { + ctr++; + ret = wc_Sha512Update(sha, (byte*)&bits, sizeof(bits)); + } + + if (ret == 0) { + /* churning V is the only string that doesn't have the type added */ + if (type != drbgInitV) + ret = wc_Sha512Update(sha, &type, sizeof(type)); + } + if (ret == 0) + ret = wc_Sha512Update(sha, inA, inASz); + if (ret == 0) { + if (inB != NULL && inBSz > 0) + ret = wc_Sha512Update(sha, inB, inBSz); + } + if (ret == 0) { + if (inC != NULL && inCSz > 0) + ret = wc_Sha512Update(sha, inC, inCSz); + } + if (ret == 0) + ret = wc_Sha512Final(sha, digest); + +#ifndef WOLFSSL_SMALL_STACK_CACHE + wc_Sha512Free(sha); +#endif + if (ret == 0) { + if (outSz > OUTPUT_BLOCK_LEN_SHA512) { + XMEMCPY(out, digest, OUTPUT_BLOCK_LEN_SHA512); + outSz -= OUTPUT_BLOCK_LEN_SHA512; + out += OUTPUT_BLOCK_LEN_SHA512; + } + else { + XMEMCPY(out, digest, outSz); + } + } + } + + ForceZero(digest, WC_SHA512_DIGEST_SIZE); + +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE) + XFREE(digest, drbg->heap, DYNAMIC_TYPE_DIGEST); +#endif + + return (ret == 0) ? DRBG_SUCCESS : DRBG_FAILURE; +} + +/* Returns: DRBG_SUCCESS or DRBG_FAILURE */ +static int Hash512_DRBG_Reseed(DRBG_SHA512_internal* drbg, const byte* seed, + word32 seedSz, + const byte* additional, word32 additionalSz) +{ + int ret; + WC_DECLARE_VAR(newV, byte, DRBG_SHA512_SEED_LEN, 0); + + if (drbg == NULL) { + return DRBG_FAILURE; + } + +#ifdef WOLFSSL_SMALL_STACK_CACHE + newV = drbg->seed_scratch; +#else + WC_ALLOC_VAR_EX(newV, byte, DRBG_SHA512_SEED_LEN, drbg->heap, + DYNAMIC_TYPE_TMP_BUFFER, return MEMORY_E); +#endif + XMEMSET(newV, 0, DRBG_SHA512_SEED_LEN); + + ret = Hash512_df(drbg, newV, DRBG_SHA512_SEED_LEN, drbgReseed, + drbg->V, sizeof(drbg->V), seed, seedSz, + additional, additionalSz); + if (ret == DRBG_SUCCESS) { + XMEMCPY(drbg->V, newV, sizeof(drbg->V)); + ForceZero(newV, DRBG_SHA512_SEED_LEN); + + ret = Hash512_df(drbg, drbg->C, sizeof(drbg->C), drbgInitC, drbg->V, + sizeof(drbg->V), NULL, 0, + NULL, 0); + } + if (ret == DRBG_SUCCESS) { + drbg->reseedCtr = 1; + } + +#ifndef WOLFSSL_SMALL_STACK_CACHE + WC_FREE_VAR_EX(newV, drbg->heap, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; +} + +/* Returns: DRBG_SUCCESS or DRBG_FAILURE */ +static int Hash512_gen(DRBG_SHA512_internal* drbg, byte* out, word32 outSz, + const byte* V) +{ + int ret = DRBG_FAILURE; + word32 i; + word32 len; +#if defined(WOLFSSL_SMALL_STACK_CACHE) + wc_Sha512* sha = &drbg->sha512; + byte* data = drbg->seed_scratch; + byte* digest = drbg->digest_scratch; +#elif defined(WOLFSSL_SMALL_STACK) + wc_Sha512 sha[1]; + byte* data = NULL; + byte* digest = NULL; +#else + wc_Sha512 sha[1]; + byte data[DRBG_SHA512_SEED_LEN]; + byte digest[WC_SHA512_DIGEST_SIZE]; +#endif + + if (drbg == NULL) { + return DRBG_FAILURE; + } + +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE) + data = (byte*)XMALLOC(DRBG_SHA512_SEED_LEN, drbg->heap, + DYNAMIC_TYPE_TMP_BUFFER); + digest = (byte*)XMALLOC(WC_SHA512_DIGEST_SIZE, drbg->heap, + DYNAMIC_TYPE_DIGEST); + if (data == NULL || digest == NULL) { + XFREE(digest, drbg->heap, DYNAMIC_TYPE_DIGEST); + XFREE(data, drbg->heap, DYNAMIC_TYPE_TMP_BUFFER); + return DRBG_FAILURE; + } +#endif + + /* Special case: outSz is 0 and out is NULL. Generate a block to save for + * the continuous test. */ + if (outSz == 0) { + outSz = 1; + } + + len = (outSz / OUTPUT_BLOCK_LEN_SHA512) + + ((outSz % OUTPUT_BLOCK_LEN_SHA512) ? 1 : 0); + + XMEMCPY(data, V, DRBG_SHA512_SEED_LEN); + for (i = 0; i < len; i++) { +#ifndef WOLFSSL_SMALL_STACK_CACHE + #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) + ret = wc_InitSha512_ex(sha, drbg->heap, drbg->devId); + #else + ret = wc_InitSha512(sha); + #endif + if (ret == 0) +#endif + ret = wc_Sha512Update(sha, data, DRBG_SHA512_SEED_LEN); + if (ret == 0) + ret = wc_Sha512Final(sha, digest); +#ifndef WOLFSSL_SMALL_STACK_CACHE + wc_Sha512Free(sha); +#endif + + if (ret == 0) { + if (out != NULL && outSz != 0) { + if (outSz >= OUTPUT_BLOCK_LEN_SHA512) { + XMEMCPY(out, digest, OUTPUT_BLOCK_LEN_SHA512); + outSz -= OUTPUT_BLOCK_LEN_SHA512; + out += OUTPUT_BLOCK_LEN_SHA512; + array_add_one(data, DRBG_SHA512_SEED_LEN); + } + else { + XMEMCPY(out, digest, outSz); + outSz = 0; + } + } + } + else { + break; + } + } + ForceZero(data, DRBG_SHA512_SEED_LEN); + +#ifndef WOLFSSL_SMALL_STACK_CACHE + WC_FREE_VAR_EX(digest, drbg->heap, DYNAMIC_TYPE_DIGEST); + WC_FREE_VAR_EX(data, drbg->heap, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return (ret == 0) ? DRBG_SUCCESS : DRBG_FAILURE; +} + +/* Returns: DRBG_SUCCESS, DRBG_NEED_RESEED, or DRBG_FAILURE */ +static int Hash512_DRBG_Generate(DRBG_SHA512_internal* drbg, byte* out, + word32 outSz, + const byte* additional, word32 additionalSz) +{ + int ret; +#ifdef WOLFSSL_SMALL_STACK_CACHE + wc_Sha512* sha = &drbg->sha512; +#else + wc_Sha512 sha[1]; +#endif + byte type; + word64 reseedCtr; + + if (drbg == NULL) { + return DRBG_FAILURE; + } + + if (drbg->reseedCtr >= WC_RESEED_INTERVAL) { + return DRBG_NEED_RESEED; + } + else { + #if defined(WOLFSSL_SMALL_STACK_CACHE) + byte* digest = drbg->digest_scratch; + #elif defined(WOLFSSL_SMALL_STACK) + byte* digest = (byte*)XMALLOC(WC_SHA512_DIGEST_SIZE, drbg->heap, + DYNAMIC_TYPE_DIGEST); + if (digest == NULL) + return DRBG_FAILURE; + #else + byte digest[WC_SHA512_DIGEST_SIZE]; + #endif + + type = drbgGenerateH; + reseedCtr = drbg->reseedCtr; + + /* SP 800-90A Section 10.1.1.4 step 2: + * If additional_input != Null, w = Hash(0x02 || V || additional_input), + * V = (V + w) mod 2^seedlen */ + ret = DRBG_SUCCESS; + if (additional != NULL && additionalSz > 0) { + byte addType = drbgGenerateW; /* 0x02 */ +#ifndef WOLFSSL_SMALL_STACK_CACHE + #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) + ret = wc_InitSha512_ex(sha, drbg->heap, drbg->devId); + #else + ret = wc_InitSha512(sha); + #endif + if (ret == 0) +#endif + ret = wc_Sha512Update(sha, &addType, sizeof(addType)); + if (ret == 0) + ret = wc_Sha512Update(sha, drbg->V, sizeof(drbg->V)); + if (ret == 0) + ret = wc_Sha512Update(sha, additional, additionalSz); + if (ret == 0) + ret = wc_Sha512Final(sha, digest); +#ifndef WOLFSSL_SMALL_STACK_CACHE + wc_Sha512Free(sha); +#endif + if (ret == 0) + array_add(drbg->V, sizeof(drbg->V), digest, + WC_SHA512_DIGEST_SIZE); + } + + if (ret == 0) + ret = Hash512_gen(drbg, out, outSz, drbg->V); + if (ret == DRBG_SUCCESS) { +#ifndef WOLFSSL_SMALL_STACK_CACHE + #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) + ret = wc_InitSha512_ex(sha, drbg->heap, drbg->devId); + #else + ret = wc_InitSha512(sha); + #endif + if (ret == 0) +#endif + ret = wc_Sha512Update(sha, &type, sizeof(type)); + if (ret == 0) + ret = wc_Sha512Update(sha, drbg->V, sizeof(drbg->V)); + if (ret == 0) + ret = wc_Sha512Final(sha, digest); + +#ifndef WOLFSSL_SMALL_STACK_CACHE + wc_Sha512Free(sha); +#endif + + if (ret == 0) { + array_add(drbg->V, sizeof(drbg->V), digest, + WC_SHA512_DIGEST_SIZE); + array_add(drbg->V, sizeof(drbg->V), drbg->C, sizeof(drbg->C)); + #ifdef LITTLE_ENDIAN_ORDER + reseedCtr = ByteReverseWord64(reseedCtr); + #endif + array_add(drbg->V, sizeof(drbg->V), + (byte*)&reseedCtr, sizeof(reseedCtr)); + ret = DRBG_SUCCESS; + } + drbg->reseedCtr++; + } + ForceZero(digest, WC_SHA512_DIGEST_SIZE); + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE) + XFREE(digest, drbg->heap, DYNAMIC_TYPE_DIGEST); + #endif + } + + return (ret == 0) ? DRBG_SUCCESS : DRBG_FAILURE; +} + +/* Returns: DRBG_SUCCESS or DRBG_FAILURE */ +static int Hash512_DRBG_Init(DRBG_SHA512_internal* drbg, const byte* seed, + word32 seedSz, const byte* nonce, word32 nonceSz, + const byte* perso, word32 persoSz) +{ + if (seed == NULL) + return DRBG_FAILURE; + + if (Hash512_df(drbg, drbg->V, sizeof(drbg->V), drbgInitV, seed, seedSz, + nonce, nonceSz, + perso, persoSz) == DRBG_SUCCESS && + Hash512_df(drbg, drbg->C, sizeof(drbg->C), drbgInitC, drbg->V, + sizeof(drbg->V), NULL, 0, + NULL, 0) == DRBG_SUCCESS) { + + drbg->reseedCtr = 1; + return DRBG_SUCCESS; + } + else { + return DRBG_FAILURE; + } +} + +/* Returns: DRBG_SUCCESS or DRBG_FAILURE */ +static int Hash512_DRBG_Instantiate(DRBG_SHA512_internal* drbg, + const byte* seed, word32 seedSz, + const byte* nonce, word32 nonceSz, + const byte* perso, word32 persoSz, + void* heap, int devId) +{ + int ret = DRBG_FAILURE; + + XMEMSET(drbg, 0, sizeof(DRBG_SHA512_internal)); + drbg->heap = heap; +#if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) + drbg->devId = devId; +#else + (void)devId; +#endif + +#ifdef WOLFSSL_SMALL_STACK_CACHE + #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) + ret = wc_InitSha512_ex(&drbg->sha512, drbg->heap, drbg->devId); + #else + ret = wc_InitSha512(&drbg->sha512); + #endif + if (ret != 0) + return ret; +#endif + + if (seed != NULL) + ret = Hash512_DRBG_Init(drbg, seed, seedSz, nonce, nonceSz, + perso, persoSz); + return ret; +} + +/* Returns: DRBG_SUCCESS or DRBG_FAILURE */ +static int Hash512_DRBG_Uninstantiate(DRBG_SHA512_internal* drbg) +{ + word32 i; + int compareSum = 0; + byte* compareDrbg = (byte*)drbg; + +#ifdef WOLFSSL_SMALL_STACK_CACHE + wc_Sha512Free(&drbg->sha512); +#endif + + ForceZero(drbg, sizeof(DRBG_SHA512_internal)); + + for (i = 0; i < sizeof(DRBG_SHA512_internal); i++) { + compareSum |= compareDrbg[i] ^ 0; + } + + return (compareSum == 0) ? DRBG_SUCCESS : DRBG_FAILURE; +} + +#endif /* WOLFSSL_DRBG_SHA512 */ + /* FIPS 140-3 IG 10.3.A / SP800-90B Health Tests for Seed Data * @@ -933,6 +1488,64 @@ int wc_RNG_TestSeed(const byte* seed, word32 seedSz) return ret; } +/* Runtime DRBG disable/enable API -- only available in non-selftest and + * FIPS v7+ builds (older FIPS/selftest random.c doesn't have these) */ +#if !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) +#ifndef NO_SHA256 +int wc_Sha256Drbg_Disable(void) +{ +#ifdef WOLFSSL_DRBG_SHA512 + if (sha512DrbgDisabled) + return BAD_STATE_E; /* can't disable both */ + sha256DrbgDisabled = 1; + return 0; +#else + return NOT_COMPILED_IN; +#endif +} + +int wc_Sha256Drbg_Enable(void) +{ + sha256DrbgDisabled = 0; + return 0; +} + +int wc_Sha256Drbg_GetStatus(void) +{ + return sha256DrbgDisabled; +} +#else +/* When SHA-256 is not compiled in, these are stubs */ +int wc_Sha256Drbg_Disable(void) { return NOT_COMPILED_IN; } +int wc_Sha256Drbg_Enable(void) { return 0; } +int wc_Sha256Drbg_GetStatus(void) { return 1; } /* always disabled */ +#endif /* !NO_SHA256 */ +#endif /* !HAVE_SELFTEST && (!HAVE_FIPS || FIPS v7+) */ + +#ifdef WOLFSSL_DRBG_SHA512 +int wc_Sha512Drbg_Disable(void) +{ +#ifndef NO_SHA256 + if (sha256DrbgDisabled) + return BAD_STATE_E; /* can't disable both */ +#endif + sha512DrbgDisabled = 1; + return 0; +} + +int wc_Sha512Drbg_Enable(void) +{ + sha512DrbgDisabled = 0; + return 0; +} + +int wc_Sha512Drbg_GetStatus(void) +{ + return sha512DrbgDisabled; +} +#endif /* WOLFSSL_DRBG_SHA512 */ + #endif /* HAVE_HASHDRBG */ /* End NIST DRBG Code */ @@ -983,11 +1596,41 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, #ifdef HAVE_HASHDRBG /* init the DBRG to known values */ +#ifndef NO_SHA256 rng->drbg = NULL; #ifdef WOLFSSL_SMALL_STACK_CACHE rng->drbg_scratch = NULL; #endif +#endif +#ifdef WOLFSSL_DRBG_SHA512 + rng->drbg512 = NULL; + #ifdef WOLFSSL_SMALL_STACK_CACHE + rng->drbg512_scratch = NULL; + rng->health_check_scratch_512 = NULL; + #endif +#endif +#ifdef WOLFSSL_SMALL_STACK_CACHE + rng->newSeed_buf = NULL; +#ifndef NO_SHA256 + rng->health_check_scratch = NULL; +#endif +#endif rng->status = DRBG_NOT_INIT; + + /* Select DRBG type: prefer SHA-512 unless disabled or not compiled */ +#ifdef WOLFSSL_DRBG_SHA512 + if (!wc_Sha512Drbg_GetStatus()) + rng->drbgType = WC_DRBG_SHA512; + else +#endif +#ifndef NO_SHA256 + if (!wc_Sha256Drbg_GetStatus()) + rng->drbgType = WC_DRBG_SHA256; + else +#endif + { + return BAD_STATE_E; /* no DRBG available */ + } #endif #if defined(HAVE_INTEL_RDSEED) || defined(HAVE_INTEL_RDRAND) || \ @@ -1043,54 +1686,110 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, seedSz = MAX_SEED_SZ; } -#if !defined(WOLFSSL_NO_MALLOC) || defined(WOLFSSL_STATIC_MEMORY) - rng->drbg = - (struct DRBG*)XMALLOC(sizeof(DRBG_internal), rng->heap, - DYNAMIC_TYPE_RNG); - if (rng->drbg == NULL) { - #if defined(DEBUG_WOLFSSL) - WOLFSSL_MSG_EX("_InitRng XMALLOC failed to allocate %d bytes", - sizeof(DRBG_internal)); - #endif - ret = MEMORY_E; - rng->status = DRBG_FAILED; - } -#else - rng->drbg = (struct DRBG*)&rng->drbg_data; -#endif /* WOLFSSL_NO_MALLOC or WOLFSSL_STATIC_MEMORY */ - -#ifdef WOLFSSL_SMALL_STACK_CACHE - if (ret == 0) { - rng->drbg_scratch = - (DRBG_internal *)XMALLOC(sizeof(DRBG_internal), rng->heap, - DYNAMIC_TYPE_RNG); - if (rng->drbg_scratch == NULL) { -#if defined(DEBUG_WOLFSSL) +#ifndef NO_SHA256 + if (rng->drbgType == WC_DRBG_SHA256) { + #if !defined(WOLFSSL_NO_MALLOC) || defined(WOLFSSL_STATIC_MEMORY) + rng->drbg = + (struct DRBG*)XMALLOC(sizeof(DRBG_internal), rng->heap, + DYNAMIC_TYPE_RNG); + if (rng->drbg == NULL) { + #if defined(DEBUG_WOLFSSL) WOLFSSL_MSG_EX("_InitRng XMALLOC failed to allocate %d bytes", sizeof(DRBG_internal)); -#endif + #endif ret = MEMORY_E; rng->status = DRBG_FAILED; } - } + #else + rng->drbg = (struct DRBG*)&rng->drbg_data; + #endif /* WOLFSSL_NO_MALLOC or WOLFSSL_STATIC_MEMORY */ - if (ret == 0) { - ret = Hash_DRBG_Instantiate((DRBG_internal *)rng->drbg_scratch, - NULL /* seed */, 0, NULL /* nonce */, 0, rng->heap, devId); - if (ret == 0) - drbg_scratch_instantiated = 1; - } + #ifdef WOLFSSL_SMALL_STACK_CACHE + if (ret == 0) { + rng->drbg_scratch = + (DRBG_internal *)XMALLOC(sizeof(DRBG_internal), rng->heap, + DYNAMIC_TYPE_RNG); + if (rng->drbg_scratch == NULL) { + #if defined(DEBUG_WOLFSSL) + WOLFSSL_MSG_EX("_InitRng XMALLOC failed to allocate %d bytes", + sizeof(DRBG_internal)); + #endif + ret = MEMORY_E; + rng->status = DRBG_FAILED; + } + } - if (ret == 0) { - rng->health_check_scratch = - (byte *)XMALLOC(RNG_HEALTH_TEST_CHECK_SIZE, rng->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (rng->health_check_scratch == NULL) { + if (ret == 0) { + ret = Hash_DRBG_Instantiate((DRBG_internal *)rng->drbg_scratch, + NULL, 0, NULL, 0, NULL, 0, rng->heap, devId); + if (ret == 0) + drbg_scratch_instantiated = 1; + } + + if (ret == 0) { + rng->health_check_scratch = + (byte *)XMALLOC(RNG_HEALTH_TEST_CHECK_SIZE, rng->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (rng->health_check_scratch == NULL) { + ret = MEMORY_E; + rng->status = DRBG_FAILED; + } + } + #endif /* WOLFSSL_SMALL_STACK_CACHE */ + } /* WC_DRBG_SHA256 */ +#endif /* !NO_SHA256 */ + +#ifdef WOLFSSL_DRBG_SHA512 + if (rng->drbgType == WC_DRBG_SHA512) { + #if !defined(WOLFSSL_NO_MALLOC) || defined(WOLFSSL_STATIC_MEMORY) + rng->drbg512 = + (struct DRBG_SHA512*)XMALLOC(sizeof(DRBG_SHA512_internal), + rng->heap, DYNAMIC_TYPE_RNG); + if (rng->drbg512 == NULL) { + #if defined(DEBUG_WOLFSSL) + WOLFSSL_MSG_EX("_InitRng XMALLOC failed to allocate %d bytes", + sizeof(DRBG_SHA512_internal)); + #endif ret = MEMORY_E; rng->status = DRBG_FAILED; } - } + #else + rng->drbg512 = (struct DRBG_SHA512*)&rng->drbg512_data; + #endif + + #ifdef WOLFSSL_SMALL_STACK_CACHE + if (ret == 0) { + rng->drbg512_scratch = + (DRBG_SHA512_internal *)XMALLOC(sizeof(DRBG_SHA512_internal), + rng->heap, DYNAMIC_TYPE_RNG); + if (rng->drbg512_scratch == NULL) { + ret = MEMORY_E; + rng->status = DRBG_FAILED; + } + } + + if (ret == 0) { + ret = Hash512_DRBG_Instantiate(rng->drbg512_scratch, + NULL, 0, NULL, 0, NULL, 0, rng->heap, devId); + if (ret == 0) + drbg_scratch_instantiated = 1; + } + + if (ret == 0) { + rng->health_check_scratch_512 = + (byte *)XMALLOC(RNG_HEALTH_TEST_CHECK_SIZE_SHA512, rng->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (rng->health_check_scratch_512 == NULL) { + ret = MEMORY_E; + rng->status = DRBG_FAILED; + } + } + #endif /* WOLFSSL_SMALL_STACK_CACHE */ + } /* WC_DRBG_SHA512 */ +#endif /* WOLFSSL_DRBG_SHA512 */ + /* newSeed_buf shared by both DRBG types for PollAndReSeed */ +#ifdef WOLFSSL_SMALL_STACK_CACHE if (ret == 0) { rng->newSeed_buf = (byte*)XMALLOC(SEED_SZ + SEED_BLOCK_SZ, rng->heap, DYNAMIC_TYPE_SEED); @@ -1171,14 +1870,29 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, } #endif - if (ret == DRBG_SUCCESS) - ret = Hash_DRBG_Instantiate((DRBG_internal *)rng->drbg, - #if defined(HAVE_FIPS) || !defined(WOLFSSL_RNG_USE_FULL_SEED) - seed + SEED_BLOCK_SZ, seedSz - SEED_BLOCK_SZ, - #else - seed, seedSz, - #endif - nonce, nonceSz, rng->heap, devId); + if (ret == DRBG_SUCCESS) { +#ifndef NO_SHA256 + if (rng->drbgType == WC_DRBG_SHA256) + ret = Hash_DRBG_Instantiate((DRBG_internal *)rng->drbg, + #if defined(HAVE_FIPS) || !defined(WOLFSSL_RNG_USE_FULL_SEED) + seed + SEED_BLOCK_SZ, seedSz - SEED_BLOCK_SZ, + #else + seed, seedSz, + #endif + nonce, nonceSz, NULL, 0, rng->heap, devId); +#endif +#ifdef WOLFSSL_DRBG_SHA512 + if (rng->drbgType == WC_DRBG_SHA512) + ret = Hash512_DRBG_Instantiate( + (DRBG_SHA512_internal *)rng->drbg512, + #if defined(HAVE_FIPS) || !defined(WOLFSSL_RNG_USE_FULL_SEED) + seed + SEED_BLOCK_SZ, seedSz - SEED_BLOCK_SZ, + #else + seed, seedSz, + #endif + nonce, nonceSz, NULL, 0, rng->heap, devId); +#endif + } } /* ret == 0 */ #ifdef WOLFSSL_SMALL_STACK @@ -1190,29 +1904,56 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, WC_FREE_VAR_EX(seed, rng->heap, DYNAMIC_TYPE_SEED); if (ret != DRBG_SUCCESS) { - #if !defined(WOLFSSL_NO_MALLOC) || defined(WOLFSSL_STATIC_MEMORY) - XFREE(rng->drbg, rng->heap, DYNAMIC_TYPE_RNG); + #ifndef NO_SHA256 + if (rng->drbgType == WC_DRBG_SHA256) { + #if !defined(WOLFSSL_NO_MALLOC) || defined(WOLFSSL_STATIC_MEMORY) + XFREE(rng->drbg, rng->heap, DYNAMIC_TYPE_RNG); + #endif + rng->drbg = NULL; + #ifdef WOLFSSL_SMALL_STACK_CACHE + XFREE(rng->health_check_scratch, rng->heap, + DYNAMIC_TYPE_TMP_BUFFER); + rng->health_check_scratch = NULL; + if (drbg_scratch_instantiated) + (void)Hash_DRBG_Uninstantiate( + (DRBG_internal *)rng->drbg_scratch); + XFREE(rng->drbg_scratch, rng->heap, DYNAMIC_TYPE_RNG); + rng->drbg_scratch = NULL; + #endif + } + #endif /* !NO_SHA256 */ + #ifdef WOLFSSL_DRBG_SHA512 + if (rng->drbgType == WC_DRBG_SHA512) { + #if !defined(WOLFSSL_NO_MALLOC) || defined(WOLFSSL_STATIC_MEMORY) + XFREE(rng->drbg512, rng->heap, DYNAMIC_TYPE_RNG); + #endif + rng->drbg512 = NULL; + #ifdef WOLFSSL_SMALL_STACK_CACHE + XFREE(rng->health_check_scratch_512, rng->heap, + DYNAMIC_TYPE_TMP_BUFFER); + rng->health_check_scratch_512 = NULL; + if (drbg_scratch_instantiated) + (void)Hash512_DRBG_Uninstantiate(rng->drbg512_scratch); + XFREE(rng->drbg512_scratch, rng->heap, DYNAMIC_TYPE_RNG); + rng->drbg512_scratch = NULL; + #endif + } #endif - rng->drbg = NULL; #ifdef WOLFSSL_SMALL_STACK_CACHE - XFREE(rng->health_check_scratch, rng->heap, DYNAMIC_TYPE_TMP_BUFFER); - rng->health_check_scratch = NULL; - XFREE(rng->newSeed_buf, rng->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(rng->newSeed_buf, rng->heap, DYNAMIC_TYPE_SEED); rng->newSeed_buf = NULL; - if (drbg_scratch_instantiated) - (void)Hash_DRBG_Uninstantiate((DRBG_internal *)rng->drbg_scratch); - XFREE(rng->drbg_scratch, rng->heap, DYNAMIC_TYPE_RNG); - rng->drbg_scratch = NULL; #endif } /* else wc_RNG_HealthTestLocal was successful */ if (ret == DRBG_SUCCESS) { #ifdef WOLFSSL_CHECK_MEM_ZERO - #ifdef HAVE_HASHDRBG - struct DRBG_internal* drbg = (struct DRBG_internal*)rng->drbg; - wc_MemZero_Add("DRBG V", &drbg->V, sizeof(drbg->V)); - wc_MemZero_Add("DRBG C", &drbg->C, sizeof(drbg->C)); + #ifndef NO_SHA256 + if (rng->drbgType == WC_DRBG_SHA256) { + struct DRBG_internal* drbg = (struct DRBG_internal*)rng->drbg; + wc_MemZero_Add("DRBG V", &drbg->V, sizeof(drbg->V)); + wc_MemZero_Add("DRBG C", &drbg->C, sizeof(drbg->C)); + } #endif #endif @@ -1373,9 +2114,20 @@ static int PollAndReSeed(WC_RNG* rng) "err %d.", ret); #endif } - if (ret == DRBG_SUCCESS) - ret = Hash_DRBG_Reseed((DRBG_internal *)rng->drbg, - newSeed + SEED_BLOCK_SZ, SEED_SZ); + if (ret == DRBG_SUCCESS) { +#ifndef NO_SHA256 + if (rng->drbgType == WC_DRBG_SHA256) + ret = Hash_DRBG_Reseed((DRBG_internal *)rng->drbg, + newSeed + SEED_BLOCK_SZ, SEED_SZ, + NULL, 0); +#endif +#ifdef WOLFSSL_DRBG_SHA512 + if (rng->drbgType == WC_DRBG_SHA512) + ret = Hash512_DRBG_Reseed( + (DRBG_SHA512_internal *)rng->drbg512, + newSeed + SEED_BLOCK_SZ, SEED_SZ, NULL, 0); +#endif + } #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE) if (newSeed != NULL) { ForceZero(newSeed, SEED_SZ + SEED_BLOCK_SZ); @@ -1471,11 +2223,35 @@ int wc_RNG_GenerateBlock(WC_RNG* rng, byte* output, word32 sz) } #endif - ret = Hash_DRBG_Generate((DRBG_internal *)rng->drbg, output, sz); - if (ret == DRBG_NEED_RESEED) { - ret = PollAndReSeed(rng); - if (ret == DRBG_SUCCESS) - ret = Hash_DRBG_Generate((DRBG_internal *)rng->drbg, output, sz); +#ifndef NO_SHA256 + if (rng->drbgType == WC_DRBG_SHA256) { + ret = Hash_DRBG_Generate((DRBG_internal *)rng->drbg, output, sz, + NULL, 0); + if (ret == DRBG_NEED_RESEED) { + ret = PollAndReSeed(rng); + if (ret == DRBG_SUCCESS) + ret = Hash_DRBG_Generate((DRBG_internal *)rng->drbg, output, + sz, NULL, 0); + } + } + else +#endif +#ifdef WOLFSSL_DRBG_SHA512 + if (rng->drbgType == WC_DRBG_SHA512) { + ret = Hash512_DRBG_Generate((DRBG_SHA512_internal *)rng->drbg512, + output, sz, NULL, 0); + if (ret == DRBG_NEED_RESEED) { + ret = PollAndReSeed(rng); + if (ret == DRBG_SUCCESS) + ret = Hash512_DRBG_Generate( + (DRBG_SHA512_internal *)rng->drbg512, output, sz, + NULL, 0); + } + } + else +#endif + { + ret = DRBG_FAILURE; } if (ret == DRBG_SUCCESS) { @@ -1560,6 +2336,7 @@ int wc_FreeRng(WC_RNG* rng) #endif #ifdef HAVE_HASHDRBG +#ifndef NO_SHA256 if (rng->drbg != NULL) { if (Hash_DRBG_Uninstantiate((DRBG_internal *)rng->drbg) != DRBG_SUCCESS) ret = RNG_FAILURE_E; @@ -1570,20 +2347,51 @@ int wc_FreeRng(WC_RNG* rng) wc_MemZero_Check(rng->drbg, sizeof(DRBG_internal)); #endif rng->drbg = NULL; - } #ifdef WOLFSSL_SMALL_STACK_CACHE - if (rng->drbg_scratch != NULL) { - if (Hash_DRBG_Uninstantiate((DRBG_internal *)rng->drbg_scratch) != DRBG_SUCCESS) + if (rng->drbg_scratch != NULL) { + if (Hash_DRBG_Uninstantiate((DRBG_internal *)rng->drbg_scratch) + != DRBG_SUCCESS) + ret = RNG_FAILURE_E; + XFREE(rng->drbg_scratch, rng->heap, DYNAMIC_TYPE_RNG); + rng->drbg_scratch = NULL; + } + XFREE(rng->health_check_scratch, rng->heap, DYNAMIC_TYPE_TMP_BUFFER); + rng->health_check_scratch = NULL; + #endif + } +#endif /* !NO_SHA256 */ + +#ifdef WOLFSSL_DRBG_SHA512 + if (rng->drbg512 != NULL) { + if (Hash512_DRBG_Uninstantiate( + (DRBG_SHA512_internal *)rng->drbg512) != DRBG_SUCCESS) ret = RNG_FAILURE_E; - XFREE(rng->drbg_scratch, rng->heap, DYNAMIC_TYPE_RNG); - rng->drbg_scratch = NULL; + + #if !defined(WOLFSSL_NO_MALLOC) || defined(WOLFSSL_STATIC_MEMORY) + XFREE(rng->drbg512, rng->heap, DYNAMIC_TYPE_RNG); + #endif + rng->drbg512 = NULL; + + #ifdef WOLFSSL_SMALL_STACK_CACHE + if (rng->drbg512_scratch != NULL) { + if (Hash512_DRBG_Uninstantiate(rng->drbg512_scratch) + != DRBG_SUCCESS) + ret = RNG_FAILURE_E; + XFREE(rng->drbg512_scratch, rng->heap, DYNAMIC_TYPE_RNG); + rng->drbg512_scratch = NULL; + } + XFREE(rng->health_check_scratch_512, rng->heap, + DYNAMIC_TYPE_TMP_BUFFER); + rng->health_check_scratch_512 = NULL; + #endif } - XFREE(rng->health_check_scratch, rng->heap, DYNAMIC_TYPE_RNG); - rng->health_check_scratch = NULL; - XFREE(rng->newSeed_buf, rng->heap, DYNAMIC_TYPE_RNG); +#endif /* WOLFSSL_DRBG_SHA512 */ + +#ifdef WOLFSSL_SMALL_STACK_CACHE + XFREE(rng->newSeed_buf, rng->heap, DYNAMIC_TYPE_SEED); rng->newSeed_buf = NULL; - #endif +#endif rng->status = DRBG_NOT_INIT; #endif /* HAVE_HASHDRBG */ @@ -1643,18 +2451,19 @@ static int wc_RNG_HealthTest_ex_internal(DRBG_internal* drbg, (void)heap; (void)devId; - if (Hash_DRBG_Init(drbg, seedA, seedASz, nonce, nonceSz) != 0) { + if (Hash_DRBG_Init(drbg, seedA, seedASz, nonce, nonceSz, + NULL, 0) != 0) { goto exit_rng_ht; } #else if (Hash_DRBG_Instantiate(drbg, seedA, seedASz, nonce, nonceSz, - heap, devId) != 0) { + NULL, 0, heap, devId) != 0) { goto exit_rng_ht; } #endif if (reseed) { - if (Hash_DRBG_Reseed(drbg, seedB, seedBSz) != 0) { + if (Hash_DRBG_Reseed(drbg, seedB, seedBSz, NULL, 0) != 0) { goto exit_rng_ht; } } @@ -1664,11 +2473,11 @@ static int wc_RNG_HealthTest_ex_internal(DRBG_internal* drbg, * answer test checks the second block of DRBG out of * the generator to ensure the internal state is updated * as expected. */ - if (Hash_DRBG_Generate(drbg, output, outputSz) != 0) { + if (Hash_DRBG_Generate(drbg, output, outputSz, NULL, 0) != 0) { goto exit_rng_ht; } - if (Hash_DRBG_Generate(drbg, output, outputSz) != 0) { + if (Hash_DRBG_Generate(drbg, output, outputSz, NULL, 0) != 0) { goto exit_rng_ht; } @@ -1711,7 +2520,8 @@ int wc_RNG_HealthTest_ex(int reseed, const byte* nonce, word32 nonceSz, #ifdef WOLFSSL_SMALL_STACK_CACHE ret = Hash_DRBG_Instantiate(drbg, - NULL /* seed */, 0, NULL /* nonce */, 0, heap, devId); + NULL /* seed */, 0, NULL /* nonce */, 0, + NULL /* perso */, 0, heap, devId); if (ret == 0) #endif { @@ -1778,10 +2588,182 @@ const FLASH_QUALIFIER byte outputB_data[] = { }; +/* SHA-512 DRBG KAT vectors for local health test. + * Source: NIST CAVP Hash_DRBG.rsp, [SHA-512], PredictionResistance=False, + * EntropyInputLen=256, NonceLen=128, PersonalizationStringLen=0, + * AdditionalInputLen=0, ReturnedBitsLen=2048. */ +#ifdef WOLFSSL_DRBG_SHA512 + +/* Reseed test vectors (COUNT=0 from reseed section) */ +static const byte sha512_seedA_data[] = { + /* EntropyInput (32 bytes) || Nonce (16 bytes) */ + 0x31, 0x44, 0xe1, 0x7a, 0x10, 0xc8, 0x56, 0x12, + 0x97, 0x64, 0xf5, 0x8f, 0xd8, 0xe4, 0x23, 0x10, + 0x20, 0x54, 0x69, 0x96, 0xc0, 0xbf, 0x6c, 0xff, + 0x8e, 0x91, 0xc2, 0x4e, 0xe0, 0x9b, 0xe3, 0x33, + 0xb1, 0x6f, 0xcb, 0x1c, 0xf0, 0xc0, 0x10, 0xf3, + 0x1f, 0xea, 0xb7, 0x33, 0x58, 0x8b, 0x8e, 0x04 +}; +static const byte sha512_reseedSeedA_data[] = { + /* EntropyInputReseed (32 bytes) */ + 0xa0, 0xb3, 0x58, 0x4c, 0x2c, 0x84, 0x12, 0xf6, + 0x18, 0x40, 0x68, 0x34, 0x40, 0x4d, 0x1e, 0xb0, + 0xce, 0x99, 0x9b, 0xa2, 0x89, 0x66, 0x05, 0x4d, + 0x7e, 0x49, 0x7e, 0x0d, 0xb6, 0x08, 0xb9, 0x67 +}; +static const byte sha512_outputA_data[] = { + 0xef, 0xa3, 0x5d, 0xd0, 0x36, 0x2a, 0xdb, 0x76, + 0x26, 0x45, 0x6b, 0x36, 0xfa, 0xc7, 0x4d, 0x3c, + 0x28, 0xd0, 0x1d, 0x92, 0x64, 0x20, 0x27, 0x5a, + 0x28, 0xbe, 0xa9, 0xc9, 0xdd, 0x75, 0x47, 0xc1, + 0x5e, 0x79, 0x31, 0x85, 0x2a, 0xc1, 0x27, 0x70, + 0x76, 0x56, 0x75, 0x35, 0x23, 0x9c, 0x1f, 0x42, + 0x9c, 0x7f, 0x75, 0xcf, 0x74, 0xc2, 0x26, 0x7d, + 0xeb, 0x6a, 0x3e, 0x59, 0x6c, 0xf3, 0x26, 0x15, + 0x6c, 0x79, 0x69, 0x41, 0x28, 0x3b, 0x8d, 0x58, + 0x3f, 0x17, 0x1c, 0x2f, 0x6e, 0x33, 0x23, 0xf7, + 0x55, 0x5e, 0x1b, 0x18, 0x1f, 0xfd, 0xa3, 0x05, + 0x07, 0x21, 0x0c, 0xb1, 0xf5, 0x89, 0xb2, 0x3c, + 0xd7, 0x18, 0x80, 0xfd, 0x44, 0x37, 0x0c, 0xac, + 0xf4, 0x33, 0x75, 0xb0, 0xdb, 0x7e, 0x33, 0x6f, + 0x12, 0xb3, 0x09, 0xbf, 0xd4, 0xf6, 0x10, 0xbb, + 0x8f, 0x20, 0xe1, 0xa1, 0x5e, 0x25, 0x3a, 0x4f, + 0xe5, 0x11, 0xa0, 0x27, 0x96, 0x8d, 0xf0, 0xb1, + 0x05, 0xa1, 0xd7, 0x3a, 0xff, 0x7c, 0x7a, 0x82, + 0x6d, 0x39, 0xf6, 0x40, 0xdf, 0xb8, 0xf5, 0x22, + 0x25, 0x9e, 0xd4, 0x02, 0x28, 0x2e, 0x2c, 0x2e, + 0x9d, 0x3a, 0x49, 0x8f, 0x51, 0x72, 0x5f, 0xe4, + 0x14, 0x1b, 0x06, 0xda, 0x55, 0x98, 0xa4, 0x2a, + 0xc1, 0xe0, 0x49, 0x4e, 0x99, 0x7d, 0x56, 0x6a, + 0x1a, 0x39, 0xb6, 0x76, 0xb9, 0x6a, 0x60, 0x03, + 0xa4, 0xc5, 0xdb, 0x84, 0xf2, 0x46, 0x58, 0x4e, + 0xe6, 0x5a, 0xf7, 0x0f, 0xf2, 0x16, 0x02, 0x78, + 0x16, 0x6d, 0xa1, 0x6d, 0x91, 0xc9, 0xb8, 0xf2, + 0xde, 0xb0, 0x27, 0x51, 0xa1, 0x08, 0x8a, 0xd6, + 0xbe, 0x4e, 0x80, 0xef, 0x96, 0x6e, 0xb7, 0x3e, + 0x66, 0xbc, 0x87, 0xca, 0xd8, 0x7c, 0x77, 0xc0, + 0xb3, 0x4a, 0x21, 0xba, 0x1d, 0xa0, 0xba, 0x6d, + 0x16, 0xca, 0x50, 0x46, 0xdc, 0x4a, 0xbd, 0xa0 +}; + +/* No-reseed test vectors (COUNT=0 from no-reseed section) */ +static const byte sha512_seedB_data[] = { + /* EntropyInput (32 bytes) || Nonce (16 bytes) */ + 0x6b, 0x50, 0xa7, 0xd8, 0xf8, 0xa5, 0x5d, 0x7a, + 0x3d, 0xf8, 0xbb, 0x40, 0xbc, 0xc3, 0xb7, 0x22, + 0xd8, 0x70, 0x8d, 0xe6, 0x7f, 0xda, 0x01, 0x0b, + 0x03, 0xc4, 0xc8, 0x4d, 0x72, 0x09, 0x6f, 0x8c, + 0x3e, 0xc6, 0x49, 0xcc, 0x62, 0x56, 0xd9, 0xfa, + 0x31, 0xdb, 0x7a, 0x29, 0x04, 0xaa, 0xf0, 0x25 +}; +static const byte sha512_outputB_data[] = { + 0x95, 0xb7, 0xf1, 0x7e, 0x98, 0x02, 0xd3, 0x57, + 0x73, 0x92, 0xc6, 0xa9, 0xc0, 0x80, 0x83, 0xb6, + 0x7d, 0xd1, 0x29, 0x22, 0x65, 0xb5, 0xf4, 0x2d, + 0x23, 0x7f, 0x1c, 0x55, 0xbb, 0x9b, 0x10, 0xbf, + 0xcf, 0xd8, 0x2c, 0x77, 0xa3, 0x78, 0xb8, 0x26, + 0x6a, 0x00, 0x99, 0x14, 0x3b, 0x3c, 0x2d, 0x64, + 0x61, 0x1e, 0xee, 0xb6, 0x9a, 0xcd, 0xc0, 0x55, + 0x95, 0x7c, 0x13, 0x9e, 0x8b, 0x19, 0x0c, 0x7a, + 0x06, 0x95, 0x5f, 0x2c, 0x79, 0x7c, 0x27, 0x78, + 0xde, 0x94, 0x03, 0x96, 0xa5, 0x01, 0xf4, 0x0e, + 0x91, 0x39, 0x6a, 0xcf, 0x8d, 0x7e, 0x45, 0xeb, + 0xdb, 0xb5, 0x3b, 0xbf, 0x8c, 0x97, 0x52, 0x30, + 0xd2, 0xf0, 0xff, 0x91, 0x06, 0xc7, 0x61, 0x19, + 0xae, 0x49, 0x8e, 0x7f, 0xbc, 0x03, 0xd9, 0x0f, + 0x8e, 0x4c, 0x51, 0x62, 0x7a, 0xed, 0x5c, 0x8d, + 0x42, 0x63, 0xd5, 0xd2, 0xb9, 0x78, 0x87, 0x3a, + 0x0d, 0xe5, 0x96, 0xee, 0x6d, 0xc7, 0xf7, 0xc2, + 0x9e, 0x37, 0xee, 0xe8, 0xb3, 0x4c, 0x90, 0xdd, + 0x1c, 0xf6, 0xa9, 0xdd, 0xb2, 0x2b, 0x4c, 0xbd, + 0x08, 0x6b, 0x14, 0xb3, 0x5d, 0xe9, 0x3d, 0xa2, + 0xd5, 0xcb, 0x18, 0x06, 0x69, 0x8c, 0xbd, 0x7b, + 0xbb, 0x67, 0xbf, 0xe3, 0xd3, 0x1f, 0xd2, 0xd1, + 0xdb, 0xd2, 0xa1, 0xe0, 0x58, 0xa3, 0xeb, 0x99, + 0xd7, 0xe5, 0x1f, 0x1a, 0x93, 0x8e, 0xed, 0x5e, + 0x1c, 0x1d, 0xe2, 0x3a, 0x6b, 0x43, 0x45, 0xd3, + 0x19, 0x14, 0x09, 0xf9, 0x2f, 0x39, 0xb3, 0x67, + 0x0d, 0x8d, 0xbf, 0xb6, 0x35, 0xd8, 0xe6, 0xa3, + 0x69, 0x32, 0xd8, 0x10, 0x33, 0xd1, 0x44, 0x8d, + 0x63, 0xb4, 0x03, 0xdd, 0xf8, 0x8e, 0x12, 0x1b, + 0x6e, 0x81, 0x9a, 0xc3, 0x81, 0x22, 0x6c, 0x13, + 0x21, 0xe4, 0xb0, 0x86, 0x44, 0xf6, 0x72, 0x7c, + 0x36, 0x8c, 0x5a, 0x9f, 0x7a, 0x4b, 0x3e, 0xe2 +}; +#endif /* WOLFSSL_DRBG_SHA512 */ + + static int wc_RNG_HealthTestLocal(WC_RNG* rng, int reseed, void* heap, int devId) { int ret = 0; + +#ifdef WOLFSSL_DRBG_SHA512 + /* SHA-512 DRBG health test path */ + if (rng->drbgType == WC_DRBG_SHA512) { + #ifdef WOLFSSL_SMALL_STACK_CACHE + byte *check512 = rng->health_check_scratch_512; + DRBG_SHA512_internal* drbg512 = rng->drbg512_scratch; + #else + WC_DECLARE_VAR(check512, byte, RNG_HEALTH_TEST_CHECK_SIZE_SHA512, 0); + WC_DECLARE_VAR(drbg512, DRBG_SHA512_internal, 1, 0); + + WC_ALLOC_VAR_EX(check512, byte, RNG_HEALTH_TEST_CHECK_SIZE_SHA512, + heap, DYNAMIC_TYPE_TMP_BUFFER, return MEMORY_E); + WC_ALLOC_VAR_EX(drbg512, DRBG_SHA512_internal, + sizeof(DRBG_SHA512_internal), heap, DYNAMIC_TYPE_TMP_BUFFER, + WC_DO_NOTHING); + #ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC + if (drbg512 == NULL) { + WC_FREE_VAR_EX(check512, heap, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } + #endif + #endif + + if (reseed) { + /* Reseed test with NIST CAVP SHA-512 vectors */ + ret = wc_RNG_HealthTest_SHA512_ex_internal( + drbg512, 1, NULL, 0, NULL, 0, + sha512_seedA_data, sizeof(sha512_seedA_data), + sha512_reseedSeedA_data, + sizeof(sha512_reseedSeedA_data), + NULL, 0, NULL, 0, + check512, RNG_HEALTH_TEST_CHECK_SIZE_SHA512, + heap, devId); + if (ret == 0) { + if (ConstantCompare(check512, sha512_outputA_data, + RNG_HEALTH_TEST_CHECK_SIZE_SHA512) != 0) + ret = -1; + } + } + else { + /* No-reseed test with NIST CAVP SHA-512 vectors */ + ret = wc_RNG_HealthTest_SHA512_ex_internal( + drbg512, 0, NULL, 0, NULL, 0, + sha512_seedB_data, sizeof(sha512_seedB_data), + NULL, 0, + NULL, 0, NULL, 0, + check512, RNG_HEALTH_TEST_CHECK_SIZE_SHA512, + heap, devId); + if (ret == 0) { + if (ConstantCompare(check512, sha512_outputB_data, + RNG_HEALTH_TEST_CHECK_SIZE_SHA512) != 0) + ret = -1; + } + } + + #ifndef WOLFSSL_SMALL_STACK_CACHE + WC_FREE_VAR_EX(check512, heap, DYNAMIC_TYPE_TMP_BUFFER); + WC_FREE_VAR_EX(drbg512, heap, DYNAMIC_TYPE_TMP_BUFFER); + #endif + return ret; + } +#endif /* WOLFSSL_DRBG_SHA512 */ + + /* SHA-256 DRBG health test path (original) */ +#ifndef NO_SHA256 + { #ifdef WOLFSSL_SMALL_STACK_CACHE byte *check = rng->health_check_scratch; DRBG_internal* drbg = (DRBG_internal *)rng->drbg_scratch; @@ -1919,9 +2901,408 @@ static int wc_RNG_HealthTestLocal(WC_RNG* rng, int reseed, void* heap, WC_FREE_VAR_EX(check, heap, DYNAMIC_TYPE_TMP_BUFFER); WC_FREE_VAR_EX(drbg, heap, DYNAMIC_TYPE_TMP_BUFFER); #endif + } /* SHA-256 path */ +#endif /* !NO_SHA256 */ + + return ret; +} + +/* ====================================================================== */ +/* SHA-512 Health Test API */ +/* ====================================================================== */ +#ifdef WOLFSSL_DRBG_SHA512 + +static int wc_RNG_HealthTest_SHA512_ex_internal(DRBG_SHA512_internal* drbg, + int reseed, const byte* nonce, word32 nonceSz, + const byte* perso, word32 persoSz, + const byte* seedA, word32 seedASz, + const byte* seedB, word32 seedBSz, + const byte* additionalA, word32 additionalASz, + const byte* additionalB, word32 additionalBSz, + byte* output, word32 outputSz, + void* heap, int devId) +{ + int ret = -1; + + if (seedA == NULL || output == NULL) { + return BAD_FUNC_ARG; + } + + if (reseed != 0 && seedB == NULL) { + return BAD_FUNC_ARG; + } + + if (outputSz != RNG_HEALTH_TEST_CHECK_SIZE_SHA512) { + return ret; + } + +#ifdef WOLFSSL_SMALL_STACK_CACHE + (void)heap; + (void)devId; + + if (Hash512_DRBG_Init(drbg, seedA, seedASz, nonce, nonceSz, + perso, persoSz) != 0) { + goto exit_rng_ht512; + } +#else + if (Hash512_DRBG_Instantiate(drbg, seedA, seedASz, nonce, nonceSz, + perso, persoSz, heap, devId) != 0) { + goto exit_rng_ht512; + } +#endif + + if (reseed) { + if (Hash512_DRBG_Reseed(drbg, seedB, seedBSz, NULL, 0) != 0) { + goto exit_rng_ht512; + } + } + + /* First generate: output discarded per NIST DRBGVS procedure */ + if (Hash512_DRBG_Generate(drbg, output, outputSz, + additionalA, additionalASz) != 0) { + goto exit_rng_ht512; + } + + /* Second generate: this is the actual test output */ + if (Hash512_DRBG_Generate(drbg, output, outputSz, + additionalB, additionalBSz) != 0) { + goto exit_rng_ht512; + } + + ret = 0; + +exit_rng_ht512: + +#ifndef WOLFSSL_SMALL_STACK_CACHE + if (Hash512_DRBG_Uninstantiate(drbg) != 0) { + ret = -1; + } +#endif + + return ret; +} + + +/* Extended API with personalization string and additional input + * for ACVP testing */ +int wc_RNG_HealthTest_SHA512_ex(int reseed, + const byte* nonce, word32 nonceSz, + const byte* persoString, word32 persoStringSz, + const byte* seedA, word32 seedASz, + const byte* seedB, word32 seedBSz, + const byte* additionalA, word32 additionalASz, + const byte* additionalB, word32 additionalBSz, + byte* output, word32 outputSz, + void* heap, int devId) +{ + int ret = -1; + DRBG_SHA512_internal* drbg; +#ifndef WOLFSSL_SMALL_STACK + DRBG_SHA512_internal drbg_var; +#endif + + if (seedA == NULL || output == NULL) { + return BAD_FUNC_ARG; + } + + if (outputSz != RNG_HEALTH_TEST_CHECK_SIZE_SHA512) { + return ret; + } + +#ifdef WOLFSSL_SMALL_STACK + drbg = (DRBG_SHA512_internal*)XMALLOC(sizeof(DRBG_SHA512_internal), heap, + DYNAMIC_TYPE_RNG); + if (drbg == NULL) { + return MEMORY_E; + } +#else + drbg = &drbg_var; +#endif + + /* SP 800-90A Sec 10.1.1.2: personalization string is concatenated + * with entropy during instantiation via Hash_df. */ + ret = Hash512_DRBG_Instantiate(drbg, seedA, seedASz, nonce, nonceSz, + persoString, persoStringSz, heap, devId); + if (ret != 0) { + goto exit_sha512_ex; + } + + if (reseed) { + if (seedB != NULL && seedBSz > 0) { + ret = Hash512_DRBG_Reseed(drbg, seedB, seedBSz, NULL, 0); + if (ret != 0) goto exit_sha512_ex; + } + } + + /* First generate (output discarded per NIST procedure) */ + ret = Hash512_DRBG_Generate(drbg, output, outputSz, + additionalA, additionalASz); + if (ret != 0) goto exit_sha512_ex; + + /* Second generate (this is the actual output) */ + ret = Hash512_DRBG_Generate(drbg, output, outputSz, + additionalB, additionalBSz); + +exit_sha512_ex: + (void)Hash512_DRBG_Uninstantiate(drbg); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(drbg, heap, DYNAMIC_TYPE_RNG); +#endif + + return (ret == DRBG_SUCCESS) ? 0 : -1; +} + + +/* Simple API matching wc_RNG_HealthTest() pattern - entropy+nonce only */ +int wc_RNG_HealthTest_SHA512(int reseed, + const byte* seedA, word32 seedASz, + const byte* seedB, word32 seedBSz, + byte* output, word32 outputSz) +{ + int ret = -1; + DRBG_SHA512_internal* drbg; +#ifndef WOLFSSL_SMALL_STACK + DRBG_SHA512_internal drbg_var; +#endif + +#ifdef WOLFSSL_SMALL_STACK + drbg = (DRBG_SHA512_internal*)XMALLOC(sizeof(DRBG_SHA512_internal), NULL, + DYNAMIC_TYPE_RNG); + if (drbg == NULL) { + return MEMORY_E; + } +#else + drbg = &drbg_var; +#endif + +#ifdef WOLFSSL_SMALL_STACK_CACHE + ret = Hash512_DRBG_Instantiate(drbg, + NULL /* seed */, 0, NULL /* nonce */, 0, + NULL, 0, NULL, INVALID_DEVID); + if (ret == 0) +#endif + { + ret = wc_RNG_HealthTest_SHA512_ex_internal( + drbg, reseed, NULL, 0, NULL, 0, + seedA, seedASz, seedB, seedBSz, + NULL, 0, NULL, 0, + output, outputSz, NULL, INVALID_DEVID); +#ifdef WOLFSSL_SMALL_STACK_CACHE + Hash512_DRBG_Uninstantiate(drbg); +#endif + } + WC_FREE_VAR_EX(drbg, NULL, DYNAMIC_TYPE_RNG); + + return ret; +} + +#endif /* WOLFSSL_DRBG_SHA512 */ + +#ifndef NO_SHA256 +/* Extended SHA-256 Hash_DRBG health test per SP 800-90A. + * Supports flexible output sizes, prediction resistance, personalization + * strings, and additional input. + * + * predResistance=0: Instantiate(entropyA, nonce, perso) -> + * Reseed(entropyB, additionalReseed) -> + * Gen1(additionalA, discard) -> Gen2(additionalB, keep) + * predResistance=1: Instantiate(entropyA, nonce, perso) -> + * Reseed(entropyB, additionalA)+Gen1(NULL, discard) -> + * Reseed(entropyC, additionalB)+Gen2(NULL, keep) + */ +int wc_RNG_HealthTest_SHA256_ex( + int predResistance, + const byte* nonce, word32 nonceSz, + const byte* persoString, word32 persoStringSz, + const byte* entropyA, word32 entropyASz, + const byte* entropyB, word32 entropyBSz, + const byte* entropyC, word32 entropyCsz, + const byte* additionalA, word32 additionalASz, + const byte* additionalB, word32 additionalBSz, + const byte* additionalReseed, word32 additionalReseedSz, + byte* output, word32 outputSz, + void* heap, int devId) +{ + int ret; + DRBG_internal* drbg; +#ifndef WOLFSSL_SMALL_STACK + DRBG_internal drbg_var; +#endif + + if (entropyA == NULL || output == NULL || outputSz == 0) { + return BAD_FUNC_ARG; + } + +#ifdef WOLFSSL_SMALL_STACK + drbg = (DRBG_internal*)XMALLOC(sizeof(DRBG_internal), heap, + DYNAMIC_TYPE_RNG); + if (drbg == NULL) { + return MEMORY_E; + } +#else + drbg = &drbg_var; +#endif + + /* Instantiate with entropy, nonce, personalization string */ + ret = Hash_DRBG_Instantiate(drbg, entropyA, entropyASz, nonce, nonceSz, + persoString, persoStringSz, heap, devId); + if (ret != 0) goto exit_sha256_ex; + + if (predResistance) { + /* Prediction resistance mode per SP 800-90A 9.3.1: + * additional_input is passed to Reseed, Generate gets NULL */ + + /* Reseed 1 with additionalA, then Generate 1 with NULL (discard) */ + if (entropyB != NULL && entropyBSz > 0) { + ret = Hash_DRBG_Reseed(drbg, entropyB, entropyBSz, + additionalA, additionalASz); + if (ret != 0) goto exit_sha256_ex; + } + ret = Hash_DRBG_Generate(drbg, output, outputSz, NULL, 0); + if (ret != 0) goto exit_sha256_ex; + + /* Reseed 2 with additionalB, then Generate 2 with NULL (keep) */ + if (entropyC != NULL && entropyCsz > 0) { + ret = Hash_DRBG_Reseed(drbg, entropyC, entropyCsz, + additionalB, additionalBSz); + if (ret != 0) goto exit_sha256_ex; + } + ret = Hash_DRBG_Generate(drbg, output, outputSz, NULL, 0); + } + else { + /* Standard mode: explicit reseed, then two generates */ + if (entropyB != NULL && entropyBSz > 0) { + ret = Hash_DRBG_Reseed(drbg, entropyB, entropyBSz, + additionalReseed, additionalReseedSz); + if (ret != 0) goto exit_sha256_ex; + } + + /* Generate 1 (output discarded per NIST DRBGVS procedure) */ + ret = Hash_DRBG_Generate(drbg, output, outputSz, + additionalA, additionalASz); + if (ret != 0) goto exit_sha256_ex; + + /* Generate 2 (this is the actual test output) */ + ret = Hash_DRBG_Generate(drbg, output, outputSz, + additionalB, additionalBSz); + } + +exit_sha256_ex: + (void)Hash_DRBG_Uninstantiate(drbg); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(drbg, heap, DYNAMIC_TYPE_RNG); +#endif return ret; } +#endif /* !NO_SHA256 */ + + +#ifdef WOLFSSL_DRBG_SHA512 +/* Extended SHA-512 Hash_DRBG health test per SP 800-90A. + * Supports flexible output sizes and prediction resistance mode. + * + * Per SP 800-90A Section 9.3.1, when prediction resistance is requested, + * the additional_input is consumed by the Reseed step and the subsequent + * Generate uses NULL additional_input. + * + * predResistance=0: Instantiate -> + * Reseed(entropyB, additionalReseed) -> + * Gen1(additionalA, discard) -> Gen2(additionalB, keep) + * predResistance=1: Instantiate -> + * Reseed(entropyB, additionalA)+Gen1(NULL, discard) -> + * Reseed(entropyC, additionalB)+Gen2(NULL, keep) + */ +int wc_RNG_HealthTest_SHA512_ex2( + int predResistance, + const byte* nonce, word32 nonceSz, + const byte* persoString, word32 persoStringSz, + const byte* entropyA, word32 entropyASz, + const byte* entropyB, word32 entropyBSz, + const byte* entropyC, word32 entropyCsz, + const byte* additionalA, word32 additionalASz, + const byte* additionalB, word32 additionalBSz, + const byte* additionalReseed, word32 additionalReseedSz, + byte* output, word32 outputSz, + void* heap, int devId) +{ + int ret; + DRBG_SHA512_internal* drbg; +#ifndef WOLFSSL_SMALL_STACK + DRBG_SHA512_internal drbg_var; +#endif + + if (entropyA == NULL || output == NULL || outputSz == 0) { + return BAD_FUNC_ARG; + } + +#ifdef WOLFSSL_SMALL_STACK + drbg = (DRBG_SHA512_internal*)XMALLOC(sizeof(DRBG_SHA512_internal), heap, + DYNAMIC_TYPE_RNG); + if (drbg == NULL) { + return MEMORY_E; + } +#else + drbg = &drbg_var; +#endif + + /* Instantiate with entropy, nonce, personalization string */ + ret = Hash512_DRBG_Instantiate(drbg, entropyA, entropyASz, nonce, nonceSz, + persoString, persoStringSz, heap, devId); + if (ret != 0) goto exit_sha512_ex2; + + if (predResistance) { + /* Prediction resistance mode per SP 800-90A 9.3.1: + * additional_input is passed to Reseed, Generate gets NULL */ + + /* Reseed 1 with additionalA, then Generate 1 with NULL (discard) */ + if (entropyB != NULL && entropyBSz > 0) { + ret = Hash512_DRBG_Reseed(drbg, entropyB, entropyBSz, + additionalA, additionalASz); + if (ret != 0) goto exit_sha512_ex2; + } + ret = Hash512_DRBG_Generate(drbg, output, outputSz, NULL, 0); + if (ret != 0) goto exit_sha512_ex2; + + /* Reseed 2 with additionalB, then Generate 2 with NULL (keep) */ + if (entropyC != NULL && entropyCsz > 0) { + ret = Hash512_DRBG_Reseed(drbg, entropyC, entropyCsz, + additionalB, additionalBSz); + if (ret != 0) goto exit_sha512_ex2; + } + ret = Hash512_DRBG_Generate(drbg, output, outputSz, NULL, 0); + } + else { + /* Standard mode: explicit reseed, then two generates */ + if (entropyB != NULL && entropyBSz > 0) { + ret = Hash512_DRBG_Reseed(drbg, entropyB, entropyBSz, + additionalReseed, additionalReseedSz); + if (ret != 0) goto exit_sha512_ex2; + } + + /* Generate 1 (output discarded per NIST DRBGVS procedure) */ + ret = Hash512_DRBG_Generate(drbg, output, outputSz, + additionalA, additionalASz); + if (ret != 0) goto exit_sha512_ex2; + + /* Generate 2 (this is the actual test output) */ + ret = Hash512_DRBG_Generate(drbg, output, outputSz, + additionalB, additionalBSz); + } + +exit_sha512_ex2: + (void)Hash512_DRBG_Uninstantiate(drbg); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(drbg, heap, DYNAMIC_TYPE_RNG); +#endif + + return (ret == DRBG_SUCCESS) ? 0 : -1; +} + +#endif /* WOLFSSL_DRBG_SHA512 */ #endif /* HAVE_HASHDRBG */ diff --git a/wolfcrypt/src/rng_bank.c b/wolfcrypt/src/rng_bank.c index fe87d86539b..17e5576bc66 100644 --- a/wolfcrypt/src/rng_bank.c +++ b/wolfcrypt/src/rng_bank.c @@ -26,6 +26,33 @@ #include #include +/* Helper to get reseedCtr from the active DRBG, regardless of SHA-256/SHA-512 */ +#ifdef WOLFSSL_DRBG_SHA512 + #define WC_RNG_BANK_RESEED_CTR(rng_ptr) \ + (((rng_ptr)->drbgType == WC_DRBG_SHA512) \ + ? ((struct DRBG_SHA512_internal *)(rng_ptr)->drbg512)->reseedCtr \ + : ((struct DRBG_internal *)(rng_ptr)->drbg)->reseedCtr) + #define WC_RNG_BANK_SET_RESEED_CTR(rng_ptr, val) \ + do { \ + if ((rng_ptr)->drbgType == WC_DRBG_SHA512) \ + ((struct DRBG_SHA512_internal *)(rng_ptr)->drbg512)->reseedCtr \ + = (val); \ + else \ + ((struct DRBG_internal *)(rng_ptr)->drbg)->reseedCtr = (val); \ + } while (0) + #define WC_RNG_BANK_DRBG_NULL(rng_ptr) \ + ((rng_ptr)->drbg == NULL && (rng_ptr)->drbg512 == NULL) +#else + #define WC_RNG_BANK_RESEED_CTR(rng_ptr) \ + (((struct DRBG_internal *)(rng_ptr)->drbg)->reseedCtr) + #define WC_RNG_BANK_SET_RESEED_CTR(rng_ptr, val) \ + do { \ + ((struct DRBG_internal *)(rng_ptr)->drbg)->reseedCtr = (val); \ + } while (0) + #define WC_RNG_BANK_DRBG_NULL(rng_ptr) \ + ((rng_ptr)->drbg == NULL) +#endif + WOLFSSL_API int wc_rng_bank_init( struct wc_rng_bank *ctx, int n_rngs, @@ -343,7 +370,7 @@ WOLFSSL_API int wc_rng_bank_checkout( *rng_inst = &bank->rngs[preferred_inst_offset]; if ((! (flags & WC_RNG_BANK_FLAG_CAN_WAIT)) && - (((struct DRBG_internal *)(*rng_inst)->rng.drbg)->reseedCtr >= + (WC_RNG_BANK_RESEED_CTR(&(*rng_inst)->rng) >= WC_RESEED_INTERVAL) && (flags & WC_RNG_BANK_FLAG_CAN_FAIL_OVER_INST) && (n_rngs_tried < bank->n_rngs)) @@ -353,7 +380,7 @@ WOLFSSL_API int wc_rng_bank_checkout( else { #ifdef WC_VERBOSE_RNG if ((! (flags & WC_RNG_BANK_FLAG_CAN_WAIT)) && - (((struct DRBG_internal *)(*rng_inst)->rng.drbg)->reseedCtr >= + (WC_RNG_BANK_RESEED_CTR(&(*rng_inst)->rng) >= WC_RESEED_INTERVAL)) { WOLFSSL_DEBUG_PRINTF( @@ -484,7 +511,7 @@ WOLFSSL_API int wc_rng_bank_inst_reinit( int devId; if ((rng_inst == NULL) || - (rng_inst->rng.drbg == NULL)) + WC_RNG_BANK_DRBG_NULL(&rng_inst->rng)) { return BAD_FUNC_ARG; } @@ -561,7 +588,7 @@ WOLFSSL_API int wc_rng_bank_seed(struct wc_rng_bank *bank, #endif break; } - else if (drbg->rng.drbg == NULL) { + else if (WC_RNG_BANK_DRBG_NULL(&drbg->rng)) { #ifdef WC_VERBOSE_RNG WOLFSSL_DEBUG_PRINTF( "WARNING: wc_rng_bank_seed(): inst#%d has null .drbg.\n", n); @@ -612,8 +639,7 @@ WOLFSSL_API int wc_rng_bank_reseed(struct wc_rng_bank *bank, if (ret != 0) return ret; - ((struct DRBG_internal *)drbg->rng.drbg)->reseedCtr = - WC_RESEED_INTERVAL; + WC_RNG_BANK_SET_RESEED_CTR(&drbg->rng, WC_RESEED_INTERVAL); if (flags & WC_RNG_BANK_FLAG_CAN_WAIT) { byte scratch[4]; diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c index 3a12311eff6..a0de108b0d3 100644 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -1054,6 +1054,47 @@ static int RsaMGF1(enum wc_HashType hType, byte* seed, word32 seedSz, } #endif /* SHA2 Hashes */ +#if defined(WOLFSSL_SHA3) && \ + (defined(WOLFSSL_SHAKE128) || defined(WOLFSSL_SHAKE256)) +/* SHAKE XOF used directly as mask generation function (not MGF1). + * Per FIPS 186-5, SHAKE can be used as the MGF for RSA-PSS. */ +static int RsaMGF_SHAKE(enum wc_HashType shakeType, byte* seed, word32 seedSz, + byte* out, word32 outSz, void* heap) +{ + wc_Shake shake; + int ret; + + (void)heap; + (void)shakeType; + +#ifdef WOLFSSL_SHAKE128 + if (shakeType == WC_HASH_TYPE_SHAKE128) + ret = wc_InitShake128(&shake, heap, INVALID_DEVID); + else +#endif + ret = wc_InitShake256(&shake, heap, INVALID_DEVID); + + if (ret == 0) { +#ifdef WOLFSSL_SHAKE128 + if (shakeType == WC_HASH_TYPE_SHAKE128) { + ret = wc_Shake128_Update(&shake, seed, seedSz); + if (ret == 0) + ret = wc_Shake128_Final(&shake, out, outSz); + wc_Shake128_Free(&shake); + } + else +#endif + { + ret = wc_Shake256_Update(&shake, seed, seedSz); + if (ret == 0) + ret = wc_Shake256_Final(&shake, out, outSz); + wc_Shake256_Free(&shake); + } + } + return ret; +} +#endif /* WOLFSSL_SHA3 && (WOLFSSL_SHAKE128 || WOLFSSL_SHAKE256) */ + /* helper function to direct which mask generation function is used switched on type input */ @@ -1099,6 +1140,52 @@ static int RsaMGF(int type, byte* seed, word32 seedSz, byte* out, heap); break; #endif + #endif + #ifdef WOLFSSL_SHA3 + #ifndef WOLFSSL_NOSHA3_224 + case WC_MGF1SHA3_224: + ret = RsaMGF1(WC_HASH_TYPE_SHA3_224, seed, seedSz, out, outSz, + heap); + break; + #endif + #ifndef WOLFSSL_NOSHA3_256 + case WC_MGF1SHA3_256: + ret = RsaMGF1(WC_HASH_TYPE_SHA3_256, seed, seedSz, out, outSz, + heap); + break; + #endif + #ifndef WOLFSSL_NOSHA3_384 + case WC_MGF1SHA3_384: + ret = RsaMGF1(WC_HASH_TYPE_SHA3_384, seed, seedSz, out, outSz, + heap); + break; + #endif + #ifndef WOLFSSL_NOSHA3_512 + case WC_MGF1SHA3_512: + ret = RsaMGF1(WC_HASH_TYPE_SHA3_512, seed, seedSz, out, outSz, + heap); + break; + #endif + #endif /* WOLFSSL_SHA3 */ + #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128) + case WC_MGF1SHAKE128: + ret = RsaMGF1(WC_HASH_TYPE_SHAKE128, seed, seedSz, out, outSz, + heap); + break; + case WC_MGFSHAKE128: + ret = RsaMGF_SHAKE(WC_HASH_TYPE_SHAKE128, seed, seedSz, out, outSz, + heap); + break; + #endif + #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256) + case WC_MGF1SHAKE256: + ret = RsaMGF1(WC_HASH_TYPE_SHAKE256, seed, seedSz, out, outSz, + heap); + break; + case WC_MGFSHAKE256: + ret = RsaMGF_SHAKE(WC_HASH_TYPE_SHAKE256, seed, seedSz, out, outSz, + heap); + break; #endif default: WOLFSSL_MSG("Unknown MGF type: check build options"); @@ -2035,9 +2122,29 @@ int wc_hash2mgf(enum wc_HashType hType) case WC_HASH_TYPE_SHA512_256: #endif case WC_HASH_TYPE_SHA3_224: +#if defined(WOLFSSL_SHA3) && !defined(WOLFSSL_NOSHA3_224) + return WC_MGF1SHA3_224; +#else + break; +#endif case WC_HASH_TYPE_SHA3_256: +#if defined(WOLFSSL_SHA3) && !defined(WOLFSSL_NOSHA3_256) + return WC_MGF1SHA3_256; +#else + break; +#endif case WC_HASH_TYPE_SHA3_384: +#if defined(WOLFSSL_SHA3) && !defined(WOLFSSL_NOSHA3_384) + return WC_MGF1SHA3_384; +#else + break; +#endif case WC_HASH_TYPE_SHA3_512: +#if defined(WOLFSSL_SHA3) && !defined(WOLFSSL_NOSHA3_512) + return WC_MGF1SHA3_512; +#else + break; +#endif case WC_HASH_TYPE_BLAKE2B: case WC_HASH_TYPE_BLAKE2S: #ifdef WOLFSSL_SM3 @@ -2045,9 +2152,11 @@ int wc_hash2mgf(enum wc_HashType hType) #endif #ifdef WOLFSSL_SHAKE128 case WC_HASH_TYPE_SHAKE128: + return WC_MGF1SHAKE128; #endif #ifdef WOLFSSL_SHAKE256 case WC_HASH_TYPE_SHAKE256: + return WC_MGF1SHAKE256; #endif default: break; diff --git a/wolfcrypt/src/wc_lms.c b/wolfcrypt/src/wc_lms.c index 7035060621c..f89e7ea5471 100644 --- a/wolfcrypt/src/wc_lms.c +++ b/wolfcrypt/src/wc_lms.c @@ -22,6 +22,11 @@ #include #if defined(WOLFSSL_HAVE_LMS) && defined(WOLFSSL_WC_LMS) + +#if FIPS_VERSION3_GE(2,0,0) + /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */ + #define FIPS_NO_WRAPPERS +#endif #include #ifdef NO_INLINE @@ -109,6 +114,19 @@ static int wc_lmskey_state_init(LmsState* state, const LmsParams* params) /* Keep a reference to the parameters for use in operations. */ state->params = params; +#ifdef WOLFSSL_LMS_SHAKE256 + if (LMS_IS_SHAKE(params->lmOtsType)) { + ret = wc_InitShake256(&state->shake, NULL, INVALID_DEVID); + if (ret == 0) { + ret = wc_InitShake256(&state->shake_k, NULL, INVALID_DEVID); + if (ret != 0) { + wc_Shake256_Free(&state->shake); + } + } + return ret; + } +#endif + /* Initialize the two hash algorithms. */ ret = wc_InitSha256(&state->hash); if (ret == 0) { @@ -127,6 +145,13 @@ static int wc_lmskey_state_init(LmsState* state, const LmsParams* params) */ static void wc_lmskey_state_free(LmsState* state) { +#ifdef WOLFSSL_LMS_SHAKE256 + if (LMS_IS_SHAKE(state->params->lmOtsType)) { + wc_Shake256_Free(&state->shake_k); + wc_Shake256_Free(&state->shake); + return; + } +#endif wc_Sha256Free(&state->hash_k); wc_Sha256Free(&state->hash); } @@ -276,6 +301,35 @@ static const wc_LmsParamsMap wc_lms_map[] = { WC_SHA256_DIGEST_SIZE) }, #endif #endif +#if LMS_MAX_HEIGHT >= 25 + { WC_LMS_PARM_L1_H25_W1 , "LMS/HSS_L1_H25_W1", + LMS_PARAMS(1, 25, 1, 1, LMS_SHA256_M32_H25, LMOTS_SHA256_N32_W1, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_L1_H25_W2 , "LMS/HSS_L1_H25_W2", + LMS_PARAMS(1, 25, 2, 1, LMS_SHA256_M32_H25, LMOTS_SHA256_N32_W2, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_L1_H25_W4 , "LMS/HSS_L1_H25_W4", + LMS_PARAMS(1, 25, 4, 2, LMS_SHA256_M32_H25, LMOTS_SHA256_N32_W4, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_L1_H25_W8 , "LMS/HSS_L1_H25_W8", + LMS_PARAMS(1, 25, 8, 3, LMS_SHA256_M32_H25, LMOTS_SHA256_N32_W8, + WC_SHA256_DIGEST_SIZE) }, +#endif +#if LMS_MAX_HEIGHT >= 10 + { WC_LMS_PARM_L1_H10_W1 , "LMS/HSS_L1_H10_W1", + LMS_PARAMS(1, 10, 1, 1, LMS_SHA256_M32_H10, LMOTS_SHA256_N32_W1, + WC_SHA256_DIGEST_SIZE) }, +#endif +#if LMS_MAX_HEIGHT >= 15 + { WC_LMS_PARM_L1_H15_W1 , "LMS/HSS_L1_H15_W1", + LMS_PARAMS(1, 15, 1, 1, LMS_SHA256_M32_H15, LMOTS_SHA256_N32_W1, + WC_SHA256_DIGEST_SIZE) }, +#endif +#if LMS_MAX_HEIGHT >= 20 + { WC_LMS_PARM_L1_H20_W1 , "LMS/HSS_L1_H20_W1", + LMS_PARAMS(1, 20, 1, 1, LMS_SHA256_M32_H20, LMOTS_SHA256_N32_W1, + WC_SHA256_DIGEST_SIZE) }, +#endif #endif /* !WOLFSSL_NO_LMS_SHA256_256 */ #ifdef WOLFSSL_LMS_SHA256_192 @@ -356,7 +410,193 @@ static const wc_LmsParamsMap wc_lms_map[] = { LMS_PARAMS(1, 20, 8, 4, LMS_SHA256_M24_H20, LMOTS_SHA256_N24_W8, WC_SHA256_192_DIGEST_SIZE) }, #endif +#if LMS_MAX_HEIGHT >= 25 + { WC_LMS_PARM_SHA256_192_L1_H25_W1 , "LMS/HSS_SHA256/192_L1_H25_W1", + LMS_PARAMS(1, 25, 1, 2, LMS_SHA256_M24_H25, LMOTS_SHA256_N24_W1, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHA256_192_L1_H25_W2 , "LMS/HSS_SHA256/192_L1_H25_W2", + LMS_PARAMS(1, 25, 2, 2, LMS_SHA256_M24_H25, LMOTS_SHA256_N24_W2, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHA256_192_L1_H25_W4 , "LMS/HSS_SHA256/192_L1_H25_W4", + LMS_PARAMS(1, 25, 4, 3, LMS_SHA256_M24_H25, LMOTS_SHA256_N24_W4, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHA256_192_L1_H25_W8 , "LMS/HSS_SHA256/192_L1_H25_W8", + LMS_PARAMS(1, 25, 8, 4, LMS_SHA256_M24_H25, LMOTS_SHA256_N24_W8, + WC_SHA256_192_DIGEST_SIZE) }, +#endif +#if LMS_MAX_HEIGHT >= 10 + { WC_LMS_PARM_SHA256_192_L1_H10_W1 , "LMS/HSS_SHA256/192_L1_H10_W1", + LMS_PARAMS(1, 10, 1, 2, LMS_SHA256_M24_H10, LMOTS_SHA256_N24_W1, + WC_SHA256_192_DIGEST_SIZE) }, +#endif +#if LMS_MAX_HEIGHT >= 15 + { WC_LMS_PARM_SHA256_192_L1_H15_W1 , "LMS/HSS_SHA256/192_L1_H15_W1", + LMS_PARAMS(1, 15, 1, 2, LMS_SHA256_M24_H15, LMOTS_SHA256_N24_W1, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHA256_192_L1_H15_W8 , "LMS/HSS_SHA256/192_L1_H15_W8", + LMS_PARAMS(1, 15, 8, 4, LMS_SHA256_M24_H15, LMOTS_SHA256_N24_W8, + WC_SHA256_192_DIGEST_SIZE) }, +#endif +#if LMS_MAX_HEIGHT >= 20 + { WC_LMS_PARM_SHA256_192_L1_H20_W1 , "LMS/HSS_SHA256/192_L1_H20_W1", + LMS_PARAMS(1, 20, 1, 2, LMS_SHA256_M24_H20, LMOTS_SHA256_N24_W1, + WC_SHA256_192_DIGEST_SIZE) }, +#endif #endif /* WOLFSSL_LMS_SHA256_192 */ + +#ifdef WOLFSSL_LMS_SHAKE256 +#ifndef WOLFSSL_NO_LMS_SHAKE256_256 + /* SHAKE256/256 L1 H5 */ + { WC_LMS_PARM_SHAKE_L1_H5_W1 , "LMS/HSS_SHAKE256/256_L1_H5_W1", + LMS_PARAMS(1, 5, 1, 1, LMS_SHAKE_M32_H5 , LMOTS_SHAKE_N32_W1, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H5_W2 , "LMS/HSS_SHAKE256/256_L1_H5_W2", + LMS_PARAMS(1, 5, 2, 1, LMS_SHAKE_M32_H5 , LMOTS_SHAKE_N32_W2, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H5_W4 , "LMS/HSS_SHAKE256/256_L1_H5_W4", + LMS_PARAMS(1, 5, 4, 2, LMS_SHAKE_M32_H5 , LMOTS_SHAKE_N32_W4, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H5_W8 , "LMS/HSS_SHAKE256/256_L1_H5_W8", + LMS_PARAMS(1, 5, 8, 3, LMS_SHAKE_M32_H5 , LMOTS_SHAKE_N32_W8, + WC_SHA256_DIGEST_SIZE) }, +#if LMS_MAX_HEIGHT >= 10 + /* SHAKE256/256 L1 H10 */ + { WC_LMS_PARM_SHAKE_L1_H10_W1 , "LMS/HSS_SHAKE256/256_L1_H10_W1", + LMS_PARAMS(1, 10, 1, 1, LMS_SHAKE_M32_H10, LMOTS_SHAKE_N32_W1, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H10_W2 , "LMS/HSS_SHAKE256/256_L1_H10_W2", + LMS_PARAMS(1, 10, 2, 1, LMS_SHAKE_M32_H10, LMOTS_SHAKE_N32_W2, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H10_W4 , "LMS/HSS_SHAKE256/256_L1_H10_W4", + LMS_PARAMS(1, 10, 4, 2, LMS_SHAKE_M32_H10, LMOTS_SHAKE_N32_W4, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H10_W8 , "LMS/HSS_SHAKE256/256_L1_H10_W8", + LMS_PARAMS(1, 10, 8, 3, LMS_SHAKE_M32_H10, LMOTS_SHAKE_N32_W8, + WC_SHA256_DIGEST_SIZE) }, +#endif +#if LMS_MAX_HEIGHT >= 15 + /* SHAKE256/256 L1 H15 */ + { WC_LMS_PARM_SHAKE_L1_H15_W1 , "LMS/HSS_SHAKE256/256_L1_H15_W1", + LMS_PARAMS(1, 15, 1, 1, LMS_SHAKE_M32_H15, LMOTS_SHAKE_N32_W1, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H15_W2 , "LMS/HSS_SHAKE256/256_L1_H15_W2", + LMS_PARAMS(1, 15, 2, 1, LMS_SHAKE_M32_H15, LMOTS_SHAKE_N32_W2, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H15_W4 , "LMS/HSS_SHAKE256/256_L1_H15_W4", + LMS_PARAMS(1, 15, 4, 2, LMS_SHAKE_M32_H15, LMOTS_SHAKE_N32_W4, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H15_W8 , "LMS/HSS_SHAKE256/256_L1_H15_W8", + LMS_PARAMS(1, 15, 8, 3, LMS_SHAKE_M32_H15, LMOTS_SHAKE_N32_W8, + WC_SHA256_DIGEST_SIZE) }, +#endif +#if LMS_MAX_HEIGHT >= 20 + /* SHAKE256/256 L1 H20 */ + { WC_LMS_PARM_SHAKE_L1_H20_W1 , "LMS/HSS_SHAKE256/256_L1_H20_W1", + LMS_PARAMS(1, 20, 1, 1, LMS_SHAKE_M32_H20, LMOTS_SHAKE_N32_W1, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H20_W2 , "LMS/HSS_SHAKE256/256_L1_H20_W2", + LMS_PARAMS(1, 20, 2, 1, LMS_SHAKE_M32_H20, LMOTS_SHAKE_N32_W2, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H20_W4 , "LMS/HSS_SHAKE256/256_L1_H20_W4", + LMS_PARAMS(1, 20, 4, 2, LMS_SHAKE_M32_H20, LMOTS_SHAKE_N32_W4, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H20_W8 , "LMS/HSS_SHAKE256/256_L1_H20_W8", + LMS_PARAMS(1, 20, 8, 3, LMS_SHAKE_M32_H20, LMOTS_SHAKE_N32_W8, + WC_SHA256_DIGEST_SIZE) }, +#endif +#if LMS_MAX_HEIGHT >= 25 + /* SHAKE256/256 L1 H25 */ + { WC_LMS_PARM_SHAKE_L1_H25_W1 , "LMS/HSS_SHAKE256/256_L1_H25_W1", + LMS_PARAMS(1, 25, 1, 1, LMS_SHAKE_M32_H25, LMOTS_SHAKE_N32_W1, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H25_W2 , "LMS/HSS_SHAKE256/256_L1_H25_W2", + LMS_PARAMS(1, 25, 2, 1, LMS_SHAKE_M32_H25, LMOTS_SHAKE_N32_W2, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H25_W4 , "LMS/HSS_SHAKE256/256_L1_H25_W4", + LMS_PARAMS(1, 25, 4, 2, LMS_SHAKE_M32_H25, LMOTS_SHAKE_N32_W4, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H25_W8 , "LMS/HSS_SHAKE256/256_L1_H25_W8", + LMS_PARAMS(1, 25, 8, 3, LMS_SHAKE_M32_H25, LMOTS_SHAKE_N32_W8, + WC_SHA256_DIGEST_SIZE) }, +#endif +#endif /* !WOLFSSL_NO_LMS_SHAKE256_256 */ + +#ifdef WOLFSSL_LMS_SHAKE256 + /* SHAKE256/192 L1 H5 */ + { WC_LMS_PARM_SHAKE192_L1_H5_W1 , "LMS/HSS_SHAKE256/192_L1_H5_W1", + LMS_PARAMS(1, 5, 1, 2, LMS_SHAKE_M24_H5 , LMOTS_SHAKE_N24_W1, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H5_W2 , "LMS/HSS_SHAKE256/192_L1_H5_W2", + LMS_PARAMS(1, 5, 2, 2, LMS_SHAKE_M24_H5 , LMOTS_SHAKE_N24_W2, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H5_W4 , "LMS/HSS_SHAKE256/192_L1_H5_W4", + LMS_PARAMS(1, 5, 4, 3, LMS_SHAKE_M24_H5 , LMOTS_SHAKE_N24_W4, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H5_W8 , "LMS/HSS_SHAKE256/192_L1_H5_W8", + LMS_PARAMS(1, 5, 8, 4, LMS_SHAKE_M24_H5 , LMOTS_SHAKE_N24_W8, + WC_SHA256_192_DIGEST_SIZE) }, +#if LMS_MAX_HEIGHT >= 10 + /* SHAKE256/192 L1 H10 */ + { WC_LMS_PARM_SHAKE192_L1_H10_W1 , "LMS/HSS_SHAKE256/192_L1_H10_W1", + LMS_PARAMS(1, 10, 1, 2, LMS_SHAKE_M24_H10, LMOTS_SHAKE_N24_W1, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H10_W2 , "LMS/HSS_SHAKE256/192_L1_H10_W2", + LMS_PARAMS(1, 10, 2, 2, LMS_SHAKE_M24_H10, LMOTS_SHAKE_N24_W2, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H10_W4 , "LMS/HSS_SHAKE256/192_L1_H10_W4", + LMS_PARAMS(1, 10, 4, 3, LMS_SHAKE_M24_H10, LMOTS_SHAKE_N24_W4, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H10_W8 , "LMS/HSS_SHAKE256/192_L1_H10_W8", + LMS_PARAMS(1, 10, 8, 4, LMS_SHAKE_M24_H10, LMOTS_SHAKE_N24_W8, + WC_SHA256_192_DIGEST_SIZE) }, +#endif +#if LMS_MAX_HEIGHT >= 15 + /* SHAKE256/192 L1 H15 */ + { WC_LMS_PARM_SHAKE192_L1_H15_W1 , "LMS/HSS_SHAKE256/192_L1_H15_W1", + LMS_PARAMS(1, 15, 1, 2, LMS_SHAKE_M24_H15, LMOTS_SHAKE_N24_W1, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H15_W2 , "LMS/HSS_SHAKE256/192_L1_H15_W2", + LMS_PARAMS(1, 15, 2, 2, LMS_SHAKE_M24_H15, LMOTS_SHAKE_N24_W2, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H15_W4 , "LMS/HSS_SHAKE256/192_L1_H15_W4", + LMS_PARAMS(1, 15, 4, 3, LMS_SHAKE_M24_H15, LMOTS_SHAKE_N24_W4, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H15_W8 , "LMS/HSS_SHAKE256/192_L1_H15_W8", + LMS_PARAMS(1, 15, 8, 4, LMS_SHAKE_M24_H15, LMOTS_SHAKE_N24_W8, + WC_SHA256_192_DIGEST_SIZE) }, +#endif +#if LMS_MAX_HEIGHT >= 20 + /* SHAKE256/192 L1 H20 */ + { WC_LMS_PARM_SHAKE192_L1_H20_W1 , "LMS/HSS_SHAKE256/192_L1_H20_W1", + LMS_PARAMS(1, 20, 1, 2, LMS_SHAKE_M24_H20, LMOTS_SHAKE_N24_W1, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H20_W2 , "LMS/HSS_SHAKE256/192_L1_H20_W2", + LMS_PARAMS(1, 20, 2, 2, LMS_SHAKE_M24_H20, LMOTS_SHAKE_N24_W2, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H20_W4 , "LMS/HSS_SHAKE256/192_L1_H20_W4", + LMS_PARAMS(1, 20, 4, 3, LMS_SHAKE_M24_H20, LMOTS_SHAKE_N24_W4, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H20_W8 , "LMS/HSS_SHAKE256/192_L1_H20_W8", + LMS_PARAMS(1, 20, 8, 4, LMS_SHAKE_M24_H20, LMOTS_SHAKE_N24_W8, + WC_SHA256_192_DIGEST_SIZE) }, +#endif +#if LMS_MAX_HEIGHT >= 25 + /* SHAKE256/192 L1 H25 */ + { WC_LMS_PARM_SHAKE192_L1_H25_W1 , "LMS/HSS_SHAKE256/192_L1_H25_W1", + LMS_PARAMS(1, 25, 1, 2, LMS_SHAKE_M24_H25, LMOTS_SHAKE_N24_W1, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H25_W2 , "LMS/HSS_SHAKE256/192_L1_H25_W2", + LMS_PARAMS(1, 25, 2, 2, LMS_SHAKE_M24_H25, LMOTS_SHAKE_N24_W2, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H25_W4 , "LMS/HSS_SHAKE256/192_L1_H25_W4", + LMS_PARAMS(1, 25, 4, 3, LMS_SHAKE_M24_H25, LMOTS_SHAKE_N24_W4, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H25_W8 , "LMS/HSS_SHAKE256/192_L1_H25_W8", + LMS_PARAMS(1, 25, 8, 4, LMS_SHAKE_M24_H25, LMOTS_SHAKE_N24_W8, + WC_SHA256_192_DIGEST_SIZE) }, +#endif +#endif /* WOLFSSL_LMS_SHAKE256 (M24 entries) */ +#endif /* WOLFSSL_LMS_SHAKE256 */ }; /* Number of parameter sets supported. */ #define WC_LMS_MAP_LEN ((int)(sizeof(wc_lms_map) / sizeof(*wc_lms_map))) diff --git a/wolfcrypt/src/wc_lms_impl.c b/wolfcrypt/src/wc_lms_impl.c index 44191dbb33c..d08590ac282 100644 --- a/wolfcrypt/src/wc_lms_impl.c +++ b/wolfcrypt/src/wc_lms_impl.c @@ -594,6 +594,69 @@ static WC_INLINE int wc_lms_hash_sha256_192_final(wc_Sha256* sha256, byte* hash) } #endif /* WOLFSSL_LMS_SHA256_192 */ +#ifdef WOLFSSL_LMS_SHAKE256 +/* Hash data using SHAKE256 and compute result. + * + * @param [in] shake SHAKE256 hash object. + * @param [in] data Data to hash. + * @param [in] len Length of data to hash. + * @param [out] hash Hash output. + * @param [in] hashLen Length of hash output. + * @return 0 on success. + */ +static WC_INLINE int wc_lms_shake256_hash(wc_Shake* shake, byte* data, + word32 len, byte* hash, word32 hashLen) +{ + int ret; + + ret = wc_Shake256_Update(shake, data, len); + if (ret == 0) { + ret = wc_Shake256_Final(shake, hash, hashLen); + } + + return ret; +} + +/* Update hash with first data using SHAKE256. + * + * @param [in] shake SHAKE256 hash object. + * @param [in] data Data to hash. + * @param [in] len Length of data to hash. + * @return 0 on success. + */ +static WC_INLINE int wc_lms_shake256_hash_first(wc_Shake* shake, + const byte* data, word32 len) +{ + return wc_Shake256_Update(shake, data, len); +} + +/* Update hash with further data using SHAKE256. + * + * @param [in] shake SHAKE256 hash object. + * @param [in] data Data to hash. + * @param [in] len Length of data to hash. + * @return 0 on success. + */ +static WC_INLINE int wc_lms_shake256_hash_update(wc_Shake* shake, + const byte* data, word32 len) +{ + return wc_Shake256_Update(shake, data, len); +} + +/* Finalize SHAKE256 hash. + * + * @param [in] shake SHAKE256 hash object. + * @param [out] hash Hash output. + * @param [in] hashLen Length of hash output. + * @return 0 on success. + */ +static WC_INLINE int wc_lms_shake256_hash_final(wc_Shake* shake, byte* hash, + word32 hashLen) +{ + return wc_Shake256_Final(shake, hash, hashLen); +} +#endif /* WOLFSSL_LMS_SHAKE256 */ + /*************************************** * LM-OTS APIs **************************************/ @@ -809,33 +872,59 @@ static int wc_lmots_msg_hash(LmsState* state, const byte* msg, word32 msgSz, /* I || u32str(q) || u16str(D_MESG) */ c16toa(LMS_D_MESG, ip); - /* H(I || u32str(q) || u16str(D_MESG) || ...) */ - ret = wc_lms_hash_first(&state->hash, buffer, LMS_MSG_PRE_LEN); - if (ret == 0) { - /* H(... || C || ...) */ - ret = wc_lms_hash_update(&state->hash, c, state->params->hash_len); - } - if (ret == 0) { - /* H(... || message) */ - ret = wc_lms_hash_update(&state->hash, msg, msgSz); - } -#ifdef WOLFSSL_LMS_SHA256_192 - if ((ret == 0) && - ((state->params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192)) { - /* Q = H(...) */ - ret = wc_lms_hash_sha256_192_final(&state->hash, q); - } - else -#endif -#ifndef WOLFSSL_NO_LMS_SHA256_256 - if (ret == 0) { - /* Q = H(...) */ - ret = wc_lms_hash_final(&state->hash, q); +#ifdef WOLFSSL_LMS_SHAKE256 + if (LMS_IS_SHAKE(state->params->lmOtsType)) { + /* H(I || u32str(q) || u16str(D_MESG) || ...) */ + ret = wc_lms_shake256_hash_first(&state->shake, buffer, + LMS_MSG_PRE_LEN); + if (ret == 0) { + /* H(... || C || ...) */ + ret = wc_lms_shake256_hash_update(&state->shake, c, + state->params->hash_len); + } + if (ret == 0) { + /* H(... || message) */ + ret = wc_lms_shake256_hash_update(&state->shake, msg, msgSz); + } + if (ret == 0) { + /* Q = H(...) */ + ret = wc_lms_shake256_hash_final(&state->shake, q, + state->params->hash_len); + } } else #endif { - ret = NOT_COMPILED_IN; + /* H(I || u32str(q) || u16str(D_MESG) || ...) */ + ret = wc_lms_hash_first(&state->hash, buffer, LMS_MSG_PRE_LEN); + if (ret == 0) { + /* H(... || C || ...) */ + ret = wc_lms_hash_update(&state->hash, c, + state->params->hash_len); + } + if (ret == 0) { + /* H(... || message) */ + ret = wc_lms_hash_update(&state->hash, msg, msgSz); + } + #ifdef WOLFSSL_LMS_SHA256_192 + if ((ret == 0) && + ((state->params->lmOtsType & LMS_HASH_MASK) == + LMS_SHA256_192)) { + /* Q = H(...) */ + ret = wc_lms_hash_sha256_192_final(&state->hash, q); + } + else + #endif + #ifndef WOLFSSL_NO_LMS_SHA256_256 + if (ret == 0) { + /* Q = H(...) */ + ret = wc_lms_hash_final(&state->hash, q); + } + else + #endif + { + ret = NOT_COMPILED_IN; + } } return ret; @@ -896,7 +985,12 @@ static int wc_lmots_compute_y_from_seed(LmsState* state, const byte* seed, params->ls, a); } #ifndef WC_LMS_FULL_HASH - if (ret == 0) { +#ifdef WOLFSSL_LMS_SHAKE256 + if ((ret == 0) && !LMS_IS_SHAKE(params->lmOtsType)) +#else + if (ret == 0) +#endif + { #ifdef WOLFSSL_LMS_SHA256_192 if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { /* Put in padding for final block. */ @@ -921,6 +1015,15 @@ static int wc_lmots_compute_y_from_seed(LmsState* state, const byte* seed, * = H(I || u32str(q) || u16str(i) || u8str(0xff) || SEED). */ c16toa(i, ip); *jp = LMS_D_FIXED; +#ifdef WOLFSSL_LMS_SHAKE256 + if (LMS_IS_SHAKE(params->lmOtsType)) { + XMEMCPY(tmp, seed, params->hash_len); + ret = wc_lms_shake256_hash(&state->shake, buffer, + LMS_HASH_BUFFER_LEN(params->hash_len), tmp, params->hash_len); + } + else +#endif + { #ifndef WC_LMS_FULL_HASH #ifdef WOLFSSL_LMS_SHA256_192 if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { @@ -956,12 +1059,22 @@ static int wc_lmots_compute_y_from_seed(LmsState* state, const byte* seed, #endif } #endif /* !WC_LMS_FULL_HASH */ + } /* Apply the hash function coefficient number of times. */ for (j = 0; (ret == 0) && (j < a[i]); j++) { /* I || u32str(q) || u16str(i) || u8str(j) || tmp */ *jp = j; /* tmp = H(I || u32str(q) || u16str(i) || u8str(j) || tmp) */ + #ifdef WOLFSSL_LMS_SHAKE256 + if (LMS_IS_SHAKE(params->lmOtsType)) { + ret = wc_lms_shake256_hash(&state->shake, buffer, + LMS_HASH_BUFFER_LEN(params->hash_len), tmp, + params->hash_len); + } + else + #endif + { #ifndef WC_LMS_FULL_HASH #ifdef WOLFSSL_LMS_SHA256_192 if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { @@ -993,6 +1106,7 @@ static int wc_lmots_compute_y_from_seed(LmsState* state, const byte* seed, #endif } #endif /* !WC_LMS_FULL_HASH */ + } } if (ret == 0) { @@ -1055,107 +1169,163 @@ static int wc_lmots_compute_kc_from_sig(LmsState* state, const byte* msg, /* I || u32str(q) || u16str(D_PBLC). */ c16toa(LMS_D_PBLC, ip); - /* H(I || u32str(q) || u16str(D_PBLC) || ...). */ - ret = wc_lms_hash_first(&state->hash_k, buffer, LMS_K_PRE_LEN); - if (ret == 0) { - /* Q = H(I || u32str(q) || u16str(D_MESG) || C || message) */ - ret = wc_lmots_msg_hash(state, msg, msgSz, c, q); - } - if (ret == 0) { - /* Calculate checksum list all coefficients. */ - ret = wc_lmots_q_expand(q, (word8)params->hash_len, params->width, - params->ls, a); - } -#ifndef WC_LMS_FULL_HASH - if (ret == 0) { - #ifdef WOLFSSL_LMS_SHA256_192 - if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { - /* Put in padding for final block. */ - LMS_SHA256_SET_LEN_47(buffer); - } - else - #endif - { - #ifndef WOLFSSL_NO_LMS_SHA256_256 - /* Put in padding for final block. */ - LMS_SHA256_SET_LEN_55(buffer); - #endif +#ifdef WOLFSSL_LMS_SHAKE256 + if (LMS_IS_SHAKE(params->lmOtsType)) { + /* H(I || u32str(q) || u16str(D_PBLC) || ...). */ + ret = wc_lms_shake256_hash_first(&state->shake_k, buffer, + LMS_K_PRE_LEN); + if (ret == 0) { + /* Q = H(I || u32str(q) || u16str(D_MESG) || C || message) */ + ret = wc_lmots_msg_hash(state, msg, msgSz, c, q); } - } -#endif /* !WC_LMS_FULL_HASH */ - - /* Compute z for each coefficient. */ - for (i = 0; (ret == 0) && (i < params->p); i++) { - unsigned int j; - - /* I || u32(str) || u16str(i) || ... */ - c16toa(i, ip); + if (ret == 0) { + /* Calculate checksum list all coefficients. */ + ret = wc_lmots_q_expand(q, (word8)params->hash_len, params->width, + params->ls, a); + } + + /* Compute z for each coefficient. */ + for (i = 0; (ret == 0) && (i < params->p); i++) { + unsigned int j; + + /* I || u32(str) || u16str(i) || ... */ + c16toa(i, ip); + + /* tmp = y[i]. + * I || u32(str) || u16str(i) || ... || tmp */ + XMEMCPY(tmp, sig_y, params->hash_len); + sig_y += params->hash_len; + + /* Finish iterations of hash from coefficient to max. */ + for (j = a[i]; (ret == 0) && (j < max); j++) { + /* I || u32str(q) || u16str(i) || u8str(j) || tmp */ + *jp = (word8)j; + /* tmp = H(I || u32str(q) || u16str(i) || u8str(j) || tmp) */ + ret = wc_lms_shake256_hash(&state->shake, buffer, + LMS_HASH_BUFFER_LEN(params->hash_len), tmp, + params->hash_len); + } - /* tmp = y[i]. - * I || u32(str) || u16str(i) || ... || tmp */ - XMEMCPY(tmp, sig_y, params->hash_len); - sig_y += params->hash_len; + if (ret == 0) { + /* H(... || z[i] || ...) (for calculating Kc). */ + ret = wc_lms_shake256_hash_update(&state->shake_k, tmp, + params->hash_len); + } + } - /* Finish iterations of hash from coefficient to max. */ - for (j = a[i]; (ret == 0) && (j < max); j++) { - /* I || u32str(q) || u16str(i) || u8str(j) || tmp */ - *jp = (word8)j; - /* tmp = H(I || u32str(q) || u16str(i) || u8str(j) || tmp) */ - #ifndef WC_LMS_FULL_HASH + if (ret == 0) { + /* Kc = H(...) */ + ret = wc_lms_shake256_hash_final(&state->shake_k, kc, + params->hash_len); + } + } + else +#endif + { + /* H(I || u32str(q) || u16str(D_PBLC) || ...). */ + ret = wc_lms_hash_first(&state->hash_k, buffer, LMS_K_PRE_LEN); + if (ret == 0) { + /* Q = H(I || u32str(q) || u16str(D_MESG) || C || message) */ + ret = wc_lmots_msg_hash(state, msg, msgSz, c, q); + } + if (ret == 0) { + /* Calculate checksum list all coefficients. */ + ret = wc_lmots_q_expand(q, (word8)params->hash_len, params->width, + params->ls, a); + } +#ifndef WC_LMS_FULL_HASH + if (ret == 0) { #ifdef WOLFSSL_LMS_SHA256_192 if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { - ret = wc_lms_sha256_192_hash_block(&state->hash, buffer, tmp); + /* Put in padding for final block. */ + LMS_SHA256_SET_LEN_47(buffer); } else #endif { #ifndef WOLFSSL_NO_LMS_SHA256_256 - ret = wc_lms_hash_block(&state->hash, buffer, tmp); - #else - ret = NOT_COMPILED_IN; + /* Put in padding for final block. */ + LMS_SHA256_SET_LEN_55(buffer); #endif } - /* Apply the hash function coefficient number of times. */ - #else - #ifdef WOLFSSL_LMS_SHA256_192 - if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { - ret = wc_lms_hash_sha256_192(&state->hash, buffer, - LMS_HASH_BUFFER_LEN(WC_SHA256_192_DIGEST_SIZE), tmp); - } - else - #endif - { - #ifndef WOLFSSL_NO_LMS_SHA256_256 - ret = wc_lms_hash(&state->hash, buffer, - LMS_HASH_BUFFER_LEN(WC_SHA256_DIGEST_SIZE), tmp); - #else - ret = NOT_COMPILED_IN; + } +#endif /* !WC_LMS_FULL_HASH */ + + /* Compute z for each coefficient. */ + for (i = 0; (ret == 0) && (i < params->p); i++) { + unsigned int j; + + /* I || u32(str) || u16str(i) || ... */ + c16toa(i, ip); + + /* tmp = y[i]. + * I || u32(str) || u16str(i) || ... || tmp */ + XMEMCPY(tmp, sig_y, params->hash_len); + sig_y += params->hash_len; + + /* Finish iterations of hash from coefficient to max. */ + for (j = a[i]; (ret == 0) && (j < max); j++) { + /* I || u32str(q) || u16str(i) || u8str(j) || tmp */ + *jp = (word8)j; + /* tmp = H(I || u32str(q) || u16str(i) || u8str(j) || tmp) */ + #ifndef WC_LMS_FULL_HASH + #ifdef WOLFSSL_LMS_SHA256_192 + if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { + ret = wc_lms_sha256_192_hash_block(&state->hash, buffer, + tmp); + } + else + #endif + { + #ifndef WOLFSSL_NO_LMS_SHA256_256 + ret = wc_lms_hash_block(&state->hash, buffer, tmp); + #else + ret = NOT_COMPILED_IN; + #endif + } + /* Apply the hash function coefficient number of times. */ + #else + #ifdef WOLFSSL_LMS_SHA256_192 + if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { + ret = wc_lms_hash_sha256_192(&state->hash, buffer, + LMS_HASH_BUFFER_LEN(WC_SHA256_192_DIGEST_SIZE), tmp); + } + else #endif + { + #ifndef WOLFSSL_NO_LMS_SHA256_256 + ret = wc_lms_hash(&state->hash, buffer, + LMS_HASH_BUFFER_LEN(WC_SHA256_DIGEST_SIZE), tmp); + #else + ret = NOT_COMPILED_IN; + #endif + } + #endif /* !WC_LMS_FULL_HASH */ } - #endif /* !WC_LMS_FULL_HASH */ - } - if (ret == 0) { - /* H(... || z[i] || ...) (for calculating Kc). */ - ret = wc_lms_hash_update(&state->hash_k, tmp, params->hash_len); + if (ret == 0) { + /* H(... || z[i] || ...) (for calculating Kc). */ + ret = wc_lms_hash_update(&state->hash_k, tmp, + params->hash_len); + } } - } -#ifdef WOLFSSL_LMS_SHA256_192 - if ((ret == 0) && - ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192)) { - /* Kc = H(...) */ - ret = wc_lms_hash_sha256_192_final(&state->hash_k, kc); - } - else -#endif - if (ret == 0) { - #ifndef WOLFSSL_NO_LMS_SHA256_256 - /* Kc = H(...) */ - ret = wc_lms_hash_final(&state->hash_k, kc); - #else - ret = NOT_COMPILED_IN; + #ifdef WOLFSSL_LMS_SHA256_192 + if ((ret == 0) && + ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192)) { + /* Kc = H(...) */ + ret = wc_lms_hash_sha256_192_final(&state->hash_k, kc); + } + else #endif + if (ret == 0) { + #ifndef WOLFSSL_NO_LMS_SHA256_256 + /* Kc = H(...) */ + ret = wc_lms_hash_final(&state->hash_k, kc); + #else + ret = NOT_COMPILED_IN; + #endif + } } return ret; @@ -1199,89 +1369,93 @@ static int wc_lmots_make_public_hash(LmsState* state, const byte* seed, byte* k) /* I || u32str(q) || u16str(D_PBLC). */ c16toa(LMS_D_PBLC, ip); - /* K = H(I || u32str(q) || u16str(D_PBLC) || ...) */ - ret = wc_lms_hash_first(&state->hash_k, buffer, LMS_K_PRE_LEN); - -#ifndef WC_LMS_FULL_HASH -#ifdef WOLFSSL_LMS_SHA256_192 - if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { - /* Put in padding for final block. */ - LMS_SHA256_SET_LEN_47(buffer); +#ifdef WOLFSSL_LMS_SHAKE256 + if (LMS_IS_SHAKE(params->lmOtsType)) { + /* K = H(I || u32str(q) || u16str(D_PBLC) || ...) */ + ret = wc_lms_shake256_hash_first(&state->shake_k, buffer, + LMS_K_PRE_LEN); + + for (i = 0; (ret == 0) && (i < params->p); i++) { + unsigned int j; + + /* tmp = x[i] + * = H(I || u32str(q) || u16str(i) || u8str(0xff) || SEED). */ + c16toa(i, ip); + *jp = LMS_D_FIXED; + XMEMCPY(tmp, seed, params->hash_len); + ret = wc_lms_shake256_hash(&state->shake, buffer, + LMS_HASH_BUFFER_LEN(params->hash_len), tmp, params->hash_len); + /* Do all iterations to calculate y. */ + for (j = 0; (ret == 0) && (j < max); j++) { + /* I || u32str(q) || u16str(i) || u8str(j) || tmp */ + *jp = (word8)j; + /* tmp = H(I || u32str(q) || u16str(i) || u8str(j) || tmp) */ + ret = wc_lms_shake256_hash(&state->shake, buffer, + LMS_HASH_BUFFER_LEN(params->hash_len), tmp, + params->hash_len); + } + if (ret == 0) { + /* K = H(... || y[i] || ...) */ + ret = wc_lms_shake256_hash_update(&state->shake_k, tmp, + params->hash_len); + } + } + if (ret == 0) { + /* K = H(I || u32str(q) || u16str(D_PBLC) || + * y[0] || ... || y[p-1]) */ + ret = wc_lms_shake256_hash_final(&state->shake_k, k, + params->hash_len); + } } else #endif { - #ifndef WOLFSSL_NO_LMS_SHA256_256 - /* Put in padding for final block. */ - LMS_SHA256_SET_LEN_55(buffer); - #endif - } -#endif /* !WC_LMS_FULL_HASH */ + /* K = H(I || u32str(q) || u16str(D_PBLC) || ...) */ + ret = wc_lms_hash_first(&state->hash_k, buffer, LMS_K_PRE_LEN); - for (i = 0; (ret == 0) && (i < params->p); i++) { - unsigned int j; - - /* tmp = x[i] - * = H(I || u32str(q) || u16str(i) || u8str(0xff) || SEED). */ - c16toa(i, ip); - *jp = LMS_D_FIXED; #ifndef WC_LMS_FULL_HASH #ifdef WOLFSSL_LMS_SHA256_192 if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { - XMEMCPY(tmp, seed, WC_SHA256_192_DIGEST_SIZE); - ret = wc_lms_sha256_192_hash_block(&state->hash, buffer, tmp); - } - else - #endif - { - #ifndef WOLFSSL_NO_LMS_SHA256_256 - XMEMCPY(tmp, seed, WC_SHA256_DIGEST_SIZE); - ret = wc_lms_hash_block(&state->hash, buffer, tmp); - #else - ret = NOT_COMPILED_IN; - #endif - } -#else - #ifdef WOLFSSL_LMS_SHA256_192 - if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { - XMEMCPY(tmp, seed, WC_SHA256_192_DIGEST_SIZE); - ret = wc_lms_hash_sha256_192(&state->hash, buffer, - LMS_HASH_BUFFER_LEN(WC_SHA256_192_DIGEST_SIZE), tmp); + /* Put in padding for final block. */ + LMS_SHA256_SET_LEN_47(buffer); } else #endif { #ifndef WOLFSSL_NO_LMS_SHA256_256 - XMEMCPY(tmp, seed, WC_SHA256_DIGEST_SIZE); - ret = wc_lms_hash(&state->hash, buffer, - LMS_HASH_BUFFER_LEN(WC_SHA256_DIGEST_SIZE), tmp); - #else - ret = NOT_COMPILED_IN; + /* Put in padding for final block. */ + LMS_SHA256_SET_LEN_55(buffer); #endif } #endif /* !WC_LMS_FULL_HASH */ - /* Do all iterations to calculate y. */ - for (j = 0; (ret == 0) && (j < max); j++) { - /* I || u32str(q) || u16str(i) || u8str(j) || tmp */ - *jp = (word8)j; - /* tmp = H(I || u32str(q) || u16str(i) || u8str(j) || tmp) */ - #ifndef WC_LMS_FULL_HASH + + for (i = 0; (ret == 0) && (i < params->p); i++) { + unsigned int j; + + /* tmp = x[i] + * = H(I || u32str(q) || u16str(i) || u8str(0xff) || SEED). */ + c16toa(i, ip); + *jp = LMS_D_FIXED; +#ifndef WC_LMS_FULL_HASH #ifdef WOLFSSL_LMS_SHA256_192 if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { + XMEMCPY(tmp, seed, WC_SHA256_192_DIGEST_SIZE); ret = wc_lms_sha256_192_hash_block(&state->hash, buffer, tmp); } else #endif { #ifndef WOLFSSL_NO_LMS_SHA256_256 + XMEMCPY(tmp, seed, WC_SHA256_DIGEST_SIZE); ret = wc_lms_hash_block(&state->hash, buffer, tmp); #else ret = NOT_COMPILED_IN; #endif } - #else +#else #ifdef WOLFSSL_LMS_SHA256_192 if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { + XMEMCPY(tmp, seed, WC_SHA256_192_DIGEST_SIZE); ret = wc_lms_hash_sha256_192(&state->hash, buffer, LMS_HASH_BUFFER_LEN(WC_SHA256_192_DIGEST_SIZE), tmp); } @@ -1289,33 +1463,76 @@ static int wc_lmots_make_public_hash(LmsState* state, const byte* seed, byte* k) #endif { #ifndef WOLFSSL_NO_LMS_SHA256_256 + XMEMCPY(tmp, seed, WC_SHA256_DIGEST_SIZE); ret = wc_lms_hash(&state->hash, buffer, LMS_HASH_BUFFER_LEN(WC_SHA256_DIGEST_SIZE), tmp); #else ret = NOT_COMPILED_IN; #endif } - #endif /* !WC_LMS_FULL_HASH */ +#endif /* !WC_LMS_FULL_HASH */ + /* Do all iterations to calculate y. */ + for (j = 0; (ret == 0) && (j < max); j++) { + /* I || u32str(q) || u16str(i) || u8str(j) || tmp */ + *jp = (word8)j; + /* tmp = H(I || u32str(q) || u16str(i) || u8str(j) || tmp) */ + #ifndef WC_LMS_FULL_HASH + #ifdef WOLFSSL_LMS_SHA256_192 + if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { + ret = wc_lms_sha256_192_hash_block(&state->hash, buffer, + tmp); + } + else + #endif + { + #ifndef WOLFSSL_NO_LMS_SHA256_256 + ret = wc_lms_hash_block(&state->hash, buffer, tmp); + #else + ret = NOT_COMPILED_IN; + #endif + } + #else + #ifdef WOLFSSL_LMS_SHA256_192 + if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { + ret = wc_lms_hash_sha256_192(&state->hash, buffer, + LMS_HASH_BUFFER_LEN(WC_SHA256_192_DIGEST_SIZE), tmp); + } + else + #endif + { + #ifndef WOLFSSL_NO_LMS_SHA256_256 + ret = wc_lms_hash(&state->hash, buffer, + LMS_HASH_BUFFER_LEN(WC_SHA256_DIGEST_SIZE), tmp); + #else + ret = NOT_COMPILED_IN; + #endif + } + #endif /* !WC_LMS_FULL_HASH */ + } + if (ret == 0) { + /* K = H(... || y[i] || ...) */ + ret = wc_lms_hash_update(&state->hash_k, tmp, + params->hash_len); + } } - if (ret == 0) { - /* K = H(... || y[i] || ...) */ - ret = wc_lms_hash_update(&state->hash_k, tmp, params->hash_len); + #ifdef WOLFSSL_LMS_SHA256_192 + if ((ret == 0) && + ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192)) { + /* K = H(I || u32str(q) || u16str(D_PBLC) || + * y[0] || ... || y[p-1]) */ + ret = wc_lms_hash_sha256_192_final(&state->hash_k, k); } - } -#ifdef WOLFSSL_LMS_SHA256_192 - if ((ret == 0) && ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192)) { - /* K = H(I || u32str(q) || u16str(D_PBLC) || y[0] || ... || y[p-1]) */ - ret = wc_lms_hash_sha256_192_final(&state->hash_k, k); - } - else -#endif - if (ret == 0) { - #ifndef WOLFSSL_NO_LMS_SHA256_256 - /* K = H(I || u32str(q) || u16str(D_PBLC) || y[0] || ... || y[p-1]) */ - ret = wc_lms_hash_final(&state->hash_k, k); - #else - ret = NOT_COMPILED_IN; + else #endif + if (ret == 0) { + #ifndef WOLFSSL_NO_LMS_SHA256_256 + /* K = H(I || u32str(q) || u16str(D_PBLC) || + * y[0] || ... || y[p-1]) */ + ret = wc_lms_hash_final(&state->hash_k, k); + #else + ret = NOT_COMPILED_IN; + #endif + } } return ret; @@ -1473,6 +1690,19 @@ static int wc_lmots_sign(LmsState* state, const byte* seed, const byte* msg, c16toa(LMS_D_C, ip); /* I || u32str(q) || u16str(0xFFFD) || u8str(0xFF) || ... */ *jp = LMS_D_FIXED; +#ifdef WOLFSSL_LMS_SHAKE256 + if (LMS_IS_SHAKE(state->params->lmOtsType)) { + /* I || u32str(q) || u16str(0xFFFD) || u8str(0xFF) || SEED */ + XMEMCPY(tmp, seed, state->params->hash_len); + /* C = H(I || u32str(q) || u16str(0xFFFD) || u8str(0xFF) || SEED) + * sig = u32str(type) || C || ... */ + ret = wc_lms_shake256_hash(&state->shake, buffer, + LMS_HASH_BUFFER_LEN(state->params->hash_len), sig_c, + state->params->hash_len); + } + else +#endif + { #ifndef WC_LMS_FULL_HASH #ifdef WOLFSSL_LMS_SHA256_192 if ((state->params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { @@ -1524,6 +1754,7 @@ static int wc_lmots_sign(LmsState* state, const byte* seed, const byte* msg, #endif } #endif /* !WC_LMS_FULL_HASH */ + } if (ret == 0) { byte* sig_y = sig_c + state->params->hash_len; @@ -1671,6 +1902,15 @@ static int wc_lms_leaf_hash(LmsState* state, const byte* seed, word32 i, /* I || u32str(r) || u16str(D_LEAF) || OTS_PUB_HASH[i] */ c16toa(LMS_D_LEAF, dp); /* temp = H(I || u32str(r) || u16str(D_LEAF) || OTS_PUB_HASH[i]) */ +#ifdef WOLFSSL_LMS_SHAKE256 + if (LMS_IS_SHAKE(state->params->lmOtsType)) { + ret = wc_lms_shake256_hash(&state->shake, buffer, + LMS_SEED_HASH_LEN(state->params->hash_len), leaf, + state->params->hash_len); + } + else +#endif + { #ifndef WC_LMS_FULL_HASH /* Put in padding for final block. */ #ifdef WOLFSSL_LMS_SHA256_192 @@ -1705,6 +1945,7 @@ static int wc_lms_leaf_hash(LmsState* state, const byte* seed, word32 i, #endif } #endif /* !WC_LMS_FULL_HASH */ + } } return ret; @@ -1735,6 +1976,18 @@ static int wc_lms_interior_hash(LmsState* state, byte* sp, word32 r, /* I || u32str(r) || u16str(D_INTR) || ... || temp */ c32toa(r, rp); +#ifdef WOLFSSL_LMS_SHAKE256 + if (LMS_IS_SHAKE(state->params->lmOtsType)) { + /* left_side = pop(data stack) + * I || u32str(r) || u16str(D_INTR) || left_side || temp */ + XMEMCPY(left, sp, state->params->hash_len); + /* temp = H(I || u32str(r) || u16str(D_INTR) || left_side || temp) */ + ret = wc_lms_shake256_hash(&state->shake, buffer, + LMS_NODE_HASH_LEN(state->params->hash_len), node, + state->params->hash_len); + } + else +#endif #ifdef WOLFSSL_LMS_SHA256_192 if ((state->params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { /* left_side = pop(data stack) @@ -2304,6 +2557,19 @@ static int wc_lms_compute_root(LmsState* state, word32 q, const byte* kc, c16toa(LMS_D_LEAF, ip); XMEMCPY(node, kc, params->hash_len); /* Put tmp into offset required for first iteration. */ +#ifdef WOLFSSL_LMS_SHAKE256 + if (LMS_IS_SHAKE(params->lmOtsType)) { + b[0][0] = node; + b[0][1] = node + params->hash_len; + b[1][0] = node + params->hash_len; + b[1][1] = node; + ret = wc_lms_shake256_hash(&state->shake, buffer, + LMS_SEED_HASH_LEN(params->hash_len), b[r & 1][0], + params->hash_len); + } + else +#endif + { #ifndef WC_LMS_FULL_HASH /* Put in padding for final block. */ #ifdef WOLFSSL_LMS_SHA256_192 @@ -2354,6 +2620,7 @@ static int wc_lms_compute_root(LmsState* state, word32 q, const byte* kc, #endif } #endif /* !WC_LMS_FULL_HASH */ + } if (ret == 0) { int i; @@ -2362,6 +2629,32 @@ static int wc_lms_compute_root(LmsState* state, word32 q, const byte* kc, c16toa(LMS_D_INTR, ip); /* Do all but last height. */ + #ifdef WOLFSSL_LMS_SHAKE256 + if (LMS_IS_SHAKE(params->lmOtsType)) { + for (i = 0; (ret == 0) && (i < params->height - 1); i++) { + /* Put path into offset required. */ + XMEMCPY(b[r & 1][1], path, params->hash_len); + path += params->hash_len; + + /* node_num = node_num / 2 */ + r >>= 1; + /* H(...||u32str(node_num/2)||..) */ + c32toa(r, rp); + ret = wc_lms_shake256_hash(&state->shake, buffer, + LMS_NODE_HASH_LEN(params->hash_len), b[r & 1][0], + params->hash_len); + } + if (ret == 0) { + /* Last height. */ + XMEMCPY(b[r & 1][1], path, params->hash_len); + r >>= 1; + c32toa(r, rp); + ret = wc_lms_shake256_hash(&state->shake, buffer, + LMS_NODE_HASH_LEN(params->hash_len), tc, params->hash_len); + } + } + else + #endif #ifdef WOLFSSL_LMS_SHA256_192 if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { for (i = 0; (ret == 0) && (i < params->height - 1); i++) { @@ -2503,6 +2796,18 @@ static int wc_lms_verify(LmsState* state, const byte* pub, const byte* msg, ret = wc_lmots_calc_kc(state, pub + LMS_TYPE_LEN, msg, msgSz, sig_lmots, kc); } + if (ret == 0) { + /* Algorithm 6a. Step 3.d-e: Check LMS type in signature matches + * the expected type from the public key. */ + const byte* sig_lms_type = sig + LMS_Q_LEN + LMS_TYPE_LEN + + params->hash_len + params->p * params->hash_len; + word32 sigType; + + ato32(sig_lms_type, &sigType); + if (sigType != (params->lmsType & LMS_H_W_MASK)) { + ret = SIG_TYPE_E; + } + } if (ret == 0) { /* Algorithm 6a. Step 2.j. */ const byte* sig_path = sig + LMS_Q_LEN + LMS_TYPE_LEN + @@ -2559,6 +2864,18 @@ static int wc_hss_derive_seed_i(LmsState* state, const byte* id, /* parent's I || q || D_CHILD_SEED || D_FIXED || parent's SEED */ XMEMCPY(tmp, seed, state->params->hash_len); /* SEED = H(parent's I || q || D_CHILD_SEED || D_FIXED || parent's SEED) */ +#ifdef WOLFSSL_LMS_SHAKE256 + if (LMS_IS_SHAKE(state->params->lmOtsType)) { + ret = wc_lms_shake256_hash(&state->shake, buffer, + LMS_HASH_BUFFER_LEN(state->params->hash_len), seed_i, + state->params->hash_len); + if (ret == 0) { + seed_i += state->params->hash_len; + } + } + else +#endif + { #ifndef WC_LMS_FULL_HASH #ifdef WOLFSSL_LMS_SHA256_192 if ((state->params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { @@ -2600,11 +2917,21 @@ static int wc_hss_derive_seed_i(LmsState* state, const byte* id, #endif } #endif /* !WC_LMS_FULL_HASH */ + } if (ret == 0) { /* parent's I || q || D_CHILD_I || D_FIXED || parent's SEED */ c16toa(LMS_D_CHILD_I, ip); /* I = H(parent's I || q || D_CHILD_I || D_FIXED || parent's SEED) */ +#ifdef WOLFSSL_LMS_SHAKE256 + if (LMS_IS_SHAKE(state->params->lmOtsType)) { + ret = wc_lms_shake256_hash(&state->shake, buffer, + LMS_HASH_BUFFER_LEN(state->params->hash_len), tmp, + state->params->hash_len); + } + else +#endif + { #ifndef WC_LMS_FULL_HASH #ifdef WOLFSSL_LMS_SHA256_192 if ((state->params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { @@ -2636,6 +2963,7 @@ static int wc_hss_derive_seed_i(LmsState* state, const byte* id, #endif } #endif /* !WC_LMS_FULL_HASH */ + } /* Copy part of hash as new I into private key. */ XMEMCPY(seed_i, tmp, LMS_I_LEN); } diff --git a/wolfcrypt/src/wc_mlkem.c b/wolfcrypt/src/wc_mlkem.c index 99b08fda915..99af9d11ac8 100644 --- a/wolfcrypt/src/wc_mlkem.c +++ b/wolfcrypt/src/wc_mlkem.c @@ -71,6 +71,11 @@ #undef WOLFSSL_RISCV_ASM #endif +#if FIPS_VERSION3_GE(2,0,0) + /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */ + #define FIPS_NO_WRAPPERS +#endif + #include #include #include @@ -392,6 +397,35 @@ int wc_MlKemKey_MakeKey(MlKemKey* key, WC_RNG* rng) ret = wc_KyberKey_MakeKeyWithRandom(key, rand, sizeof(rand)); } +#ifdef HAVE_FIPS + /* Pairwise Consistency Test (PCT) per FIPS 140-3 / ISO 19790:2012 + * Section 7.10.3.3: encapsulate with ek, decapsulate with dk, + * verify shared secrets match. */ + if (ret == 0) { + byte pct_ct[WC_ML_KEM_MAX_CIPHER_TEXT_SIZE]; + byte pct_ss1[WC_ML_KEM_SS_SZ]; + byte pct_ss2[WC_ML_KEM_SS_SZ]; + word32 ctSz = 0; + + ret = wc_MlKemKey_CipherTextSize(key, &ctSz); + + if (ret == 0) + ret = wc_MlKemKey_Encapsulate(key, pct_ct, pct_ss1, rng); + + if (ret == 0) + ret = wc_MlKemKey_Decapsulate(key, pct_ss2, pct_ct, ctSz); + + if (ret == 0) { + if (XMEMCMP(pct_ss1, pct_ss2, WC_ML_KEM_SS_SZ) != 0) + ret = ML_KEM_PCT_E; + } + + ForceZero(pct_ss1, sizeof(pct_ss1)); + ForceZero(pct_ss2, sizeof(pct_ss2)); + ForceZero(pct_ct, sizeof(pct_ct)); + } +#endif /* HAVE_FIPS */ + /* Ensure seeds are zeroized. */ ForceZero((void*)rand, (word32)sizeof(rand)); @@ -647,6 +681,9 @@ int wc_MlKemKey_MakeKeyWithRandom(MlKemKey* key, const unsigned char* rand, } #endif + /* Note: PCT is performed in wc_MlKemKey_MakeKey() which calls this + * function and has the RNG parameter needed for encapsulation. */ + return ret; } #endif /* !WOLFSSL_MLKEM_NO_MAKE_KEY */ diff --git a/wolfcrypt/src/wc_slhdsa.c b/wolfcrypt/src/wc_slhdsa.c index 46adf35f72b..b25a878c1aa 100644 --- a/wolfcrypt/src/wc_slhdsa.c +++ b/wolfcrypt/src/wc_slhdsa.c @@ -21,6 +21,11 @@ #include +#if FIPS_VERSION3_GE(2,0,0) + /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */ + #define FIPS_NO_WRAPPERS +#endif + #include #ifdef WOLFSSL_HAVE_SLHDSA @@ -35,6 +40,11 @@ #endif #include #include +#ifdef WOLFSSL_SLHDSA_SHA2 + #include + #include + #include +#endif #if defined(USE_INTEL_SPEEDUP) /* CPU information for Intel. */ @@ -370,6 +380,27 @@ static const SlhDsaParameters SlhDsaParams[] = #ifndef WOLFSSL_SLHDSA_PARAM_NO_256F SLHDSA_PARAMETERS(SLHDSA_SHAKE256F, 32, 68, 17, 4, 9, 35), #endif +#ifdef WOLFSSL_SLHDSA_SHA2 + /* n, h, d, h_m, a, k */ +#ifndef WOLFSSL_SLHDSA_PARAM_NO_SHA2_128S + SLHDSA_PARAMETERS(SLHDSA_SHA2_128S, 16, 63, 7, 9, 12, 14), +#endif +#ifndef WOLFSSL_SLHDSA_PARAM_NO_SHA2_128F + SLHDSA_PARAMETERS(SLHDSA_SHA2_128F, 16, 66, 22, 3, 6, 33), +#endif +#ifndef WOLFSSL_SLHDSA_PARAM_NO_SHA2_192S + SLHDSA_PARAMETERS(SLHDSA_SHA2_192S, 24, 63, 7, 9, 14, 17), +#endif +#ifndef WOLFSSL_SLHDSA_PARAM_NO_SHA2_192F + SLHDSA_PARAMETERS(SLHDSA_SHA2_192F, 24, 66, 22, 3, 8, 33), +#endif +#ifndef WOLFSSL_SLHDSA_PARAM_NO_SHA2_256S + SLHDSA_PARAMETERS(SLHDSA_SHA2_256S, 32, 64, 8, 8, 14, 22), +#endif +#ifndef WOLFSSL_SLHDSA_PARAM_NO_SHA2_256F + SLHDSA_PARAMETERS(SLHDSA_SHA2_256F, 32, 68, 17, 4, 9, 35), +#endif +#endif /* WOLFSSL_SLHDSA_SHA2 */ }; /* Number of parameters in array. */ @@ -571,32 +602,758 @@ static int slhdsakey_hash_shake_4(wc_Shake* shake, const byte* data1, } else #endif - { - /* Process the state using C code. */ - BlockSha3(state); - } - /* Copy hash result, of the required length, from the state into hash. */ - XMEMCPY(hash, shake->s, hash_len); + { + /* Process the state using C code. */ + BlockSha3(state); + } + /* Copy hash result, of the required length, from the state into hash. */ + XMEMCPY(hash, shake->s, hash_len); + + return 0; +#else + /* Copy the first block of data into the cached data buffer. */ + XMEMCPY(shake->t, data1, data1_len); + /* Encode HashAddress into the cached data buffer next. */ + HA_Encode(adrs, shake->t + data1_len); + /* Copy the second block of data into the cached data buffer next. */ + XMEMCPY(shake->t + data1_len + SLHDSA_HA_SZ, data2, data2_len); + /* Copy the third block of data into the cached data buffer next. */ + XMEMCPY(shake->t + data1_len + SLHDSA_HA_SZ + data2_len, data3, data3_len); + + /* Update count of bytes cached. */ + shake->i = data1_len + SLHDSA_HA_SZ + data2_len + data3_len; + + /* Calculate and output hash. */ + return wc_Shake256_Final(shake, hash, hash_len); +#endif +} + +/****************************************************************************** + * SHA2 Hash Functions (FIPS 205, Section 11.2) + ******************************************************************************/ + +#ifdef WOLFSSL_SLHDSA_SHA2 + +/* Size of compressed HashAddress (ADRS^c) per FIPS 205 Section 11.2. */ +#define SLHDSA_HAC_SZ 22 + +/* Encode a compressed HashAddress (ADRS^c). + * + * FIPS 205. Section 11.2. + * Byte 0: low byte of adrs[0] (layer) + * Bytes 1-8: adrs[2..3] (low 8 bytes of tree address) + * Byte 9: low byte of adrs[4] (type) + * Bytes 10-21: adrs[5..7] (remaining 12 bytes, verbatim) + * + * @param [in] adrs HashAddress to encode (8 x word32). + * @param [out] address Buffer to encode into (22 bytes). + */ +static void HA_Encode_Compressed(const word32* adrs, byte* address) +{ + /* Byte 0: low byte of layer address. */ + address[0] = (byte)adrs[0]; + /* Bytes 1-4: adrs[2] (tree address high word). */ + c32toa(adrs[2], address + 1); + /* Bytes 5-8: adrs[3] (tree address low word). */ + c32toa(adrs[3], address + 5); + /* Byte 9: low byte of type. */ + address[9] = (byte)adrs[4]; + /* Bytes 10-13: adrs[5] (key pair address / padding). */ + c32toa(adrs[5], address + 10); + /* Bytes 14-17: adrs[6] (chain address / tree height). */ + c32toa(adrs[6], address + 14); + /* Bytes 18-21: adrs[7] (hash address / tree index). */ + c32toa(adrs[7], address + 18); +} + +/* Pre-compute SHA2 midstates for PK.seed. + * + * SHA-256: PK.seed || pad(64 - n) is exactly one 64-byte block. + * SHA-512: PK.seed || pad(128 - n) is exactly one 128-byte block. + * + * @param [in, out] key SLH-DSA key with pk_seed set at key->sk[2*n]. + * @return 0 on success. + */ +static int slhdsakey_precompute_sha2_midstates(SlhDsaKey* key) +{ + int ret; + byte n = key->params->n; + const byte* pk_seed = key->sk + 2 * n; + byte block[WC_SHA512_BLOCK_SIZE]; + + /* SHA-256 midstate: PK.seed || zeros to fill 64-byte block. */ + XMEMSET(block, 0, WC_SHA256_BLOCK_SIZE); + XMEMCPY(block, pk_seed, n); + ret = wc_InitSha256(&key->hash.sha2.sha256_mid); + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256_mid, block, + WC_SHA256_BLOCK_SIZE); + } + + /* SHA-512 midstate: PK.seed || zeros to fill 128-byte block. + * Only needed for categories 3 and 5 (n > 16). */ + if ((ret == 0) && (n > 16)) { + XMEMSET(block, 0, WC_SHA512_BLOCK_SIZE); + XMEMCPY(block, pk_seed, n); + ret = wc_InitSha512(&key->hash.sha2.sha512_mid); + if (ret == 0) { + ret = wc_Sha512Update(&key->hash.sha2.sha512_mid, block, + WC_SHA512_BLOCK_SIZE); + } + } + + return ret; +} + +/* SHA2 F function. + * + * FIPS 205. Section 11.2. + * F(PK.seed, ADRS, M1) = Trunc_n(SHA-256(PK.seed||pad(64-n)||ADRS^c||M1)) + * + * Uses pre-computed midstate for the first block. + * + * @param [in] key SLH-DSA key (SHA2 hash objects + midstate). + * @param [in] pk_seed Public key seed (unused - midstate). + * @param [in] adrs HashAddress. + * @param [in] m Message of n bytes. + * @param [in] n Number of bytes in hash output. + * @param [out] hash Buffer to hold hash output. + * @return 0 on success. + */ +static int slhdsakey_hash_f_sha2(SlhDsaKey* key, const byte* pk_seed, + const word32* adrs, const byte* m, byte n, byte* hash) +{ + int ret; + byte address[SLHDSA_HAC_SZ]; + byte digest[WC_SHA256_DIGEST_SIZE]; + + (void)pk_seed; + + /* Encode compressed address. */ + HA_Encode_Compressed(adrs, address); + + /* Restore SHA-256 midstate. */ + ret = wc_Sha256Copy(&key->hash.sha2.sha256_mid, &key->hash.sha2.sha256); + if (ret == 0) { + /* Update with compressed ADRS and message. */ + ret = wc_Sha256Update(&key->hash.sha2.sha256, address, SLHDSA_HAC_SZ); + } + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256, m, n); + } + if (ret == 0) { + ret = wc_Sha256Final(&key->hash.sha2.sha256, digest); + } + if (ret == 0) { + /* Truncate to n bytes. */ + XMEMCPY(hash, digest, n); + } + + return ret; +} + +/* SHA2 H function. + * + * FIPS 205. Section 11.2. + * Cat 1: H(PK.seed, ADRS, M2) = Trunc_n(SHA-256(PK.seed||pad||ADRS^c||M2)) + * Cat 3,5: H(PK.seed, ADRS, M2) = Trunc_n(SHA-512(PK.seed||pad||ADRS^c||M2)) + * + * @param [in] key SLH-DSA key. + * @param [in] pk_seed Public key seed (unused - midstate). + * @param [in] adrs HashAddress. + * @param [in] node Message of 2n bytes. + * @param [in] n Number of bytes in hash output. + * @param [out] hash Buffer to hold hash output. + * @return 0 on success. + */ +static int slhdsakey_hash_h_sha2(SlhDsaKey* key, const byte* pk_seed, + const word32* adrs, const byte* node, byte n, byte* hash) +{ + int ret; + byte address[SLHDSA_HAC_SZ]; + + (void)pk_seed; + + /* Encode compressed address. */ + HA_Encode_Compressed(adrs, address); + + if (n == 16) { + /* Category 1: use SHA-256. */ + byte digest[WC_SHA256_DIGEST_SIZE]; + + ret = wc_Sha256Copy(&key->hash.sha2.sha256_mid, + &key->hash.sha2.sha256); + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256, address, + SLHDSA_HAC_SZ); + } + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256, node, 2 * n); + } + if (ret == 0) { + ret = wc_Sha256Final(&key->hash.sha2.sha256, digest); + } + if (ret == 0) { + XMEMCPY(hash, digest, n); + } + } + else { + /* Categories 3, 5: use SHA-512. */ + byte digest[WC_SHA512_DIGEST_SIZE]; + + ret = wc_Sha512Copy(&key->hash.sha2.sha512_mid, + &key->hash.sha2.sha512); + if (ret == 0) { + ret = wc_Sha512Update(&key->hash.sha2.sha512, address, + SLHDSA_HAC_SZ); + } + if (ret == 0) { + ret = wc_Sha512Update(&key->hash.sha2.sha512, node, 2 * n); + } + if (ret == 0) { + ret = wc_Sha512Final(&key->hash.sha2.sha512, digest); + } + if (ret == 0) { + XMEMCPY(hash, digest, n); + } + } + + return ret; +} + +/* SHA2 H function with two separate n-byte halves. + * + * Same as slhdsakey_hash_h_sha2 but M2 = m1 || m2. + * + * @param [in] key SLH-DSA key. + * @param [in] pk_seed Public key seed (unused - midstate). + * @param [in] adrs HashAddress. + * @param [in] m1 First n bytes of message. + * @param [in] m2 Second n bytes of message. + * @param [in] n Number of bytes in hash output. + * @param [out] hash Buffer to hold hash output. + * @return 0 on success. + */ +static int slhdsakey_hash_h_2_sha2(SlhDsaKey* key, const byte* pk_seed, + const word32* adrs, const byte* m1, const byte* m2, byte n, byte* hash) +{ + int ret; + byte address[SLHDSA_HAC_SZ]; + + (void)pk_seed; + + /* Encode compressed address. */ + HA_Encode_Compressed(adrs, address); + + if (n == 16) { + /* Category 1: use SHA-256. */ + byte digest[WC_SHA256_DIGEST_SIZE]; + + ret = wc_Sha256Copy(&key->hash.sha2.sha256_mid, + &key->hash.sha2.sha256); + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256, address, + SLHDSA_HAC_SZ); + } + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256, m1, n); + } + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256, m2, n); + } + if (ret == 0) { + ret = wc_Sha256Final(&key->hash.sha2.sha256, digest); + } + if (ret == 0) { + XMEMCPY(hash, digest, n); + } + } + else { + /* Categories 3, 5: use SHA-512. */ + byte digest[WC_SHA512_DIGEST_SIZE]; + + ret = wc_Sha512Copy(&key->hash.sha2.sha512_mid, + &key->hash.sha2.sha512); + if (ret == 0) { + ret = wc_Sha512Update(&key->hash.sha2.sha512, address, + SLHDSA_HAC_SZ); + } + if (ret == 0) { + ret = wc_Sha512Update(&key->hash.sha2.sha512, m1, n); + } + if (ret == 0) { + ret = wc_Sha512Update(&key->hash.sha2.sha512, m2, n); + } + if (ret == 0) { + ret = wc_Sha512Final(&key->hash.sha2.sha512, digest); + } + if (ret == 0) { + XMEMCPY(hash, digest, n); + } + } + + return ret; +} + +/* SHA2 PRF function. + * + * FIPS 205. Section 11.2. + * PRF(PK.seed, SK.seed, ADRS) = + * Trunc_n(SHA-256(PK.seed || pad(64-n) || ADRS^c || SK.seed)) + * + * @param [in] key SLH-DSA key. + * @param [in] pk_seed Public key seed (unused - midstate). + * @param [in] sk_seed Private key seed. + * @param [in] adrs HashAddress. + * @param [in] n Number of bytes in hash output. + * @param [out] hash Buffer to hold hash output. + * @return 0 on success. + */ +static int slhdsakey_hash_prf_sha2(SlhDsaKey* key, const byte* pk_seed, + const byte* sk_seed, const word32* adrs, byte n, byte* hash) +{ + int ret; + byte address[SLHDSA_HAC_SZ]; + byte digest[WC_SHA256_DIGEST_SIZE]; + + (void)pk_seed; + + /* Encode compressed address. */ + HA_Encode_Compressed(adrs, address); + + /* Restore SHA-256 midstate. */ + ret = wc_Sha256Copy(&key->hash.sha2.sha256_mid, &key->hash.sha2.sha256); + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256, address, SLHDSA_HAC_SZ); + } + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256, sk_seed, n); + } + if (ret == 0) { + ret = wc_Sha256Final(&key->hash.sha2.sha256, digest); + } + if (ret == 0) { + XMEMCPY(hash, digest, n); + } + + return ret; +} + +/* SHA2 T_l streaming: start with address. + * + * Restores midstate then updates with compressed ADRS. + * + * @param [in] key SLH-DSA key. + * @param [in] pk_seed Public key seed (unused - midstate). + * @param [in] adrs HashAddress. + * @param [in] n Number of bytes of hash output (determines cat). + * @return 0 on success. + */ +static int slhdsakey_hash_start_addr_sha2(SlhDsaKey* key, + const byte* pk_seed, const word32* adrs, byte n) +{ + int ret; + byte address[SLHDSA_HAC_SZ]; + + (void)pk_seed; + + HA_Encode_Compressed(adrs, address); + + if (n == 16) { + /* Category 1: SHA-256 -- use sha256_2 (T_l must not collide with + * sha256 which is used by F and H). */ + ret = wc_Sha256Copy(&key->hash.sha2.sha256_mid, + &key->hash.sha2.sha256_2); + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256_2, address, + SLHDSA_HAC_SZ); + } + } + else { + /* Categories 3, 5: SHA-512 -- use sha512_2 (T_l must not collide + * with sha512 which is used by H). */ + ret = wc_Sha512Copy(&key->hash.sha2.sha512_mid, + &key->hash.sha2.sha512_2); + if (ret == 0) { + ret = wc_Sha512Update(&key->hash.sha2.sha512_2, address, + SLHDSA_HAC_SZ); + } + } + + return ret; +} + +/* SHA2 T_l streaming: update with data. + * + * @param [in] key SLH-DSA key. + * @param [in] data Data to hash. + * @param [in] len Length of data. + * @return 0 on success. + */ +static int slhdsakey_hash_update_sha2(SlhDsaKey* key, const byte* data, + word32 len) +{ + if (key->params->n == 16) { + return wc_Sha256Update(&key->hash.sha2.sha256_2, data, len); + } + else { + return wc_Sha512Update(&key->hash.sha2.sha512_2, data, len); + } +} + +/* SHA2 T_l streaming: finalize. + * + * @param [in] key SLH-DSA key. + * @param [out] hash Output buffer. + * @param [in] len Desired output length (truncate to n). + * @return 0 on success. + */ +static int slhdsakey_hash_final_sha2(SlhDsaKey* key, byte* hash, word32 len) +{ + int ret; + byte n = key->params->n; + + if (n == 16) { + byte digest[WC_SHA256_DIGEST_SIZE]; + ret = wc_Sha256Final(&key->hash.sha2.sha256_2, digest); + if (ret == 0) { + XMEMCPY(hash, digest, (len < n) ? len : n); + } + } + else { + byte digest[WC_SHA512_DIGEST_SIZE]; + ret = wc_Sha512Final(&key->hash.sha2.sha512_2, digest); + if (ret == 0) { + XMEMCPY(hash, digest, (len < n) ? len : n); + } + } + + return ret; +} + +/* Local MGF1 implementation for H_msg. + * + * FIPS 205. Section 11.2. + * H_msg uses MGF1-SHA-256/512(R || PK.seed || digest, m) where m is the + * required output length. + * + * @param [in] key SLH-DSA key (for hash objects). + * @param [in] seed Seed data for MGF1. + * @param [in] seedLen Length of seed. + * @param [out] out Output buffer. + * @param [in] outLen Required output length. + * @return 0 on success. + */ +static int slhdsakey_mgf1_sha2(SlhDsaKey* key, const byte* seed, + word32 seedLen, byte* out, word32 outLen) +{ + int ret = 0; + word32 counter = 0; + word32 done = 0; + byte n = key->params->n; + + while ((ret == 0) && (done < outLen)) { + byte cBuf[4]; + word32 left = outLen - done; + + c32toa(counter, cBuf); + + if (n == 16) { + /* Category 1: MGF1-SHA-256. */ + byte digest[WC_SHA256_DIGEST_SIZE]; + word32 cpLen = (left < WC_SHA256_DIGEST_SIZE) ? + left : WC_SHA256_DIGEST_SIZE; + + ret = wc_InitSha256(&key->hash.sha2.sha256_2); + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256_2, seed, seedLen); + } + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256_2, cBuf, 4); + } + if (ret == 0) { + ret = wc_Sha256Final(&key->hash.sha2.sha256_2, digest); + } + if (ret == 0) { + XMEMCPY(out + done, digest, cpLen); + done += cpLen; + } + } + else { + /* Categories 3, 5: MGF1-SHA-512. */ + byte digest[WC_SHA512_DIGEST_SIZE]; + word32 cpLen = (left < WC_SHA512_DIGEST_SIZE) ? + left : WC_SHA512_DIGEST_SIZE; + + ret = wc_InitSha512(&key->hash.sha2.sha512_2); + if (ret == 0) { + ret = wc_Sha512Update(&key->hash.sha2.sha512_2, seed, seedLen); + } + if (ret == 0) { + ret = wc_Sha512Update(&key->hash.sha2.sha512_2, cBuf, 4); + } + if (ret == 0) { + ret = wc_Sha512Final(&key->hash.sha2.sha512_2, digest); + } + if (ret == 0) { + XMEMCPY(out + done, digest, cpLen); + done += cpLen; + } + } + counter++; + } + + return ret; +} + +/* SHA2 PRF_msg function. + * + * FIPS 205. Section 11.2. + * PRF_msg(SK.prf, opt_rand, M) = + * Trunc_n(HMAC-SHA-256/512(SK.prf, opt_rand || M)) + * + * @param [in] key SLH-DSA key. + * @param [in] sk_prf SK.prf seed. + * @param [in] opt_rand Random or PK.seed. + * @param [in] hdr Message header (2 bytes). + * @param [in] ctx Context data (may be NULL). + * @param [in] ctxSz Context data length. + * @param [in] msg Message data. + * @param [in] msgSz Message data length. + * @param [in] n Number of bytes in hash output. + * @param [out] hash Buffer to hold hash output. + * @return 0 on success. + */ +static int slhdsakey_prf_msg_sha2(SlhDsaKey* key, const byte* sk_prf, + const byte* opt_rand, const byte* hdr, const byte* ctx, byte ctxSz, + const byte* msg, word32 msgSz, byte n, byte* hash) +{ + int ret; + Hmac hmac; + int hmacType; + byte digest[WC_SHA512_DIGEST_SIZE]; + + if (n == 16) { + hmacType = WC_SHA256; + } + else { + hmacType = WC_SHA512; + } + + ret = wc_HmacInit(&hmac, key->heap, INVALID_DEVID); + if (ret == 0) { + ret = wc_HmacSetKey(&hmac, hmacType, sk_prf, n); + } + if (ret == 0) { + ret = wc_HmacUpdate(&hmac, opt_rand, n); + } + if ((ret == 0) && (hdr != NULL)) { + ret = wc_HmacUpdate(&hmac, hdr, 2); + } + if ((ret == 0) && (ctxSz > 0) && (ctx != NULL)) { + ret = wc_HmacUpdate(&hmac, ctx, ctxSz); + } + if (ret == 0) { + ret = wc_HmacUpdate(&hmac, msg, msgSz); + } + if (ret == 0) { + ret = wc_HmacFinal(&hmac, digest); + } + wc_HmacFree(&hmac); + + if (ret == 0) { + XMEMCPY(hash, digest, n); + } + + return ret; +} + +/* SHA2 H_msg function. + * + * FIPS 205. Section 11.2. + * H_msg(R, PK.seed, PK.root, M) = MGF1-SHA-256/512( + * R || PK.seed || SHA-256/512(R || PK.seed || PK.root || M), m) + * + * @param [in] key SLH-DSA key. + * @param [in] r Randomizer (n bytes from signature). + * @param [in] hdr Message header (2 bytes). + * @param [in] ctx Context data (may be NULL). + * @param [in] ctxSz Context data length. + * @param [in] msg Message data. + * @param [in] msgSz Message data length. + * @param [out] md Output message digest. + * @param [in] mdLen Required digest length (dl1+dl2+dl3). + * @return 0 on success. + */ +static int slhdsakey_h_msg_sha2(SlhDsaKey* key, const byte* r, + const byte* hdr, const byte* ctx, byte ctxSz, const byte* msg, + word32 msgSz, byte* md, word32 mdLen) +{ + int ret; + byte n = key->params->n; + const byte* pk_seed = key->sk + 2 * n; + const byte* pk_root = key->sk + 3 * n; + + if (n == 16) { + /* Category 1: SHA-256 + MGF1-SHA-256. */ + byte innerHash[WC_SHA256_DIGEST_SIZE]; + /* Seed for MGF1: R || PK.seed || innerHash. */ + byte mgfSeed[32 + 16 + WC_SHA256_DIGEST_SIZE]; + + /* Step 1: innerHash = SHA-256(R || PK.seed || PK.root || M). */ + ret = wc_InitSha256(&key->hash.sha2.sha256_2); + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256_2, r, n); + } + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256_2, pk_seed, n); + } + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256_2, pk_root, n); + } + if ((ret == 0) && (hdr != NULL)) { + ret = wc_Sha256Update(&key->hash.sha2.sha256_2, hdr, 2); + } + if ((ret == 0) && (ctxSz > 0) && (ctx != NULL)) { + ret = wc_Sha256Update(&key->hash.sha2.sha256_2, ctx, ctxSz); + } + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256_2, msg, msgSz); + } + if (ret == 0) { + ret = wc_Sha256Final(&key->hash.sha2.sha256_2, innerHash); + } + + /* Step 2: MGF1-SHA-256(R || PK.seed || innerHash, mdLen). */ + if (ret == 0) { + XMEMCPY(mgfSeed, r, n); + XMEMCPY(mgfSeed + n, pk_seed, n); + XMEMCPY(mgfSeed + 2 * n, innerHash, WC_SHA256_DIGEST_SIZE); + ret = slhdsakey_mgf1_sha2(key, mgfSeed, + 2 * n + WC_SHA256_DIGEST_SIZE, md, mdLen); + } + } + else { + /* Categories 3, 5: SHA-512 + MGF1-SHA-512. */ + byte innerHash[WC_SHA512_DIGEST_SIZE]; + /* Seed for MGF1: R || PK.seed || innerHash. */ + byte mgfSeed[32 + 32 + WC_SHA512_DIGEST_SIZE]; + + /* Step 1: innerHash = SHA-512(R || PK.seed || PK.root || M). */ + ret = wc_InitSha512(&key->hash.sha2.sha512_2); + if (ret == 0) { + ret = wc_Sha512Update(&key->hash.sha2.sha512_2, r, n); + } + if (ret == 0) { + ret = wc_Sha512Update(&key->hash.sha2.sha512_2, pk_seed, n); + } + if (ret == 0) { + ret = wc_Sha512Update(&key->hash.sha2.sha512_2, pk_root, n); + } + if ((ret == 0) && (hdr != NULL)) { + ret = wc_Sha512Update(&key->hash.sha2.sha512_2, hdr, 2); + } + if ((ret == 0) && (ctxSz > 0) && (ctx != NULL)) { + ret = wc_Sha512Update(&key->hash.sha2.sha512_2, ctx, ctxSz); + } + if (ret == 0) { + ret = wc_Sha512Update(&key->hash.sha2.sha512_2, msg, msgSz); + } + if (ret == 0) { + ret = wc_Sha512Final(&key->hash.sha2.sha512_2, innerHash); + } + + /* Step 2: MGF1-SHA-512(R || PK.seed || innerHash, mdLen). */ + if (ret == 0) { + XMEMCPY(mgfSeed, r, n); + XMEMCPY(mgfSeed + n, pk_seed, n); + XMEMCPY(mgfSeed + 2 * n, innerHash, WC_SHA512_DIGEST_SIZE); + ret = slhdsakey_mgf1_sha2(key, mgfSeed, + 2 * n + WC_SHA512_DIGEST_SIZE, md, mdLen); + } + } + + return ret; +} + +#endif /* WOLFSSL_SLHDSA_SHA2 */ + +/****************************************************************************** + * Dispatching Hash Macros + ******************************************************************************/ + +/* When WOLFSSL_SLHDSA_SHA2 is defined, macros dispatch between SHAKE and SHA2 + * based on the key's parameter set. When not defined, macros call SHAKE + * directly (zero overhead). */ + +#ifdef WOLFSSL_SLHDSA_SHA2 + +/* SHAKE wrapper functions for SHA2 dispatch macros. */ +static int slhdsakey_hash_f_shake(SlhDsaKey* key, const byte* pk_seed, + const word32* adrs, const byte* m, byte n, byte* hash) +{ +#ifndef WOLFSSL_WC_SLHDSA_SMALL + return slhdsakey_hash_shake_3(&key->hash.shk.shake, pk_seed, n, adrs, m, + n, hash, n); +#else + return slhdsakey_hash_shake_4(&key->hash.shk.shake, pk_seed, n, adrs, m, + n, NULL, 0, hash, n); +#endif +} - return 0; +static int slhdsakey_hash_h_shake(SlhDsaKey* key, const byte* pk_seed, + const word32* adrs, const byte* node, byte n, byte* hash) +{ +#ifndef WOLFSSL_WC_SLHDSA_SMALL + return slhdsakey_hash_shake_3(&key->hash.shk.shake, pk_seed, n, adrs, node, + 2 * n, hash, n); #else - /* Copy the first block of data into the cached data buffer. */ - XMEMCPY(shake->t, data1, data1_len); - /* Encode HashAddress into the cached data buffer next. */ - HA_Encode(adrs, shake->t + data1_len); - /* Copy the second block of data into the cached data buffer next. */ - XMEMCPY(shake->t + data1_len + SLHDSA_HA_SZ, data2, data2_len); - /* Copy the third block of data into the cached data buffer next. */ - XMEMCPY(shake->t + data1_len + SLHDSA_HA_SZ + data2_len, data3, data3_len); + return slhdsakey_hash_shake_4(&key->hash.shk.shake, pk_seed, n, adrs, node, + 2 * n, NULL, 0, hash, n); +#endif +} - /* Update count of bytes cached. */ - shake->i = data1_len + SLHDSA_HA_SZ + data2_len + data3_len; +static int slhdsakey_hash_h_2_shake(SlhDsaKey* key, const byte* pk_seed, + const word32* adrs, const byte* m1, const byte* m2, byte n, byte* hash) +{ + return slhdsakey_hash_shake_4(&key->hash.shk.shake, pk_seed, n, adrs, m1, + n, m2, n, hash, n); +} - /* Calculate and output hash. */ - return wc_Shake256_Final(shake, hash, hash_len); +static int slhdsakey_hash_prf_shake(SlhDsaKey* key, const byte* pk_seed, + const byte* sk_seed, const word32* adrs, byte n, byte* hash) +{ +#ifndef WOLFSSL_WC_SLHDSA_SMALL + return slhdsakey_hash_shake_3(&key->hash.shk.shake, pk_seed, n, adrs, + sk_seed, n, hash, n); +#else + return slhdsakey_hash_shake_4(&key->hash.shk.shake, pk_seed, n, adrs, + sk_seed, n, NULL, 0, hash, n); #endif } +#define HASH_PRF(k, pk_seed, sk_seed, adrs, n, o) \ + (SLHDSA_IS_SHA2((k)->params->param) ? \ + slhdsakey_hash_prf_sha2(k, pk_seed, sk_seed, adrs, n, o) : \ + slhdsakey_hash_prf_shake(k, pk_seed, sk_seed, adrs, n, o)) + +#define HASH_F(k, pk_seed, adrs, m, n, o) \ + (SLHDSA_IS_SHA2((k)->params->param) ? \ + slhdsakey_hash_f_sha2(k, pk_seed, adrs, m, n, o) : \ + slhdsakey_hash_f_shake(k, pk_seed, adrs, m, n, o)) + +#define HASH_H(k, pk_seed, adrs, node, n, o) \ + (SLHDSA_IS_SHA2((k)->params->param) ? \ + slhdsakey_hash_h_sha2(k, pk_seed, adrs, node, n, o) : \ + slhdsakey_hash_h_shake(k, pk_seed, adrs, node, n, o)) + +#define HASH_H_2(k, pk_seed, adrs, m1, m2, n, o) \ + (SLHDSA_IS_SHA2((k)->params->param) ? \ + slhdsakey_hash_h_2_sha2(k, pk_seed, adrs, m1, m2, n, o) : \ + slhdsakey_hash_h_2_shake(k, pk_seed, adrs, m1, m2, n, o)) + +#else /* !WOLFSSL_SLHDSA_SHA2 */ + #ifndef WOLFSSL_WC_SLHDSA_SMALL /* PRF hash. * @@ -606,7 +1363,7 @@ static int slhdsakey_hash_shake_4(wc_Shake* shake, const byte* data1, * FIPS 205. Section 11.1. * PRF(PK.seed, SK.seed, ADRS) = SHAKE256(PK.seed || ADRS || SK.seed, 8n) * - * @param [in] shake SHAKE-256 object. + * @param [in] key SLH-DSA key. * @param [in] pk_seed Public key seed. * @param [in] sk_seed Private key seed. * @param [in] adrs HashAddress. @@ -615,128 +1372,70 @@ static int slhdsakey_hash_shake_4(wc_Shake* shake, const byte* data1, * @return 0 on success. * @return SHAKE-256 error return code on digest failure. */ -#define HASH_PRF(shake, pk_seed, sk_seed, adrs, n, hash) \ - slhdsakey_hash_shake_3(shake, pk_seed, n, adrs, sk_seed, n, hash, n) -/* Hash F. - * - * FIPS 205. Section 4.1. - * F(PK.seed, ADRS, M1) (Bn x B32 x Bn -> Bn ) is a hash function that takes - * an n-byte message as input and produces an n-byte output. - * FIPS 205. Section 11.1. - * F(PK.seed, ADRS, M1) = SHAKE256(PK.seed || ADRS || M1, 8n) - * - * @param [in] shake SHAKE-256 object. - * @param [in] pk_seed Public key seed. - * @param [in] adrs HashAddress. - * @param [in] m Message of n bytes. - * @param [in] n Number of bytes in hash output. - * @param [out] hash Buffer to hold hash output. - * @return 0 on success. - * @return SHAKE-256 error return code on digest failure. - */ -#define HASH_F(shake, pk_seed, adrs, m, n, hash) \ - slhdsakey_hash_shake_3(shake, pk_seed, n, adrs, m, n, hash, n) -/* Hash H. - * - * FIPS 205. Section 4.1. - * H(PK.seed, ADRS, M2) (Bn x B32 x B2n -> Bn ) is a special case of Tl that - * takes a 2n-byte message as input. - * FIPS 205. Section 11.1. - * H(PK.seed, ADRS, M2) = SHAKE256(PK.seed || ADRS || M2, 8n) - * - * @param [in] shake SHAKE-256 object. - * @param [in] pk_seed Public key seed. - * @param [in] adrs HashAddress. - * @param [in] m Message of 2*n bytes. - * @param [in] n Number of bytes in hash output. - * @param [out] hash Buffer to hold hash output. - * @return 0 on success. - * @return SHAKE-256 error return code on digest failure. - */ -#define HASH_H(shake, pk_seed, adrs, node, n, hash) \ - slhdsakey_hash_shake_3(shake, pk_seed, n, adrs, node, 2 * (n), hash, (n)) +#define HASH_PRF(k, pk_seed, sk_seed, adrs, n, o) \ + slhdsakey_hash_shake_3(&(k)->hash.shk.shake, pk_seed, n, adrs, \ + sk_seed, n, o, n) +/* Hash F. */ +#define HASH_F(k, pk_seed, adrs, m, n, o) \ + slhdsakey_hash_shake_3(&(k)->hash.shk.shake, pk_seed, n, adrs, m, n, \ + o, n) +/* Hash H. */ +#define HASH_H(k, pk_seed, adrs, node, n, o) \ + slhdsakey_hash_shake_3(&(k)->hash.shk.shake, pk_seed, n, adrs, node, \ + 2 * (n), o, (n)) #else -/* PRF hash. - * - * FIPS 205. Section 4.1. - * PRF(PK.seed, SK.seed, ADRS) (Bn x Bn x B32 -> Bn) is a PRF that is used to - * generate the secret values in WOTS+ and FORS private keys. - * FIPS 205. Section 11.1. - * F(PK.seed, SK.seed, ADRS) = SHAKE256(PK.seed || ADRS || SK.seed, 8n) - * - * @param [in] shake SHAKE-256 object. - * @param [in] pk_seed Public key seed. - * @param [in] sk_seed Private key seed. - * @param [in] adrs HashAddress. - * @param [in] n Number of bytes in hash output. - * @param [out] hash Buffer to hold hash output. - * @return 0 on success. - * @return SHAKE-256 error return code on digest failure. - */ -#define HASH_PRF(shake, pk_seed, sk_seed, adrs, n, hash) \ - slhdsakey_hash_shake_4(shake, pk_seed, n, adrs, sk_seed, n, NULL, 0, \ - hash, n) -/* Hash F. - * - * FIPS 205. Section 4.1. - * F(PK.seed, ADRS, M1) (Bn x B32 x Bn -> Bn ) is a hash function that takes - * an n-byte message as input and produces an n-byte output. - * FIPS 205. Section 11.1. - * F(PK.seed, ADRS, M1) = SHAKE256(PK.seed || ADRS || M1, 8n) - * - * @param [in] shake SHAKE-256 object. - * @param [in] pk_seed Public key seed. - * @param [in] adrs HashAddress. - * @param [in] m Message of n bytes. - * @param [in] n Number of bytes in hash output. - * @param [out] hash Buffer to hold hash output. - * @return 0 on success. - * @return SHAKE-256 error return code on digest failure. - */ -#define HASH_F(shake, pk_seed, adrs, m, n, hash) \ - slhdsakey_hash_shake_4(shake, pk_seed, n, adrs, m, n, NULL, 0, hash, n) -/* Hash H. - * - * FIPS 205. Section 4.1. - * H(PK.seed, ADRS, M2) (Bn x B32 x B2n -> Bn ) is a special case of Tl that - * takes a 2n-byte message as input. - * FIPS 205. Section 11.1. - * H(PK.seed, ADRS, M2) = SHAKE256(PK.seed || ADRS || M2, 8n) - * - * @param [in] shake SHAKE-256 object. - * @param [in] pk_seed Public key seed. - * @param [in] adrs HashAddress. - * @param [in] m Message of 2*n bytes. - * @param [in] n Number of bytes in hash output. - * @param [out] hash Buffer to hold hash output. - * @return 0 on success. - * @return SHAKE-256 error return code on digest failure. - */ -#define HASH_H(shake, pk_seed, adrs, node, n, hash) \ - slhdsakey_hash_shake_4(shake, pk_seed, n, adrs, node, 2 * n, NULL, 0, \ - hash, n) +/* PRF hash. */ +#define HASH_PRF(k, pk_seed, sk_seed, adrs, n, o) \ + slhdsakey_hash_shake_4(&(k)->hash.shk.shake, pk_seed, n, adrs, \ + sk_seed, n, NULL, 0, o, n) +/* Hash F. */ +#define HASH_F(k, pk_seed, adrs, m, n, o) \ + slhdsakey_hash_shake_4(&(k)->hash.shk.shake, pk_seed, n, adrs, m, n, \ + NULL, 0, o, n) +/* Hash H. */ +#define HASH_H(k, pk_seed, adrs, node, n, o) \ + slhdsakey_hash_shake_4(&(k)->hash.shk.shake, pk_seed, n, adrs, node, \ + 2 * n, NULL, 0, o, n) #endif -/* Hash H with 2n byte message as two separate n byte parameters. - * - * FIPS 205. Section 4.1. - * H(PK.seed, ADRS, M2) (Bn x B32 x B2n -> Bn ) is a special case of Tl that - * takes a 2n-byte message as input. - * FIPS 205. Section 11.1. - * H(PK.seed, ADRS, M2) = SHAKE256(PK.seed || ADRS || M2, 8n) - * - * @param [in] shake SHAKE-256 object. - * @param [in] pk_seed Public key seed. - * @param [in] adrs HashAddress. - * @param [in] m1 First n bytes of message. - * @param [in] m2 Second n bytes of message. - * @param [in] n Number of bytes in hash output. - * @param [out] hash Buffer to hold hash output. - * @return 0 on success. - * @return SHAKE-256 error return code on digest failure. - */ -#define HASH_H_2(shake, pk_seed, adrs, m1, m2, n, hash) \ - slhdsakey_hash_shake_4(shake, pk_seed, n, adrs, m1, n, m2, n, hash, n) +/* Hash H with 2n byte message as two separate n byte parameters. */ +#define HASH_H_2(k, pk_seed, adrs, m1, m2, n, o) \ + slhdsakey_hash_shake_4(&(k)->hash.shk.shake, pk_seed, n, adrs, m1, n, \ + m2, n, o, n) + +#endif /* WOLFSSL_SLHDSA_SHA2 */ + +/* T_l streaming dispatch macros for the secondary hash (used by WOTS+ pk + * compression and FORS root computation). */ +#ifdef WOLFSSL_SLHDSA_SHA2 + +#define HASH_T_START_ADDR(k, pk_seed, adrs, n) \ + (SLHDSA_IS_SHA2((k)->params->param) ? \ + slhdsakey_hash_start_addr_sha2(k, pk_seed, adrs, n) : \ + slhdsakey_hash_start_addr(&(k)->hash.shk.shake2, pk_seed, adrs, n)) + +#define HASH_T_UPDATE(k, d, l) \ + (SLHDSA_IS_SHA2((k)->params->param) ? \ + slhdsakey_hash_update_sha2(k, d, l) : \ + slhdsakey_hash_update(&(k)->hash.shk.shake2, d, l)) + +#define HASH_T_FINAL(k, o, l) \ + (SLHDSA_IS_SHA2((k)->params->param) ? \ + slhdsakey_hash_final_sha2(k, o, l) : \ + slhdsakey_hash_final(&(k)->hash.shk.shake2, o, l)) + +#else + +#define HASH_T_START_ADDR(k, pk_seed, adrs, n) \ + slhdsakey_hash_start_addr(&(k)->hash.shk.shake2, pk_seed, adrs, n) + +#define HASH_T_UPDATE(k, d, l) \ + slhdsakey_hash_update(&(k)->hash.shk.shake2, d, l) + +#define HASH_T_FINAL(k, o, l) \ + slhdsakey_hash_final(&(k)->hash.shk.shake2, o, l) + +#endif /* WOLFSSL_SLHDSA_SHA2 */ /* Start hashing with SHAKE-256. * @@ -925,13 +1624,13 @@ static int slhdsakey_chain(SlhDsaKey* key, const byte* x, byte i, byte s, /* Set the hash address for first iteration. */ HA_SetHashAddress(adrs, i); /* First iteration of hash using input and writing to output buffers. */ - ret = HASH_F(&key->shake, pk_seed, adrs, x, n, node); + ret = HASH_F(key, pk_seed, adrs, x, n, node); if (ret == 0) { for (j = i + 1; j < i + s; j++) { /* Set the hash address. */ HA_SetHashAddress(adrs, j); /* Iterate hash using output buffer as input. */ - ret = HASH_F(&key->shake, pk_seed, adrs, node, n, node); + ret = HASH_F(key, pk_seed, adrs, node, n, node); if (ret != 0) { break; } @@ -2139,7 +2838,7 @@ static int slhdsakey_wots_pkgen_chain_x4_16(SlhDsaKey* key, const byte* sk_seed, } } if (ret == 0) { - ret = slhdsakey_hash_update(&key->shake2, sk, len * 16); + ret = HASH_T_UPDATE(key, sk, len * 16); } WC_FREE_VAR_EX(sk, key->heap, DYNAMIC_TYPE_SLHDSA); @@ -2207,7 +2906,7 @@ static int slhdsakey_wots_pkgen_chain_x4_24(SlhDsaKey* key, const byte* sk_seed, } } if (ret == 0) { - ret = slhdsakey_hash_update(&key->shake2, sk, len * 24); + ret = HASH_T_UPDATE(key, sk, len * 24); } WC_FREE_VAR_EX(sk, key->heap, DYNAMIC_TYPE_SLHDSA); @@ -2275,7 +2974,7 @@ static int slhdsakey_wots_pkgen_chain_x4_32(SlhDsaKey* key, const byte* sk_seed, } } if (ret == 0) { - ret = slhdsakey_hash_update(&key->shake2, sk, len * 32); + ret = HASH_T_UPDATE(key, sk, len * 32); } WC_FREE_VAR_EX(sk, key->heap, DYNAMIC_TYPE_SLHDSA); @@ -2396,7 +3095,7 @@ static int slhdsakey_wots_pkgen_chain_c(SlhDsaKey* key, const byte* sk_seed, /* Step 5. Set chain address for WOTS PRF. */ HA_SetChainAddress(sk_adrs, i); /* Step 6. PRF hash seeds and chain address. */ - ret = HASH_PRF(&key->shake, pk_seed, sk_seed, sk_adrs, n, + ret = HASH_PRF(key, pk_seed, sk_seed, sk_adrs, n, sk + i * n); if (ret != 0) { break; @@ -2413,7 +3112,7 @@ static int slhdsakey_wots_pkgen_chain_c(SlhDsaKey* key, const byte* sk_seed, } if (ret == 0) { /* Step 13: Compress public key. */ - ret = slhdsakey_hash_update(&key->shake2, sk, len * n); + ret = HASH_T_UPDATE(key, sk, len * n); } WC_FREE_VAR_EX(sk, key->heap, DYNAMIC_TYPE_SLHDSA); #else @@ -2424,7 +3123,7 @@ static int slhdsakey_wots_pkgen_chain_c(SlhDsaKey* key, const byte* sk_seed, /* Step 5. Set chain address for WOTS PRF. */ HA_SetChainAddress(sk_adrs, i); /* Step 6. PRF hash seeds and chain address. */ - ret = HASH_PRF(&key->shake, pk_seed, sk_seed, sk_adrs, n, sk); + ret = HASH_PRF(key, pk_seed, sk_seed, sk_adrs, n, sk); if (ret != 0) { break; } @@ -2437,7 +3136,7 @@ static int slhdsakey_wots_pkgen_chain_c(SlhDsaKey* key, const byte* sk_seed, } /* Step 13: Compress public key - for each tmp. */ - ret = slhdsakey_hash_update(&key->shake2, sk, n); + ret = HASH_T_UPDATE(key, sk, n); if (ret != 0) { break; } @@ -2482,7 +3181,7 @@ static int slhdsakey_wots_pkgen(SlhDsaKey* key, const byte* sk_seed, HA_Copy(wotspk_adrs, adrs); HA_SetTypeAndClearNotKPA(wotspk_adrs, HA_WOTS_PK); /* Step 13. Start hash with public key seed and address. */ - ret = slhdsakey_hash_start_addr(&key->shake2, pk_seed, wotspk_adrs, n); + ret = HASH_T_START_ADDR(key, pk_seed, wotspk_adrs, n); } if (ret == 0) { HashAddress sk_adrs; @@ -2506,7 +3205,7 @@ static int slhdsakey_wots_pkgen(SlhDsaKey* key, const byte* sk_seed, } if (ret == 0) { /* Step 13: Output hash of compressed public key. */ - ret = slhdsakey_hash_final(&key->shake2, node, n); + ret = HASH_T_FINAL(key, node, n); } return ret; @@ -2908,7 +3607,7 @@ static int slhdsakey_wots_sign(SlhDsaKey* key, const byte* m, /* Step 12: Set chain address for WOTS PRF. */ HA_SetChainAddress(sk_adrs, i); /* Step 13. PRF hash seeds and chain address. */ - ret = HASH_PRF(&key->shake, pk_seed, sk_seed, sk_adrs, n, sig); + ret = HASH_PRF(key, pk_seed, sk_seed, sk_adrs, n, sig); if (ret != 0) { break; } @@ -3281,14 +3980,14 @@ static int slhdsakey_wots_pk_from_sig_x4(SlhDsaKey* key, const byte* sig, if (ret == 0) { HA_Copy(wotspk_adrs, adrs); HA_SetTypeAndClearNotKPA(wotspk_adrs, HA_WOTS_PK); - ret = slhdsakey_hash_start_addr(&key->shake2, pk_seed, wotspk_adrs, n); + ret = HASH_T_START_ADDR(key, pk_seed, wotspk_adrs, n); } if (ret == 0) { - ret = slhdsakey_hash_update(&key->shake2, nodes, len * n); + ret = HASH_T_UPDATE(key, nodes, len * n); sig += len * n; } if (ret == 0) { - ret = slhdsakey_hash_final(&key->shake2, pk_sig, n); + ret = HASH_T_FINAL(key, pk_sig, n); } WC_FREE_VAR_EX(nodes, key->heap, DYNAMIC_TYPE_SLHDSA); @@ -3354,15 +4053,15 @@ static int slhdsakey_wots_pk_from_sig_c(SlhDsaKey* key, const byte* sig, HA_Copy(wotspk_adrs, adrs); HA_SetTypeAndClearNotKPA(wotspk_adrs, HA_WOTS_PK); /* Step 15: Hash the public key seed and WOTS PK address ... */ - ret = slhdsakey_hash_start_addr(&key->shake2, pk_seed, wotspk_adrs, n); + ret = HASH_T_START_ADDR(key, pk_seed, wotspk_adrs, n); } if (ret == 0) { /* Step 15: Update with the nodes ... */ - ret = slhdsakey_hash_update(&key->shake2, nodes, len * n); + ret = HASH_T_UPDATE(key, nodes, len * n); } if (ret == 0) { /* Step 15: Generate root node - public key signature. */ - ret = slhdsakey_hash_final(&key->shake2, pk_sig, n); + ret = HASH_T_FINAL(key, pk_sig, n); } WC_FREE_VAR_EX(nodes, key->heap, DYNAMIC_TYPE_SLHDSA); @@ -3408,7 +4107,7 @@ static int slhdsakey_wots_pk_from_sig_c(SlhDsaKey* key, const byte* sig, HA_Copy(wotspk_adrs, adrs); HA_SetTypeAndClearNotKPA(wotspk_adrs, HA_WOTS_PK); /* Step 15: Hash the public key seed and WOTS PK address ... */ - ret = slhdsakey_hash_start_addr(&key->shake2, pk_seed, wotspk_adrs, n); + ret = HASH_T_START_ADDR(key, pk_seed, wotspk_adrs, n); if (ret == 0) { /* Step 8: For each value in msg. */ for (i = 0; i < len; i++) { @@ -3421,7 +4120,7 @@ static int slhdsakey_wots_pk_from_sig_c(SlhDsaKey* key, const byte* sig, break; } /* Step 15: Update with node ... */ - ret = slhdsakey_hash_update(&key->shake2, node, n); + ret = HASH_T_UPDATE(key, node, n); if (ret != 0) { break; } @@ -3431,7 +4130,7 @@ static int slhdsakey_wots_pk_from_sig_c(SlhDsaKey* key, const byte* sig, } if (ret == 0) { /* Step 15: Generate root node - public key signature. */ - ret = slhdsakey_hash_final(&key->shake2, pk_sig, n); + ret = HASH_T_FINAL(key, pk_sig, n); } return ret; @@ -3587,7 +4286,7 @@ static int slhdsakey_xmss_node(SlhDsaKey* key, const byte* sk_seed, int i, HA_SetTreeHeight(adrs, z - k); HA_SetTreeIndex(adrs, (m * i + j) >> (z - k)); /* Step 11: Calculate node from two below. */ - ret = HASH_H(&key->shake, pk_seed, adrs, nodes + k * n, + ret = HASH_H(key, pk_seed, adrs, nodes + k * n, n, nodes + (k - 1 + ((j >> (z-k)) & 1)) * n); if (ret != 0) { break; @@ -3608,7 +4307,7 @@ static int slhdsakey_xmss_node(SlhDsaKey* key, const byte* sk_seed, int i, HA_SetTreeHeight(adrs, z); HA_SetTreeIndex(adrs, i); /* Step 11: Calculate node from two below. */ - ret = HASH_H(&key->shake, pk_seed, adrs, nodes, n, node); + ret = HASH_H(key, pk_seed, adrs, nodes, n, node); } } @@ -3679,7 +4378,7 @@ static int slhdsakey_xmss_node(SlhDsaKey* key, const byte* sk_seed, int i, HA_SetTreeHeight(adrs, z); HA_SetTreeIndex(adrs, i); /* Step 11: Calculate node from two below. */ - ret = HASH_H(&key->shake, pk_seed, adrs, nodes, n, node); + ret = HASH_H(key, pk_seed, adrs, nodes, n, node); } } @@ -3829,11 +4528,11 @@ static int slhdsakey_xmss_pk_from_sig(SlhDsaKey* key, word32 idx, /* Step 10: Check which order to put nodes. */ if (side == 0) { /* Steps 12,17: Calculate node with sig node on right. */ - ret = HASH_H_2(&key->shake, pk_seed, adrs, node, auth, n, node); + ret = HASH_H_2(key, pk_seed, adrs, node, auth, n, node); } else { /* Steps 15,17: Calculate node with sig node on left. */ - ret = HASH_H_2(&key->shake, pk_seed, adrs, auth, node, n, node); + ret = HASH_H_2(key, pk_seed, adrs, auth, node, n, node); } if (ret != 0) { break; @@ -4076,7 +4775,7 @@ static int slhdsakey_fors_sk_gen(SlhDsaKey* key, const byte* sk_seed, /* Step 4: Set tree index. */ HA_SetTreeIndex(sk_adrs, idx); /* Step 5: Hash seeds and address. */ - return HASH_PRF(&key->shake, pk_seed, sk_seed, sk_adrs, key->params->n, + return HASH_PRF(key, pk_seed, sk_seed, sk_adrs, key->params->n, node); } @@ -4297,7 +4996,7 @@ static int slhdsakey_fors_node_x4_z0(SlhDsaKey* key, const byte* sk_seed, /* Step 4: Set tree index. */ HA_SetTreeIndex(adrs, i); /* Step 5: Compute node from public key seed, address and value. */ - ret = HASH_F(&key->shake, pk_seed, adrs, node, n, node); + ret = HASH_F(key, pk_seed, adrs, node, n, node); } return ret; @@ -4349,7 +5048,7 @@ static int slhdsakey_fors_node_x4_z1(SlhDsaKey* key, const byte* sk_seed, /* Step 4: Set tree index. */ HA_SetTreeIndex(adrs, 2 * i + 0); /* Step 5: Compute node from public key seed, address and value. */ - ret = HASH_F(&key->shake, pk_seed, adrs, nodes, n, nodes); + ret = HASH_F(key, pk_seed, adrs, nodes, n, nodes); } /* Step 8: Compute right node. */ if (ret == 0) { @@ -4361,7 +5060,7 @@ static int slhdsakey_fors_node_x4_z1(SlhDsaKey* key, const byte* sk_seed, /* Step 4: Set tree index. */ HA_SetTreeIndex(adrs, 2 * i + 1); /* Step 5: Compute node from public key seed, address and value. */ - ret = HASH_F(&key->shake, pk_seed, adrs, nodes + n, n, nodes + n); + ret = HASH_F(key, pk_seed, adrs, nodes + n, n, nodes + n); } if (ret == 0) { /* Step 9: Set tree height. */ @@ -4369,7 +5068,7 @@ static int slhdsakey_fors_node_x4_z1(SlhDsaKey* key, const byte* sk_seed, /* Step 10: Set tree index. */ HA_SetTreeIndex(adrs, i); /* Step 11: Compute node from public key seed, address and nodes. */ - ret = HASH_H(&key->shake, pk_seed, adrs, nodes, n, node); + ret = HASH_H(key, pk_seed, adrs, nodes, n, node); } return ret; @@ -4480,14 +5179,14 @@ static int slhdsakey_fors_node_x4_low(SlhDsaKey* key, const byte* sk_seed, /* Step 10: Set tree index. */ HA_SetTreeIndex(adrs, 2 * i + 0); /* Step 11: Compute node from public key seed, address and nodes. */ - ret = HASH_H(&key->shake, pk_seed, adrs, nodes, n, nodes); + ret = HASH_H(key, pk_seed, adrs, nodes, n, nodes); } /* Step 8: Compute right node. */ if (ret == 0) { /* Step 10: Set tree index. */ HA_SetTreeIndex(adrs, 2 * i + 1); /* Step 11: Compute node from public key seed, address and nodes. */ - ret = HASH_H(&key->shake, pk_seed, adrs, nodes + 2 * n, n, + ret = HASH_H(key, pk_seed, adrs, nodes + 2 * n, n, nodes + 1 * n); } if (ret == 0) { @@ -4496,7 +5195,7 @@ static int slhdsakey_fors_node_x4_low(SlhDsaKey* key, const byte* sk_seed, /* Step 10: Set tree index. */ HA_SetTreeIndex(adrs, i); /* Step 11: Compute node from public key seed, address and nodes. */ - ret = HASH_H(&key->shake, pk_seed, adrs, nodes, n, node); + ret = HASH_H(key, pk_seed, adrs, nodes, n, node); } WC_FREE_VAR_EX(nodes, key->heap, DYNAMIC_TYPE_SLHDSA); @@ -4592,14 +5291,14 @@ static int slhdsakey_fors_node_x4_high(SlhDsaKey* key, const byte* sk_seed, /* Step 10: Set tree index. */ HA_SetTreeIndex(adrs, 2 * i + 0); /* Step 11: Compute node from public key seed, address and nodes. */ - ret = HASH_H(&key->shake, pk_seed, adrs, nodes, n, nodes); + ret = HASH_H(key, pk_seed, adrs, nodes, n, nodes); } /* Step 8: Compute right node. */ if ((ret == 0) && (z2 > 1)) { /* Step 10: Set tree index. */ HA_SetTreeIndex(adrs, 2 * i + 1); /* Step 11: Compute node from public key seed, address and nodes. */ - ret = HASH_H(&key->shake, pk_seed, adrs, nodes + 2 * n, n, + ret = HASH_H(key, pk_seed, adrs, nodes + 2 * n, n, nodes + 1 * n); } if (ret == 0) { @@ -4608,7 +5307,7 @@ static int slhdsakey_fors_node_x4_high(SlhDsaKey* key, const byte* sk_seed, /* Step 10: Set tree index. */ HA_SetTreeIndex(adrs, i); /* Step 11: Compute node from public key seed, address and nodes. */ - ret = HASH_H(&key->shake, pk_seed, adrs, nodes, n, node); + ret = HASH_H(key, pk_seed, adrs, nodes, n, node); } WC_FREE_VAR_EX(nodes, key->heap, DYNAMIC_TYPE_SLHDSA); @@ -4725,7 +5424,7 @@ static int slhdsakey_fors_node_c(SlhDsaKey* key, const byte* sk_seed, word32 i, /* Step 4: Set tree index. */ HA_SetTreeIndex(adrs, i); /* Step 5: Compute node from public key seed, address and value. */ - ret = HASH_F(&key->shake, pk_seed, adrs, node, n, node); + ret = HASH_F(key, pk_seed, adrs, node, n, node); } } /* Step 6: Non leaf node. */ @@ -4754,7 +5453,7 @@ static int slhdsakey_fors_node_c(SlhDsaKey* key, const byte* sk_seed, word32 i, HA_SetTreeIndex(adrs, m * i + j); /* Step 5: Compute node from public key seed, address and value. */ - ret = HASH_F(&key->shake, pk_seed, adrs, nodes + o, n, + ret = HASH_F(key, pk_seed, adrs, nodes + o, n, nodes + o); if (ret != 0) { break; @@ -4771,7 +5470,7 @@ static int slhdsakey_fors_node_c(SlhDsaKey* key, const byte* sk_seed, word32 i, HA_SetTreeIndex(adrs, (m * i + j) >> (z - k)); /* Step 11: Compute node from public key seed, address * and left and right nodes. */ - ret = HASH_H(&key->shake, pk_seed, adrs, nodes + k * n, + ret = HASH_H(key, pk_seed, adrs, nodes + k * n, n, nodes + (k - 1 + ((j >> (z-k)) & 1)) * n); if (ret != 0) { break; @@ -4790,7 +5489,7 @@ static int slhdsakey_fors_node_c(SlhDsaKey* key, const byte* sk_seed, word32 i, HA_SetTreeIndex(adrs, i); /* Step 11: Compute node from public key seed, address * and nodes. */ - ret = HASH_H(&key->shake, pk_seed, adrs, nodes, n, node); + ret = HASH_H(key, pk_seed, adrs, nodes, n, node); } } @@ -4847,7 +5546,7 @@ static int slhdsakey_fors_node_c(SlhDsaKey* key, const byte* sk_seed, word32 i, /* Step 4: Set tree index. */ HA_SetTreeIndex(adrs, i); /* Step 5: Compute node from public key seed, address and value. */ - ret = HASH_F(&key->shake, pk_seed, adrs, node, n, node); + ret = HASH_F(key, pk_seed, adrs, node, n, node); } } else { @@ -4867,7 +5566,7 @@ static int slhdsakey_fors_node_c(SlhDsaKey* key, const byte* sk_seed, word32 i, /* Step 10: Set tree index. */ HA_SetTreeIndex(adrs, i); /* Step 11: Compute node from public key seed, address and nodes. */ - ret = HASH_H(&key->shake, pk_seed, adrs, nodes, n, node); + ret = HASH_H(key, pk_seed, adrs, nodes, n, node); } } @@ -5275,7 +5974,7 @@ static int slhdsakey_fors_pk_from_sig_x4(SlhDsaKey* key, const byte* sig_fors, /* Step 5: Set tree index for address. */ HA_SetTreeIndex(adrs, idx); /* Step 6: Compute node from public key seed, address and value. */ - ret = HASH_F(&key->shake, pk_seed, adrs, sig_fors, n, node + i * n); + ret = HASH_F(key, pk_seed, adrs, sig_fors, n, node + i * n); if (ret != 0) { break; } @@ -5296,12 +5995,12 @@ static int slhdsakey_fors_pk_from_sig_x4(SlhDsaKey* key, const byte* sig_fors, /* Step 10: Check which side node is on. */ if (side == 0) { /* Step 12: Hash node || auth node. */ - ret = HASH_H_2(&key->shake, pk_seed, adrs, node + i * n, + ret = HASH_H_2(key, pk_seed, adrs, node + i * n, sig_fors, n, node + i * n); } else { /* Step 15: Hash auth node || node. */ - ret = HASH_H_2(&key->shake, pk_seed, adrs, sig_fors, + ret = HASH_H_2(key, pk_seed, adrs, sig_fors, node + i * n, n, node + i * n); } if (ret != 0) { @@ -5317,7 +6016,7 @@ static int slhdsakey_fors_pk_from_sig_x4(SlhDsaKey* key, const byte* sig_fors, } if (ret == 0) { /* Step 24: Add more root nodes to hash ... */ - ret = slhdsakey_hash_update(&key->shake2, node, i * n); + ret = HASH_T_UPDATE(key, node, i * n); } WC_FREE_VAR_EX(node, key->heap, DYNAMIC_TYPE_SLHDSA); @@ -5394,7 +6093,7 @@ static int slhdsakey_fors_pk_from_sig_c(SlhDsaKey* key, const byte* sig_fors, /* Step 5: Set tree index for address. */ HA_SetTreeIndex(adrs, idx); /* Step 6: Compute node from public key seed, address and value. */ - ret = HASH_F(&key->shake, pk_seed, adrs, sig_fors, n, node + i * n); + ret = HASH_F(key, pk_seed, adrs, sig_fors, n, node + i * n); if (ret != 0) { break; } @@ -5415,12 +6114,12 @@ static int slhdsakey_fors_pk_from_sig_c(SlhDsaKey* key, const byte* sig_fors, /* Step 10: Check which side node is on. */ if (bit == 0) { /* Step 12: Hash node || auth node. */ - ret = HASH_H_2(&key->shake, pk_seed, adrs, node + i * n, + ret = HASH_H_2(key, pk_seed, adrs, node + i * n, sig_fors, n, node + i * n); } else { /* Step 15: Hash auth node || node. */ - ret = HASH_H_2(&key->shake, pk_seed, adrs, sig_fors, + ret = HASH_H_2(key, pk_seed, adrs, sig_fors, node + i * n, n, node + i * n); } if (ret != 0) { @@ -5436,7 +6135,7 @@ static int slhdsakey_fors_pk_from_sig_c(SlhDsaKey* key, const byte* sig_fors, } if (ret == 0) { /* Step 24: Add more root nodes to hash ... */ - ret = slhdsakey_hash_update(&key->shake2, node, i * n); + ret = HASH_T_UPDATE(key, node, i * n); } WC_FREE_VAR_EX(node, key->heap, DYNAMIC_TYPE_SLHDSA); @@ -5505,7 +6204,7 @@ static int slhdsakey_fors_pk_from_sig_c(SlhDsaKey* key, const byte* sig_fors, /* Step 5: Set tree index for address. */ HA_SetTreeIndex(adrs, idx); /* Step 6: Compute node from public key seed, address and value. */ - ret = HASH_F(&key->shake, pk_seed, adrs, sig_fors, n, node); + ret = HASH_F(key, pk_seed, adrs, sig_fors, n, node); if (ret != 0) { break; } @@ -5526,12 +6225,12 @@ static int slhdsakey_fors_pk_from_sig_c(SlhDsaKey* key, const byte* sig_fors, /* Step 10: Check which side node is on. */ if (bit == 0) { /* Step 12: Hash node || auth node. */ - ret = HASH_H_2(&key->shake, pk_seed, adrs, node, sig_fors, n, + ret = HASH_H_2(key, pk_seed, adrs, node, sig_fors, n, node); } else { /* Step 15: Hash auth node || node. */ - ret = HASH_H_2(&key->shake, pk_seed, adrs, sig_fors, node, n, + ret = HASH_H_2(key, pk_seed, adrs, sig_fors, node, n, node); } if (ret != 0) { @@ -5542,7 +6241,7 @@ static int slhdsakey_fors_pk_from_sig_c(SlhDsaKey* key, const byte* sig_fors, } if (ret == 0) { /* Step 24: Add root node to hash ... */ - ret = slhdsakey_hash_update(&key->shake2, node, n); + ret = HASH_T_UPDATE(key, node, n); } if (ret != 0) { break; @@ -5595,7 +6294,7 @@ static int slhdsakey_fors_pk_from_sig(SlhDsaKey* key, const byte* sig_fors, /* Steps 22-23: Set type and clear all but key pair address. */ HA_SetTypeAndClearNotKPA(forspk_adrs, HA_FORS_ROOTS); /* Step 24: Add public key seed and FORS roots address to hash ... */ - ret = slhdsakey_hash_start_addr(&key->shake2, pk_seed, forspk_adrs, n); + ret = HASH_T_START_ADDR(key, pk_seed, forspk_adrs, n); /* Steps 2-20: Compute roots and add to hash. */ #if defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_WC_SLHDSA_SMALL) @@ -5614,7 +6313,7 @@ static int slhdsakey_fors_pk_from_sig(SlhDsaKey* key, const byte* sig_fors, if (ret == 0) { /* Step 24. Compute FORS public key. */ - ret = slhdsakey_hash_final(&key->shake2, pk_fors, n); + ret = HASH_T_FINAL(key, pk_fors, n); } return ret; @@ -5664,15 +6363,7 @@ int wc_SlhDsaKey_Init(SlhDsaKey* key, enum SlhDsaParam param, void* heap, /* Zeroize key. */ XMEMSET(key, 0, sizeof(SlhDsaKey)); - /* Initialize SHAKE-256 object. */ - ret = wc_InitShake256(&key->shake, key->heap, INVALID_DEVID); - } - if (ret == 0) { - /* Initialize second SHAKE-256 object. */ - ret = wc_InitShake256(&key->shake2, key->heap, INVALID_DEVID); - } - if (ret == 0) { - /* Set the parameters into key. */ + /* Set the parameters into key early so SLHDSA_IS_SHA2 works. */ key->params = &SlhDsaParams[idx]; /* Set heap hint to use with all allocations. */ key->heap = heap; @@ -5680,6 +6371,32 @@ int wc_SlhDsaKey_Init(SlhDsaKey* key, enum SlhDsaParam param, void* heap, /* Set device id. */ key->devId = devId; #endif + +#ifdef WOLFSSL_SLHDSA_SHA2 + if (SLHDSA_IS_SHA2(param)) { + /* Initialize SHA2 hash objects. */ + ret = wc_InitSha256(&key->hash.sha2.sha256); + if (ret == 0) { + ret = wc_InitSha256(&key->hash.sha2.sha256_2); + } + if ((ret == 0) && (key->params->n > 16)) { + ret = wc_InitSha512(&key->hash.sha2.sha512); + if (ret == 0) { + ret = wc_InitSha512(&key->hash.sha2.sha512_2); + } + } + } + else +#endif + { + /* Initialize SHAKE-256 objects. */ + ret = wc_InitShake256(&key->hash.shk.shake, key->heap, + INVALID_DEVID); + if (ret == 0) { + ret = wc_InitShake256(&key->hash.shk.shake2, key->heap, + INVALID_DEVID); + } + } } (void)devId; @@ -5701,9 +6418,25 @@ void wc_SlhDsaKey_Free(SlhDsaKey* key) if ((key != NULL) && (key->params != NULL)) { /* Ensure the private key data is zeroized. */ ForceZero(key->sk, key->params->n * 2); - /* Dispose of the SHAKE-256 objects. */ - wc_Shake256_Free(&key->shake2); - wc_Shake256_Free(&key->shake); +#ifdef WOLFSSL_SLHDSA_SHA2 + if (SLHDSA_IS_SHA2(key->params->param)) { + /* Dispose of the SHA2 hash objects. */ + wc_Sha256Free(&key->hash.sha2.sha256); + wc_Sha256Free(&key->hash.sha2.sha256_2); + wc_Sha256Free(&key->hash.sha2.sha256_mid); + if (key->params->n > 16) { + wc_Sha512Free(&key->hash.sha2.sha512); + wc_Sha512Free(&key->hash.sha2.sha512_2); + wc_Sha512Free(&key->hash.sha2.sha512_mid); + } + } + else +#endif + { + /* Dispose of the SHAKE-256 objects. */ + wc_Shake256_Free(&key->hash.shk.shake2); + wc_Shake256_Free(&key->hash.shk.shake); + } } } @@ -5890,6 +6623,16 @@ int wc_SlhDsaKey_MakeKeyWithRandom(SlhDsaKey* key, const byte* sk_seed, XMEMCPY(key->sk + 2 * n, pk_seed, n); } +#ifdef WOLFSSL_SLHDSA_SHA2 + /* Pre-compute SHA2 midstates now that PK.seed is set. */ + if (SLHDSA_IS_SHA2(key->params->param)) { + ret = slhdsakey_precompute_sha2_midstates(key); + } + if (ret != 0) { + return ret; + } +#endif + /* Step 1: Set address to all zeroes. */ HA_Init(adrs); /* Step 2: Set the address layer to the top of the subtree. */ @@ -5965,36 +6708,113 @@ static int slhdsakey_sign(SlhDsaKey* key, byte* md, byte* sig) return ret; } -/* Generate a pure SLH-DSA signature. +/* Lower-level sign: slh_sign_internal(M, SK, addrnd). * - * FIPS 205. Section 10.2.2. Algorithm 22. - * slh_sign(M, ctx, SK) - * 1: if |ctx| > 255 then - * 2: return falsity - * > return an error indication if the context string is too long - * 3: end if - * 4: addrnd <-$- Bn > skip lines 4 through 7 for the deterministic variant - * 5: if addrnd = NULL then - * 6: return falsity - * > return an error indication if random bit generation failed - * 7: end if - * 8: M' <- toByte(0, 1) || toByte(|ctx|, 1) || ctx || M - * > omit addrnd for the deterministic variant - * 9: SIG <- slh_sign_internal(M', SK, addrnd) - * 10: return SIG + * Takes M directly and performs PRF_msg, H_msg, and the FORS + hypertree + * signing -- Algorithm 19 without the M' construction of Algorithm 22. * * FIPS 205. Section 9.2. Algorithm 19. * slh_sign_internal(M, SK, addrnd) - * ... * 2: opt_rand <- addrnd - * > substitute opt_rand <- PK.seed for the deterministic variant - * 3: R <- PRFmsg (SK.prf, opt_rand, M) > generate randomizer + * 3: R <- PRFmsg(SK.prf, opt_rand, M) * 4: SIG <- R - * 5: digest <- Hmsg(R, PK.seed, PK.root, M) > compute message digest - * 6: md <- digest [0 : upper(k.a / 8)] > first upper(k.a / 8)] bytes + * 5: digest <- Hmsg(R, PK.seed, PK.root, M) + * 6: md <- digest[0 : upper(k*a / 8)] * ... * - * Note: ctx length is of type byte which means it can never be more than 255. + * @param [in] key SLH-DSA key (private key must be set). + * @param [in] m Message (goes directly to PRF_msg and H_msg). + * @param [in] mSz Length of message in bytes. + * @param [out] sig Buffer to hold signature. + * @param [in, out] sigSz On in, buffer length. On out, signature length. + * @param [in] addRnd opt_rand (PK.seed for deterministic). + * @return 0 on success. + */ +static int slhdsakey_sign_internal_msg(SlhDsaKey* key, const byte* m, + word32 mSz, byte* sig, word32* sigSz, const byte* addRnd) +{ + int ret = 0; + + /* Validate parameters. */ + if ((key == NULL) || (key->params == NULL) || (m == NULL) || + (sig == NULL) || (sigSz == NULL) || (addRnd == NULL)) { + ret = BAD_FUNC_ARG; + } + else if (*sigSz < key->params->sigLen) { + ret = BAD_LENGTH_E; + } + else if ((key->flags & WC_SLHDSA_FLAG_PRIVATE) == 0) { + ret = MISSING_KEY; + } + if (ret == 0) { + byte md[SLHDSA_MAX_MD]; + byte n = key->params->n; + +#ifdef WOLFSSL_SLHDSA_SHA2 + if (SLHDSA_IS_SHA2(key->params->param)) { + /* SHA2: PRF_msg = Trunc_n(HMAC(SK.prf, opt_rand || M)). + * Internal interface: no M' header, pass whole M directly. */ + ret = slhdsakey_prf_msg_sha2(key, key->sk + n, addRnd, + NULL, NULL, 0, m, mSz, n, sig); + if (ret == 0) { + /* SHA2: H_msg via MGF1. No header for internal interface. */ + ret = slhdsakey_h_msg_sha2(key, sig, + NULL, NULL, 0, m, mSz, + md, key->params->dl1 + key->params->dl2 + + key->params->dl3); + sig += n; + } + } + else +#endif + { + /* SHAKE: PRF_msg = SHAKE256(SK.prf || opt_rand || M, 8n). */ + { + wc_Shake tmpShake; + ret = wc_InitShake256(&tmpShake, NULL, INVALID_DEVID); + if (ret == 0) ret = wc_Shake256_Update(&tmpShake, key->sk + n, n); + if (ret == 0) ret = wc_Shake256_Update(&tmpShake, addRnd, n); + if (ret == 0) ret = wc_Shake256_Update(&tmpShake, m, mSz); + if (ret == 0) ret = wc_Shake256_Final(&tmpShake, sig, n); + wc_Shake256_Free(&tmpShake); + } + /* SHAKE: H_msg = SHAKE256(R || PK.seed || PK.root || M, ...). */ + if (ret == 0) { + ret = wc_InitShake256(&key->hash.shk.shake, NULL, INVALID_DEVID); + } + if (ret == 0) { + ret = wc_Shake256_Update(&key->hash.shk.shake, sig, n); + sig += n; + } + if (ret == 0) { + ret = wc_Shake256_Update(&key->hash.shk.shake, + key->sk + 2 * n, 2 * n); + } + if (ret == 0) { + ret = wc_Shake256_Update(&key->hash.shk.shake, m, mSz); + } + if (ret == 0) { + ret = wc_Shake256_Final(&key->hash.shk.shake, md, + key->params->dl1 + key->params->dl2 + key->params->dl3); + } + } + if (ret == 0) { + ret = slhdsakey_sign(key, md, sig); + } + if (ret == 0) { + *sigSz = key->params->sigLen; + } + } + + return ret; +} + +/* Upper-level sign: construct M' from ctx + msg, then call internal. + * + * FIPS 205. Section 10.2.2. Algorithm 22. + * slh_sign(M, ctx, SK) + * 8: M' <- toByte(0, 1) || toByte(|ctx|, 1) || ctx || M + * 9: SIG <- slh_sign_internal(M', SK, addrnd) * * @param [in] key SLH-DSA key. * @param [in] ctx Context of signing. @@ -6004,6 +6824,7 @@ static int slhdsakey_sign(SlhDsaKey* key, byte* md, byte* sig) * @param [out] sig Buffer to hold signature. * @param [in, out] sigSz On in, length of signature buffer. * On out, length of signature data. + * @param [in] addRnd opt_rand (PK.seed for deterministic, random otherwise). * @return 0 on success. * @return BAD_FUNC_ARG when key, key's parameters, msg, sig, sigSz or addRnd * is NULL. @@ -6036,65 +6857,76 @@ static int slhdsakey_sign_external(SlhDsaKey* key, const byte* ctx, byte ctxSz, } /* Check we have a private key to sign with. */ else if ((key->flags & WC_SLHDSA_FLAG_PRIVATE) == 0) { - ret = MISSING_KEY; - } - if (ret == 0) { - byte md[SLHDSA_MAX_MD]; - byte hdr[2]; - byte n = key->params->n; - - /* Alg 22, Step 8: Set first two bytes to pass to hash ... */ - hdr[0] = 0; - hdr[1] = ctxSz; - - /* Alg 19, Step 3: Start hash with private key PRF seed ... */ - ret = slhdsakey_hash_start(&key->shake, key->sk + n, n); - if (ret == 0) { - /* Alg 19, Step 3: Add addrnd to hash ... */ - ret = slhdsakey_hash_update(&key->shake, addRnd, n); - } - if (ret == 0) { - /* Alg 19, Step 3: Add M' header ... */ - ret = slhdsakey_hash_update(&key->shake, hdr, sizeof(hdr)); - } - if ((ret == 0) && (ctxSz > 0)) { - /* Alg 19, Step 3: Add ctx ... */ - ret = slhdsakey_hash_update(&key->shake, ctx, ctxSz); - } - if (ret == 0) { - /* Alg 19, Step 3: Add M ... */ - ret = slhdsakey_hash_update(&key->shake, msg, msgSz); - } - if (ret == 0) { - /* Alg 19, Steps 3-4: Compute randomizer into signature. */ - ret = slhdsakey_hash_final(&key->shake, sig, n); - } - if (ret == 0) { - /* Alg 19, Step 5: Start hash with signature ... */ - ret = slhdsakey_hash_start(&key->shake, sig, n); - /* Move over randomizer. */ - sig += n; - } - if (ret == 0) { - /* Alg 19, Step 5: Add public key seed and root ... */ - ret = slhdsakey_hash_update(&key->shake, key->sk + 2 * n, 2 * n); - } - if (ret == 0) { - /* Alg 19, Step 5: Add M' header ... */ - ret = slhdsakey_hash_update(&key->shake, hdr, sizeof(hdr)); - } - if ((ret == 0) && (ctxSz > 0)) { - /* Alg 19, Step 5: Add ctx ... */ - ret = slhdsakey_hash_update(&key->shake, ctx, ctxSz); - } - if (ret == 0) { - /* Alg 19, Step 5: Add M ... */ - ret = slhdsakey_hash_update(&key->shake, msg, msgSz); + ret = MISSING_KEY; + } + if (ret == 0) { + byte md[SLHDSA_MAX_MD]; + byte hdr[2]; + byte n = key->params->n; + + /* Alg 22, Step 8: M' = toByte(0,1) || toByte(|ctx|,1) || ctx || M. + * We stream the M' components into PRF_msg and H_msg. */ + hdr[0] = 0; + hdr[1] = ctxSz; + +#ifdef WOLFSSL_SLHDSA_SHA2 + if (SLHDSA_IS_SHA2(key->params->param)) { + /* SHA2: PRF_msg via HMAC. */ + ret = slhdsakey_prf_msg_sha2(key, key->sk + n, addRnd, hdr, ctx, + ctxSz, msg, msgSz, n, sig); + if (ret == 0) { + /* SHA2: H_msg via MGF1. */ + ret = slhdsakey_h_msg_sha2(key, sig, hdr, ctx, ctxSz, msg, + msgSz, md, key->params->dl1 + key->params->dl2 + + key->params->dl3); + /* Move over randomizer. */ + sig += n; + } } - if (ret == 0) { - /* Alg 19, Steps 5-6: Compute digest of required length. */ - ret = slhdsakey_hash_final(&key->shake, md, key->params->dl1 + - key->params->dl2 + key->params->dl3); + else +#endif + { + /* SHAKE: PRF_msg streaming with M' = hdr || ctx || msg. */ + ret = slhdsakey_hash_start(&key->hash.shk.shake, key->sk + n, n); + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, addRnd, n); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, hdr, + sizeof(hdr)); + } + if ((ret == 0) && (ctxSz > 0)) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, ctx, ctxSz); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, msg, msgSz); + } + if (ret == 0) { + ret = slhdsakey_hash_final(&key->hash.shk.shake, sig, n); + } + /* SHAKE: H_msg streaming. */ + if (ret == 0) { + ret = slhdsakey_hash_start(&key->hash.shk.shake, sig, n); + sig += n; + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, + key->sk + 2 * n, 2 * n); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, hdr, + sizeof(hdr)); + } + if ((ret == 0) && (ctxSz > 0)) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, ctx, ctxSz); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, msg, msgSz); + } + if (ret == 0) { + ret = slhdsakey_hash_final(&key->hash.shk.shake, md, + key->params->dl1 + key->params->dl2 + key->params->dl3); + } } if (ret == 0) { /* Alg 19. Steps 7-19 */ @@ -6226,6 +7058,51 @@ int wc_SlhDsaKey_Sign(SlhDsaKey* key, const byte* ctx, byte ctxSz, return ret; } + +/* Sign using internal interface -- M' provided directly (deterministic). + * + * opt_rand = PK.seed for the deterministic variant. + * + * @param [in] key SLH-DSA key. + * @param [in] mprime M' message (already in internal format). + * @param [in] mprimeSz Length of M' in bytes. + * @param [out] sig Buffer to hold signature. + * @param [in, out] sigSz On in, buffer length. On out, signature length. + * @return 0 on success. + */ +int wc_SlhDsaKey_SignMsgDeterministic(SlhDsaKey* key, const byte* mprime, + word32 mprimeSz, byte* sig, word32* sigSz) +{ + int ret; + + if ((key == NULL) || (key->params == NULL)) { + ret = BAD_FUNC_ARG; + } + else { + ret = slhdsakey_sign_internal_msg(key, mprime, mprimeSz, sig, sigSz, + key->sk + 2 * key->params->n); + } + + return ret; +} + +/* Sign using internal interface -- M' provided directly (with explicit random). + * + * @param [in] key SLH-DSA key. + * @param [in] mprime M' message (already in internal format). + * @param [in] mprimeSz Length of M' in bytes. + * @param [out] sig Buffer to hold signature. + * @param [in, out] sigSz On in, buffer length. On out, signature length. + * @param [in] addRnd opt_rand value. + * @return 0 on success. + */ +int wc_SlhDsaKey_SignMsgWithRandom(SlhDsaKey* key, const byte* mprime, + word32 mprimeSz, byte* sig, word32* sigSz, const byte* addRnd) +{ + return slhdsakey_sign_internal_msg(key, mprime, mprimeSz, sig, sigSz, + addRnd); +} + #endif /* Verify SLH-DSA signature. @@ -6337,38 +7214,112 @@ int wc_SlhDsaKey_Verify(SlhDsaKey* key, const byte* ctx, byte ctxSz, if (ret == 0) { byte md[SLHDSA_MAX_MD]; byte n = key->params->n; + byte hdr[2]; - /* Alg 20, Step 8: Hash randomizer ... */ - ret = slhdsakey_hash_start(&key->shake, sig, n); - if (ret == 0) { - /* Alg 20, Step 8: Update hash with public key seed and root ... */ - ret = slhdsakey_hash_update(&key->shake, key->sk + 2 * n, 2 * n); - } - if (ret == 0) { - byte hdr[2]; + /* Alg 23, Step 4: Make M' header. */ + hdr[0] = 0; + hdr[1] = ctxSz; - /* Alg 23, Step 4: Make M' header. */ - hdr[0] = 0; - hdr[1] = ctxSz; - /* Alg 20, Step 8: Update hash with M' header ... */ - ret = slhdsakey_hash_update(&key->shake, hdr, sizeof(hdr)); +#ifdef WOLFSSL_SLHDSA_SHA2 + if (SLHDSA_IS_SHA2(key->params->param)) { + /* SHA2: H_msg via MGF1 (no PRF_msg for verify). */ + ret = slhdsakey_h_msg_sha2(key, sig, hdr, ctx, ctxSz, msg, msgSz, + md, key->params->dl1 + key->params->dl2 + key->params->dl3); } - if ((ret == 0) && (ctxSz > 0)) { - /* Alg 20, Step 8: Update hash with context ... */ - ret = slhdsakey_hash_update(&key->shake, ctx, ctxSz); + else +#endif + { + /* SHAKE: H_msg streaming. */ + ret = slhdsakey_hash_start(&key->hash.shk.shake, sig, n); + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, + key->sk + 2 * n, 2 * n); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, hdr, + sizeof(hdr)); + } + if ((ret == 0) && (ctxSz > 0)) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, ctx, ctxSz); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, msg, msgSz); + } + if (ret == 0) { + ret = slhdsakey_hash_final(&key->hash.shk.shake, md, + key->params->dl1 + key->params->dl2 + key->params->dl3); + } } if (ret == 0) { - /* Alg 20, Step 8: Update hash with message ... */ - ret = slhdsakey_hash_update(&key->shake, msg, msgSz); + /* Alg 23, Step 5: Verify M'. + * Alg 20, Steps 4,6-18: Verify digest. */ + ret = slhdsakey_verify(key, md, sig); } - if (ret == 0) { - /* Alg 20, Step 8: Compute message digest. */ - ret = slhdsakey_hash_final(&key->shake, md, key->params->dl1 + - key->params->dl2 + key->params->dl3); + } + + return ret; +} + +/* Verify SLH-DSA signature using internal interface -- M' provided directly. + * + * FIPS 205. Section 9.3. Algorithm 20. + * slh_verify_internal(M', SIG, PK) + * + * @param [in] key SLH-DSA key. + * @param [in] mprime M' message (already in internal format). + * @param [in] mprimeSz Length of M' in bytes. + * @param [in] sig Signature data. + * @param [in] sigSz Length of signature in bytes. + * @return 0 on success. + * @return SIG_VERIFY_E on verification failure. + */ +int wc_SlhDsaKey_VerifyMsg(SlhDsaKey* key, const byte* mprime, + word32 mprimeSz, const byte* sig, word32 sigSz) +{ + int ret = 0; + + /* Validate parameters. */ + if ((key == NULL) || (key->params == NULL) || (mprime == NULL) || + (sig == NULL)) { + ret = BAD_FUNC_ARG; + } + else if (sigSz != key->params->sigLen) { + ret = BAD_LENGTH_E; + } + else if ((key->flags & WC_SLHDSA_FLAG_PUBLIC) == 0) { + ret = MISSING_KEY; + } + if (ret == 0) { + byte md[SLHDSA_MAX_MD]; + byte n = key->params->n; + +#ifdef WOLFSSL_SLHDSA_SHA2 + if (SLHDSA_IS_SHA2(key->params->param)) { + /* SHA2: H_msg. Internal interface: no M' header, pass whole + * message directly. */ + ret = slhdsakey_h_msg_sha2(key, sig, + NULL, NULL, 0, mprime, mprimeSz, + md, key->params->dl1 + key->params->dl2 + key->params->dl3); + } + else +#endif + { + /* SHAKE: H_msg = SHAKE(R || PK.seed || PK.root || M). */ + ret = slhdsakey_hash_start(&key->hash.shk.shake, sig, n); + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, + key->sk + 2 * n, 2 * n); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, + mprime, mprimeSz); + } + if (ret == 0) { + ret = slhdsakey_hash_final(&key->hash.shk.shake, md, + key->params->dl1 + key->params->dl2 + key->params->dl3); + } } if (ret == 0) { - /* Alg 23, Step 5: Verify M'. - * Alg 20, Steps 4,6-18: Verify digest. */ ret = slhdsakey_verify(key, md, sig); } } @@ -6424,6 +7375,32 @@ static const byte slhdsakey_oid_shake256[] = { 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0c }; #endif +#ifdef WOLFSSL_SHA3 +#ifndef WOLFSSL_NOSHA3_224 +/* OID for SHA3-224 for hash signing/verification. */ +static const byte slhdsakey_oid_sha3_224[] = { + 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x07 +}; +#endif +#ifndef WOLFSSL_NOSHA3_256 +/* OID for SHA3-256 for hash signing/verification. */ +static const byte slhdsakey_oid_sha3_256[] = { + 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08 +}; +#endif +#ifndef WOLFSSL_NOSHA3_384 +/* OID for SHA3-384 for hash signing/verification. */ +static const byte slhdsakey_oid_sha3_384[] = { + 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09 +}; +#endif +#ifndef WOLFSSL_NOSHA3_512 +/* OID for SHA3-512 for hash signing/verification. */ +static const byte slhdsakey_oid_sha3_512[] = { + 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0a +}; +#endif +#endif /* Pre-hash the message with the hash specified. * @@ -6507,6 +7484,40 @@ static int slhdsakey_prehash_msg(const byte* msg, word32 msgSz, *phLen = WC_SHA3_512_DIGEST_SIZE; ret = wc_Shake256Hash(msg, msgSz, ph, WC_SHA3_512_DIGEST_SIZE); break; + #endif + #ifdef WOLFSSL_SHA3 + #ifndef WOLFSSL_NOSHA3_224 + case WC_HASH_TYPE_SHA3_224: + *oid = slhdsakey_oid_sha3_224; + *oidLen = (byte)sizeof(slhdsakey_oid_sha3_224); + *phLen = WC_SHA3_224_DIGEST_SIZE; + ret = wc_Sha3_224Hash(msg, msgSz, ph); + break; + #endif + #ifndef WOLFSSL_NOSHA3_256 + case WC_HASH_TYPE_SHA3_256: + *oid = slhdsakey_oid_sha3_256; + *oidLen = (byte)sizeof(slhdsakey_oid_sha3_256); + *phLen = WC_SHA3_256_DIGEST_SIZE; + ret = wc_Sha3_256Hash(msg, msgSz, ph); + break; + #endif + #ifndef WOLFSSL_NOSHA3_384 + case WC_HASH_TYPE_SHA3_384: + *oid = slhdsakey_oid_sha3_384; + *oidLen = (byte)sizeof(slhdsakey_oid_sha3_384); + *phLen = WC_SHA3_384_DIGEST_SIZE; + ret = wc_Sha3_384Hash(msg, msgSz, ph); + break; + #endif + #ifndef WOLFSSL_NOSHA3_512 + case WC_HASH_TYPE_SHA3_512: + *oid = slhdsakey_oid_sha3_512; + *oidLen = (byte)sizeof(slhdsakey_oid_sha3_512); + *phLen = WC_SHA3_512_DIGEST_SIZE; + ret = wc_Sha3_512Hash(msg, msgSz, ph); + break; + #endif #endif default: ret = NOT_COMPILED_IN; @@ -6626,62 +7637,74 @@ static int slhdsakey_signhash_external(SlhDsaKey* key, const byte* ctx, hdr[0] = 1; hdr[1] = ctxSz; - /* Alg 19, Step 3: Start hash with private key PRF seed ... */ - ret = slhdsakey_hash_start(&key->shake, key->sk + n, n); - if (ret == 0) { - /* Alg 19, Step 3: Add addrnd to hash ... */ - ret = slhdsakey_hash_update(&key->shake, addRnd, n); - } - if (ret == 0) { - /* Alg 19, Step 3: Add M' header ... */ - ret = slhdsakey_hash_update(&key->shake, hdr, sizeof(hdr)); - } - if ((ret == 0) && (ctxSz > 0)) { - /* Alg 19, Step 3: Add ctx ... */ - ret = slhdsakey_hash_update(&key->shake, ctx, ctxSz); - } - if (ret == 0) { - /* Alg 23, Step 24, Alg 19, Step 3: Add M' OID ... */ - ret = slhdsakey_hash_update(&key->shake, oid, oidLen); - } - if (ret == 0) { - /* Alg 23, Step 24, Alg 19, Step 3: Add M' pre-hash ... */ - ret = slhdsakey_hash_update(&key->shake, ph, phLen); - } - if (ret == 0) { - /* Alg 19, Step 3-4: Compute randomizer into signature. */ - ret = slhdsakey_hash_final(&key->shake, sig, n); - } - if (ret == 0) { - /* Alg 19, Step 5: Start hash with signature ... */ - ret = slhdsakey_hash_start(&key->shake, sig, n); - /* Move over randomizer. */ - sig += n; - } - if (ret == 0) { - /* Alg 19, Step 5: Add public key seed and root ... */ - ret = slhdsakey_hash_update(&key->shake, key->sk + 2 * n, 2 * n); - } - if (ret == 0) { - /* Alg 19, Step 5: Add M' header ... */ - ret = slhdsakey_hash_update(&key->shake, hdr, sizeof(hdr)); - } - if ((ret == 0) && (ctxSz > 0)) { - /* Alg 19, Step 5: Add ctx ... */ - ret = slhdsakey_hash_update(&key->shake, ctx, ctxSz); - } - if (ret == 0) { - /* Alg 23, Step 24, Alg 19, Step 5: Add M' OID ... */ - ret = slhdsakey_hash_update(&key->shake, oid, oidLen); - } - if (ret == 0) { - /* Alg 23, Step 24, Alg 19, Step 5: Add M' pre-hash ... */ - ret = slhdsakey_hash_update(&key->shake, ph, phLen); +#ifdef WOLFSSL_SLHDSA_SHA2 + if (SLHDSA_IS_SHA2(key->params->param)) { + /* SHA2: Build oid||ph as message for PRF_msg/H_msg. */ + byte phMsg[80]; /* Max: 11 byte OID + 64 byte hash */ + word32 phMsgLen = oidLen + phLen; + + XMEMCPY(phMsg, oid, oidLen); + XMEMCPY(phMsg + oidLen, ph, phLen); + + ret = slhdsakey_prf_msg_sha2(key, key->sk + n, addRnd, hdr, ctx, + ctxSz, phMsg, phMsgLen, n, sig); + if (ret == 0) { + ret = slhdsakey_h_msg_sha2(key, sig, hdr, ctx, ctxSz, phMsg, + phMsgLen, md, key->params->dl1 + key->params->dl2 + + key->params->dl3); + sig += n; + } } - if (ret == 0) { - /* Alg 19, Steps 5-6: Compute digest of required length. */ - ret = slhdsakey_hash_final(&key->shake, md, key->params->dl1 + - key->params->dl2 + key->params->dl3); + else +#endif + { + /* SHAKE: PRF_msg streaming. */ + ret = slhdsakey_hash_start(&key->hash.shk.shake, key->sk + n, n); + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, addRnd, n); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, hdr, + sizeof(hdr)); + } + if ((ret == 0) && (ctxSz > 0)) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, ctx, ctxSz); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, oid, oidLen); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, ph, phLen); + } + if (ret == 0) { + ret = slhdsakey_hash_final(&key->hash.shk.shake, sig, n); + } + /* SHAKE: H_msg streaming. */ + if (ret == 0) { + ret = slhdsakey_hash_start(&key->hash.shk.shake, sig, n); + sig += n; + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, + key->sk + 2 * n, 2 * n); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, hdr, + sizeof(hdr)); + } + if ((ret == 0) && (ctxSz > 0)) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, ctx, ctxSz); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, oid, oidLen); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, ph, phLen); + } + if (ret == 0) { + ret = slhdsakey_hash_final(&key->hash.shk.shake, md, + key->params->dl1 + key->params->dl2 + key->params->dl3); + } } if (ret == 0) { /* Alg 19. Steps 7-19 */ @@ -6919,37 +7942,51 @@ int wc_SlhDsaKey_VerifyHash(SlhDsaKey* key, const byte* ctx, byte ctxSz, if (ret == 0) { byte n = key->params->n; byte md[SLHDSA_MAX_MD]; + byte hdr[2]; - /* Alg 20, Step 8: Hash randomizer ... */ - ret = slhdsakey_hash_start(&key->shake, sig, n); - if (ret == 0) { - /* Alg 20, Step 8: Update hash with public key seed and root ... */ - ret = slhdsakey_hash_update(&key->shake, key->sk + 2 * n, 2 * n); - } - if (ret == 0) { - byte hdr[2]; + /* Alg 24, Step 20: Make M' header. */ + hdr[0] = 1; + hdr[1] = ctxSz; - /* Alg 24, Step 20: Make M' header. */ - hdr[0] = 1; - hdr[1] = ctxSz; - ret = slhdsakey_hash_update(&key->shake, hdr, sizeof(hdr)); - } - if ((ret == 0) && (ctxSz > 0)) { - /* Alg 20, Step 8: Update hash with message ... */ - ret = slhdsakey_hash_update(&key->shake, ctx, ctxSz); - } - if (ret == 0) { - /* Alg 24, Step 20; Alg 20, Step 8: Update with M' OID ... */ - ret = slhdsakey_hash_update(&key->shake, oid, oidLen); - } - if (ret == 0) { - /* Alg 24, Step 20; Alg 20, Step 8: Update with M' pre-hash ... */ - ret = slhdsakey_hash_update(&key->shake, ph, phLen); +#ifdef WOLFSSL_SLHDSA_SHA2 + if (SLHDSA_IS_SHA2(key->params->param)) { + /* SHA2: Build oid||ph as message for H_msg. */ + byte phMsg[80]; /* Max: 11 byte OID + 64 byte hash */ + word32 phMsgLen = oidLen + phLen; + + XMEMCPY(phMsg, oid, oidLen); + XMEMCPY(phMsg + oidLen, ph, phLen); + + ret = slhdsakey_h_msg_sha2(key, sig, hdr, ctx, ctxSz, phMsg, + phMsgLen, md, key->params->dl1 + key->params->dl2 + + key->params->dl3); } - if (ret == 0) { - /* Alg 20, Step 8: Compute message digest. */ - ret = slhdsakey_hash_final(&key->shake, md, key->params->dl1 + - key->params->dl2 + key->params->dl3); + else +#endif + { + /* SHAKE: H_msg streaming. */ + ret = slhdsakey_hash_start(&key->hash.shk.shake, sig, n); + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, + key->sk + 2 * n, 2 * n); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, hdr, + sizeof(hdr)); + } + if ((ret == 0) && (ctxSz > 0)) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, ctx, ctxSz); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, oid, oidLen); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, ph, phLen); + } + if (ret == 0) { + ret = slhdsakey_hash_final(&key->hash.shk.shake, md, + key->params->dl1 + key->params->dl2 + key->params->dl3); + } } if (ret == 0) { /* Alg 24, Step 21: Verify M'. @@ -6989,6 +8026,11 @@ int wc_SlhDsaKey_ImportPrivate(SlhDsaKey* key, const byte* priv, word32 privLen) /* Copy private and public key data into SLH-DSA key object. */ XMEMCPY(key->sk, priv, 4 * key->params->n); key->flags = WC_SLHDSA_FLAG_BOTH_KEYS; +#ifdef WOLFSSL_SLHDSA_SHA2 + if (SLHDSA_IS_SHA2(key->params->param)) { + ret = slhdsakey_precompute_sha2_midstates(key); + } +#endif } return ret; @@ -7020,6 +8062,11 @@ int wc_SlhDsaKey_ImportPublic(SlhDsaKey* key, const byte* pub, word32 pubLen) /* Copy public key data into SLH-DSA key object. */ XMEMCPY(key->sk + 2 * key->params->n, pub, 2 * key->params->n); key->flags = WC_SLHDSA_FLAG_PUBLIC; +#ifdef WOLFSSL_SLHDSA_SHA2 + if (SLHDSA_IS_SHA2(key->params->param)) { + ret = slhdsakey_precompute_sha2_midstates(key); + } +#endif } return ret; @@ -7235,6 +8282,26 @@ int wc_SlhDsaKey_PrivateSizeFromParam(enum SlhDsaParam param) case SLHDSA_SHAKE256F: ret = WC_SLHDSA_SHAKE256F_PRIV_LEN; break; +#ifdef WOLFSSL_SLHDSA_SHA2 + case SLHDSA_SHA2_128S: + ret = WC_SLHDSA_SHA2_128S_PRIV_LEN; + break; + case SLHDSA_SHA2_128F: + ret = WC_SLHDSA_SHA2_128F_PRIV_LEN; + break; + case SLHDSA_SHA2_192S: + ret = WC_SLHDSA_SHA2_192S_PRIV_LEN; + break; + case SLHDSA_SHA2_192F: + ret = WC_SLHDSA_SHA2_192F_PRIV_LEN; + break; + case SLHDSA_SHA2_256S: + ret = WC_SLHDSA_SHA2_256S_PRIV_LEN; + break; + case SLHDSA_SHA2_256F: + ret = WC_SLHDSA_SHA2_256F_PRIV_LEN; + break; +#endif default: ret = NOT_COMPILED_IN; break; @@ -7273,6 +8340,26 @@ int wc_SlhDsaKey_PublicSizeFromParam(enum SlhDsaParam param) case SLHDSA_SHAKE256F: ret = WC_SLHDSA_SHAKE256F_PUB_LEN; break; +#ifdef WOLFSSL_SLHDSA_SHA2 + case SLHDSA_SHA2_128S: + ret = WC_SLHDSA_SHA2_128S_PUB_LEN; + break; + case SLHDSA_SHA2_128F: + ret = WC_SLHDSA_SHA2_128F_PUB_LEN; + break; + case SLHDSA_SHA2_192S: + ret = WC_SLHDSA_SHA2_192S_PUB_LEN; + break; + case SLHDSA_SHA2_192F: + ret = WC_SLHDSA_SHA2_192F_PUB_LEN; + break; + case SLHDSA_SHA2_256S: + ret = WC_SLHDSA_SHA2_256S_PUB_LEN; + break; + case SLHDSA_SHA2_256F: + ret = WC_SLHDSA_SHA2_256F_PUB_LEN; + break; +#endif default: ret = NOT_COMPILED_IN; break; @@ -7310,6 +8397,26 @@ int wc_SlhDsaKey_SigSizeFromParam(enum SlhDsaParam param) case SLHDSA_SHAKE256F: ret = WC_SLHDSA_SHAKE256F_SIG_LEN; break; +#ifdef WOLFSSL_SLHDSA_SHA2 + case SLHDSA_SHA2_128S: + ret = WC_SLHDSA_SHA2_128S_SIG_LEN; + break; + case SLHDSA_SHA2_128F: + ret = WC_SLHDSA_SHA2_128F_SIG_LEN; + break; + case SLHDSA_SHA2_192S: + ret = WC_SLHDSA_SHA2_192S_SIG_LEN; + break; + case SLHDSA_SHA2_192F: + ret = WC_SLHDSA_SHA2_192F_SIG_LEN; + break; + case SLHDSA_SHA2_256S: + ret = WC_SLHDSA_SHA2_256S_SIG_LEN; + break; + case SLHDSA_SHA2_256F: + ret = WC_SLHDSA_SHA2_256F_SIG_LEN; + break; +#endif default: ret = NOT_COMPILED_IN; break; diff --git a/wolfcrypt/src/wc_xmss.c b/wolfcrypt/src/wc_xmss.c index ef7248d209e..dfc6375e4e3 100644 --- a/wolfcrypt/src/wc_xmss.c +++ b/wolfcrypt/src/wc_xmss.c @@ -22,6 +22,11 @@ #include #ifdef WOLFSSL_HAVE_XMSS + +#if FIPS_VERSION3_GE(2,0,0) + /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */ + #define FIPS_NO_WRAPPERS +#endif #include #ifdef NO_INLINE diff --git a/wolfcrypt/src/wolfentropy.c b/wolfcrypt/src/wolfentropy.c index c05e56f6572..30c67d167e8 100644 --- a/wolfcrypt/src/wolfentropy.c +++ b/wolfcrypt/src/wolfentropy.c @@ -354,19 +354,37 @@ static word64 entropy_state[ENTROPY_NUM_WORDS + EXTRA_ENTROPY_WORDS] = {0}; /* Using memory will take different amount of times depending on the CPU's * caches and business. + * + * Returns int (not void) because the SHA-3 conditioning calls go through + * FIPS wrappers. When the FIPS module is in FAILED state (e.g. integrity + * hash mismatch during first build before fips-hash.sh), every SHA-3 call + * returns FIPS_NOT_ALLOWED_E. Without checking these returns, this function + * would silently loop through all ENTROPY_NUM_UPDATES iterations on every + * noise sample, each iteration firing the FIPS error callback -- producing + * tens of thousands of spurious error reports during Entropy_Init(). + * + * Non-FIPS builds never hit this path because SHA-3 calls always succeed + * without a CAST gate. We use int returns unconditionally (rather than + * void in non-FIPS, int in FIPS) to maintain a common ABI in case these + * functions become public API as wolfentropy matures. */ -static void Entropy_MemUse(void) +static int Entropy_MemUse(void) { int i; static byte d[WC_SHA3_256_DIGEST_SIZE]; int j; + int ret; for (j = 0; j < ENTROPY_NUM_UPDATES; j++) { /* Hash the first 32 64-bit words of state. */ - wc_Sha3_256_Update(&entropyHash, (byte*)entropy_state, + ret = wc_Sha3_256_Update(&entropyHash, (byte*)entropy_state, sizeof(*entropy_state) * ENTROPY_NUM_64BIT_WORDS); + if (ret != 0) + return ret; /* Get pseudo-random indices. */ - wc_Sha3_256_Final(&entropyHash, d); + ret = wc_Sha3_256_Final(&entropyHash, d); + if (ret != 0) + return ret; for (i = 0; i < ENTROPY_NUM_64BIT_WORDS; i++) { /* Choose a 64-bit word from a pseudo-random block.*/ @@ -378,6 +396,8 @@ static void Entropy_MemUse(void) entropy_state[i] += entropy_state[idx]; } } + + return 0; } @@ -390,34 +410,40 @@ static word64 entropy_last_time = 0; * * Called to test raw entropy. * - * @return 64-bit value that is the noise. + * @param [out] sample 64-bit noise value (time delta). + * @return 0 on success. + * @return Negative on failure (e.g. FIPS module not operational). */ -static word64 Entropy_GetSample(void) +static int Entropy_GetSample(word64* sample) { word64 now; - word64 ret; + int ret = 0; #ifdef HAVE_FIPS /* First sample must be disregard when in FIPS. */ if (entropy_last_time == 0) { /* Get sample which triggers CAST in FIPS mode. */ - Entropy_MemUse(); + ret = Entropy_MemUse(); + if (ret != 0) + return ret; /* Start entropy time after CASTs. */ entropy_last_time = Entropy_TimeHiRes(); } #endif /* Use memory such that it will take an unpredictable amount of time. */ - Entropy_MemUse(); + ret = Entropy_MemUse(); + if (ret != 0) + return ret; /* Get the time now to subtract from previous end time. */ now = Entropy_TimeHiRes(); /* Calculate time diff since last sampling. */ - ret = now - entropy_last_time; + *sample = now - entropy_last_time; /* Store last time. */ entropy_last_time = now; - return ret; + return 0; } /* Get as many samples of noise as required. @@ -426,18 +452,29 @@ static word64 Entropy_GetSample(void) * * @param [out] noise Buffer to hold samples. * @param [in] samples Number of one byte samples to get. + * @return 0 on success. + * @return Negative on hash failure (e.g. FIPS module not operational). */ -static void Entropy_GetNoise(unsigned char* noise, int samples) +static int Entropy_GetNoise(unsigned char* noise, int samples) { int i; + int ret; + word64 sample; /* Do it once to get things going. */ - Entropy_MemUse(); + ret = Entropy_MemUse(); + if (ret != 0) + return ret; /* Get as many samples as required. */ for (i = 0; i < samples; i++) { - noise[i] = (byte)Entropy_GetSample(); + ret = Entropy_GetSample(&sample); + if (ret != 0) + return ret; + noise[i] = (byte)sample; } + + return 0; } /* Generate raw entropy for performing assessment. @@ -458,7 +495,7 @@ int wc_Entropy_GetRawEntropy(unsigned char* raw, int cnt) if (ret == 0) #endif { - Entropy_GetNoise(raw, cnt); + ret = Entropy_GetNoise(raw, cnt); } #ifdef ENTROPY_MEMUSE_THREADED /* Stop the counter thread to avoid thrashing the system. */ @@ -670,7 +707,7 @@ static int Entropy_HealthTest_Startup(void) Entropy_HealthTest_Reset(); /* Fill initial sample buffer with noise. */ - Entropy_GetNoise(initial, ENTROPY_INITIAL_COUNT); + ret = Entropy_GetNoise(initial, ENTROPY_INITIAL_COUNT); /* Health check initial noise. */ for (i = 0; (ret == 0) && (i < ENTROPY_INITIAL_COUNT); i++) { ret = Entropy_HealthTest_Repetition(initial[i]); @@ -799,7 +836,7 @@ int wc_Entropy_Get(int bits, unsigned char* entropy, word32 len) } /* Get raw entropy noise. */ - Entropy_GetNoise(noise, noise_len); + ret = Entropy_GetNoise(noise, noise_len); /* Health check each noise value. */ for (i = 0; (ret == 0) && (i < noise_len); i++) { ret = Entropy_HealthTest_Repetition(noise[i]); diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 80866209c5f..b5bf2f17ccd 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -1056,6 +1056,15 @@ static void myFipsCb(int ok, int err, const char* hash) if (err == WC_NO_ERR_TRACE(IN_CORE_FIPS_E)) { printf("In core integrity hash check failure, copy above hash\n"); printf("into verifyCore[] in fips_test.c and rebuild\n"); +#ifdef TEST_ALWAYS_RUN_TO_END + /* When TEST_ALWAYS_RUN_TO_END is defined, testwolfcrypt tries to + * run every test even after failures. But with a wrong integrity + * hash the FIPS module is in FAILED state and every API call will + * fail, fire this callback, and produce millions of lines of + * redundant output. Exit now -- the hash has been printed for + * fips-hash.sh to extract, and no test can possibly pass. */ + exit(IN_CORE_FIPS_E); +#endif } #ifdef REALLY_LONG_DRBG_CONTINUOUS_TEST only_run_cb_once = 0; @@ -2784,17 +2793,21 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\ #endif #ifdef WOLFSSL_HAVE_MLKEM + PRIVATE_KEY_UNLOCK(); if ( (ret = mlkem_test()) != 0) TEST_FAIL("MLKEM test failed!\n", ret); else TEST_PASS("MLKEM test passed!\n"); + PRIVATE_KEY_LOCK(); #endif #ifdef HAVE_DILITHIUM + PRIVATE_KEY_UNLOCK(); if ( (ret = dilithium_test()) != 0) TEST_FAIL("DILITHIUM test failed!\n", ret); else TEST_PASS("DILITHIUM test passed!\n"); + PRIVATE_KEY_LOCK(); #endif #if defined(WOLFSSL_HAVE_XMSS) @@ -3689,8 +3702,6 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t error_test(void) int first; int last; } missing[] = { - { -124, -124 }, - { -167, -169 }, { WC_SPAN1_LAST_E - 1, WC_SPAN2_FIRST_E + 1 }, { WC_SPAN2_LAST_E - 1, WC_SPAN2_MIN_CODE_E } }; @@ -20549,14 +20560,37 @@ static wc_test_ret_t _rng_test(WC_RNG* rng) WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { #endif - ((struct DRBG_internal *)rng->drbg)->reseedCtr = WC_RESEED_INTERVAL; + #if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + if (rng->drbgType == WC_DRBG_SHA512) { + ((struct DRBG_SHA512_internal *)rng->drbg512)->reseedCtr = + WC_RESEED_INTERVAL; + } + else + #endif + { + ((struct DRBG_internal *)rng->drbg)->reseedCtr = + WC_RESEED_INTERVAL; + } ret = wc_RNG_GenerateBlock(rng, block, sizeof(block)); if (ret != 0) return WC_TEST_RET_ENC_EC(ret); - if (((struct DRBG_internal *)rng->drbg)->reseedCtr == WC_RESEED_INTERVAL) - return WC_TEST_RET_ENC_NC; + #if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + if (rng->drbgType == WC_DRBG_SHA512) { + if (((struct DRBG_SHA512_internal *)rng->drbg512)->reseedCtr == + WC_RESEED_INTERVAL) + return WC_TEST_RET_ENC_NC; + } + else + #endif + { + if (((struct DRBG_internal *)rng->drbg)->reseedCtr == + WC_RESEED_INTERVAL) + return WC_TEST_RET_ENC_NC; + } #ifdef WOLF_CRYPTO_CB } #endif @@ -20877,6 +20911,150 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_test(void) if (XMEMCMP(test2Output, output, sizeof(output)) != 0) return WC_TEST_RET_ENC_NC; +#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + /* SHA-512 DRBG Health Tests using NIST CAVP test vectors. + * Source: NIST CAVP drbgtestvectors.zip, Hash_DRBG.rsp, [SHA-512], + * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm- + * Validation-Program/documents/drbg/drbgtestvectors.zip */ + { + /* No-reseed test: drbgvectors_no_reseed/Hash_DRBG.rsp, [SHA-512], + * PredictionResistance=False, EntropyInputLen=256, NonceLen=128, + * PersonalizationStringLen=0, AdditionalInputLen=0, + * ReturnedBitsLen=2048, COUNT=0. + * EntropyInput || Nonce concatenated as seedA. */ + WOLFSSL_SMALL_STACK_STATIC const byte sha512test1Entropy[] = + { + /* EntropyInput (32 bytes) */ + 0x6b, 0x50, 0xa7, 0xd8, 0xf8, 0xa5, 0x5d, 0x7a, + 0x3d, 0xf8, 0xbb, 0x40, 0xbc, 0xc3, 0xb7, 0x22, + 0xd8, 0x70, 0x8d, 0xe6, 0x7f, 0xda, 0x01, 0x0b, + 0x03, 0xc4, 0xc8, 0x4d, 0x72, 0x09, 0x6f, 0x8c, + /* Nonce (16 bytes) */ + 0x3e, 0xc6, 0x49, 0xcc, 0x62, 0x56, 0xd9, 0xfa, + 0x31, 0xdb, 0x7a, 0x29, 0x04, 0xaa, 0xf0, 0x25 + }; + WOLFSSL_SMALL_STACK_STATIC const byte sha512test1Output[] = + { + 0x95, 0xb7, 0xf1, 0x7e, 0x98, 0x02, 0xd3, 0x57, + 0x73, 0x92, 0xc6, 0xa9, 0xc0, 0x80, 0x83, 0xb6, + 0x7d, 0xd1, 0x29, 0x22, 0x65, 0xb5, 0xf4, 0x2d, + 0x23, 0x7f, 0x1c, 0x55, 0xbb, 0x9b, 0x10, 0xbf, + 0xcf, 0xd8, 0x2c, 0x77, 0xa3, 0x78, 0xb8, 0x26, + 0x6a, 0x00, 0x99, 0x14, 0x3b, 0x3c, 0x2d, 0x64, + 0x61, 0x1e, 0xee, 0xb6, 0x9a, 0xcd, 0xc0, 0x55, + 0x95, 0x7c, 0x13, 0x9e, 0x8b, 0x19, 0x0c, 0x7a, + 0x06, 0x95, 0x5f, 0x2c, 0x79, 0x7c, 0x27, 0x78, + 0xde, 0x94, 0x03, 0x96, 0xa5, 0x01, 0xf4, 0x0e, + 0x91, 0x39, 0x6a, 0xcf, 0x8d, 0x7e, 0x45, 0xeb, + 0xdb, 0xb5, 0x3b, 0xbf, 0x8c, 0x97, 0x52, 0x30, + 0xd2, 0xf0, 0xff, 0x91, 0x06, 0xc7, 0x61, 0x19, + 0xae, 0x49, 0x8e, 0x7f, 0xbc, 0x03, 0xd9, 0x0f, + 0x8e, 0x4c, 0x51, 0x62, 0x7a, 0xed, 0x5c, 0x8d, + 0x42, 0x63, 0xd5, 0xd2, 0xb9, 0x78, 0x87, 0x3a, + 0x0d, 0xe5, 0x96, 0xee, 0x6d, 0xc7, 0xf7, 0xc2, + 0x9e, 0x37, 0xee, 0xe8, 0xb3, 0x4c, 0x90, 0xdd, + 0x1c, 0xf6, 0xa9, 0xdd, 0xb2, 0x2b, 0x4c, 0xbd, + 0x08, 0x6b, 0x14, 0xb3, 0x5d, 0xe9, 0x3d, 0xa2, + 0xd5, 0xcb, 0x18, 0x06, 0x69, 0x8c, 0xbd, 0x7b, + 0xbb, 0x67, 0xbf, 0xe3, 0xd3, 0x1f, 0xd2, 0xd1, + 0xdb, 0xd2, 0xa1, 0xe0, 0x58, 0xa3, 0xeb, 0x99, + 0xd7, 0xe5, 0x1f, 0x1a, 0x93, 0x8e, 0xed, 0x5e, + 0x1c, 0x1d, 0xe2, 0x3a, 0x6b, 0x43, 0x45, 0xd3, + 0x19, 0x14, 0x09, 0xf9, 0x2f, 0x39, 0xb3, 0x67, + 0x0d, 0x8d, 0xbf, 0xb6, 0x35, 0xd8, 0xe6, 0xa3, + 0x69, 0x32, 0xd8, 0x10, 0x33, 0xd1, 0x44, 0x8d, + 0x63, 0xb4, 0x03, 0xdd, 0xf8, 0x8e, 0x12, 0x1b, + 0x6e, 0x81, 0x9a, 0xc3, 0x81, 0x22, 0x6c, 0x13, + 0x21, 0xe4, 0xb0, 0x86, 0x44, 0xf6, 0x72, 0x7c, + 0x36, 0x8c, 0x5a, 0x9f, 0x7a, 0x4b, 0x3e, 0xe2 + }; + + /* Reseed test: drbgvectors_pr_false/Hash_DRBG.rsp, [SHA-512], + * PredictionResistance=False, EntropyInputLen=256, NonceLen=128, + * PersonalizationStringLen=0, AdditionalInputLen=0, + * ReturnedBitsLen=2048, COUNT=0. */ + WOLFSSL_SMALL_STACK_STATIC const byte sha512test2EntropyA[] = + { + /* EntropyInput (32 bytes) */ + 0x31, 0x44, 0xe1, 0x7a, 0x10, 0xc8, 0x56, 0x12, + 0x97, 0x64, 0xf5, 0x8f, 0xd8, 0xe4, 0x23, 0x10, + 0x20, 0x54, 0x69, 0x96, 0xc0, 0xbf, 0x6c, 0xff, + 0x8e, 0x91, 0xc2, 0x4e, 0xe0, 0x9b, 0xe3, 0x33, + /* Nonce (16 bytes) */ + 0xb1, 0x6f, 0xcb, 0x1c, 0xf0, 0xc0, 0x10, 0xf3, + 0x1f, 0xea, 0xb7, 0x33, 0x58, 0x8b, 0x8e, 0x04 + }; + WOLFSSL_SMALL_STACK_STATIC const byte sha512test2EntropyB[] = + { + /* EntropyInputReseed (32 bytes) */ + 0xa0, 0xb3, 0x58, 0x4c, 0x2c, 0x84, 0x12, 0xf6, + 0x18, 0x40, 0x68, 0x34, 0x40, 0x4d, 0x1e, 0xb0, + 0xce, 0x99, 0x9b, 0xa2, 0x89, 0x66, 0x05, 0x4d, + 0x7e, 0x49, 0x7e, 0x0d, 0xb6, 0x08, 0xb9, 0x67 + }; + WOLFSSL_SMALL_STACK_STATIC const byte sha512test2Output[] = + { + 0xef, 0xa3, 0x5d, 0xd0, 0x36, 0x2a, 0xdb, 0x76, + 0x26, 0x45, 0x6b, 0x36, 0xfa, 0xc7, 0x4d, 0x3c, + 0x28, 0xd0, 0x1d, 0x92, 0x64, 0x20, 0x27, 0x5a, + 0x28, 0xbe, 0xa9, 0xc9, 0xdd, 0x75, 0x47, 0xc1, + 0x5e, 0x79, 0x31, 0x85, 0x2a, 0xc1, 0x27, 0x70, + 0x76, 0x56, 0x75, 0x35, 0x23, 0x9c, 0x1f, 0x42, + 0x9c, 0x7f, 0x75, 0xcf, 0x74, 0xc2, 0x26, 0x7d, + 0xeb, 0x6a, 0x3e, 0x59, 0x6c, 0xf3, 0x26, 0x15, + 0x6c, 0x79, 0x69, 0x41, 0x28, 0x3b, 0x8d, 0x58, + 0x3f, 0x17, 0x1c, 0x2f, 0x6e, 0x33, 0x23, 0xf7, + 0x55, 0x5e, 0x1b, 0x18, 0x1f, 0xfd, 0xa3, 0x05, + 0x07, 0x21, 0x0c, 0xb1, 0xf5, 0x89, 0xb2, 0x3c, + 0xd7, 0x18, 0x80, 0xfd, 0x44, 0x37, 0x0c, 0xac, + 0xf4, 0x33, 0x75, 0xb0, 0xdb, 0x7e, 0x33, 0x6f, + 0x12, 0xb3, 0x09, 0xbf, 0xd4, 0xf6, 0x10, 0xbb, + 0x8f, 0x20, 0xe1, 0xa1, 0x5e, 0x25, 0x3a, 0x4f, + 0xe5, 0x11, 0xa0, 0x27, 0x96, 0x8d, 0xf0, 0xb1, + 0x05, 0xa1, 0xd7, 0x3a, 0xff, 0x7c, 0x7a, 0x82, + 0x6d, 0x39, 0xf6, 0x40, 0xdf, 0xb8, 0xf5, 0x22, + 0x25, 0x9e, 0xd4, 0x02, 0x28, 0x2e, 0x2c, 0x2e, + 0x9d, 0x3a, 0x49, 0x8f, 0x51, 0x72, 0x5f, 0xe4, + 0x14, 0x1b, 0x06, 0xda, 0x55, 0x98, 0xa4, 0x2a, + 0xc1, 0xe0, 0x49, 0x4e, 0x99, 0x7d, 0x56, 0x6a, + 0x1a, 0x39, 0xb6, 0x76, 0xb9, 0x6a, 0x60, 0x03, + 0xa4, 0xc5, 0xdb, 0x84, 0xf2, 0x46, 0x58, 0x4e, + 0xe6, 0x5a, 0xf7, 0x0f, 0xf2, 0x16, 0x02, 0x78, + 0x16, 0x6d, 0xa1, 0x6d, 0x91, 0xc9, 0xb8, 0xf2, + 0xde, 0xb0, 0x27, 0x51, 0xa1, 0x08, 0x8a, 0xd6, + 0xbe, 0x4e, 0x80, 0xef, 0x96, 0x6e, 0xb7, 0x3e, + 0x66, 0xbc, 0x87, 0xca, 0xd8, 0x7c, 0x77, 0xc0, + 0xb3, 0x4a, 0x21, 0xba, 0x1d, 0xa0, 0xba, 0x6d, + 0x16, 0xca, 0x50, 0x46, 0xdc, 0x4a, 0xbd, 0xa0 + }; + + byte output512[WC_SHA512_DIGEST_SIZE * 4]; /* 256 bytes */ + + /* Test 1: SHA-512 DRBG no-reseed */ + ret = wc_RNG_HealthTest_SHA512(0, + sha512test1Entropy, sizeof(sha512test1Entropy), + NULL, 0, + output512, sizeof(output512)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + if (XMEMCMP(sha512test1Output, output512, sizeof(output512)) != 0) + return WC_TEST_RET_ENC_NC; + + /* Test 2: SHA-512 DRBG with reseed */ + ret = wc_RNG_HealthTest_SHA512(1, + sha512test2EntropyA, sizeof(sha512test2EntropyA), + sha512test2EntropyB, sizeof(sha512test2EntropyB), + output512, sizeof(output512)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + if (XMEMCMP(sha512test2Output, output512, sizeof(output512)) != 0) + return WC_TEST_RET_ENC_NC; + } +#endif /* WOLFSSL_DRBG_SHA512 && !HAVE_SELFTEST && FIPS v7+ */ + /* Basic RNG generate block test */ if ((ret = random_rng_test()) != 0) return ret; @@ -21097,8 +21275,20 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_bank_test(void) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); for (i = 0; i < bank->n_rngs; ++i) { + #if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + word64 bankReseedCtr; + if (bank->rngs[i].rng.drbgType == WC_DRBG_SHA512) + bankReseedCtr = ((struct DRBG_SHA512_internal *) + bank->rngs[i].rng.drbg512)->reseedCtr; + else + bankReseedCtr = ((struct DRBG_internal *) + bank->rngs[i].rng.drbg)->reseedCtr; + if (bankReseedCtr != WC_RESEED_INTERVAL) + #else if (((struct DRBG_internal *)bank->rngs[i].rng.drbg) ->reseedCtr != WC_RESEED_INTERVAL) + #endif { ERROR_OUT(WC_TEST_RET_ENC_I(i), out); } @@ -51836,6 +52026,77 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test_verify_only(void) #endif /* if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_SMALL_STACK) */ #if defined(WOLFSSL_HAVE_SLHDSA) + +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY +/* KeyGen KAT: deterministic key generation cross-validated against NIST CAVP + * vectors. Verifies that MakeKeyWithRandom produces the expected sk and pk + * for a given parameter set. */ +static wc_test_ret_t slhdsa_keygen_kat(enum SlhDsaParam param, + const byte* sk_seed, word32 sk_seed_sz, + const byte* sk_prf, word32 sk_prf_sz, + const byte* pk_seed, word32 pk_seed_sz, + const byte* expected_sk, word32 expected_sk_sz, + const byte* expected_pk, word32 expected_pk_sz) +{ + int ret; + WC_DECLARE_VAR(key, SlhDsaKey, 1, HEAP_HINT); + byte sk_out[WC_SLHDSA_MAX_PRIV_LEN]; + byte pk_out[WC_SLHDSA_MAX_PUB_LEN]; + word32 outLen; + + WC_ALLOC_VAR_EX(key, SlhDsaKey, 1, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER, return WC_TEST_RET_ENC_EC(MEMORY_E)); + XMEMSET(key, 0, sizeof(*key)); + + ret = wc_SlhDsaKey_Init(key, param, NULL, INVALID_DEVID); + if (ret != 0) { + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + } + + ret = wc_SlhDsaKey_MakeKeyWithRandom(key, + sk_seed, sk_seed_sz, sk_prf, sk_prf_sz, pk_seed, pk_seed_sz); + if (ret != 0) { + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + } + + outLen = WC_SLHDSA_MAX_PRIV_LEN; + PRIVATE_KEY_UNLOCK(); + ret = wc_SlhDsaKey_ExportPrivate(key, sk_out, &outLen); + PRIVATE_KEY_LOCK(); + if (ret != 0) { + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + } + if (outLen != expected_sk_sz) { + ERROR_OUT(WC_TEST_RET_ENC_I(outLen), out); + } + if (XMEMCMP(sk_out, expected_sk, outLen) != 0) { + ERROR_OUT(WC_TEST_RET_ENC_NC, out); + } + + outLen = WC_SLHDSA_MAX_PUB_LEN; + ret = wc_SlhDsaKey_ExportPublic(key, pk_out, &outLen); + if (ret != 0) { + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + } + if (outLen != expected_pk_sz) { + ERROR_OUT(WC_TEST_RET_ENC_I(outLen), out); + } + if (XMEMCMP(pk_out, expected_pk, outLen) != 0) { + ERROR_OUT(WC_TEST_RET_ENC_NC, out); + } + +out: +#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC + if (key) +#endif + { + wc_SlhDsaKey_Free(key); + } + WC_FREE_VAR_EX(key, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + return ret; +} +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ + #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY static wc_test_ret_t slhdsa_test_param(enum SlhDsaParam param) { @@ -51878,8 +52139,10 @@ static wc_test_ret_t slhdsa_test_param(enum SlhDsaParam param) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); } sigLen = WC_SLHDSA_MAX_SIG_LEN; + PRIVATE_KEY_UNLOCK(); ret = wc_SlhDsaKey_Sign(key, ctx, 0, msg, (word32)sizeof(msg), sig, &sigLen, &rng); + PRIVATE_KEY_LOCK(); if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); } @@ -51904,14 +52167,57 @@ static wc_test_ret_t slhdsa_test_param(enum SlhDsaParam param) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); } + { +#ifdef WOLFSSL_SLHDSA_SHA2 + enum wc_HashType phType = SLHDSA_IS_SHA2(param) ? + WC_HASH_TYPE_SHA256 : WC_HASH_TYPE_SHAKE256; +#else + enum wc_HashType phType = WC_HASH_TYPE_SHAKE256; +#endif + sigLen = WC_SLHDSA_MAX_SIG_LEN; + PRIVATE_KEY_UNLOCK(); + ret = wc_SlhDsaKey_SignHash(key, ctx, 0, msg, (word32)sizeof(msg), + phType, sig, &sigLen, &rng); + PRIVATE_KEY_LOCK(); + if (ret != 0) { + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + } + ret = wc_SlhDsaKey_VerifyHash(key_vfy, ctx, 0, msg, (word32)sizeof(msg), + phType, sig, sigLen); + } + if (ret != 0) { + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + } + + /* Additional pre-hash test: SHA-384 exercises a different OID path */ +#ifdef WOLFSSL_SHA384 sigLen = WC_SLHDSA_MAX_SIG_LEN; + PRIVATE_KEY_UNLOCK(); ret = wc_SlhDsaKey_SignHash(key, ctx, 0, msg, (word32)sizeof(msg), - WC_HASH_TYPE_SHAKE256, sig, &sigLen, &rng); + WC_HASH_TYPE_SHA384, sig, &sigLen, &rng); + PRIVATE_KEY_LOCK(); if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); } ret = wc_SlhDsaKey_VerifyHash(key_vfy, ctx, 0, msg, (word32)sizeof(msg), - WC_HASH_TYPE_SHAKE256, sig, sigLen); + WC_HASH_TYPE_SHA384, sig, sigLen); + if (ret != 0) { + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + } +#endif + + /* Internal interface: SignMsgDeterministic + VerifyMsg round-trip. + * These take M' directly (no 0x00||len(ctx)||ctx||M wrapping). */ + sigLen = WC_SLHDSA_MAX_SIG_LEN; + PRIVATE_KEY_UNLOCK(); + ret = wc_SlhDsaKey_SignMsgDeterministic(key, + msg, (word32)sizeof(msg), sig, &sigLen); + PRIVATE_KEY_LOCK(); + if (ret != 0) { + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + } + ret = wc_SlhDsaKey_VerifyMsg(key_vfy, + msg, (word32)sizeof(msg), sig, sigLen); if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); } @@ -53007,7 +53313,9 @@ wc_test_ret_t slhdsa_test(void) } outLen = WC_SLHDSA_MAX_PRIV_LEN; + PRIVATE_KEY_UNLOCK(); ret = wc_SlhDsaKey_ExportPrivate(key, sk, &outLen); + PRIVATE_KEY_LOCK(); if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); } @@ -53049,8 +53357,10 @@ wc_test_ret_t slhdsa_test(void) #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY outLen = (word32)sizeof(sig_shake128s); + PRIVATE_KEY_UNLOCK(); ret = wc_SlhDsaKey_SignWithRandom(key, ctx, 0, msg, (word32)sizeof(msg), sig, &outLen, pk_seed_shake128s); + PRIVATE_KEY_LOCK(); if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); } @@ -53065,6 +53375,601 @@ wc_test_ret_t slhdsa_test(void) #endif #endif + /* --- SHA2 KeyGen KATs (NIST CAVP cross-validation) --- + * These verify that deterministic key generation produces the exact pk/sk + * that NIST expects. Covers both SHA-256 (cat 1, n=16) and SHA-512 + * (cat 3 n=24, cat 5 n=32) code paths. */ +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128S + { + /* NIST CAVP SLH-DSA-SHA2-128s keyGen vector (tgId=1, tcId=1). + * Same seeds as SHAKE128S; pk_root differs due to SHA-256 hash. */ + static const byte sk_seed_sha2_128s[] = { + 0x17, 0x3D, 0x04, 0xC9, 0x38, 0xC1, 0xC3, 0x6B, + 0xF2, 0x89, 0xC3, 0xC0, 0x22, 0xD0, 0x4B, 0x14 + }; + static const byte sk_prf_sha2_128s[] = { + 0x63, 0xAE, 0x23, 0xC4, 0x1A, 0xA5, 0x46, 0xDA, + 0x58, 0x97, 0x74, 0xAC, 0x20, 0xB7, 0x45, 0xC4 + }; + static const byte pk_seed_sha2_128s[] = { + 0x0D, 0x79, 0x47, 0x77, 0x91, 0x4C, 0x99, 0x76, + 0x68, 0x27, 0xF0, 0xF0, 0x9C, 0xA9, 0x72, 0xBE + }; + static const byte expected_sk_sha2_128s[] = { + 0x17, 0x3D, 0x04, 0xC9, 0x38, 0xC1, 0xC3, 0x6B, + 0xF2, 0x89, 0xC3, 0xC0, 0x22, 0xD0, 0x4B, 0x14, + 0x63, 0xAE, 0x23, 0xC4, 0x1A, 0xA5, 0x46, 0xDA, + 0x58, 0x97, 0x74, 0xAC, 0x20, 0xB7, 0x45, 0xC4, + 0x0D, 0x79, 0x47, 0x77, 0x91, 0x4C, 0x99, 0x76, + 0x68, 0x27, 0xF0, 0xF0, 0x9C, 0xA9, 0x72, 0xBE, + 0x01, 0x62, 0xC1, 0x02, 0x19, 0xD4, 0x22, 0xAD, + 0xBA, 0x13, 0x59, 0xE6, 0xAA, 0x65, 0x29, 0x9C + }; + static const byte expected_pk_sha2_128s[] = { + 0x0D, 0x79, 0x47, 0x77, 0x91, 0x4C, 0x99, 0x76, + 0x68, 0x27, 0xF0, 0xF0, 0x9C, 0xA9, 0x72, 0xBE, + 0x01, 0x62, 0xC1, 0x02, 0x19, 0xD4, 0x22, 0xAD, + 0xBA, 0x13, 0x59, 0xE6, 0xAA, 0x65, 0x29, 0x9C + }; + ret = slhdsa_keygen_kat(SLHDSA_SHA2_128S, + sk_seed_sha2_128s, (word32)sizeof(sk_seed_sha2_128s), + sk_prf_sha2_128s, (word32)sizeof(sk_prf_sha2_128s), + pk_seed_sha2_128s, (word32)sizeof(pk_seed_sha2_128s), + expected_sk_sha2_128s, (word32)sizeof(expected_sk_sha2_128s), + expected_pk_sha2_128s, (word32)sizeof(expected_pk_sha2_128s)); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHA2_128S keyGen KAT", 0); + goto out; + } + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192S + { + /* NIST CAVP SLH-DSA-SHA2-192s keyGen vector (tgId=5, tcId=41). + * Uses SHA-512 for H and T_l operations (n=24). */ + static const byte sk_seed_sha2_192s[] = { + 0x04, 0x02, 0x66, 0x52, 0x9C, 0x18, 0x64, 0x08, + 0x89, 0x25, 0x50, 0x6C, 0x20, 0xA6, 0x24, 0xA2, + 0xB6, 0xD5, 0x0C, 0xD7, 0x7C, 0x1C, 0x6F, 0x0D + }; + static const byte sk_prf_sha2_192s[] = { + 0x28, 0x41, 0x15, 0x0A, 0xE8, 0x15, 0x75, 0x12, + 0xEF, 0x34, 0xA3, 0x43, 0xFF, 0xEA, 0x77, 0xFF, + 0x7D, 0x9E, 0x81, 0x4B, 0x45, 0xA8, 0xB4, 0x14 + }; + static const byte pk_seed_sha2_192s[] = { + 0x64, 0x46, 0x26, 0x65, 0xF4, 0x20, 0x28, 0x86, + 0x20, 0x6A, 0x8F, 0x63, 0x22, 0x67, 0x18, 0x6C, + 0xA6, 0xA1, 0xCA, 0xD0, 0x8A, 0x2B, 0x9A, 0x86 + }; + static const byte expected_sk_sha2_192s[] = { + 0x04, 0x02, 0x66, 0x52, 0x9C, 0x18, 0x64, 0x08, + 0x89, 0x25, 0x50, 0x6C, 0x20, 0xA6, 0x24, 0xA2, + 0xB6, 0xD5, 0x0C, 0xD7, 0x7C, 0x1C, 0x6F, 0x0D, + 0x28, 0x41, 0x15, 0x0A, 0xE8, 0x15, 0x75, 0x12, + 0xEF, 0x34, 0xA3, 0x43, 0xFF, 0xEA, 0x77, 0xFF, + 0x7D, 0x9E, 0x81, 0x4B, 0x45, 0xA8, 0xB4, 0x14, + 0x64, 0x46, 0x26, 0x65, 0xF4, 0x20, 0x28, 0x86, + 0x20, 0x6A, 0x8F, 0x63, 0x22, 0x67, 0x18, 0x6C, + 0xA6, 0xA1, 0xCA, 0xD0, 0x8A, 0x2B, 0x9A, 0x86, + 0x2C, 0x6A, 0x7B, 0xC4, 0xAC, 0x4A, 0xAA, 0x84, + 0xAC, 0xCE, 0xF6, 0x0D, 0x52, 0x9F, 0x03, 0x11, + 0x27, 0x4F, 0x20, 0x5E, 0x8D, 0xA6, 0x42, 0xC9 + }; + static const byte expected_pk_sha2_192s[] = { + 0x64, 0x46, 0x26, 0x65, 0xF4, 0x20, 0x28, 0x86, + 0x20, 0x6A, 0x8F, 0x63, 0x22, 0x67, 0x18, 0x6C, + 0xA6, 0xA1, 0xCA, 0xD0, 0x8A, 0x2B, 0x9A, 0x86, + 0x2C, 0x6A, 0x7B, 0xC4, 0xAC, 0x4A, 0xAA, 0x84, + 0xAC, 0xCE, 0xF6, 0x0D, 0x52, 0x9F, 0x03, 0x11, + 0x27, 0x4F, 0x20, 0x5E, 0x8D, 0xA6, 0x42, 0xC9 + }; + ret = slhdsa_keygen_kat(SLHDSA_SHA2_192S, + sk_seed_sha2_192s, (word32)sizeof(sk_seed_sha2_192s), + sk_prf_sha2_192s, (word32)sizeof(sk_prf_sha2_192s), + pk_seed_sha2_192s, (word32)sizeof(pk_seed_sha2_192s), + expected_sk_sha2_192s, (word32)sizeof(expected_sk_sha2_192s), + expected_pk_sha2_192s, (word32)sizeof(expected_pk_sha2_192s)); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHA2_192S keyGen KAT", 0); + goto out; + } + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256S + { + /* NIST CAVP SLH-DSA-SHA2-256s keyGen vector (tgId=9, tcId=81). + * Uses SHA-512 for H and T_l operations (n=32). */ + static const byte sk_seed_sha2_256s[] = { + 0xFC, 0xBF, 0x36, 0xA9, 0x80, 0x7B, 0x30, 0x69, + 0x7B, 0xE0, 0x63, 0xA5, 0x10, 0x5E, 0x09, 0x1B, + 0x41, 0x2A, 0x39, 0x1D, 0xD3, 0x9E, 0x13, 0x26, + 0xEB, 0xA2, 0x3C, 0xBD, 0x40, 0x96, 0xCA, 0x77 + }; + static const byte sk_prf_sha2_256s[] = { + 0xEF, 0x41, 0x21, 0xC0, 0x8D, 0xD7, 0x1B, 0xE9, + 0x13, 0x57, 0x2F, 0x1F, 0x91, 0xE5, 0x7D, 0x0A, + 0xCB, 0xCD, 0x5C, 0xEC, 0x28, 0x53, 0x9A, 0xC2, + 0x75, 0x83, 0x2B, 0xBA, 0xA6, 0xC1, 0x10, 0x81 + }; + static const byte pk_seed_sha2_256s[] = { + 0xA0, 0xB4, 0xF5, 0x54, 0x9E, 0xBC, 0xAD, 0xB9, + 0x51, 0xDC, 0x2E, 0x51, 0x2C, 0x76, 0xB0, 0x62, + 0x0D, 0x8F, 0xB8, 0x10, 0x0B, 0x4E, 0xE8, 0x86, + 0xEF, 0x87, 0x84, 0x78, 0x0D, 0x52, 0xA2, 0x54 + }; + static const byte expected_sk_sha2_256s[] = { + 0xFC, 0xBF, 0x36, 0xA9, 0x80, 0x7B, 0x30, 0x69, + 0x7B, 0xE0, 0x63, 0xA5, 0x10, 0x5E, 0x09, 0x1B, + 0x41, 0x2A, 0x39, 0x1D, 0xD3, 0x9E, 0x13, 0x26, + 0xEB, 0xA2, 0x3C, 0xBD, 0x40, 0x96, 0xCA, 0x77, + 0xEF, 0x41, 0x21, 0xC0, 0x8D, 0xD7, 0x1B, 0xE9, + 0x13, 0x57, 0x2F, 0x1F, 0x91, 0xE5, 0x7D, 0x0A, + 0xCB, 0xCD, 0x5C, 0xEC, 0x28, 0x53, 0x9A, 0xC2, + 0x75, 0x83, 0x2B, 0xBA, 0xA6, 0xC1, 0x10, 0x81, + 0xA0, 0xB4, 0xF5, 0x54, 0x9E, 0xBC, 0xAD, 0xB9, + 0x51, 0xDC, 0x2E, 0x51, 0x2C, 0x76, 0xB0, 0x62, + 0x0D, 0x8F, 0xB8, 0x10, 0x0B, 0x4E, 0xE8, 0x86, + 0xEF, 0x87, 0x84, 0x78, 0x0D, 0x52, 0xA2, 0x54, + 0x3E, 0x57, 0xAB, 0x49, 0x4D, 0x47, 0x06, 0x8F, + 0xFE, 0xE4, 0xB8, 0x24, 0x4A, 0xAD, 0x6F, 0x19, + 0xCD, 0xF9, 0x4A, 0x21, 0x72, 0xBD, 0x13, 0x4A, + 0x15, 0xA6, 0xB5, 0xF2, 0x98, 0xD5, 0xA8, 0x0E + }; + static const byte expected_pk_sha2_256s[] = { + 0xA0, 0xB4, 0xF5, 0x54, 0x9E, 0xBC, 0xAD, 0xB9, + 0x51, 0xDC, 0x2E, 0x51, 0x2C, 0x76, 0xB0, 0x62, + 0x0D, 0x8F, 0xB8, 0x10, 0x0B, 0x4E, 0xE8, 0x86, + 0xEF, 0x87, 0x84, 0x78, 0x0D, 0x52, 0xA2, 0x54, + 0x3E, 0x57, 0xAB, 0x49, 0x4D, 0x47, 0x06, 0x8F, + 0xFE, 0xE4, 0xB8, 0x24, 0x4A, 0xAD, 0x6F, 0x19, + 0xCD, 0xF9, 0x4A, 0x21, 0x72, 0xBD, 0x13, 0x4A, + 0x15, 0xA6, 0xB5, 0xF2, 0x98, 0xD5, 0xA8, 0x0E + }; + ret = slhdsa_keygen_kat(SLHDSA_SHA2_256S, + sk_seed_sha2_256s, (word32)sizeof(sk_seed_sha2_256s), + sk_prf_sha2_256s, (word32)sizeof(sk_prf_sha2_256s), + pk_seed_sha2_256s, (word32)sizeof(pk_seed_sha2_256s), + expected_sk_sha2_256s, (word32)sizeof(expected_sk_sha2_256s), + expected_pk_sha2_256s, (word32)sizeof(expected_pk_sha2_256s)); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHA2_256S keyGen KAT", 0); + goto out; + } + } +#endif + + /* --- SHAKE KeyGen KATs (128f, 192s/f, 256s/f) --- */ +#ifdef WOLFSSL_SLHDSA_PARAM_128F + { + /* NIST CAVP SLH-DSA-SHAKE-128f keyGen vector (tgId=4, tcId=31) */ + static const byte sk_seed_shake_128f[] = { + 0x39, 0x56, 0xAB, 0x39, 0x1B, 0x4D, 0x22, 0xFC, + 0x90, 0x7A, 0xF0, 0x74, 0x03, 0x26, 0xD0, 0x61 + }; + static const byte sk_prf_shake_128f[] = { + 0xAB, 0x0E, 0xB2, 0x06, 0x43, 0x6F, 0x2B, 0x86, + 0xEB, 0xE0, 0x86, 0xD7, 0x77, 0x39, 0xB3, 0xE4 + }; + static const byte pk_seed_shake_128f[] = { + 0x56, 0x50, 0x5C, 0x22, 0x9F, 0x4E, 0x7F, 0xA6, + 0xB2, 0x01, 0x71, 0x4C, 0x7D, 0xCC, 0x9D, 0xA3 + }; + static const byte expected_sk_shake_128f[] = { + 0x39, 0x56, 0xAB, 0x39, 0x1B, 0x4D, 0x22, 0xFC, + 0x90, 0x7A, 0xF0, 0x74, 0x03, 0x26, 0xD0, 0x61, + 0xAB, 0x0E, 0xB2, 0x06, 0x43, 0x6F, 0x2B, 0x86, + 0xEB, 0xE0, 0x86, 0xD7, 0x77, 0x39, 0xB3, 0xE4, + 0x56, 0x50, 0x5C, 0x22, 0x9F, 0x4E, 0x7F, 0xA6, + 0xB2, 0x01, 0x71, 0x4C, 0x7D, 0xCC, 0x9D, 0xA3, + 0x66, 0x57, 0x8F, 0x1F, 0x24, 0xC3, 0xFE, 0x37, + 0x1C, 0x97, 0xC1, 0x4C, 0xE0, 0xE7, 0x9C, 0xDC + }; + static const byte expected_pk_shake_128f[] = { + 0x56, 0x50, 0x5C, 0x22, 0x9F, 0x4E, 0x7F, 0xA6, + 0xB2, 0x01, 0x71, 0x4C, 0x7D, 0xCC, 0x9D, 0xA3, + 0x66, 0x57, 0x8F, 0x1F, 0x24, 0xC3, 0xFE, 0x37, + 0x1C, 0x97, 0xC1, 0x4C, 0xE0, 0xE7, 0x9C, 0xDC + }; + ret = slhdsa_keygen_kat(SLHDSA_SHAKE128F, + sk_seed_shake_128f, (word32)sizeof(sk_seed_shake_128f), + sk_prf_shake_128f, (word32)sizeof(sk_prf_shake_128f), + pk_seed_shake_128f, (word32)sizeof(pk_seed_shake_128f), + expected_sk_shake_128f, (word32)sizeof(expected_sk_shake_128f), + expected_pk_shake_128f, (word32)sizeof(expected_pk_shake_128f)); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHAKE128F keyGen KAT", 0); + goto out; + } + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_192S + { + /* NIST CAVP SLH-DSA-SHAKE-192s keyGen vector (tgId=6, tcId=51) */ + static const byte sk_seed_shake_192s[] = { + 0x87, 0x32, 0x62, 0x18, 0x60, 0xE9, 0xA6, 0xE1, + 0x88, 0x7B, 0xE5, 0x5F, 0x7A, 0xF6, 0x92, 0xB9, + 0x8E, 0xB4, 0xC1, 0x0B, 0x25, 0x99, 0xF9, 0x4A + }; + static const byte sk_prf_shake_192s[] = { + 0xD5, 0xCC, 0x9D, 0x64, 0x70, 0xD8, 0xB2, 0x11, + 0x36, 0x15, 0x8E, 0x8B, 0x17, 0x10, 0xF1, 0xFB, + 0xE0, 0x3E, 0xCE, 0xD3, 0x7E, 0xD4, 0xAC, 0x68 + }; + static const byte pk_seed_shake_192s[] = { + 0x53, 0xFC, 0x64, 0xD4, 0x6D, 0x7E, 0x16, 0x53, + 0xEB, 0xBB, 0x36, 0xED, 0x5F, 0xBC, 0x12, 0xC6, + 0xE7, 0xCE, 0xF3, 0xCB, 0x75, 0x64, 0x82, 0xC8 + }; + static const byte expected_sk_shake_192s[] = { + 0x87, 0x32, 0x62, 0x18, 0x60, 0xE9, 0xA6, 0xE1, + 0x88, 0x7B, 0xE5, 0x5F, 0x7A, 0xF6, 0x92, 0xB9, + 0x8E, 0xB4, 0xC1, 0x0B, 0x25, 0x99, 0xF9, 0x4A, + 0xD5, 0xCC, 0x9D, 0x64, 0x70, 0xD8, 0xB2, 0x11, + 0x36, 0x15, 0x8E, 0x8B, 0x17, 0x10, 0xF1, 0xFB, + 0xE0, 0x3E, 0xCE, 0xD3, 0x7E, 0xD4, 0xAC, 0x68, + 0x53, 0xFC, 0x64, 0xD4, 0x6D, 0x7E, 0x16, 0x53, + 0xEB, 0xBB, 0x36, 0xED, 0x5F, 0xBC, 0x12, 0xC6, + 0xE7, 0xCE, 0xF3, 0xCB, 0x75, 0x64, 0x82, 0xC8, + 0xC6, 0x20, 0x45, 0x2E, 0x86, 0x4E, 0x84, 0x97, + 0xE1, 0xB3, 0x8A, 0x7B, 0x04, 0x44, 0x92, 0x19, + 0xAC, 0xD9, 0xE4, 0x39, 0x3F, 0x9C, 0x88, 0xEF + }; + static const byte expected_pk_shake_192s[] = { + 0x53, 0xFC, 0x64, 0xD4, 0x6D, 0x7E, 0x16, 0x53, + 0xEB, 0xBB, 0x36, 0xED, 0x5F, 0xBC, 0x12, 0xC6, + 0xE7, 0xCE, 0xF3, 0xCB, 0x75, 0x64, 0x82, 0xC8, + 0xC6, 0x20, 0x45, 0x2E, 0x86, 0x4E, 0x84, 0x97, + 0xE1, 0xB3, 0x8A, 0x7B, 0x04, 0x44, 0x92, 0x19, + 0xAC, 0xD9, 0xE4, 0x39, 0x3F, 0x9C, 0x88, 0xEF + }; + ret = slhdsa_keygen_kat(SLHDSA_SHAKE192S, + sk_seed_shake_192s, (word32)sizeof(sk_seed_shake_192s), + sk_prf_shake_192s, (word32)sizeof(sk_prf_shake_192s), + pk_seed_shake_192s, (word32)sizeof(pk_seed_shake_192s), + expected_sk_shake_192s, (word32)sizeof(expected_sk_shake_192s), + expected_pk_shake_192s, (word32)sizeof(expected_pk_shake_192s)); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHAKE192S keyGen KAT", 0); + goto out; + } + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_192F + { + /* NIST CAVP SLH-DSA-SHAKE-192f keyGen vector (tgId=8, tcId=71) */ + static const byte sk_seed_shake_192f[] = { + 0xFB, 0x7A, 0x2C, 0x2C, 0x75, 0xCE, 0x6C, 0x96, + 0xB5, 0xF4, 0x32, 0x8E, 0x0A, 0xB3, 0x00, 0x47, + 0x6F, 0xC6, 0xF8, 0x64, 0xCB, 0x5B, 0x0B, 0x99 + }; + static const byte sk_prf_shake_192f[] = { + 0x99, 0x0E, 0xCB, 0x72, 0x6C, 0xA8, 0x22, 0xA4, + 0xE3, 0x65, 0x2D, 0xD9, 0x2E, 0xC0, 0xAA, 0xB7, + 0x63, 0x7E, 0xA4, 0x1C, 0x04, 0x82, 0xAE, 0x28 + }; + static const byte pk_seed_shake_192f[] = { + 0x68, 0xDC, 0xC6, 0x71, 0xE3, 0x53, 0x4F, 0x81, + 0xA3, 0x52, 0xC2, 0x75, 0xB6, 0xA2, 0x5F, 0x90, + 0x6D, 0x2E, 0xD0, 0xFF, 0x62, 0xB8, 0xB4, 0xE3 + }; + static const byte expected_sk_shake_192f[] = { + 0xFB, 0x7A, 0x2C, 0x2C, 0x75, 0xCE, 0x6C, 0x96, + 0xB5, 0xF4, 0x32, 0x8E, 0x0A, 0xB3, 0x00, 0x47, + 0x6F, 0xC6, 0xF8, 0x64, 0xCB, 0x5B, 0x0B, 0x99, + 0x99, 0x0E, 0xCB, 0x72, 0x6C, 0xA8, 0x22, 0xA4, + 0xE3, 0x65, 0x2D, 0xD9, 0x2E, 0xC0, 0xAA, 0xB7, + 0x63, 0x7E, 0xA4, 0x1C, 0x04, 0x82, 0xAE, 0x28, + 0x68, 0xDC, 0xC6, 0x71, 0xE3, 0x53, 0x4F, 0x81, + 0xA3, 0x52, 0xC2, 0x75, 0xB6, 0xA2, 0x5F, 0x90, + 0x6D, 0x2E, 0xD0, 0xFF, 0x62, 0xB8, 0xB4, 0xE3, + 0x98, 0xF1, 0xA9, 0x87, 0x6C, 0xB0, 0x82, 0xA4, + 0x8E, 0x9A, 0xE2, 0xC8, 0x62, 0xB2, 0x89, 0x48, + 0x6A, 0x39, 0x25, 0xCE, 0xFC, 0x6F, 0xF4, 0xBE + }; + static const byte expected_pk_shake_192f[] = { + 0x68, 0xDC, 0xC6, 0x71, 0xE3, 0x53, 0x4F, 0x81, + 0xA3, 0x52, 0xC2, 0x75, 0xB6, 0xA2, 0x5F, 0x90, + 0x6D, 0x2E, 0xD0, 0xFF, 0x62, 0xB8, 0xB4, 0xE3, + 0x98, 0xF1, 0xA9, 0x87, 0x6C, 0xB0, 0x82, 0xA4, + 0x8E, 0x9A, 0xE2, 0xC8, 0x62, 0xB2, 0x89, 0x48, + 0x6A, 0x39, 0x25, 0xCE, 0xFC, 0x6F, 0xF4, 0xBE + }; + ret = slhdsa_keygen_kat(SLHDSA_SHAKE192F, + sk_seed_shake_192f, (word32)sizeof(sk_seed_shake_192f), + sk_prf_shake_192f, (word32)sizeof(sk_prf_shake_192f), + pk_seed_shake_192f, (word32)sizeof(pk_seed_shake_192f), + expected_sk_shake_192f, (word32)sizeof(expected_sk_shake_192f), + expected_pk_shake_192f, (word32)sizeof(expected_pk_shake_192f)); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHAKE192F keyGen KAT", 0); + goto out; + } + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_256S + { + /* NIST CAVP SLH-DSA-SHAKE-256s keyGen vector (tgId=10, tcId=91) */ + static const byte sk_seed_shake_256s[] = { + 0xE4, 0x40, 0xE3, 0x96, 0x44, 0xA1, 0x1A, 0x6A, + 0x58, 0xE8, 0x50, 0xC0, 0x9C, 0x8F, 0x03, 0xC2, + 0x73, 0xE4, 0x65, 0x23, 0x7F, 0x3B, 0xEF, 0x7C, + 0x58, 0xDE, 0x62, 0x28, 0x1E, 0x67, 0x6C, 0xEA + }; + static const byte sk_prf_shake_256s[] = { + 0x99, 0xC1, 0x99, 0xC0, 0x0D, 0xB3, 0x0F, 0x84, + 0x99, 0xA6, 0x1B, 0x5B, 0x9D, 0xC8, 0xA3, 0x61, + 0x72, 0x5F, 0x6A, 0xE8, 0x0E, 0x97, 0x03, 0x71, + 0x76, 0xF4, 0x08, 0xC3, 0x0B, 0x38, 0x84, 0x4D + }; + static const byte pk_seed_shake_256s[] = { + 0xD7, 0xB5, 0xE7, 0x55, 0xB4, 0x87, 0x9F, 0xDE, + 0x32, 0x88, 0xA2, 0x1A, 0xF3, 0xE3, 0x2F, 0xBB, + 0x00, 0x6F, 0xD9, 0xB8, 0xBC, 0x2B, 0x18, 0x0E, + 0xB9, 0xB0, 0xD8, 0x2C, 0x9F, 0x31, 0x57, 0xAF + }; + static const byte expected_sk_shake_256s[] = { + 0xE4, 0x40, 0xE3, 0x96, 0x44, 0xA1, 0x1A, 0x6A, + 0x58, 0xE8, 0x50, 0xC0, 0x9C, 0x8F, 0x03, 0xC2, + 0x73, 0xE4, 0x65, 0x23, 0x7F, 0x3B, 0xEF, 0x7C, + 0x58, 0xDE, 0x62, 0x28, 0x1E, 0x67, 0x6C, 0xEA, + 0x99, 0xC1, 0x99, 0xC0, 0x0D, 0xB3, 0x0F, 0x84, + 0x99, 0xA6, 0x1B, 0x5B, 0x9D, 0xC8, 0xA3, 0x61, + 0x72, 0x5F, 0x6A, 0xE8, 0x0E, 0x97, 0x03, 0x71, + 0x76, 0xF4, 0x08, 0xC3, 0x0B, 0x38, 0x84, 0x4D, + 0xD7, 0xB5, 0xE7, 0x55, 0xB4, 0x87, 0x9F, 0xDE, + 0x32, 0x88, 0xA2, 0x1A, 0xF3, 0xE3, 0x2F, 0xBB, + 0x00, 0x6F, 0xD9, 0xB8, 0xBC, 0x2B, 0x18, 0x0E, + 0xB9, 0xB0, 0xD8, 0x2C, 0x9F, 0x31, 0x57, 0xAF, + 0x02, 0xAC, 0xD6, 0xB3, 0x19, 0x8E, 0xE1, 0xC9, + 0xFE, 0x9A, 0xFE, 0x61, 0xFD, 0x86, 0xD1, 0xE0, + 0x87, 0x7A, 0xD9, 0x06, 0x19, 0x80, 0xB5, 0x7B, + 0x17, 0x8C, 0xE2, 0x71, 0x91, 0xD8, 0xEB, 0x1B + }; + static const byte expected_pk_shake_256s[] = { + 0xD7, 0xB5, 0xE7, 0x55, 0xB4, 0x87, 0x9F, 0xDE, + 0x32, 0x88, 0xA2, 0x1A, 0xF3, 0xE3, 0x2F, 0xBB, + 0x00, 0x6F, 0xD9, 0xB8, 0xBC, 0x2B, 0x18, 0x0E, + 0xB9, 0xB0, 0xD8, 0x2C, 0x9F, 0x31, 0x57, 0xAF, + 0x02, 0xAC, 0xD6, 0xB3, 0x19, 0x8E, 0xE1, 0xC9, + 0xFE, 0x9A, 0xFE, 0x61, 0xFD, 0x86, 0xD1, 0xE0, + 0x87, 0x7A, 0xD9, 0x06, 0x19, 0x80, 0xB5, 0x7B, + 0x17, 0x8C, 0xE2, 0x71, 0x91, 0xD8, 0xEB, 0x1B + }; + ret = slhdsa_keygen_kat(SLHDSA_SHAKE256S, + sk_seed_shake_256s, (word32)sizeof(sk_seed_shake_256s), + sk_prf_shake_256s, (word32)sizeof(sk_prf_shake_256s), + pk_seed_shake_256s, (word32)sizeof(pk_seed_shake_256s), + expected_sk_shake_256s, (word32)sizeof(expected_sk_shake_256s), + expected_pk_shake_256s, (word32)sizeof(expected_pk_shake_256s)); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHAKE256S keyGen KAT", 0); + goto out; + } + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_256F + { + /* NIST CAVP SLH-DSA-SHAKE-256f keyGen vector (tgId=12, tcId=111) */ + static const byte sk_seed_shake_256f[] = { + 0x2A, 0xC9, 0x40, 0x38, 0x58, 0xD1, 0x86, 0xB1, + 0x72, 0xED, 0xD8, 0xDF, 0x9C, 0x78, 0xA1, 0x14, + 0x49, 0x89, 0x36, 0x81, 0x48, 0x7D, 0x3A, 0xF0, + 0xDA, 0xD0, 0xEC, 0x34, 0x1E, 0x8A, 0xCA, 0x48 + }; + static const byte sk_prf_shake_256f[] = { + 0xAF, 0xA2, 0x77, 0x1B, 0xAE, 0x6C, 0x17, 0xDD, + 0x6F, 0x77, 0xB4, 0xE3, 0x80, 0x8B, 0x05, 0xF5, + 0x6F, 0x31, 0xB8, 0xF4, 0x12, 0x8D, 0xF2, 0xCC, + 0xB6, 0x77, 0xF0, 0x28, 0x3C, 0xFB, 0x18, 0xDA + }; + static const byte pk_seed_shake_256f[] = { + 0x55, 0x9B, 0xC8, 0x83, 0x10, 0x5E, 0x8B, 0xA0, + 0x26, 0x46, 0x48, 0xB5, 0x32, 0x62, 0x61, 0x55, + 0xF8, 0x7E, 0xDB, 0x4B, 0xED, 0xCF, 0xC1, 0x2A, + 0x24, 0x20, 0x4D, 0x3B, 0x69, 0x6D, 0x53, 0x70 + }; + static const byte expected_sk_shake_256f[] = { + 0x2A, 0xC9, 0x40, 0x38, 0x58, 0xD1, 0x86, 0xB1, + 0x72, 0xED, 0xD8, 0xDF, 0x9C, 0x78, 0xA1, 0x14, + 0x49, 0x89, 0x36, 0x81, 0x48, 0x7D, 0x3A, 0xF0, + 0xDA, 0xD0, 0xEC, 0x34, 0x1E, 0x8A, 0xCA, 0x48, + 0xAF, 0xA2, 0x77, 0x1B, 0xAE, 0x6C, 0x17, 0xDD, + 0x6F, 0x77, 0xB4, 0xE3, 0x80, 0x8B, 0x05, 0xF5, + 0x6F, 0x31, 0xB8, 0xF4, 0x12, 0x8D, 0xF2, 0xCC, + 0xB6, 0x77, 0xF0, 0x28, 0x3C, 0xFB, 0x18, 0xDA, + 0x55, 0x9B, 0xC8, 0x83, 0x10, 0x5E, 0x8B, 0xA0, + 0x26, 0x46, 0x48, 0xB5, 0x32, 0x62, 0x61, 0x55, + 0xF8, 0x7E, 0xDB, 0x4B, 0xED, 0xCF, 0xC1, 0x2A, + 0x24, 0x20, 0x4D, 0x3B, 0x69, 0x6D, 0x53, 0x70, + 0x7A, 0x15, 0x8F, 0xF5, 0xD3, 0x0E, 0x34, 0x28, + 0x18, 0x3A, 0x3B, 0x3A, 0x96, 0xA0, 0xE4, 0xA3, + 0x41, 0xA2, 0xA1, 0x6E, 0x5A, 0x62, 0x26, 0xAF, + 0x37, 0x4D, 0x1E, 0xFB, 0x39, 0xA3, 0x5D, 0xF6 + }; + static const byte expected_pk_shake_256f[] = { + 0x55, 0x9B, 0xC8, 0x83, 0x10, 0x5E, 0x8B, 0xA0, + 0x26, 0x46, 0x48, 0xB5, 0x32, 0x62, 0x61, 0x55, + 0xF8, 0x7E, 0xDB, 0x4B, 0xED, 0xCF, 0xC1, 0x2A, + 0x24, 0x20, 0x4D, 0x3B, 0x69, 0x6D, 0x53, 0x70, + 0x7A, 0x15, 0x8F, 0xF5, 0xD3, 0x0E, 0x34, 0x28, + 0x18, 0x3A, 0x3B, 0x3A, 0x96, 0xA0, 0xE4, 0xA3, + 0x41, 0xA2, 0xA1, 0x6E, 0x5A, 0x62, 0x26, 0xAF, + 0x37, 0x4D, 0x1E, 0xFB, 0x39, 0xA3, 0x5D, 0xF6 + }; + ret = slhdsa_keygen_kat(SLHDSA_SHAKE256F, + sk_seed_shake_256f, (word32)sizeof(sk_seed_shake_256f), + sk_prf_shake_256f, (word32)sizeof(sk_prf_shake_256f), + pk_seed_shake_256f, (word32)sizeof(pk_seed_shake_256f), + expected_sk_shake_256f, (word32)sizeof(expected_sk_shake_256f), + expected_pk_shake_256f, (word32)sizeof(expected_pk_shake_256f)); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHAKE256F keyGen KAT", 0); + goto out; + } + } +#endif + + /* --- SHA2 fast variant KeyGen KATs --- */ +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128F + { + /* NIST CAVP SLH-DSA-SHA2-128f keyGen vector (tgId=3, tcId=21) */ + static const byte sk_seed_sha2_128f[] = { + 0xC4, 0x2B, 0xCB, 0x3B, 0x5A, 0x6F, 0x33, 0x1F, + 0x5C, 0xCE, 0x89, 0x92, 0x53, 0xC6, 0xD9, 0xE2 + }; + static const byte sk_prf_sha2_128f[] = { + 0x9F, 0xF2, 0xB7, 0xEA, 0xD7, 0xA0, 0x4B, 0xAB, + 0x17, 0x94, 0xDB, 0x8C, 0xC6, 0x59, 0xC3, 0xB4 + }; + static const byte pk_seed_sha2_128f[] = { + 0xA8, 0x68, 0xF1, 0xBD, 0x5D, 0xEB, 0xC1, 0x2D, + 0x4C, 0x9F, 0xAD, 0x66, 0xAA, 0xBD, 0x0A, 0x94 + }; + static const byte expected_sk_sha2_128f[] = { + 0xC4, 0x2B, 0xCB, 0x3B, 0x5A, 0x6F, 0x33, 0x1F, + 0x5C, 0xCE, 0x89, 0x92, 0x53, 0xC6, 0xD9, 0xE2, + 0x9F, 0xF2, 0xB7, 0xEA, 0xD7, 0xA0, 0x4B, 0xAB, + 0x17, 0x94, 0xDB, 0x8C, 0xC6, 0x59, 0xC3, 0xB4, + 0xA8, 0x68, 0xF1, 0xBD, 0x5D, 0xEB, 0xC1, 0x2D, + 0x4C, 0x9F, 0xAD, 0x66, 0xAA, 0xBD, 0x0A, 0x94, + 0xB5, 0x46, 0xDF, 0x24, 0x7B, 0xE4, 0xC4, 0x57, + 0xF3, 0xD4, 0x67, 0xCD, 0xFC, 0xFA, 0xBD, 0x39 + }; + static const byte expected_pk_sha2_128f[] = { + 0xA8, 0x68, 0xF1, 0xBD, 0x5D, 0xEB, 0xC1, 0x2D, + 0x4C, 0x9F, 0xAD, 0x66, 0xAA, 0xBD, 0x0A, 0x94, + 0xB5, 0x46, 0xDF, 0x24, 0x7B, 0xE4, 0xC4, 0x57, + 0xF3, 0xD4, 0x67, 0xCD, 0xFC, 0xFA, 0xBD, 0x39 + }; + ret = slhdsa_keygen_kat(SLHDSA_SHA2_128F, + sk_seed_sha2_128f, (word32)sizeof(sk_seed_sha2_128f), + sk_prf_sha2_128f, (word32)sizeof(sk_prf_sha2_128f), + pk_seed_sha2_128f, (word32)sizeof(pk_seed_sha2_128f), + expected_sk_sha2_128f, (word32)sizeof(expected_sk_sha2_128f), + expected_pk_sha2_128f, (word32)sizeof(expected_pk_sha2_128f)); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHA2_128F keyGen KAT", 0); + goto out; + } + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192F + { + /* NIST CAVP SLH-DSA-SHA2-192f keyGen vector (tgId=7, tcId=61) */ + static const byte sk_seed_sha2_192f[] = { + 0xA0, 0x21, 0xB4, 0xB9, 0xD6, 0xDE, 0xE1, 0x68, + 0x72, 0x2B, 0xC1, 0x02, 0x25, 0xE5, 0x0A, 0x94, + 0x66, 0x42, 0xAF, 0x63, 0x0C, 0x3C, 0x7C, 0x7D + }; + static const byte sk_prf_sha2_192f[] = { + 0x69, 0xE3, 0xA4, 0x0B, 0xA0, 0x9D, 0xF2, 0xAC, + 0x16, 0x5B, 0x79, 0x2A, 0x07, 0xF0, 0x64, 0xAC, + 0x5F, 0xC2, 0x8D, 0x8C, 0x99, 0xA5, 0x80, 0xF4 + }; + static const byte pk_seed_sha2_192f[] = { + 0xEE, 0x48, 0x23, 0xD0, 0x9E, 0x79, 0x85, 0x47, + 0x06, 0xDA, 0xA8, 0x0A, 0xE3, 0x17, 0x9B, 0x5B, + 0xC8, 0xC2, 0xE9, 0x40, 0x9D, 0x63, 0x28, 0xA3 + }; + static const byte expected_sk_sha2_192f[] = { + 0xA0, 0x21, 0xB4, 0xB9, 0xD6, 0xDE, 0xE1, 0x68, + 0x72, 0x2B, 0xC1, 0x02, 0x25, 0xE5, 0x0A, 0x94, + 0x66, 0x42, 0xAF, 0x63, 0x0C, 0x3C, 0x7C, 0x7D, + 0x69, 0xE3, 0xA4, 0x0B, 0xA0, 0x9D, 0xF2, 0xAC, + 0x16, 0x5B, 0x79, 0x2A, 0x07, 0xF0, 0x64, 0xAC, + 0x5F, 0xC2, 0x8D, 0x8C, 0x99, 0xA5, 0x80, 0xF4, + 0xEE, 0x48, 0x23, 0xD0, 0x9E, 0x79, 0x85, 0x47, + 0x06, 0xDA, 0xA8, 0x0A, 0xE3, 0x17, 0x9B, 0x5B, + 0xC8, 0xC2, 0xE9, 0x40, 0x9D, 0x63, 0x28, 0xA3, + 0x35, 0x77, 0xFD, 0x58, 0x4B, 0xC0, 0x78, 0x4C, + 0x55, 0x9C, 0xDB, 0x24, 0x37, 0xA4, 0x6F, 0x7F, + 0x75, 0x3C, 0x33, 0x63, 0x69, 0x41, 0x9A, 0xCF + }; + static const byte expected_pk_sha2_192f[] = { + 0xEE, 0x48, 0x23, 0xD0, 0x9E, 0x79, 0x85, 0x47, + 0x06, 0xDA, 0xA8, 0x0A, 0xE3, 0x17, 0x9B, 0x5B, + 0xC8, 0xC2, 0xE9, 0x40, 0x9D, 0x63, 0x28, 0xA3, + 0x35, 0x77, 0xFD, 0x58, 0x4B, 0xC0, 0x78, 0x4C, + 0x55, 0x9C, 0xDB, 0x24, 0x37, 0xA4, 0x6F, 0x7F, + 0x75, 0x3C, 0x33, 0x63, 0x69, 0x41, 0x9A, 0xCF + }; + ret = slhdsa_keygen_kat(SLHDSA_SHA2_192F, + sk_seed_sha2_192f, (word32)sizeof(sk_seed_sha2_192f), + sk_prf_sha2_192f, (word32)sizeof(sk_prf_sha2_192f), + pk_seed_sha2_192f, (word32)sizeof(pk_seed_sha2_192f), + expected_sk_sha2_192f, (word32)sizeof(expected_sk_sha2_192f), + expected_pk_sha2_192f, (word32)sizeof(expected_pk_sha2_192f)); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHA2_192F keyGen KAT", 0); + goto out; + } + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256F + { + /* NIST CAVP SLH-DSA-SHA2-256f keyGen vector (tgId=11, tcId=101) */ + static const byte sk_seed_sha2_256f[] = { + 0x18, 0x52, 0x37, 0x02, 0xA0, 0xFE, 0x2C, 0x9E, + 0x48, 0x89, 0x48, 0xB1, 0x27, 0x18, 0x5B, 0xAB, + 0x93, 0xD3, 0xF0, 0x2C, 0x3D, 0x7C, 0x23, 0xA1, + 0xB3, 0x79, 0xF7, 0x62, 0xDE, 0x05, 0x09, 0xE5 + }; + static const byte sk_prf_sha2_256f[] = { + 0x6A, 0xB0, 0xD9, 0xF9, 0x35, 0x40, 0xBD, 0x80, + 0x9D, 0x1D, 0x2E, 0x8A, 0x05, 0x04, 0x40, 0xAA, + 0x81, 0xE8, 0x53, 0x75, 0x04, 0x70, 0xE2, 0xB0, + 0x0C, 0x95, 0x9D, 0xBD, 0x3B, 0xE4, 0x0E, 0x2B + }; + static const byte pk_seed_sha2_256f[] = { + 0xD7, 0x12, 0x5F, 0x5D, 0x00, 0xBA, 0x47, 0xF1, + 0xFC, 0x8D, 0x4C, 0x32, 0xC2, 0xF5, 0x7C, 0x44, + 0x4B, 0xD3, 0x84, 0xD7, 0xCE, 0x77, 0x0B, 0xC5, + 0x0D, 0xD5, 0x98, 0x0C, 0x1D, 0x12, 0x64, 0xD0 + }; + static const byte expected_sk_sha2_256f[] = { + 0x18, 0x52, 0x37, 0x02, 0xA0, 0xFE, 0x2C, 0x9E, + 0x48, 0x89, 0x48, 0xB1, 0x27, 0x18, 0x5B, 0xAB, + 0x93, 0xD3, 0xF0, 0x2C, 0x3D, 0x7C, 0x23, 0xA1, + 0xB3, 0x79, 0xF7, 0x62, 0xDE, 0x05, 0x09, 0xE5, + 0x6A, 0xB0, 0xD9, 0xF9, 0x35, 0x40, 0xBD, 0x80, + 0x9D, 0x1D, 0x2E, 0x8A, 0x05, 0x04, 0x40, 0xAA, + 0x81, 0xE8, 0x53, 0x75, 0x04, 0x70, 0xE2, 0xB0, + 0x0C, 0x95, 0x9D, 0xBD, 0x3B, 0xE4, 0x0E, 0x2B, + 0xD7, 0x12, 0x5F, 0x5D, 0x00, 0xBA, 0x47, 0xF1, + 0xFC, 0x8D, 0x4C, 0x32, 0xC2, 0xF5, 0x7C, 0x44, + 0x4B, 0xD3, 0x84, 0xD7, 0xCE, 0x77, 0x0B, 0xC5, + 0x0D, 0xD5, 0x98, 0x0C, 0x1D, 0x12, 0x64, 0xD0, + 0x0A, 0xD5, 0x19, 0x7F, 0xFC, 0xBA, 0xAF, 0xE1, + 0x1B, 0x1E, 0x41, 0x3F, 0x26, 0xAD, 0xB1, 0x50, + 0x4C, 0xE1, 0xC3, 0xF5, 0xC4, 0x0C, 0x1D, 0xCD, + 0xA1, 0x4E, 0x99, 0xFD, 0x12, 0x6D, 0x5B, 0x81 + }; + static const byte expected_pk_sha2_256f[] = { + 0xD7, 0x12, 0x5F, 0x5D, 0x00, 0xBA, 0x47, 0xF1, + 0xFC, 0x8D, 0x4C, 0x32, 0xC2, 0xF5, 0x7C, 0x44, + 0x4B, 0xD3, 0x84, 0xD7, 0xCE, 0x77, 0x0B, 0xC5, + 0x0D, 0xD5, 0x98, 0x0C, 0x1D, 0x12, 0x64, 0xD0, + 0x0A, 0xD5, 0x19, 0x7F, 0xFC, 0xBA, 0xAF, 0xE1, + 0x1B, 0x1E, 0x41, 0x3F, 0x26, 0xAD, 0xB1, 0x50, + 0x4C, 0xE1, 0xC3, 0xF5, 0xC4, 0x0C, 0x1D, 0xCD, + 0xA1, 0x4E, 0x99, 0xFD, 0x12, 0x6D, 0x5B, 0x81 + }; + ret = slhdsa_keygen_kat(SLHDSA_SHA2_256F, + sk_seed_sha2_256f, (word32)sizeof(sk_seed_sha2_256f), + sk_prf_sha2_256f, (word32)sizeof(sk_prf_sha2_256f), + pk_seed_sha2_256f, (word32)sizeof(pk_seed_sha2_256f), + expected_sk_sha2_256f, (word32)sizeof(expected_sk_sha2_256f), + expected_pk_sha2_256f, (word32)sizeof(expected_pk_sha2_256f)); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHA2_256F keyGen KAT", 0); + goto out; + } + } +#endif +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ + #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY #ifdef WOLFSSL_SLHDSA_PARAM_128S ret = slhdsa_test_param(SLHDSA_SHAKE128S); @@ -53108,6 +54013,48 @@ wc_test_ret_t slhdsa_test(void) goto out; } #endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128S + ret = slhdsa_test_param(SLHDSA_SHA2_128S); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHA2_128S", 0); + goto out; + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128F + ret = slhdsa_test_param(SLHDSA_SHA2_128F); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHA2_128F", 0); + goto out; + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192S + ret = slhdsa_test_param(SLHDSA_SHA2_192S); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHA2_192S", 0); + goto out; + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192F + ret = slhdsa_test_param(SLHDSA_SHA2_192F); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHA2_192F", 0); + goto out; + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256S + ret = slhdsa_test_param(SLHDSA_SHA2_256S); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHA2_256S", 0); + goto out; + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256F + ret = slhdsa_test_param(SLHDSA_SHA2_256F); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHA2_256F", 0); + goto out; + } +#endif #endif out: @@ -64571,7 +65518,7 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) len = (word32)sizeof(seed); if (info->seed.sz < len) len = info->seed.sz; - XMEMCPY(info->seed.seed, seed, sizeof(seed)); + XMEMCPY(info->seed.seed, seed, len); info->seed.seed += len; info->seed.sz -= len; (*seedWord32)++; @@ -66511,7 +67458,10 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aes_siv_test(void) #else printf("Test Profile: Default (Aggressive multi-threaded)\n"); #endif - printf("Expected statistical false positive rate: ~%.2f failures\n", + printf("Current expected statistical false positive rate with ADP/RCT" + ": NONE\n"); + printf("Historical expected statistical false positive rate with " + "continuous test: ~%.2f failures\n", (double)total_iterations * 32.0 / 4294967296.0); for (i = 0; i < NUM_THREADS; i++) { diff --git a/wolfssl/wolfcrypt/dilithium.h b/wolfssl/wolfcrypt/dilithium.h index dc6114f3e6c..61e1b63c74a 100644 --- a/wolfssl/wolfcrypt/dilithium.h +++ b/wolfssl/wolfcrypt/dilithium.h @@ -832,6 +832,9 @@ WOLFSSL_API int wc_dilithium_sign_ctx_hash_with_seed(const byte* ctx, byte ctxLen, int hashAlg, const byte* hash, word32 hashLen, byte* sig, word32 *sigLen, dilithium_key* key, const byte* seed); +WOLFSSL_API +int wc_dilithium_sign_mu_with_seed(const byte* mu, word32 muLen, + byte* sig, word32 *sigLen, dilithium_key* key, const byte* seed); #endif WOLFSSL_API int wc_dilithium_verify_msg(const byte* sig, word32 sigLen, const byte* msg, @@ -844,6 +847,9 @@ WOLFSSL_API int wc_dilithium_verify_ctx_hash(const byte* sig, word32 sigLen, const byte* ctx, byte ctxLen, int hashAlg, const byte* hash, word32 hashLen, int* res, dilithium_key* key); +WOLFSSL_API +int wc_dilithium_verify_mu(const byte* sig, word32 sigLen, const byte* mu, + word32 muLen, int* res, dilithium_key* key); #ifndef WC_NO_CONSTRUCTORS WOLFSSL_API diff --git a/wolfssl/wolfcrypt/error-crypt.h b/wolfssl/wolfcrypt/error-crypt.h index f879aabc3bb..15027fcbe14 100644 --- a/wolfssl/wolfcrypt/error-crypt.h +++ b/wolfssl/wolfcrypt/error-crypt.h @@ -88,7 +88,7 @@ enum wolfCrypt_ErrorCodes { AES_EAX_AUTH_E = -122, /* AES-EAX Authentication check failure */ KEY_EXHAUSTED_E = -123, /* No longer usable for operation. */ - /* -124 unused. */ + ML_KEM_KAT_FIPS_E = -124, /* ML-KEM KAT failure */ MEMORY_E = -125, /* out of memory error */ VAR_STATE_CHANGE_E = -126, /* var state modified by different thread */ @@ -136,7 +136,9 @@ enum wolfCrypt_ErrorCodes { ED448_KAT_FIPS_E = -164, /* Ed448 Known answer test failure */ PBKDF2_KAT_FIPS_E = -165, /* PBKDF2 Known answer test failure */ WC_KEY_MISMATCH_E = -166, /* Error for private/public key mismatch */ - /* -167..-169 unused. */ + ML_DSA_KAT_FIPS_E = -167, /* ML-DSA KAT failure */ + LMS_KAT_FIPS_E = -168, /* LMS KAT failure */ + XMSS_KAT_FIPS_E = -169, /* XMSS KAT failure */ ECC_BAD_ARG_E = -170, /* ECC input argument of wrong type */ ASN_ECC_KEY_E = -171, /* ASN ECC bad input */ @@ -311,10 +313,14 @@ enum wolfCrypt_ErrorCodes { * not match stored hash*/ BUSY_E = -1006, /* Object is busy */ ALREADY_E = -1007, /* Operation was redundant or preempted */ - - SEQ_OVERFLOW_E = -1008, /* Sequence counter would overflow */ - WC_SPAN2_LAST_E = -1008, /* Update to indicate last used error code */ - WC_LAST_E = -1008, /* the last code used either here or in + ML_KEM_PCT_E = -1008, /* ML-KEM Pairwise Consistency Test failure */ + ML_DSA_PCT_E = -1009, /* ML-DSA Pairwise Consistency Test failure */ + DRBG_SHA512_KAT_FIPS_E = -1010, /* SHA-512 DRBG KAT failure */ + + SEQ_OVERFLOW_E = -1011, /* Sequence counter would overflow */ + SLH_DSA_KAT_FIPS_E = -1012, /* SLH-DSA CAST KAT failure */ + WC_SPAN2_LAST_E = -1012, /* Update to indicate last used error code */ + WC_LAST_E = -1012, /* the last code used either here or in * error-ssl.h */ WC_SPAN2_MIN_CODE_E = -1999, /* Last usable code in span 2 */ diff --git a/wolfssl/wolfcrypt/fips_test.h b/wolfssl/wolfcrypt/fips_test.h index e4e8bf84d23..de2b506df2c 100644 --- a/wolfssl/wolfcrypt/fips_test.h +++ b/wolfssl/wolfcrypt/fips_test.h @@ -74,7 +74,13 @@ enum FipsCastId { FIPS_CAST_PBKDF2 = 18, /* v7.0.0 + */ FIPS_CAST_AES_ECB = 19, - FIPS_CAST_COUNT = 20 + FIPS_CAST_ML_KEM = 20, + FIPS_CAST_ML_DSA = 21, + FIPS_CAST_LMS = 22, + FIPS_CAST_XMSS = 23, + FIPS_CAST_DRBG_SHA512 = 24, + FIPS_CAST_SLH_DSA = 25, + FIPS_CAST_COUNT = 26 }; enum FipsCastStateId { diff --git a/wolfssl/wolfcrypt/lms.h b/wolfssl/wolfcrypt/lms.h index 8ba69d98a3e..19a7a0543c4 100644 --- a/wolfssl/wolfcrypt/lms.h +++ b/wolfssl/wolfcrypt/lms.h @@ -118,6 +118,15 @@ enum wc_LmsParm { WC_LMS_PARM_L4_H5_W8 = 33, WC_LMS_PARM_L4_H10_W4 = 34, WC_LMS_PARM_L4_H10_W8 = 35, + /* H25 parameter sets for SHA-256/256 */ + WC_LMS_PARM_L1_H25_W1 = 56, + WC_LMS_PARM_L1_H25_W2 = 57, + WC_LMS_PARM_L1_H25_W4 = 58, + WC_LMS_PARM_L1_H25_W8 = 59, + /* W1 for non-H5 heights */ + WC_LMS_PARM_L1_H10_W1 = 60, + WC_LMS_PARM_L1_H15_W1 = 61, + WC_LMS_PARM_L1_H20_W1 = 62, #endif #ifdef WOLFSSL_LMS_SHA256_192 @@ -141,6 +150,61 @@ enum wc_LmsParm { WC_LMS_PARM_SHA256_192_L3_H5_W8 = 50, WC_LMS_PARM_SHA256_192_L3_H10_W4 = 51, WC_LMS_PARM_SHA256_192_L4_H5_W8 = 52, + /* H25 for SHA-256/192 */ + WC_LMS_PARM_SHA256_192_L1_H25_W1 = 63, + WC_LMS_PARM_SHA256_192_L1_H25_W2 = 64, + WC_LMS_PARM_SHA256_192_L1_H25_W4 = 65, + WC_LMS_PARM_SHA256_192_L1_H25_W8 = 66, + /* W1 for non-H5 heights (SHA-256/192) */ + WC_LMS_PARM_SHA256_192_L1_H10_W1 = 67, + WC_LMS_PARM_SHA256_192_L1_H15_W1 = 68, + WC_LMS_PARM_SHA256_192_L1_H20_W1 = 69, + WC_LMS_PARM_SHA256_192_L1_H15_W8 = 70, +#endif + +#ifdef WOLFSSL_LMS_SHAKE256 + /* SHAKE256/256, 32-byte output */ + WC_LMS_PARM_SHAKE_L1_H5_W1 = 100, + WC_LMS_PARM_SHAKE_L1_H5_W2 = 101, + WC_LMS_PARM_SHAKE_L1_H5_W4 = 102, + WC_LMS_PARM_SHAKE_L1_H5_W8 = 103, + WC_LMS_PARM_SHAKE_L1_H10_W1 = 104, + WC_LMS_PARM_SHAKE_L1_H10_W2 = 105, + WC_LMS_PARM_SHAKE_L1_H10_W4 = 106, + WC_LMS_PARM_SHAKE_L1_H10_W8 = 107, + WC_LMS_PARM_SHAKE_L1_H15_W1 = 108, + WC_LMS_PARM_SHAKE_L1_H15_W2 = 109, + WC_LMS_PARM_SHAKE_L1_H15_W4 = 110, + WC_LMS_PARM_SHAKE_L1_H15_W8 = 111, + WC_LMS_PARM_SHAKE_L1_H20_W1 = 112, + WC_LMS_PARM_SHAKE_L1_H20_W2 = 113, + WC_LMS_PARM_SHAKE_L1_H20_W4 = 114, + WC_LMS_PARM_SHAKE_L1_H20_W8 = 115, + WC_LMS_PARM_SHAKE_L1_H25_W1 = 116, + WC_LMS_PARM_SHAKE_L1_H25_W2 = 117, + WC_LMS_PARM_SHAKE_L1_H25_W4 = 118, + WC_LMS_PARM_SHAKE_L1_H25_W8 = 119, + /* SHAKE256/192, 24-byte output */ + WC_LMS_PARM_SHAKE192_L1_H5_W1 = 120, + WC_LMS_PARM_SHAKE192_L1_H5_W2 = 121, + WC_LMS_PARM_SHAKE192_L1_H5_W4 = 122, + WC_LMS_PARM_SHAKE192_L1_H5_W8 = 123, + WC_LMS_PARM_SHAKE192_L1_H10_W1 = 124, + WC_LMS_PARM_SHAKE192_L1_H10_W2 = 125, + WC_LMS_PARM_SHAKE192_L1_H10_W4 = 126, + WC_LMS_PARM_SHAKE192_L1_H10_W8 = 127, + WC_LMS_PARM_SHAKE192_L1_H15_W1 = 128, + WC_LMS_PARM_SHAKE192_L1_H15_W2 = 129, + WC_LMS_PARM_SHAKE192_L1_H15_W4 = 130, + WC_LMS_PARM_SHAKE192_L1_H15_W8 = 131, + WC_LMS_PARM_SHAKE192_L1_H20_W1 = 132, + WC_LMS_PARM_SHAKE192_L1_H20_W2 = 133, + WC_LMS_PARM_SHAKE192_L1_H20_W4 = 134, + WC_LMS_PARM_SHAKE192_L1_H20_W8 = 135, + WC_LMS_PARM_SHAKE192_L1_H25_W1 = 136, + WC_LMS_PARM_SHAKE192_L1_H25_W2 = 137, + WC_LMS_PARM_SHAKE192_L1_H25_W4 = 138, + WC_LMS_PARM_SHAKE192_L1_H25_W8 = 139, #endif }; diff --git a/wolfssl/wolfcrypt/random.h b/wolfssl/wolfcrypt/random.h index db7d58a97ef..67e640bb297 100644 --- a/wolfssl/wolfcrypt/random.h +++ b/wolfssl/wolfcrypt/random.h @@ -52,11 +52,15 @@ #endif #endif -/* Size of the BRBG seed */ +/* Size of the DRBG seed (SHA-256) */ #ifndef DRBG_SEED_LEN #define DRBG_SEED_LEN (440/8) #endif +#ifdef WOLFSSL_DRBG_SHA512 + #define DRBG_SHA512_SEED_LEN (888/8) /* 111 bytes per SP 800-90A Table 2 */ +#endif + #if !defined(CUSTOM_RAND_TYPE) /* To maintain compatibility the default is byte */ @@ -104,9 +108,16 @@ #endif #elif defined(HAVE_HASHDRBG) #ifdef NO_SHA256 - #error "Hash DRBG requires SHA-256." + #ifndef WOLFSSL_DRBG_SHA512 + #error "Hash DRBG requires SHA-256 or SHA-512." + #endif #endif /* NO_SHA256 */ - #include + #ifndef NO_SHA256 + #include + #endif + #ifdef WOLFSSL_DRBG_SHA512 + #include + #endif #elif defined(HAVE_WNR) /* allow whitewood as direct RNG source using wc_GenerateSeed directly */ #elif defined(HAVE_INTEL_RDRAND) @@ -239,7 +250,33 @@ struct OS_Seed { #define WC_DRBG_SEED_BLOCK_SZ SEED_BLOCK_SZ -#define WC_DRBG_SEED_SZ (RNG_SECURITY_STRENGTH*ENTROPY_SCALE_FACTOR/8) +/* WC_DRBG_SEED_SZ is the number of bytes of raw entropy gathered from the + * NDRNG at instantiation and reseed. We deliberately "overseed" beyond the + * NIST minimum (security_strength bits) to account for entropy sources that + * may deliver fewer than 1 bit of real entropy per bit of output. With the + * default FIPS ENTROPY_SCALE_FACTOR of 4 this yields 256*4/8 = 128 bytes = + * 1024 bits of raw seed material, guaranteeing at least 256 bits of real + * entropy even if the source provides only 1 good bit per 4. + * + * Hash_df then compresses this seed material into the internal V and C state + * vectors (seedlen = 440 bits for SHA-256, 888 bits for SHA-512 per + * SP 800-90A Table 2). + * + * In FIPS mode (ENTROPY_SCALE_FACTOR >= 4) the base is already >= 128 bytes + * which exceeds DRBG_SHA512_SEED_LEN (111), so both DRBGs use the same + * seed size. In non-FIPS mode we use the base for both DRBGs so that + * enabling SHA-512 DRBG does not inflate the per-init entropy cost. + * SP 800-90A requires only security_strength bits (256 = 32 bytes) of + * entropy regardless of hash size; hash_df compresses the seed material + * into the internal V/C state vectors. */ +#define WC_DRBG_SEED_SZ_BASE (RNG_SECURITY_STRENGTH*ENTROPY_SCALE_FACTOR/8) + +#if defined(HAVE_FIPS) && defined(WOLFSSL_DRBG_SHA512) && \ + (WC_DRBG_SEED_SZ_BASE < DRBG_SHA512_SEED_LEN) + #define WC_DRBG_SEED_SZ DRBG_SHA512_SEED_LEN +#else + #define WC_DRBG_SEED_SZ WC_DRBG_SEED_SZ_BASE +#endif /* The maximum seed size will be the seed size plus a seed block for the * test, and an additional half of the seed size. This additional half @@ -248,8 +285,14 @@ struct OS_Seed { #define WC_DRBG_MAX_SEED_SZ (WC_DRBG_SEED_SZ + WC_DRBG_SEED_SZ/2 + \ SEED_BLOCK_SZ) -#define RNG_HEALTH_TEST_CHECK_SIZE (WC_SHA256_DIGEST_SIZE * 4) +#ifndef NO_SHA256 + #define RNG_HEALTH_TEST_CHECK_SIZE (WC_SHA256_DIGEST_SIZE * 4) +#endif +#ifdef WOLFSSL_DRBG_SHA512 + #define RNG_HEALTH_TEST_CHECK_SIZE_SHA512 (WC_SHA512_DIGEST_SIZE * 4) +#endif +#ifndef NO_SHA256 struct DRBG_internal { #ifdef WORD64_AVAILABLE word64 reseedCtr; @@ -268,8 +311,34 @@ struct DRBG_internal { byte digest_scratch[WC_SHA256_DIGEST_SIZE]; #endif }; +#endif /* !NO_SHA256 */ + +#ifdef WOLFSSL_DRBG_SHA512 +struct DRBG_SHA512_internal { + word64 reseedCtr; + byte V[DRBG_SHA512_SEED_LEN]; + byte C[DRBG_SHA512_SEED_LEN]; + void* heap; +#if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) + int devId; +#endif +#ifdef WOLFSSL_SMALL_STACK_CACHE + wc_Sha512 sha512; + byte seed_scratch[DRBG_SHA512_SEED_LEN]; + byte digest_scratch[WC_SHA512_DIGEST_SIZE]; +#endif +}; +#endif /* WOLFSSL_DRBG_SHA512 */ #endif /* HAVE_HASHDRBG */ +/* DRBG type enum */ +#ifdef HAVE_HASHDRBG +enum wc_DrbgType { + WC_DRBG_SHA256 = 0, + WC_DRBG_SHA512 = 1, +}; +#endif + /* RNG health states */ #define WC_DRBG_NOT_INIT 0 #define WC_DRBG_OK 1 @@ -301,17 +370,35 @@ struct WC_RNG { #ifdef HAVE_ANONYMOUS_INLINE_AGGREGATES struct { #endif - /* Hash-based Deterministic Random Bit Generator */ + #ifndef NO_SHA256 + /* SHA-256 Hash-based Deterministic Random Bit Generator */ struct DRBG* drbg; #if defined(WOLFSSL_NO_MALLOC) && !defined(WOLFSSL_STATIC_MEMORY) struct DRBG_internal drbg_data; #endif #ifdef WOLFSSL_SMALL_STACK_CACHE - /* Scratch buffers -- all preallocated by _InitRng(). */ + /* SHA-256 scratch buffers -- preallocated by _InitRng(). */ struct DRBG_internal *drbg_scratch; byte *health_check_scratch; + #endif + #endif /* !NO_SHA256 */ + #ifdef WOLFSSL_SMALL_STACK_CACHE + /* Seed buffer for PollAndReSeed -- shared by both DRBG types */ byte *newSeed_buf; #endif + #ifdef WOLFSSL_DRBG_SHA512 + /* SHA-512 Hash-based Deterministic Random Bit Generator */ + struct DRBG_SHA512* drbg512; + #if defined(WOLFSSL_NO_MALLOC) && !defined(WOLFSSL_STATIC_MEMORY) + struct DRBG_SHA512_internal drbg512_data; + #endif + #ifdef WOLFSSL_SMALL_STACK_CACHE + /* SHA-512 scratch buffers -- preallocated by _InitRng(). */ + struct DRBG_SHA512_internal *drbg512_scratch; + byte *health_check_scratch_512; + #endif + #endif /* WOLFSSL_DRBG_SHA512 */ + byte drbgType; /* WC_DRBG_SHA256 or WC_DRBG_SHA512 */ #ifdef HAVE_ANONYMOUS_INLINE_AGGREGATES }; #endif @@ -407,6 +494,89 @@ WOLFSSL_API int wc_FreeRng(WC_RNG* rng); const byte* seedB, word32 seedBSz, byte* output, word32 outputSz, void* heap, int devId); +#if !defined(NO_SHA256) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + /* Extended SHA-256 Hash_DRBG health test per SP 800-90A. + * Flexible output size, prediction resistance, personalization + * strings, and additional input support. */ + WOLFSSL_API int wc_RNG_HealthTest_SHA256_ex( + int predResistance, + const byte* nonce, word32 nonceSz, + const byte* persoString, + word32 persoStringSz, + const byte* entropyA, + word32 entropyASz, + const byte* entropyB, + word32 entropyBSz, + const byte* entropyC, + word32 entropyCsz, + const byte* additionalA, + word32 additionalASz, + const byte* additionalB, + word32 additionalBSz, + const byte* additionalReseed, + word32 additionalReseedSz, + byte* output, word32 outputSz, + void* heap, int devId); +#endif /* !NO_SHA256 && !HAVE_SELFTEST && FIPS v7+ */ +#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + WOLFSSL_API int wc_RNG_HealthTest_SHA512(int reseed, + const byte* seedA, word32 seedASz, + const byte* seedB, word32 seedBSz, + byte* output, word32 outputSz); + WOLFSSL_API int wc_RNG_HealthTest_SHA512_ex(int reseed, + const byte* nonce, word32 nonceSz, + const byte* persoString, + word32 persoStringSz, + const byte* seedA, word32 seedASz, + const byte* seedB, word32 seedBSz, + const byte* additionalA, + word32 additionalASz, + const byte* additionalB, + word32 additionalBSz, + byte* output, word32 outputSz, + void* heap, int devId); + /* Extended SHA-512 Hash_DRBG health test per SP 800-90A. + * Flexible output size, prediction resistance support. + * predResistance=1: additionalA/B go to Reseed per SP 800-90A 9.3.1, + * Generate gets NULL additional input. + * predResistance=0: additionalReseed goes to Reseed, additionalA/B go + * to Generate calls 1 and 2 respectively. */ + WOLFSSL_API int wc_RNG_HealthTest_SHA512_ex2( + int predResistance, + const byte* nonce, word32 nonceSz, + const byte* persoString, + word32 persoStringSz, + const byte* entropyA, + word32 entropyASz, + const byte* entropyB, + word32 entropyBSz, + const byte* entropyC, + word32 entropyCsz, + const byte* additionalA, + word32 additionalASz, + const byte* additionalB, + word32 additionalBSz, + const byte* additionalReseed, + word32 additionalReseedSz, + byte* output, word32 outputSz, + void* heap, int devId); +#endif /* WOLFSSL_DRBG_SHA512 && !HAVE_SELFTEST && FIPS v7+ */ + + /* Runtime DRBG disable/enable API */ +#if !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + WOLFSSL_API int wc_Sha256Drbg_Disable(void); + WOLFSSL_API int wc_Sha256Drbg_Enable(void); + WOLFSSL_API int wc_Sha256Drbg_GetStatus(void); +#ifdef WOLFSSL_DRBG_SHA512 + WOLFSSL_API int wc_Sha512Drbg_Disable(void); + WOLFSSL_API int wc_Sha512Drbg_Enable(void); + WOLFSSL_API int wc_Sha512Drbg_GetStatus(void); +#endif +#endif /* !HAVE_SELFTEST && (!HAVE_FIPS || FIPS v7+) */ + #endif /* HAVE_HASHDRBG */ #ifdef __cplusplus diff --git a/wolfssl/wolfcrypt/rsa.h b/wolfssl/wolfcrypt/rsa.h index 6c6c2185e35..69cc33486aa 100644 --- a/wolfssl/wolfcrypt/rsa.h +++ b/wolfssl/wolfcrypt/rsa.h @@ -426,6 +426,14 @@ WOLFSSL_API int wc_RsaPublicKeyDecodeRaw(const byte* n, word32 nSz, #define WC_MGF1SHA512 3 #define WC_MGF1SHA512_224 5 #define WC_MGF1SHA512_256 6 +#define WC_MGF1SHA3_224 7 +#define WC_MGF1SHA3_256 8 +#define WC_MGF1SHA3_384 9 +#define WC_MGF1SHA3_512 10 +#define WC_MGF1SHAKE128 11 +#define WC_MGF1SHAKE256 12 +#define WC_MGFSHAKE128 13 +#define WC_MGFSHAKE256 14 /* Padding types */ #define WC_RSA_PKCSV15_PAD 0 diff --git a/wolfssl/wolfcrypt/wc_lms.h b/wolfssl/wolfcrypt/wc_lms.h index 914ffa13712..8ae9a870c2a 100644 --- a/wolfssl/wolfcrypt/wc_lms.h +++ b/wolfssl/wolfcrypt/wc_lms.h @@ -94,6 +94,9 @@ #include #include +#ifdef WOLFSSL_LMS_SHAKE256 +#include +#endif /* When raw hash access APIs are disabled or unavailable (WOLFSSL_NO_HASH_RAW), * fall back to using the full hash API calls. */ @@ -122,10 +125,10 @@ #define LMS_MAX_HEIGHT WOLFSSL_LMS_MAX_HEIGHT #else /* Maximum height of a tree supported by implementation. */ - #define LMS_MAX_HEIGHT 20 + #define LMS_MAX_HEIGHT 25 #endif -#if (LMS_MAX_HEIGHT < 5) || (LMS_MAX_HEIGHT > 20) - #error "LMS parameters only support heights 5-20." +#if (LMS_MAX_HEIGHT < 5) || (LMS_MAX_HEIGHT > 25) + #error "LMS parameters only support heights 5-25." #endif /* Length of I in bytes. */ @@ -312,10 +315,16 @@ #define LMS_SHA256 0x0000 /* Indicates using SHA-256/192 for hashing. */ #define LMS_SHA256_192 0x1000 +/* Indicates using SHAKE256/256 for hashing. */ +#define LMS_SHAKE256 0x2000 +/* Indicates using SHAKE256/192 for hashing. */ +#define LMS_SHAKE256_192 0x3000 /* Mask to get hashing algorithm from type. */ #define LMS_HASH_MASK 0xf000 /* Mask to get height or Winternitz width from type. */ #define LMS_H_W_MASK 0x0fff +/* Bit test: non-zero if type uses SHAKE256. */ +#define LMS_IS_SHAKE(type) (((type) & 0x2000) != 0) /* LMS Parameters. */ /* SHA-256 hash, 32-bytes of hash used, tree height of 5. */ @@ -349,15 +358,55 @@ /* SHA-256 hash, 32-bytes of hash used, tree height of 25. */ #define LMS_SHA256_M24_H25 (0x0e | LMS_SHA256_192) -/* SHA-256 hash, 32-bytes of hash used, Winternitz width of 1 bit. */ +/* SHA-256 hash, 24-bytes of hash used, Winternitz width of 1 bit. */ #define LMOTS_SHA256_N24_W1 (0x05 | LMS_SHA256_192) -/* SHA-256 hash, 32-bytes of hash used, Winternitz width of 2 bits. */ +/* SHA-256 hash, 24-bytes of hash used, Winternitz width of 2 bits. */ #define LMOTS_SHA256_N24_W2 (0x06 | LMS_SHA256_192) -/* SHA-256 hash, 32-bytes of hash used, Winternitz width of 4 bits. */ +/* SHA-256 hash, 24-bytes of hash used, Winternitz width of 4 bits. */ #define LMOTS_SHA256_N24_W4 (0x07 | LMS_SHA256_192) -/* SHA-256 hash, 32-bytes of hash used, Winternitz width of 8 bits. */ +/* SHA-256 hash, 24-bytes of hash used, Winternitz width of 8 bits. */ #define LMOTS_SHA256_N24_W8 (0x08 | LMS_SHA256_192) +/* SHAKE256 hash, 32-bytes of hash used, tree height of 5. */ +#define LMS_SHAKE_M32_H5 (0x0f | LMS_SHAKE256) +/* SHAKE256 hash, 32-bytes of hash used, tree height of 10. */ +#define LMS_SHAKE_M32_H10 (0x10 | LMS_SHAKE256) +/* SHAKE256 hash, 32-bytes of hash used, tree height of 15. */ +#define LMS_SHAKE_M32_H15 (0x11 | LMS_SHAKE256) +/* SHAKE256 hash, 32-bytes of hash used, tree height of 20. */ +#define LMS_SHAKE_M32_H20 (0x12 | LMS_SHAKE256) +/* SHAKE256 hash, 32-bytes of hash used, tree height of 25. */ +#define LMS_SHAKE_M32_H25 (0x13 | LMS_SHAKE256) + +/* SHAKE256 hash, 32-bytes of hash used, Winternitz width of 1 bit. */ +#define LMOTS_SHAKE_N32_W1 (0x09 | LMS_SHAKE256) +/* SHAKE256 hash, 32-bytes of hash used, Winternitz width of 2 bits. */ +#define LMOTS_SHAKE_N32_W2 (0x0a | LMS_SHAKE256) +/* SHAKE256 hash, 32-bytes of hash used, Winternitz width of 4 bits. */ +#define LMOTS_SHAKE_N32_W4 (0x0b | LMS_SHAKE256) +/* SHAKE256 hash, 32-bytes of hash used, Winternitz width of 8 bits. */ +#define LMOTS_SHAKE_N32_W8 (0x0c | LMS_SHAKE256) + +/* SHAKE256 hash, 24-bytes of hash used, tree height of 5. */ +#define LMS_SHAKE_M24_H5 (0x14 | LMS_SHAKE256_192) +/* SHAKE256 hash, 24-bytes of hash used, tree height of 10. */ +#define LMS_SHAKE_M24_H10 (0x15 | LMS_SHAKE256_192) +/* SHAKE256 hash, 24-bytes of hash used, tree height of 15. */ +#define LMS_SHAKE_M24_H15 (0x16 | LMS_SHAKE256_192) +/* SHAKE256 hash, 24-bytes of hash used, tree height of 20. */ +#define LMS_SHAKE_M24_H20 (0x17 | LMS_SHAKE256_192) +/* SHAKE256 hash, 24-bytes of hash used, tree height of 25. */ +#define LMS_SHAKE_M24_H25 (0x18 | LMS_SHAKE256_192) + +/* SHAKE256 hash, 24-bytes of hash used, Winternitz width of 1 bit. */ +#define LMOTS_SHAKE_N24_W1 (0x0d | LMS_SHAKE256_192) +/* SHAKE256 hash, 24-bytes of hash used, Winternitz width of 2 bits. */ +#define LMOTS_SHAKE_N24_W2 (0x0e | LMS_SHAKE256_192) +/* SHAKE256 hash, 24-bytes of hash used, Winternitz width of 4 bits. */ +#define LMOTS_SHAKE_N24_W4 (0x0f | LMS_SHAKE256_192) +/* SHAKE256 hash, 24-bytes of hash used, Winternitz width of 8 bits. */ +#define LMOTS_SHAKE_N24_W8 (0x10 | LMS_SHAKE256_192) + typedef struct LmsParams { /* Number of tree levels. */ word8 levels; @@ -408,10 +457,16 @@ typedef struct LmsState { #endif /* LMS parameters. */ const LmsParams* params; - /* Hash algorithm. */ + /* Hash algorithm (SHA-256). */ wc_Sha256 hash; - /* Hash algorithm for calculating K. */ + /* Hash algorithm for calculating K (SHA-256). */ wc_Sha256 hash_k; +#ifdef WOLFSSL_LMS_SHAKE256 + /* Hash algorithm (SHAKE256). */ + wc_Shake shake; + /* Hash algorithm for calculating K (SHAKE256). */ + wc_Shake shake_k; +#endif } LmsState; #ifndef WOLFSSL_WC_LMS_SMALL diff --git a/wolfssl/wolfcrypt/wc_slhdsa.h b/wolfssl/wolfcrypt/wc_slhdsa.h index 19ee86fbb28..f8ade51b076 100644 --- a/wolfssl/wolfcrypt/wc_slhdsa.h +++ b/wolfssl/wolfcrypt/wc_slhdsa.h @@ -26,8 +26,20 @@ #include #include +#ifdef WOLFSSL_SLHDSA_SHA2 + #include + #include + #include +#endif + +#if FIPS_VERSION3_GE(7,0,0) + #include +#endif + #ifdef WOLFSSL_HAVE_SLHDSA +/* ======== SHAKE parameter guards ======== */ + /* When a bits/opt is defined then ensure 'NO' defines are off. */ #ifdef WOLFSSL_SLHDSA_PARAM_128S #undef WOLFSSL_SLHDSA_PARAM_NO_128S @@ -155,6 +167,141 @@ #define WOLFSSL_SLHDSA_PARAM_NO_256 #endif +/* ======== SHA2 parameter guards ======== */ +#ifdef WOLFSSL_SLHDSA_SHA2 + +/* When a SHA2 param is defined, ensure 'NO' defines are off. */ +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128S + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_128S + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_128 + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128F + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_128F + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_128 + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192S + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_192S + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_192 + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192F + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_192F + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_192 + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256S + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_256S + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_256 + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256F + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_256F + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_256 + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST +#endif + +/* Derive aggregate 'NO' defines for SHA2. */ +#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128S) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128F) + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_128 + #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_128 +#endif +#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192S) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192F) + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_192 + #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_192 +#endif +#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256S) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256F) + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_256 + #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_256 +#endif +#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128S) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192S) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256S) + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL + #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL +#endif +#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128F) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192F) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256F) + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST + #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST +#endif + +/* Turn on SHA2 parameter set based on 'NO' defines. */ +#if !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128S) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL) + #undef WOLFSSL_SLHDSA_PARAM_SHA2_128S + #define WOLFSSL_SLHDSA_PARAM_SHA2_128S +#endif +#if !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128F) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST) + #undef WOLFSSL_SLHDSA_PARAM_SHA2_128F + #define WOLFSSL_SLHDSA_PARAM_SHA2_128F +#endif +#if !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192S) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL) + #undef WOLFSSL_SLHDSA_PARAM_SHA2_192S + #define WOLFSSL_SLHDSA_PARAM_SHA2_192S +#endif +#if !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192F) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST) + #undef WOLFSSL_SLHDSA_PARAM_SHA2_192F + #define WOLFSSL_SLHDSA_PARAM_SHA2_192F +#endif +#if !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256S) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL) + #undef WOLFSSL_SLHDSA_PARAM_SHA2_256S + #define WOLFSSL_SLHDSA_PARAM_SHA2_256S +#endif +#if !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256F) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST) + #undef WOLFSSL_SLHDSA_PARAM_SHA2_256F + #define WOLFSSL_SLHDSA_PARAM_SHA2_256F +#endif + +/* Re-derive aggregate NOs for SHA2. */ +#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128S) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192S) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256S) + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL + #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL +#endif +#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128F) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192F) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256F) + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST + #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST +#endif +#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128S) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128F) + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_128 + #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_128 +#endif +#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192S) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192F) + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_192 + #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_192 +#endif +#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256S) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256F) + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_256 + #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_256 +#endif + +#endif /* WOLFSSL_SLHDSA_SHA2 */ + +/* ======== SHAKE size defines ======== */ + /* Seed length for SLH-DSA SHAKE-128s/f. */ #define WC_SLHDSA_SHAKE128_SEED_LEN 16 /* Seed length for SLH-DSA SHAKE-192s/f. */ @@ -216,8 +363,76 @@ /* Seed length for SLH-DSA SHAKE-256f. */ #define WC_SLHDSA_SHAKE256F_SEED_LEN WC_SLHDSA_SHAKE256_SEED_LEN -/* Determine maximum private and public key lengths based on maximum SHAKE-256 - * output length. */ +/* ======== SHA2 size defines ======== */ +#ifdef WOLFSSL_SLHDSA_SHA2 + +/* Seed length for SLH-DSA SHA2-128s/f. */ +#define WC_SLHDSA_SHA2_128_SEED_LEN 16 +/* Seed length for SLH-DSA SHA2-192s/f. */ +#define WC_SLHDSA_SHA2_192_SEED_LEN 24 +/* Seed length for SLH-DSA SHA2-256s/f. */ +#define WC_SLHDSA_SHA2_256_SEED_LEN 32 + +/* Private key length for SLH-DSA SHA2-128s. */ +#define WC_SLHDSA_SHA2_128S_PRIV_LEN (4 * 16) +/* Public key length for SLH-DSA SHA2-128s. */ +#define WC_SLHDSA_SHA2_128S_PUB_LEN (2 * 16) +/* Signature length for SLH-DSA SHA2-128s. */ +#define WC_SLHDSA_SHA2_128S_SIG_LEN 7856 +/* Seed length for SLH-DSA SHA2-128s. */ +#define WC_SLHDSA_SHA2_128S_SEED_LEN WC_SLHDSA_SHA2_128_SEED_LEN + +/* Private key length for SLH-DSA SHA2-128f. */ +#define WC_SLHDSA_SHA2_128F_PRIV_LEN (4 * 16) +/* Public key length for SLH-DSA SHA2-128f. */ +#define WC_SLHDSA_SHA2_128F_PUB_LEN (2 * 16) +/* Signature length for SLH-DSA SHA2-128f. */ +#define WC_SLHDSA_SHA2_128F_SIG_LEN 17088 +/* Seed length for SLH-DSA SHA2-128f. */ +#define WC_SLHDSA_SHA2_128F_SEED_LEN WC_SLHDSA_SHA2_128_SEED_LEN + +/* Private key length for SLH-DSA SHA2-192s. */ +#define WC_SLHDSA_SHA2_192S_PRIV_LEN (4 * 24) +/* Public key length for SLH-DSA SHA2-192s. */ +#define WC_SLHDSA_SHA2_192S_PUB_LEN (2 * 24) +/* Signature length for SLH-DSA SHA2-192s. */ +#define WC_SLHDSA_SHA2_192S_SIG_LEN 16224 +/* Seed length for SLH-DSA SHA2-192s. */ +#define WC_SLHDSA_SHA2_192S_SEED_LEN WC_SLHDSA_SHA2_192_SEED_LEN + +/* Private key length for SLH-DSA SHA2-192f. */ +#define WC_SLHDSA_SHA2_192F_PRIV_LEN (4 * 24) +/* Public key length for SLH-DSA SHA2-192f. */ +#define WC_SLHDSA_SHA2_192F_PUB_LEN (2 * 24) +/* Signature length for SLH-DSA SHA2-192f. */ +#define WC_SLHDSA_SHA2_192F_SIG_LEN 35664 +/* Seed length for SLH-DSA SHA2-192f. */ +#define WC_SLHDSA_SHA2_192F_SEED_LEN WC_SLHDSA_SHA2_192_SEED_LEN + +/* Private key length for SLH-DSA SHA2-256s. */ +#define WC_SLHDSA_SHA2_256S_PRIV_LEN (4 * 32) +/* Public key length for SLH-DSA SHA2-256s. */ +#define WC_SLHDSA_SHA2_256S_PUB_LEN (2 * 32) +/* Signature length for SLH-DSA SHA2-256s. */ +#define WC_SLHDSA_SHA2_256S_SIG_LEN 29792 +/* Seed length for SLH-DSA SHA2-256s. */ +#define WC_SLHDSA_SHA2_256S_SEED_LEN WC_SLHDSA_SHA2_256_SEED_LEN + +/* Private key length for SLH-DSA SHA2-256f. */ +#define WC_SLHDSA_SHA2_256F_PRIV_LEN (4 * 32) +/* Public key length for SLH-DSA SHA2-256f. */ +#define WC_SLHDSA_SHA2_256F_PUB_LEN (2 * 32) +/* Signature length for SLH-DSA SHA2-256f. */ +#define WC_SLHDSA_SHA2_256F_SIG_LEN 49856 +/* Seed length for SLH-DSA SHA2-256f. */ +#define WC_SLHDSA_SHA2_256F_SEED_LEN WC_SLHDSA_SHA2_256_SEED_LEN + +#endif /* WOLFSSL_SLHDSA_SHA2 */ + +/* ======== Maximum size defines ======== */ + +/* Determine maximum private and public key lengths based on maximum 256-bit + * output length. SHA2 variants have identical sizes to SHAKE counterparts. */ #ifndef WOLFSSL_SLHDSA_PARAM_NO_256 /* Maximum private key length. */ #define WC_SLHDSA_MAX_PRIV_LEN WC_SLHDSA_SHAKE256F_PRIV_LEN @@ -279,8 +494,23 @@ enum SlhDsaParam { SLHDSA_SHAKE192F = 3, /* SLH-DSA SHAKE192f */ SLHDSA_SHAKE256S = 4, /* SLH-DSA SHAKE256s */ SLHDSA_SHAKE256F = 5, /* SLH-DSA SHAKE256f */ +#ifdef WOLFSSL_SLHDSA_SHA2 + SLHDSA_SHA2_128S = 6, /* SLH-DSA SHA2-128s */ + SLHDSA_SHA2_128F = 7, /* SLH-DSA SHA2-128f */ + SLHDSA_SHA2_192S = 8, /* SLH-DSA SHA2-192s */ + SLHDSA_SHA2_192F = 9, /* SLH-DSA SHA2-192f */ + SLHDSA_SHA2_256S = 10, /* SLH-DSA SHA2-256s */ + SLHDSA_SHA2_256F = 11, /* SLH-DSA SHA2-256f */ +#endif }; +/* Helper macro to detect SHA2 parameter sets. */ +#ifdef WOLFSSL_SLHDSA_SHA2 + #define SLHDSA_IS_SHA2(p) ((p) >= SLHDSA_SHA2_128S) +#else + #define SLHDSA_IS_SHA2(p) (0) +#endif + /* Pre-defined parameter values. */ typedef struct SlhDsaParameters { enum SlhDsaParam param; /* Parameter set id. */ @@ -317,10 +547,31 @@ typedef struct SlhDsaKey { /* sk_seed | sk_prf | pk_seed, pk_root */ byte sk[32 * 4]; - /* First SHAKE-256 object. */ - wc_Shake shake; - /* Second SHAKE-256 object. */ - wc_Shake shake2; + /* Hash objects for SHAKE or SHA2. */ + union { + struct { + /* Primary SHAKE-256 object. */ + wc_Shake shake; + /* Secondary SHAKE-256 object (T_l streaming). */ + wc_Shake shake2; + } shk; +#ifdef WOLFSSL_SLHDSA_SHA2 + struct { + /* F, PRF (all cats) + H, T_l (cat 1). */ + wc_Sha256 sha256; + /* T_l streaming (cat 1), H_msg scratch. */ + wc_Sha256 sha256_2; + /* H, T_l (cats 3, 5). */ + wc_Sha512 sha512; + /* H_msg streaming (cats 3, 5). */ + wc_Sha512 sha512_2; + /* Pre-computed midstate: PK.seed || pad(64 - n). */ + wc_Sha256 sha256_mid; + /* Pre-computed midstate: PK.seed || pad(128 - n). */ + wc_Sha512 sha512_mid; + } sha2; +#endif + } hash; } SlhDsaKey; WOLFSSL_API int wc_SlhDsaKey_Init(SlhDsaKey* key, enum SlhDsaParam param, @@ -344,6 +595,15 @@ WOLFSSL_API int wc_SlhDsaKey_Sign(SlhDsaKey* key, const byte* ctx, WOLFSSL_API int wc_SlhDsaKey_Verify(SlhDsaKey* key, const byte* ctx, byte ctxSz, const byte* msg, word32 msgSz, const byte* sig, word32 sigSz); +/* Internal interface: M' provided directly (no M' construction). */ +WOLFSSL_API int wc_SlhDsaKey_SignMsgDeterministic(SlhDsaKey* key, + const byte* mprime, word32 mprimeSz, byte* sig, word32* sigSz); +WOLFSSL_API int wc_SlhDsaKey_SignMsgWithRandom(SlhDsaKey* key, + const byte* mprime, word32 mprimeSz, byte* sig, word32* sigSz, + const byte* addRnd); +WOLFSSL_API int wc_SlhDsaKey_VerifyMsg(SlhDsaKey* key, const byte* mprime, + word32 mprimeSz, const byte* sig, word32 sigSz); + WOLFSSL_API int wc_SlhDsaKey_SignHashDeterministic(SlhDsaKey* key, const byte* ctx, byte ctxSz, const byte* msg, word32 msgSz, enum wc_HashType hashType, byte* sig, word32* sigSz);