Fix AES-EAX to allow empty plaintext

The one-shot wc_AesEaxEncryptAuth/wc_AesEaxDecryptAuth and the
incremental wc_AesEaxEncryptUpdate/wc_AesEaxDecryptUpdate functions
unconditionally required non-NULL out/in/authIn pointers, returning
BAD_FUNC_ARG even when the corresponding length was 0.

EAX mode with empty plaintext is a valid authentication-only operation
that produces just an authentication tag (OMAC over nonce and AAD).
This is permitted by the EAX specification (Bellare, Rogaway, Wagner
2004) and exercised by Wycheproof test vectors.

Fix: gate NULL pointer checks on the corresponding length being > 0.
In the incremental Update functions, skip the AES-CTR and CMAC
ciphertext update when inSz is 0 to avoid passing NULL to
wc_AesCtrEncrypt (which also rejects NULL unconditionally).
This commit is contained in:
Mark Atwood
2026-03-24 05:53:04 -07:00
committed by Mark Atwood
parent c4c71eece3
commit a7cc526747
+40 -32
View File
@@ -16779,8 +16779,9 @@ int wc_AesEaxEncryptAuth(const byte* key, word32 keySz, byte* out,
int ret;
int eaxInited = 0;
if (key == NULL || out == NULL || in == NULL || nonce == NULL
|| authTag == NULL || authIn == NULL) {
if (key == NULL || nonce == NULL || authTag == NULL
|| (inSz > 0 && (out == NULL || in == NULL))
|| (authInSz > 0 && authIn == NULL)) {
return BAD_FUNC_ARG;
}
@@ -16842,8 +16843,9 @@ int wc_AesEaxDecryptAuth(const byte* key, word32 keySz, byte* out,
int ret;
int eaxInited = 0;
if (key == NULL || out == NULL || in == NULL || nonce == NULL
|| authTag == NULL || authIn == NULL) {
if (key == NULL || nonce == NULL || authTag == NULL
|| (inSz > 0 && (out == NULL || in == NULL))
|| (authInSz > 0 && authIn == NULL)) {
return BAD_FUNC_ARG;
}
@@ -17031,24 +17033,27 @@ int wc_AesEaxEncryptUpdate(AesEax* eax, byte* out,
{
int ret;
if (eax == NULL || out == NULL || in == NULL) {
if (eax == NULL || (inSz > 0 && (out == NULL || in == NULL))
|| (authInSz > 0 && authIn == NULL)) {
return BAD_FUNC_ARG;
}
/*
* Encrypt the plaintext using AES CTR
* C = CTR(M)
*/
if ((ret = wc_AesCtrEncrypt(&eax->aes, out, in, inSz)) != 0) {
return ret;
}
if (inSz > 0) {
/*
* Encrypt the plaintext using AES CTR
* C = CTR(M)
*/
if ((ret = wc_AesCtrEncrypt(&eax->aes, out, in, inSz)) != 0) {
return ret;
}
/*
* update OMAC with new ciphertext
* C' = OMAC^2_K(C)
*/
if ((ret = wc_CmacUpdate(&eax->ciphertextCmac, out, inSz)) != 0) {
return ret;
/*
* update OMAC with new ciphertext
* C' = OMAC^2_K(C)
*/
if ((ret = wc_CmacUpdate(&eax->ciphertextCmac, out, inSz)) != 0) {
return ret;
}
}
/* If there exists new auth data, update the OMAC for that as well */
@@ -17076,24 +17081,27 @@ int wc_AesEaxDecryptUpdate(AesEax* eax, byte* out,
{
int ret;
if (eax == NULL || out == NULL || in == NULL) {
if (eax == NULL || (inSz > 0 && (out == NULL || in == NULL))
|| (authInSz > 0 && authIn == NULL)) {
return BAD_FUNC_ARG;
}
/*
* Decrypt the plaintext using AES CTR
* C = CTR(M)
*/
if ((ret = wc_AesCtrEncrypt(&eax->aes, out, in, inSz)) != 0) {
return ret;
}
if (inSz > 0) {
/*
* Decrypt the plaintext using AES CTR
* C = CTR(M)
*/
if ((ret = wc_AesCtrEncrypt(&eax->aes, out, in, inSz)) != 0) {
return ret;
}
/*
* update OMAC with new ciphertext
* C' = OMAC^2_K(C)
*/
if ((ret = wc_CmacUpdate(&eax->ciphertextCmac, in, inSz)) != 0) {
return ret;
/*
* update OMAC with new ciphertext
* C' = OMAC^2_K(C)
*/
if ((ret = wc_CmacUpdate(&eax->ciphertextCmac, in, inSz)) != 0) {
return ret;
}
}
/* If there exists new auth data, update the OMAC for that as well */