@@ -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