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