Skip to content

Commit 68d8029

Browse files
MarkAtwoodclaude
andcommitted
Fix ChaCha20-Poly1305 and XChaCha20-Poly1305 one-shot APIs to allow empty plaintext
Three functions rejected zero-length plaintext with BAD_FUNC_ARG: 1. wc_ChaCha20Poly1305_Decrypt: required outPlaintext != NULL even when inCiphertextLen is 0. RFC 8439 Section 2.8 permits empty plaintext (authentication-only mode). 2. wc_ChaCha20Poly1305_UpdateData: required inData/outData != NULL unconditionally, and called wc_Chacha_Process with NULL pointers even when dataLen is 0 (which also rejects NULL). 3. wc_XChaCha20Poly1305_crypt_oneshot: required dst != NULL even when dst_len is 0. Fix: gate all NULL checks and processing calls on the respective length being > 0. Also guard the ForceZero error cleanup in the one-shot decrypt path, which would pass NULL to ForceZero on error with zero-length plaintext. Note: the streaming API Final() fix for empty plaintext was merged upstream separately (PR #10040). This commit fixes the one-shot and UpdateData paths that the streaming fix did not cover. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Found via Wycheproof test vectors.
1 parent c4c71ee commit 68d8029

1 file changed

Lines changed: 9 additions & 6 deletions

File tree

wolfcrypt/src/chacha20_poly1305.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,13 @@ int wc_ChaCha20Poly1305_Decrypt(
9393
WC_DECLARE_VAR(aead, ChaChaPoly_Aead, 1, 0);
9494
byte calculatedAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE];
9595

96-
/* Validate function arguments */
96+
/* Validate function arguments.
97+
* outPlaintext may be NULL when inCiphertextLen is 0
98+
* (authentication-only, no plaintext to decrypt). */
9799
if (!inKey || !inIV ||
98100
(inCiphertextLen > 0 && inCiphertext == NULL) ||
99101
!inAuthTag ||
100-
!outPlaintext)
102+
(inCiphertextLen > 0 && !outPlaintext))
101103
{
102104
return BAD_FUNC_ARG;
103105
}
@@ -119,7 +121,7 @@ int wc_ChaCha20Poly1305_Decrypt(
119121
if (ret == 0)
120122
ret = wc_ChaCha20Poly1305_CheckTag(inAuthTag, calculatedAuthTag);
121123

122-
if (ret != 0) {
124+
if (ret != 0 && inCiphertextLen > 0) {
123125
/* zero plaintext on error */
124126
ForceZero(outPlaintext, inCiphertextLen);
125127
}
@@ -229,7 +231,8 @@ int wc_ChaCha20Poly1305_UpdateData(ChaChaPoly_Aead* aead,
229231
{
230232
int ret = 0;
231233

232-
if (aead == NULL || inData == NULL || outData == NULL) {
234+
if (aead == NULL ||
235+
(dataLen > 0 && (inData == NULL || outData == NULL))) {
233236
return BAD_FUNC_ARG;
234237
}
235238
if (aead->state != CHACHA20_POLY1305_STATE_READY &&
@@ -249,7 +252,7 @@ int wc_ChaCha20Poly1305_UpdateData(ChaChaPoly_Aead* aead,
249252
aead->state = CHACHA20_POLY1305_STATE_DATA;
250253

251254
/* Perform ChaCha20 encrypt/decrypt and Poly1305 auth calc */
252-
if (ret == 0) {
255+
if (ret == 0 && dataLen > 0) {
253256
if (aead->isEncrypt) {
254257
ret = wc_Chacha_Process(&aead->chacha, outData, inData, dataLen);
255258
if (ret == 0)
@@ -401,7 +404,7 @@ static WC_INLINE int wc_XChaCha20Poly1305_crypt_oneshot(
401404
dst_len = src_len - (size_t)POLY1305_DIGEST_SIZE;
402405
}
403406

404-
if ((dst == NULL) || (src == NULL)) {
407+
if ((dst_len > 0 && dst == NULL) || (src == NULL)) {
405408
ret = BAD_FUNC_ARG;
406409
goto out;
407410
}

0 commit comments

Comments
 (0)