From 5924524920ac867a1ba45a591bb8da9aa7f85907 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Thu, 29 Jan 2026 10:14:03 +1000 Subject: [PATCH] SHA-3: harden against glitch attack Check loop counts to ensure glitching didn't change number of times loop was performed. --- .wolfssl_known_macro_extras | 1 + configure.ac | 2 +- wolfcrypt/src/sha3.c | 211 ++++++++++++++++++++++++------------ 3 files changed, 144 insertions(+), 70 deletions(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 246ded2a456..af5a97f0807 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -637,6 +637,7 @@ WC_RSA_NONBLOCK WC_RSA_NONBLOCK_TIME WC_RSA_NO_FERMAT_CHECK WC_RWLOCK_OPS_INLINE +WC_SHA3_HARDEN WC_SHA384 WC_SHA384_DIGEST_SIZE WC_SHA512 diff --git a/configure.ac b/configure.ac index 0e987002833..e248005e0be 100644 --- a/configure.ac +++ b/configure.ac @@ -2726,7 +2726,7 @@ AC_ARG_ENABLE([faultharden], if test "$ENABLED_FAULTHARDEN" = "yes" then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_CHECK_SIG_FAULTS -DWOLFSSL_CHECK_VER_FAULTS" + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_CHECK_SIG_FAULTS -DWOLFSSL_CHECK_VER_FAULTS -DWC_SHA3_HARDEN" fi AC_ARG_ENABLE([compileharden], diff --git a/wolfcrypt/src/sha3.c b/wolfcrypt/src/sha3.c index da73966d99d..8fbca30b2d7 100644 --- a/wolfcrypt/src/sha3.c +++ b/wolfcrypt/src/sha3.c @@ -585,7 +585,7 @@ static WC_INLINE word64 Load64Unaligned(const unsigned char *a) * a Array of bytes. * returns a 64-bit integer. */ -static word64 Load64BitBigEndian(const byte* a) +static word64 Load64BitLittleEndian(const byte* a) { word64 n = 0; int i; @@ -595,6 +595,31 @@ static word64 Load64BitBigEndian(const byte* a) return n; } +#elif defined(WC_SHA3_HARDEN) +static WC_INLINE word64 Load64Unaligned(const unsigned char *a) +{ +#ifdef WC_64BIT_CPU + return *(word64*)a; +#elif defined(WC_32BIT_CPU) + return (((word64)((word32*)a)[1]) << 32) || + ((word32*)a)[0]; +#else + return (((word64)((word16*)a)[3]) << 48) || + (((word64)((word16*)a)[2]) << 32) || + (((word64)((word16*)a)[1]) << 16) || + ((word16*)a)[0]; +#endif +} + +/* Convert the array of bytes, in little-endian order, to a 64-bit integer. + * + * a Array of bytes. + * returns a 64-bit integer. + */ +static word64 Load64BitLittleEndian(const byte* a) +{ + return Load64Unaligned(a); +} #endif /* Initialize the state for a SHA3-224 hash operation. @@ -687,6 +712,10 @@ static int Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, byte p) { word32 i; word32 blocks; +#ifdef WC_SHA3_HARDEN + byte check = 0; + byte total_check = 0; +#endif #if defined(WOLFSSL_USE_SAVE_VECTOR_REGISTERS) && defined(USE_INTEL_SPEEDUP) if (SHA3_BLOCK == sha3_block_avx2) { @@ -703,19 +732,37 @@ static int Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, byte p) t = &sha3->t[sha3->i]; for (i = 0; i < l; i++) { t[i] = data[i]; + #ifdef WC_SHA3_HARDEN + check++; + #endif } + #ifdef WC_SHA3_HARDEN + if (check != l) { + return BAD_COND_E; + } + total_check += l; + #endif data += i; len -= i; sha3->i = (byte)(sha3->i + i); if (sha3->i == p * 8) { - #if !defined(BIG_ENDIAN_ORDER) + #if !defined(BIG_ENDIAN_ORDER) && !defined(WC_SHA3_HARDEN) xorbuf(sha3->s, sha3->t, (word32)(p * 8)); - #else + #else for (i = 0; i < p; i++) { - sha3->s[i] ^= Load64BitBigEndian(sha3->t + 8 * i); + sha3->s[i] ^= Load64BitLittleEndian(sha3->t + 8 * i); + #ifdef WC_SHA3_HARDEN + check++; + #endif + } + #ifdef WC_SHA3_HARDEN + if (check != p + l) { + return BAD_COND_E; } + total_check += p; #endif + #endif #ifdef SHA3_FUNC_PTR (*SHA3_BLOCK)(sha3->s); #else @@ -733,14 +780,25 @@ static int Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, byte p) blocks = 0; } #endif +#ifdef WC_SHA3_HARDEN + total_check += blocks * p; +#endif for (; blocks > 0; blocks--) { - #if !defined(BIG_ENDIAN_ORDER) +#if !defined(BIG_ENDIAN_ORDER) && !defined(WC_SHA3_HARDEN) xorbuf(sha3->s, data, (word32)(p * 8)); - #else +#else for (i = 0; i < p; i++) { sha3->s[i] ^= Load64Unaligned(data + 8 * i); + #ifdef WC_SHA3_HARDEN + check++; + #endif + } + #ifdef WC_SHA3_HARDEN + if (check != total_check - ((blocks - 1) * p)) { + return BAD_COND_E; } #endif +#endif #ifdef SHA3_FUNC_PTR (*SHA3_BLOCK)(sha3->s); #else @@ -749,6 +807,11 @@ static int Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, byte p) len -= p * 8U; data += p * 8U; } +#ifdef WC_SHA3_HARDEN + if (check != total_check) { + return BAD_COND_E; + } +#endif #if defined(WOLFSSL_USE_SAVE_VECTOR_REGISTERS) && defined(USE_INTEL_SPEEDUP) if (SHA3_BLOCK == sha3_block_avx2) { RESTORE_VECTOR_REGISTERS(); @@ -774,11 +837,14 @@ static int Sha3Final(wc_Sha3* sha3, byte padChar, byte* hash, byte p, word32 l) { word32 rate = p * 8U; word32 j; -#if defined(BIG_ENDIAN_ORDER) +#if defined(BIG_ENDIAN_ORDER) || defined(WC_SHA3_HARDEN) word32 i; #endif +#ifdef WC_SHA3_HARDEN + int check = 0; +#endif -#if !defined(BIG_ENDIAN_ORDER) +#if !defined(BIG_ENDIAN_ORDER) && !defined(WC_SHA3_HARDEN) xorbuf(sha3->s, sha3->t, sha3->i); #ifdef WOLFSSL_HASH_FLAGS if ((p == WC_SHA3_256_COUNT) && (sha3->flags & WC_HASH_SHA3_KECCAK256)) { @@ -800,8 +866,16 @@ static int Sha3Final(wc_Sha3* sha3, byte padChar, byte* hash, byte p, word32 l) XMEMSET(sha3->t + sha3->i + 1, 0, rate - 1U - (sha3->i + 1U)); } for (i = 0; i < p; i++) { - sha3->s[i] ^= Load64BitBigEndian(sha3->t + 8 * i); + sha3->s[i] ^= Load64BitLittleEndian(sha3->t + 8 * i); + #ifdef WC_SHA3_HARDEN + check++; + #endif } +#ifdef WC_SHA3_HARDEN + if (check != p) { + return BAD_COND_E; + } +#endif #endif #if defined(WOLFSSL_USE_SAVE_VECTOR_REGISTERS) && defined(USE_INTEL_SPEEDUP) @@ -843,80 +917,79 @@ static int Sha3Final(wc_Sha3* sha3, byte padChar, byte* hash, byte p, word32 l) #endif #if defined(STM32_HASH_SHA3) - /* Supports CubeMX HAL or Standard Peripheral Library */ +/* Supports CubeMX HAL or Standard Peripheral Library */ - static int wc_InitSha3(wc_Sha3* sha3, void* heap, int devId) - { - if (sha3 == NULL) - return BAD_FUNC_ARG; +static int wc_InitSha3(wc_Sha3* sha3, void* heap, int devId) +{ + if (sha3 == NULL) + return BAD_FUNC_ARG; - (void)devId; - (void)heap; + (void)devId; + (void)heap; - XMEMSET(sha3, 0, sizeof(wc_Sha3)); - wc_Stm32_Hash_Init(&sha3->stmCtx); - return 0; - } + XMEMSET(sha3, 0, sizeof(wc_Sha3)); + wc_Stm32_Hash_Init(&sha3->stmCtx); + return 0; +} - static int Stm32GetAlgo(byte p) - { - switch(p) { - case WC_SHA3_224_COUNT: - return HASH_ALGOSELECTION_SHA3_224; - case WC_SHA3_256_COUNT: - return HASH_ALGOSELECTION_SHA3_256; - case WC_SHA3_384_COUNT: - return HASH_ALGOSELECTION_SHA3_384; - case WC_SHA3_512_COUNT: - return HASH_ALGOSELECTION_SHA3_512; - } - /* Should never get here */ - return WC_SHA3_224_COUNT; +static int Stm32GetAlgo(byte p) +{ + switch(p) { + case WC_SHA3_224_COUNT: + return HASH_ALGOSELECTION_SHA3_224; + case WC_SHA3_256_COUNT: + return HASH_ALGOSELECTION_SHA3_256; + case WC_SHA3_384_COUNT: + return HASH_ALGOSELECTION_SHA3_384; + case WC_SHA3_512_COUNT: + return HASH_ALGOSELECTION_SHA3_512; } + /* Should never get here */ + return WC_SHA3_224_COUNT; +} - static int wc_Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, byte p) - { - int ret = 0; +static int wc_Sha3Update(wc_Sha3* sha3, const byte* data, word32 len, byte p) +{ + int ret = 0; - if (sha3 == NULL) { - return BAD_FUNC_ARG; - } - if (data == NULL && len == 0) { - /* valid, but do nothing */ - return 0; - } - if (data == NULL) { - return BAD_FUNC_ARG; - } + if (sha3 == NULL) { + return BAD_FUNC_ARG; + } + if (data == NULL && len == 0) { + /* valid, but do nothing */ + return 0; + } + if (data == NULL) { + return BAD_FUNC_ARG; + } - ret = wolfSSL_CryptHwMutexLock(); - if (ret == 0) { - ret = wc_Stm32_Hash_Update(&sha3->stmCtx, - Stm32GetAlgo(p), data, len, p * 8); - wolfSSL_CryptHwMutexUnLock(); - } - return ret; + ret = wolfSSL_CryptHwMutexLock(); + if (ret == 0) { + ret = wc_Stm32_Hash_Update(&sha3->stmCtx, Stm32GetAlgo(p), data, len, + p * 8); + wolfSSL_CryptHwMutexUnLock(); } + return ret; +} - static int wc_Sha3Final(wc_Sha3* sha3, byte* hash, byte p, byte len) - { - int ret = 0; +static int wc_Sha3Final(wc_Sha3* sha3, byte* hash, byte p, byte len) +{ + int ret = 0; - if (sha3 == NULL || hash == NULL) { - return BAD_FUNC_ARG; - } + if (sha3 == NULL || hash == NULL) { + return BAD_FUNC_ARG; + } - ret = wolfSSL_CryptHwMutexLock(); - if (ret == 0) { - ret = wc_Stm32_Hash_Final(&sha3->stmCtx, - Stm32GetAlgo(p), hash, len); - wolfSSL_CryptHwMutexUnLock(); - } + ret = wolfSSL_CryptHwMutexLock(); + if (ret == 0) { + ret = wc_Stm32_Hash_Final(&sha3->stmCtx, Stm32GetAlgo(p), hash, len); + wolfSSL_CryptHwMutexUnLock(); + } - (void)wc_InitSha3(sha3, NULL, 0); /* reset state */ + (void)wc_InitSha3(sha3, NULL, 0); /* reset state */ - return ret; - } + return ret; +} #elif defined(PSOC6_HASH_SHA3) static int wc_InitSha3(wc_Sha3* sha3, void* heap, int devId)