Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .wolfssl_known_macro_extras
Original file line number Diff line number Diff line change
Expand Up @@ -785,9 +785,7 @@ WOLFSSL_ARMASM_NEON_NO_TABLE_LOOKUP
WOLFSSL_ARM_ARCH_NEON_64BIT
WOLFSSL_ASCON_UNROLL
WOLFSSL_ASN_EXTRA
WOLFSSL_ASN_TEMPLATE_NEED_SET_INT32
WOLFSSL_ASN_TEMPLATE_TYPE_CHECK
WOLFSSL_ASYNC_CERT_YIELD
WOLFSSL_ATECC508
WOLFSSL_ATECC508A_NOSOFTECC
WOLFSSL_ATECC508A_TLS
Expand Down Expand Up @@ -881,7 +879,6 @@ WOLFSSL_MANUALLY_SELECT_DEVICE_CONFIG
WOLFSSL_MDK5
WOLFSSL_MEM_FAIL_COUNT
WOLFSSL_MICROCHIP_AESGCM
WOLFSSL_MLKEM_DYNAMIC_KEYS
WOLFSSL_MLKEM_INVNTT_UNROLL
WOLFSSL_MLKEM_NO_MALLOC
WOLFSSL_MLKEM_NTT_UNROLL
Expand Down
16 changes: 13 additions & 3 deletions wolfcrypt/src/aes.c
Original file line number Diff line number Diff line change
Expand Up @@ -11319,6 +11319,10 @@ int WARN_UNUSED_RESULT AES_GCM_decrypt_C(
ALIGN16 byte Tprime[WC_AES_BLOCK_SIZE];
ALIGN16 byte EKY0[WC_AES_BLOCK_SIZE];
volatile sword32 res;
#ifndef WC_AES_GCM_DEC_AUTH_EARLY
byte mask;
word32 i;
#endif

if (ivSz == GCM_NONCE_MID_SZ) {
/* Counter is IV with bottom 4 bytes set to: 0x00,0x00,0x00,0x01. */
Expand Down Expand Up @@ -11438,10 +11442,16 @@ int WARN_UNUSED_RESULT AES_GCM_decrypt_C(
*/
ret = (ret & ~res);
ret |= (res & WC_NO_ERR_TRACE(AES_GCM_AUTH_E));
#endif
if (ret != 0) {
ForceZero(out, sz);
/* Mask the output on auth failure instead of branching, to keep the tag
Comment thread
Frauschi marked this conversation as resolved.
* compare constant time. res is all-ones on mismatch, zero on match. A
* single vectorizable pass is cheaper than folding the mask into the
* decrypt loop. Not needed for WC_AES_GCM_DEC_AUTH_EARLY: there the tag is
* checked before decryption, so out is never written on a mismatch. */
mask = (byte)res;
Comment thread
Frauschi marked this conversation as resolved.
for (i = 0; i < sz; i++) {
out[i] &= (byte)~mask;
}
#endif
return ret;
}
#elif (defined(__aarch64__) || defined(WOLFSSL_ARMASM_NO_HW_CRYPTO)) || \
Expand Down
45 changes: 45 additions & 0 deletions wolfcrypt/test/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -19170,6 +19170,51 @@ static wc_test_ret_t aesgcm_setiv_test(Aes* enc, Aes* dec)
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
if (XMEMCMP(p, resultP, sizeof(p)))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);

/* A tampered tag must fail decryption. On the software C path the output
* buffer is additionally cleared so unauthenticated plaintext is never
* released. The AES-NI/asm paths do not clear it, so the zero-check is
* limited to the C path, which is forced here by disabling AES-NI for
* this one call. */
{
#ifdef WOLFSSL_AESNI
Comment thread
danielinux marked this conversation as resolved.
int saved_use_aesni = dec->use_aesni;
dec->use_aesni = 0;
#endif
resultT[0] ^= 0xB5;
XMEMSET(resultP, 0x5A, sizeof(p));
ret = wc_AesGcmDecrypt(dec, resultP, resultC, sizeof(p),
randIV, sizeof(randIV), resultT, 16, a, sizeof(a));
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &dec->asyncDev, WC_ASYNC_FLAG_NONE);
#endif
resultT[0] ^= 0xB5;
#ifdef WOLFSSL_AESNI
dec->use_aesni = saved_use_aesni;
#endif
if (ret != WC_NO_ERR_TRACE(AES_GCM_AUTH_E))
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
#if !defined(WOLFSSL_ARMASM) && !defined(WOLFSSL_RISCV_ASM) && \
!defined(WOLFSSL_PPC64_ASM) && \
!defined(WOLFSSL_PPC32_ASM) && !defined(STM32_CRYPTO_AES_GCM) && \
!defined(WOLFSSL_AFALG_XILINX_AES) && !defined(WOLFSSL_XILINX_CRYPT) && \
!defined(WOLFSSL_KCAPI_AES) && !defined(WOLFSSL_DEVCRYPTO_AES) && \
!defined(WOLFSSL_ESP32_CRYPT) && !defined(WOLFSSL_IMXRT_DCP) && \
!defined(WOLFSSL_SILABS_SE_ACCEL) && !defined(HAVE_FIPS) && \
!defined(WC_AES_GCM_DEC_AUTH_EARLY) && !defined(WOLFSSL_ASYNC_CRYPT)
{
/* C path clears the output buffer on authentication failure.
* The FIPS module's AES-GCM decrypt does not clear it, so skip
* this check under HAVE_FIPS. */
word32 z;
for (z = 0; z < (word32)sizeof(p); z++) {
if (resultP[z] != 0)
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
}
}
#endif
ret = 0;
}
#endif /* HAVE_AES_DECRYPT */

out:
Expand Down
Loading