Skip to content

Commit 87aace1

Browse files
committed
Validate PKCS#7 padding bytes in AES-CBC-PAD decrypt
WP11_AesCbcPad_DecryptFinal only checked the last byte as the pad count without verifying all padding bytes matched. This allowed tampered ciphertext to decrypt without error. Add constant-time validation that padCnt is 1..AES_BLOCK_SIZE and all padding bytes equal padCnt, returning BAD_PADDING_E on failure. Add test exercising tampered ciphertext in both one-shot and multi-part decrypt paths. F-821
1 parent 0f35bc8 commit 87aace1

3 files changed

Lines changed: 574 additions & 0 deletions

File tree

src/internal.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12993,7 +12993,26 @@ int WP11_AesCbcPad_DecryptFinal(unsigned char* dec, word32* decSz,
1299312993
ret = wc_AesCbcDecrypt(&cbc->aes, cbc->partial, cbc->partial,
1299412994
cbc->partialSz);
1299512995
if (ret == 0) {
12996+
byte padBad;
12997+
1299612998
padCnt = cbc->partial[AES_BLOCK_SIZE-1];
12999+
13000+
/* Validate PKCS#7 padding in constant time:
13001+
* padCnt must be 1..AES_BLOCK_SIZE and all padding bytes must equal
13002+
* padCnt. */
13003+
padBad = (byte)(0 - (padCnt == 0));
13004+
padBad |= (byte)(0 - (padCnt > AES_BLOCK_SIZE));
13005+
for (i = 0; i < AES_BLOCK_SIZE; i++) {
13006+
/* inPad is 0xFF when i is in the padding region, 0x00 otherwise */
13007+
byte inPad = (byte)(0 -
13008+
((unsigned)(AES_BLOCK_SIZE - 1 - i) < (unsigned)padCnt));
13009+
padBad |= inPad & (cbc->partial[i] ^ padCnt);
13010+
}
13011+
if (padBad) {
13012+
ret = BAD_PADDING_E;
13013+
}
13014+
}
13015+
if (ret == 0) {
1299713016
outSz = AES_BLOCK_SIZE - (padCnt & (0 - (padCnt <= AES_BLOCK_SIZE)));
1299813017
for (i = 0; i < AES_BLOCK_SIZE; i++) {
1299913018
mask = (size_t)0 - (i != outSz);

0 commit comments

Comments
 (0)