Skip to content

Commit c0bc5ef

Browse files
authored
Merge pull request #10307 from padelsbach/nxp-aes-multiblock
Fix AES multiblock issues for NXP DCP
2 parents 401e9e2 + 2fa541b commit c0bc5ef

2 files changed

Lines changed: 152 additions & 2 deletions

File tree

wolfcrypt/src/port/nxp/dcp_port.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ int DCPAesCbcEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
255255
if (ret)
256256
ret = WC_HW_E;
257257
else
258-
XMEMCPY(aes->reg, out, WC_AES_BLOCK_SIZE);
258+
XMEMCPY(aes->reg, out + sz - WC_AES_BLOCK_SIZE, WC_AES_BLOCK_SIZE);
259259
dcp_unlock();
260260
return ret;
261261
}
@@ -265,12 +265,15 @@ int DCPAesCbcDecrypt(Aes* aes, byte* out, const byte* in, word32 sz)
265265
int ret;
266266
if (sz % 16)
267267
return BAD_FUNC_ARG;
268+
/* Snapshot last ciphertext block before decrypt; in-place decryption
269+
* (in == out) overwrites the input with plaintext. */
270+
XMEMCPY(aes->tmp, in + sz - WC_AES_BLOCK_SIZE, WC_AES_BLOCK_SIZE);
268271
dcp_lock();
269272
ret = DCP_AES_DecryptCbc(DCP, &aes->handle, in, out, sz, (const byte *)aes->reg);
270273
if (ret)
271274
ret = WC_HW_E;
272275
else
273-
XMEMCPY(aes->reg, in, WC_AES_BLOCK_SIZE);
276+
XMEMCPY(aes->reg, aes->tmp, WC_AES_BLOCK_SIZE);
274277
dcp_unlock();
275278
return ret;
276279
}

wolfcrypt/test/test.c

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16844,6 +16844,153 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aes_cbc_test(void)
1684416844
}
1684516845
#endif /* HAVE_AES_DECRYPT */
1684616846

16847+
/* Multi-block streaming: exercises the IV-handoff path with sz > 16
16848+
* so that out[0] and out[sz-16] differ. Hardware backends that stash
16849+
* the wrong ciphertext block into aes->reg between calls (e.g. the
16850+
* first block instead of the last) will fail the second KAT. */
16851+
{
16852+
WOLFSSL_SMALL_STACK_STATIC const byte msg4[] = {
16853+
0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,
16854+
0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a,
16855+
0xae,0x2d,0x8a,0x57,0x1e,0x03,0xac,0x9c,
16856+
0x9e,0xb7,0x6f,0xac,0x45,0xaf,0x8e,0x51,
16857+
0x30,0xc8,0x1c,0x46,0xa3,0x5c,0xe4,0x11,
16858+
0xe5,0xfb,0xc1,0x19,0x1a,0x0a,0x52,0xef,
16859+
0xf6,0x9f,0x24,0x45,0xdf,0x4f,0x9b,0x17,
16860+
0xad,0x2b,0x41,0x7b,0xe6,0x6c,0x37,0x10
16861+
};
16862+
WOLFSSL_SMALL_STACK_STATIC const byte verify4[] = {
16863+
0x76,0x49,0xab,0xac,0x81,0x19,0xb2,0x46,
16864+
0xce,0xe9,0x8e,0x9b,0x12,0xe9,0x19,0x7d,
16865+
0x50,0x86,0xcb,0x9b,0x50,0x72,0x19,0xee,
16866+
0x95,0xdb,0x11,0x3a,0x91,0x76,0x78,0xb2,
16867+
0x73,0xbe,0xd6,0xb8,0xe3,0xc1,0x74,0x3b,
16868+
0x71,0x16,0xe6,0x9e,0x22,0x22,0x95,0x16,
16869+
0x3f,0xf1,0xca,0xa1,0x68,0x1f,0xac,0x09,
16870+
0x12,0x0e,0xca,0x30,0x75,0x86,0xe1,0xa7
16871+
};
16872+
16873+
ret = wc_AesSetKey(enc, key2, sizeof(key2), iv2, AES_ENCRYPTION);
16874+
if (ret != 0)
16875+
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
16876+
16877+
XMEMSET(cipher, 0, sizeof(cipher));
16878+
ret = wc_AesCbcEncrypt(enc, cipher, msg4, WC_AES_BLOCK_SIZE * 2);
16879+
#if defined(WOLFSSL_ASYNC_CRYPT)
16880+
ret = wc_AsyncWait(ret, &enc->asyncDev, WC_ASYNC_FLAG_NONE);
16881+
#endif
16882+
if (ret != 0)
16883+
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
16884+
16885+
ret = wc_AesCbcEncrypt(enc, cipher + WC_AES_BLOCK_SIZE * 2,
16886+
msg4 + WC_AES_BLOCK_SIZE * 2,
16887+
WC_AES_BLOCK_SIZE * 2);
16888+
#if defined(WOLFSSL_ASYNC_CRYPT)
16889+
ret = wc_AsyncWait(ret, &enc->asyncDev, WC_ASYNC_FLAG_NONE);
16890+
#endif
16891+
if (ret != 0)
16892+
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
16893+
16894+
if (XMEMCMP(cipher, verify4, sizeof(verify4))) {
16895+
WOLFSSL_MSG("wc_AesCbcEncrypt streaming failed cipher compare");
16896+
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
16897+
}
16898+
16899+
/* In-place multi-block streaming encrypt: input and output
16900+
* overlap. The next-call IV is read from the output buffer,
16901+
* which always holds ciphertext post-call, so this must work
16902+
* for any correct backend regardless of aliasing. */
16903+
ret = wc_AesSetKey(enc, key2, sizeof(key2), iv2, AES_ENCRYPTION);
16904+
if (ret != 0)
16905+
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
16906+
16907+
XMEMCPY(cipher, msg4, sizeof(msg4));
16908+
16909+
ret = wc_AesCbcEncrypt(enc, cipher, cipher, WC_AES_BLOCK_SIZE * 2);
16910+
#if defined(WOLFSSL_ASYNC_CRYPT)
16911+
ret = wc_AsyncWait(ret, &enc->asyncDev, WC_ASYNC_FLAG_NONE);
16912+
#endif
16913+
if (ret != 0)
16914+
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
16915+
16916+
ret = wc_AesCbcEncrypt(enc, cipher + WC_AES_BLOCK_SIZE * 2,
16917+
cipher + WC_AES_BLOCK_SIZE * 2,
16918+
WC_AES_BLOCK_SIZE * 2);
16919+
#if defined(WOLFSSL_ASYNC_CRYPT)
16920+
ret = wc_AsyncWait(ret, &enc->asyncDev, WC_ASYNC_FLAG_NONE);
16921+
#endif
16922+
if (ret != 0)
16923+
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
16924+
16925+
if (XMEMCMP(cipher, verify4, sizeof(verify4))) {
16926+
WOLFSSL_MSG("wc_AesCbcEncrypt in-place streaming failed"
16927+
" cipher compare");
16928+
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
16929+
}
16930+
16931+
#ifdef HAVE_AES_DECRYPT
16932+
ret = wc_AesSetKey(dec, key2, sizeof(key2), iv2, AES_DECRYPTION);
16933+
if (ret != 0)
16934+
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
16935+
16936+
XMEMSET(plain, 0, sizeof(plain));
16937+
ret = wc_AesCbcDecrypt(dec, plain, verify4, WC_AES_BLOCK_SIZE * 2);
16938+
#if defined(WOLFSSL_ASYNC_CRYPT)
16939+
ret = wc_AsyncWait(ret, &dec->asyncDev, WC_ASYNC_FLAG_NONE);
16940+
#endif
16941+
if (ret != 0)
16942+
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
16943+
16944+
ret = wc_AesCbcDecrypt(dec, plain + WC_AES_BLOCK_SIZE * 2,
16945+
verify4 + WC_AES_BLOCK_SIZE * 2,
16946+
WC_AES_BLOCK_SIZE * 2);
16947+
#if defined(WOLFSSL_ASYNC_CRYPT)
16948+
ret = wc_AsyncWait(ret, &dec->asyncDev, WC_ASYNC_FLAG_NONE);
16949+
#endif
16950+
if (ret != 0)
16951+
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
16952+
16953+
if (XMEMCMP(plain, msg4, sizeof(msg4))) {
16954+
WOLFSSL_MSG("wc_AesCbcDecrypt streaming failed plain compare");
16955+
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
16956+
}
16957+
16958+
/* In-place multi-block streaming decrypt: input and output
16959+
* overlap, so backends must snapshot the last ciphertext block
16960+
* BEFORE decrypting (it is clobbered by the plaintext write).
16961+
* Backends that read the IV for the next call from the output
16962+
* buffer after decrypt will stash plaintext and garble the
16963+
* first block of the next call. */
16964+
ret = wc_AesSetKey(dec, key2, sizeof(key2), iv2, AES_DECRYPTION);
16965+
if (ret != 0)
16966+
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
16967+
16968+
XMEMCPY(plain, verify4, sizeof(verify4));
16969+
16970+
ret = wc_AesCbcDecrypt(dec, plain, plain, WC_AES_BLOCK_SIZE * 2);
16971+
#if defined(WOLFSSL_ASYNC_CRYPT)
16972+
ret = wc_AsyncWait(ret, &dec->asyncDev, WC_ASYNC_FLAG_NONE);
16973+
#endif
16974+
if (ret != 0)
16975+
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
16976+
16977+
ret = wc_AesCbcDecrypt(dec, plain + WC_AES_BLOCK_SIZE * 2,
16978+
plain + WC_AES_BLOCK_SIZE * 2,
16979+
WC_AES_BLOCK_SIZE * 2);
16980+
#if defined(WOLFSSL_ASYNC_CRYPT)
16981+
ret = wc_AsyncWait(ret, &dec->asyncDev, WC_ASYNC_FLAG_NONE);
16982+
#endif
16983+
if (ret != 0)
16984+
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out);
16985+
16986+
if (XMEMCMP(plain, msg4, sizeof(msg4))) {
16987+
WOLFSSL_MSG("wc_AesCbcDecrypt in-place streaming failed"
16988+
" plain compare");
16989+
ERROR_OUT(WC_TEST_RET_ENC_NC, out);
16990+
}
16991+
#endif /* HAVE_AES_DECRYPT */
16992+
}
16993+
1684716994
aes_cbc_oneshot_test();
1684816995
}
1684916996
#endif /* WOLFSSL_AES_128 && !HAVE_RENESAS_SYNC */

0 commit comments

Comments
 (0)