/* test_aes.c
 *
 * Copyright (C) 2006-2026 wolfSSL Inc.
 *
 * This file is part of wolfSSL.
 *
 * wolfSSL is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * wolfSSL is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
 */

#include <tests/unit.h>

#ifdef NO_INLINE
    #include <wolfssl/wolfcrypt/misc.h>
#else
    #define WOLFSSL_MISC_INCLUDED
    #include <wolfcrypt/src/misc.c>
#endif

#include <wolfssl/wolfcrypt/aes.h>
#include <wolfssl/wolfcrypt/wc_encrypt.h>
#include <wolfssl/wolfcrypt/types.h>
/* <wolfssl/internal.h> is required because the CryptoCB TLS 1.3 key-zeroing
 * tests below inspect session state (ssl->keys.*_write_key,
 * ssl->encrypt.aes->devCtx) to verify that the TLS-layer staging buffers are
 * zeroed after a CryptoCB-driven AES-GCM key offload.  The tests live here
 * rather than in test_tls13.c because they exercise a CryptoCB-AES
 * interaction and share the existing AES test harness. */
#include <wolfssl/internal.h>
#include <tests/api/api.h>
#include <tests/api/test_aes.h>
#include <tests/utils.h>

#if defined(HAVE_SELFTEST) || (defined(HAVE_FIPS_VERSION) && \
    (HAVE_FIPS_VERSION <= 2))
    #define GCM_NONCE_MAX_SZ    16
    #define CCM_NONCE_MAX_SZ    13
#endif

/*******************************************************************************
 * AES
 ******************************************************************************/

#ifndef NO_AES
static int test_wc_AesSetKey_BadArgs(Aes* aes, byte* key, word32 keyLen,
    byte* iv)
{
    EXPECT_DECLS;

    ExpectIntEQ(wc_AesSetKey(NULL, NULL, keyLen, iv, AES_ENCRYPTION),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesSetKey(NULL, key , keyLen, iv, AES_ENCRYPTION),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesSetKey(aes , key , 48    , iv, AES_ENCRYPTION),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    return EXPECT_RESULT();
}

static int test_wc_AesSetKey_WithKey(Aes* aes, byte* key, word32 keyLen,
    byte* iv, int ret)
{
    EXPECT_DECLS;

    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, iv, AES_ENCRYPTION), ret);
    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, NULL, AES_DECRYPTION), ret);

    return EXPECT_RESULT();
}
#endif

/*
 * Testing function for wc_AesSetKey().
 */
int test_wc_AesSetKey(void)
{
    EXPECT_DECLS;
#ifndef NO_AES
    Aes  aes;
    byte key16[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    byte key24[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37
    };
    byte key32[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    byte badKey16[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65
    };
    byte iv[] = "1234567890abcdef";
    byte* key;
    word32 keyLen;

#if defined(WOLFSSL_AES_128)
    key = key16;
    keyLen = (word32)sizeof(key16) / sizeof(byte);
#elif defined(WOLFSSL_AES_192)
    key = key24;
    keyLen = (word32)sizeof(key24) / sizeof(byte);
#else
    key = key32;
    keyLen = (word32)sizeof(key32) / sizeof(byte);
#endif

    XMEMSET(&aes, 0, sizeof(Aes));

    ExpectIntEQ(wc_AesInit(NULL, NULL, INVALID_DEVID),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);

    EXPECT_TEST(test_wc_AesSetKey_BadArgs(&aes, key, keyLen, iv));

#ifdef WOLFSSL_AES_128
    EXPECT_TEST(test_wc_AesSetKey_WithKey(&aes, key16,
        (word32)sizeof(key16) / sizeof(byte), iv, 0));
#else
    EXPECT_TEST(test_wc_AesSetKey_WithKey(&aes, key16,
        (word32)sizeof(key16) / sizeof(byte), iv, BAD_FUNC_ARG));
#endif
#ifdef WOLFSSL_AES_192
    EXPECT_TEST(test_wc_AesSetKey_WithKey(&aes, key24,
        (word32)sizeof(key24) / sizeof(byte), iv, 0));
#else
    EXPECT_TEST(test_wc_AesSetKey_WithKey(&aes, key24,
        (word32)sizeof(key24) / sizeof(byte), iv, BAD_FUNC_ARG));
#endif
#ifdef WOLFSSL_AES_256
    EXPECT_TEST(test_wc_AesSetKey_WithKey(&aes, key32,
        (word32)sizeof(key32) / sizeof(byte), iv, 0));
#else
    EXPECT_TEST(test_wc_AesSetKey_WithKey(&aes, key32,
        (word32)sizeof(key32) / sizeof(byte), iv, BAD_FUNC_ARG));
#endif

    ExpectIntEQ(wc_AesSetKey(&aes, badKey16,
        (word32)sizeof(badKey16) / sizeof(byte), iv, AES_ENCRYPTION),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    wc_AesFree(&aes);
#endif
    return EXPECT_RESULT();
} /* END test_wc_AesSetKey */

/*
 * Testing function for wc_AesSetIV
 */
int test_wc_AesSetIV(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES)
    Aes     aes;
#if defined(WOLFSSL_AES_128)
    byte    key16[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
#endif
    byte    iv1[]    = "1234567890abcdef";
    byte    iv2[]    = "0987654321fedcba";

    ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);

#if defined(WOLFSSL_AES_128)
    ExpectIntEQ(wc_AesSetKey(&aes, key16, (word32) sizeof(key16) / sizeof(byte),
        iv1, AES_ENCRYPTION), 0);
#endif
    ExpectIntEQ(wc_AesSetIV(&aes, iv2), 0);

    ExpectIntEQ(wc_AesSetIV(NULL, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesSetIV(NULL, iv1), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesSetIV(&aes, NULL), 0);

    wc_AesFree(&aes);
#endif
    return EXPECT_RESULT();
} /* test_wc_AesSetIV */


/*******************************************************************************
 * AES Direct
 ******************************************************************************/

#if !defined(NO_AES) && defined(WOLFSSL_AES_DIRECT) && \
    (!defined(HAVE_FIPS) || !defined(HAVE_FIPS_VERSION) || \
        (HAVE_FIPS_VERSION > 6)) && !defined(HAVE_SELFTEST)
static int test_wc_AesEncryptDecryptDirect_WithKey(Aes* aes, byte* key,
    word32 keyLen, byte* expected)
{
    EXPECT_DECLS;
    byte plain[WC_AES_BLOCK_SIZE];
    byte cipher[WC_AES_BLOCK_SIZE];
#ifdef HAVE_AES_DECRYPT
    byte decrypted[WC_AES_BLOCK_SIZE];
#endif

    XMEMSET(plain, 0, WC_AES_BLOCK_SIZE);

    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, NULL, AES_ENCRYPTION), 0);

    ExpectIntEQ(wc_AesEncryptDirect(NULL, NULL, NULL),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    ExpectIntEQ(wc_AesEncryptDirect(aes, cipher, plain), 0);
    ExpectBufEQ(cipher, expected, WC_AES_BLOCK_SIZE);

#ifdef HAVE_AES_DECRYPT
    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, NULL, AES_DECRYPTION), 0);
    ExpectIntEQ(wc_AesDecryptDirect(NULL, NULL, NULL),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesDecryptDirect(aes, decrypted, cipher), 0);
    ExpectBufEQ(decrypted, plain, WC_AES_BLOCK_SIZE);
#endif

    return EXPECT_RESULT();
}
#endif

int test_wc_AesEncryptDecryptDirect(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(WOLFSSL_AES_DIRECT) && \
    (!defined(HAVE_FIPS) || !defined(HAVE_FIPS_VERSION) || \
        (HAVE_FIPS_VERSION > 6)) && !defined(HAVE_SELFTEST)
    Aes aes;
#if defined(WOLFSSL_AES_128)
    byte key16[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    byte expected16[WC_AES_BLOCK_SIZE] = {
        0x0b, 0x9b, 0x15, 0xda, 0x4b, 0x44, 0xa0, 0xf5,
        0x15, 0x1d, 0xcf, 0xc4, 0xc0, 0x1f, 0x35, 0xd5,
    };
#endif
#if defined(WOLFSSL_AES_192)
    byte key24[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    byte expected24[WC_AES_BLOCK_SIZE] = {
        0xbe, 0x55, 0x02, 0x05, 0xfc, 0x91, 0xe8, 0x9c,
        0x9b, 0x9c, 0xc4, 0x70, 0x93, 0xb9, 0x0a, 0x08,
    };
#endif
#if defined(WOLFSSL_AES_256)
    byte key32[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    byte expected32[WC_AES_BLOCK_SIZE] = {
        0x7d, 0xbd, 0x88, 0x27, 0x2f, 0xb2, 0x59, 0x37,
        0x69, 0x2a, 0x3b, 0x81, 0x00, 0x47, 0x41, 0x75,
    };
#endif

    XMEMSET(&aes, 0, sizeof(Aes));
    ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);

#ifdef WOLFSSL_AES_128
    EXPECT_TEST(test_wc_AesEncryptDecryptDirect_WithKey(&aes, key16,
        (word32)sizeof(key16) / sizeof(byte), expected16));
#endif
#ifdef WOLFSSL_AES_192
    EXPECT_TEST(test_wc_AesEncryptDecryptDirect_WithKey(&aes, key24,
        (word32)sizeof(key24) / sizeof(byte), expected24));
#endif
#ifdef WOLFSSL_AES_256
    EXPECT_TEST(test_wc_AesEncryptDecryptDirect_WithKey(&aes, key32,
        (word32)sizeof(key32) / sizeof(byte), expected32));
#endif

    wc_AesFree(&aes);
#endif
    return EXPECT_RESULT();
}

/*******************************************************************************
 * AES-ECB
 ******************************************************************************/

#if !defined(NO_AES) && defined(HAVE_AES_ECB)
/* Assembly code doing 8 iterations at a time. */
#define ECB_LEN     (15 * WC_AES_BLOCK_SIZE)

static int test_wc_AesEcbEncryptDecrypt_BadArgs(Aes* aes, byte* key,
    word32 keyLen)
{
    EXPECT_DECLS;
    byte plain[WC_AES_BLOCK_SIZE];
    byte cipher[WC_AES_BLOCK_SIZE];
    byte decrypted[WC_AES_BLOCK_SIZE];

    XMEMSET(plain, 0, WC_AES_BLOCK_SIZE);
    XMEMSET(cipher, 0, WC_AES_BLOCK_SIZE);

    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, NULL, AES_DECRYPTION), 0);
    ExpectIntEQ(wc_AesEcbEncrypt(NULL, NULL, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesEcbEncrypt(aes, NULL, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesEcbEncrypt(NULL, cipher, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesEcbEncrypt(NULL, NULL, plain, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesEcbEncrypt(aes, cipher, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesEcbEncrypt(aes, NULL, plain, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesEcbEncrypt(NULL, cipher, plain, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, NULL, AES_DECRYPTION), 0);
    ExpectIntEQ(wc_AesEcbDecrypt(NULL, NULL, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesEcbDecrypt(aes, NULL, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesEcbDecrypt(NULL, decrypted, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesEcbDecrypt(NULL, NULL, cipher, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesEcbDecrypt(aes, decrypted, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesEcbDecrypt(aes, NULL, cipher, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesEcbDecrypt(NULL, decrypted, cipher, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    return EXPECT_RESULT();
}

static int test_wc_AesEcbEncryptDecrypt_WithKey(Aes* aes, byte* key,
    word32 keyLen, byte* expected)
{
    EXPECT_DECLS;
    WC_DECLARE_VAR(plain, byte, ECB_LEN, NULL);
    WC_DECLARE_VAR(cipher, byte, ECB_LEN, NULL);
    WC_DECLARE_VAR(decrypted, byte, ECB_LEN, NULL);

    WC_ALLOC_VAR(plain, byte, ECB_LEN, NULL);
    WC_ALLOC_VAR(cipher, byte, ECB_LEN, NULL);
    WC_ALLOC_VAR(decrypted, byte, ECB_LEN, NULL);

#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC
    ExpectNotNull(plain);
    ExpectNotNull(cipher);
    ExpectNotNull(decrypted);
#endif

    XMEMSET(plain, 0, ECB_LEN);

    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, NULL, AES_ENCRYPTION), 0);
    ExpectIntEQ(wc_AesEcbEncrypt(aes, cipher, plain, WC_AES_BLOCK_SIZE), 0);
    ExpectBufEQ(cipher, expected, WC_AES_BLOCK_SIZE);

#ifdef HAVE_AES_DECRYPT
    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, NULL, AES_DECRYPTION), 0);
    ExpectIntEQ(wc_AesEcbDecrypt(aes, decrypted, cipher, WC_AES_BLOCK_SIZE),
        0);
    ExpectBufEQ(decrypted, plain, WC_AES_BLOCK_SIZE);
#endif

    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, NULL, AES_ENCRYPTION), 0);
    ExpectIntEQ(wc_AesEcbEncrypt(aes, cipher, plain, 32), 0);
    ExpectBufEQ(cipher + WC_AES_BLOCK_SIZE, cipher, WC_AES_BLOCK_SIZE);
    ExpectBufEQ(cipher, expected, WC_AES_BLOCK_SIZE);
#ifdef HAVE_AES_DECRYPT
    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, NULL, AES_DECRYPTION), 0);
    ExpectIntEQ(wc_AesEcbDecrypt(aes, decrypted, cipher, 32), 0);
    ExpectBufEQ(decrypted, plain, 32);
#endif

    WC_FREE_VAR(plain, NULL);
    WC_FREE_VAR(cipher, NULL);
    WC_FREE_VAR(decrypted, NULL);
    return EXPECT_RESULT();
}

static int test_wc_AesEcbEncryptDecrypt_MultiBlocks(Aes* aes, byte* key,
    word32 keyLen, byte* expected)
{
    EXPECT_DECLS;
    int sz;
    int cnt;
    WC_DECLARE_VAR(plain, byte, ECB_LEN, NULL);
    WC_DECLARE_VAR(cipher, byte, ECB_LEN, NULL);
    WC_DECLARE_VAR(decrypted, byte, ECB_LEN, NULL);

    WC_ALLOC_VAR(plain, byte, ECB_LEN, NULL);
    WC_ALLOC_VAR(cipher, byte, ECB_LEN, NULL);
    WC_ALLOC_VAR(decrypted, byte, ECB_LEN, NULL);

#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC
    ExpectNotNull(plain);
    ExpectNotNull(cipher);
    ExpectNotNull(decrypted);
#endif

    XMEMSET(plain, 0, ECB_LEN);

    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, NULL, AES_ENCRYPTION), 0);
    /* Test multiple blocks. */
    for (sz = WC_AES_BLOCK_SIZE; sz <= ECB_LEN; sz += WC_AES_BLOCK_SIZE) {
        XMEMSET(cipher, 0x00, ECB_LEN);
        for (cnt = 0; cnt + sz <= ECB_LEN; cnt += sz) {
            ExpectIntEQ(wc_AesEcbEncrypt(aes, cipher + cnt, plain + cnt, sz),
                0);
        }
        if (cnt < ECB_LEN) {
            ExpectIntEQ(wc_AesEcbEncrypt(aes, cipher + cnt, plain + cnt,
                ECB_LEN - cnt), 0);
        }
        for (cnt = 0; cnt < ECB_LEN; cnt += WC_AES_BLOCK_SIZE) {
            ExpectBufEQ(cipher + cnt, expected, WC_AES_BLOCK_SIZE);
        }
    }
#ifdef HAVE_AES_DECRYPT
    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, NULL, AES_DECRYPTION), 0);
    for (sz = WC_AES_BLOCK_SIZE; sz <= ECB_LEN; sz += WC_AES_BLOCK_SIZE) {
        XMEMSET(decrypted, 0xff, ECB_LEN);
        for (cnt = 0; cnt + sz <= ECB_LEN; cnt += sz) {
            ExpectIntEQ(wc_AesEcbDecrypt(aes, decrypted + cnt, cipher + cnt,
                sz), 0);
        }
        if (cnt < ECB_LEN) {
            ExpectIntEQ(wc_AesEcbDecrypt(aes, decrypted + cnt, cipher + cnt,
                ECB_LEN - cnt), 0);
        }
        for (cnt = 0; cnt < ECB_LEN; cnt += WC_AES_BLOCK_SIZE) {
            ExpectBufEQ(decrypted + cnt, plain, WC_AES_BLOCK_SIZE);
        }
    }
#endif

    WC_FREE_VAR(plain, NULL);
    WC_FREE_VAR(cipher, NULL);
    WC_FREE_VAR(decrypted, NULL);
    return EXPECT_RESULT();
}

static int test_wc_AesEcbEncryptDecrypt_SameBuffer(Aes* aes, byte* key,
    word32 keyLen, byte* expected)
{
    EXPECT_DECLS;
    int cnt;
    WC_DECLARE_VAR(plain, byte, ECB_LEN, NULL);
    WC_DECLARE_VAR(cipher, byte, ECB_LEN, NULL);

    WC_ALLOC_VAR(plain, byte, ECB_LEN, NULL);
    WC_ALLOC_VAR(cipher, byte, ECB_LEN, NULL);

#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC
    ExpectNotNull(plain);
    ExpectNotNull(cipher);
#endif

    XMEMSET(plain, 0, ECB_LEN);

    /* Testing using same buffer for input and output. */
    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, NULL, AES_ENCRYPTION), 0);
    XMEMCPY(cipher, plain, ECB_LEN);
    ExpectIntEQ(wc_AesEcbEncrypt(aes, cipher, cipher, ECB_LEN), 0);
    for (cnt = 0; cnt < ECB_LEN; cnt += WC_AES_BLOCK_SIZE) {
        ExpectBufEQ(cipher + cnt, expected, WC_AES_BLOCK_SIZE);
    }
#ifdef HAVE_AES_DECRYPT
    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen,
        NULL, AES_DECRYPTION), 0);
    ExpectIntEQ(wc_AesEcbDecrypt(aes, cipher, cipher, ECB_LEN), 0);
    for (cnt = 0; cnt < ECB_LEN; cnt += WC_AES_BLOCK_SIZE) {
        ExpectBufEQ(cipher + cnt, plain, WC_AES_BLOCK_SIZE);
    }
#endif

    WC_FREE_VAR(plain, NULL);
    WC_FREE_VAR(cipher, NULL);
    return EXPECT_RESULT();
}
#endif

int test_wc_AesEcbEncryptDecrypt(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(HAVE_AES_ECB)
    Aes aes;
#if defined(WOLFSSL_AES_128)
    byte key16[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    byte expected16[WC_AES_BLOCK_SIZE] = {
        0x0b, 0x9b, 0x15, 0xda, 0x4b, 0x44, 0xa0, 0xf5,
        0x15, 0x1d, 0xcf, 0xc4, 0xc0, 0x1f, 0x35, 0xd5,
    };
#endif
#if defined(WOLFSSL_AES_192)
    byte key24[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    byte expected24[WC_AES_BLOCK_SIZE] = {
        0xbe, 0x55, 0x02, 0x05, 0xfc, 0x91, 0xe8, 0x9c,
        0x9b, 0x9c, 0xc4, 0x70, 0x93, 0xb9, 0x0a, 0x08,
    };
#endif
#if defined(WOLFSSL_AES_256)
    byte key32[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    byte expected32[WC_AES_BLOCK_SIZE] = {
        0x7d, 0xbd, 0x88, 0x27, 0x2f, 0xb2, 0x59, 0x37,
        0x69, 0x2a, 0x3b, 0x81, 0x00, 0x47, 0x41, 0x75,
    };
#endif
    byte* key;
    word32 keyLen;
    byte* expected;

#if defined(WOLFSSL_AES_128)
    key = key16;
    keyLen = (word32)sizeof(key16) / sizeof(byte);
    expected = expected16;
#elif defined(WOLFSSL_AES_192)
    key = key24;
    keyLen = (word32)sizeof(key24) / sizeof(byte);
    expected = expected24;
#else
    key = key32;
    keyLen = (word32)sizeof(key32) / sizeof(byte);
    expected = expected32;
#endif

    XMEMSET(&aes, 0, sizeof(Aes));
    ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);

    EXPECT_TEST(test_wc_AesEcbEncryptDecrypt_BadArgs(&aes, key, keyLen));

#if defined(WOLFSSL_AES_128)
    EXPECT_TEST(test_wc_AesEcbEncryptDecrypt_WithKey(&aes, key16,
        (word32)sizeof(key16) / sizeof(byte), expected16));
#endif
#if defined(WOLFSSL_AES_192)
    EXPECT_TEST(test_wc_AesEcbEncryptDecrypt_WithKey(&aes, key24,
        (word32)sizeof(key24) / sizeof(byte), expected24));
#endif
#if defined(WOLFSSL_AES_256)
    EXPECT_TEST(test_wc_AesEcbEncryptDecrypt_WithKey(&aes, key32,
        (word32)sizeof(key32) / sizeof(byte), expected32));
#endif

    EXPECT_TEST(test_wc_AesEcbEncryptDecrypt_MultiBlocks(&aes, key, keyLen,
        expected));
    EXPECT_TEST(test_wc_AesEcbEncryptDecrypt_SameBuffer(&aes, key, keyLen,
        expected));

    wc_AesFree(&aes);
#endif
    return EXPECT_RESULT();
}

/*******************************************************************************
 * AES-CBC
 ******************************************************************************/

#if !defined(NO_AES) && defined(HAVE_AES_CBC)
/* Assembly code doing 8 iterations at a time. */
#define CBC_LEN     (9 * WC_AES_BLOCK_SIZE)

static int test_wc_AesCbcEncryptDecrypt_BadArgs(Aes* aes, byte* key,
    word32 keyLen, byte* iv)
{
    EXPECT_DECLS;
    byte    plain[WC_AES_BLOCK_SIZE];
    byte    cipher[WC_AES_BLOCK_SIZE];
    byte    decrypted[WC_AES_BLOCK_SIZE];

    XMEMSET(plain, 0, WC_AES_BLOCK_SIZE);
    XMEMSET(cipher, 0, WC_AES_BLOCK_SIZE);
    XMEMSET(decrypted, 0, WC_AES_BLOCK_SIZE);

    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, iv, AES_ENCRYPTION), 0);
    ExpectIntEQ(wc_AesCbcEncrypt(NULL, NULL, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCbcEncrypt(aes, NULL, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCbcEncrypt(NULL, cipher, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCbcEncrypt(NULL, NULL, plain, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCbcEncrypt(aes, cipher, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCbcEncrypt(aes, NULL, plain, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCbcEncrypt(NULL, cipher, plain, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, iv, AES_DECRYPTION), 0);
    ExpectIntEQ(wc_AesCbcDecrypt(NULL, NULL, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCbcDecrypt(aes, NULL, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCbcDecrypt(NULL, decrypted, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCbcDecrypt(NULL, NULL, cipher, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCbcDecrypt(aes, decrypted, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCbcDecrypt(aes, NULL, cipher, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCbcDecrypt(NULL, decrypted, cipher, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    ExpectIntEQ(wc_AesCbcDecryptWithKey(NULL, NULL, 0, NULL, keyLen, NULL),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCbcDecryptWithKey(decrypted, NULL, 0, NULL, keyLen, NULL),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCbcDecryptWithKey(NULL, cipher, 0, NULL, keyLen, NULL),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCbcDecryptWithKey(NULL, NULL, 0, key, keyLen, NULL),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCbcDecryptWithKey(NULL, NULL, 0, NULL, keyLen, iv),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCbcDecryptWithKey(decrypted, cipher,
        WC_AES_BLOCK_SIZE * 2, key, keyLen, NULL),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCbcDecryptWithKey(decrypted, cipher,
        WC_AES_BLOCK_SIZE * 2, NULL, keyLen, iv),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCbcDecryptWithKey(decrypted, NULL,
        WC_AES_BLOCK_SIZE * 2, key, keyLen, iv),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCbcDecryptWithKey(NULL, cipher,
        WC_AES_BLOCK_SIZE * 2, key, keyLen, iv),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    return EXPECT_RESULT();
}

static int test_wc_AesCbcEncryptDecrypt_WithKey(Aes* aes, byte* key,
    word32 keyLen, byte* iv, byte* vector, byte* vector_enc, word32 vector_len)
{
    EXPECT_DECLS;
    byte    plain[WC_AES_BLOCK_SIZE * 2];
    byte    cipher[WC_AES_BLOCK_SIZE * 2];
    byte    decrypted[WC_AES_BLOCK_SIZE * 2];

    XMEMSET(plain, 0, WC_AES_BLOCK_SIZE * 2);
    XMEMSET(cipher, 0, WC_AES_BLOCK_SIZE * 2);
    XMEMSET(decrypted, 0, WC_AES_BLOCK_SIZE * 2);

    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, iv, AES_ENCRYPTION), 0);
#if defined(HAVE_FIPS) && defined(HAVE_FIPS_VERSION) && \
    (HAVE_FIPS_VERSION == 2) && defined(WOLFSSL_AESNI)
    fprintf(stderr, "Zero length inputs not supported with AESNI in FIPS "
                    "mode (v2), skip test");
#else
    /* Test passing in size of 0  */
    XMEMSET(cipher, 0x00, WC_AES_BLOCK_SIZE * 2);
    ExpectIntEQ(wc_AesCbcEncrypt(aes, cipher, vector, 0), 0);
    /* Check enc was not modified */
    {
        int i;
        for (i = 0; i < (int)WC_AES_BLOCK_SIZE * 2; i++)
            ExpectIntEQ(cipher[i], 0x00);
    }
#endif
    ExpectIntEQ(wc_AesCbcEncrypt(aes, cipher, vector, vector_len),
        0);
    ExpectBufEQ(cipher, vector_enc, vector_len);
#ifdef WOLFSSL_AES_CBC_LENGTH_CHECKS
    ExpectIntEQ(wc_AesCbcEncrypt(aes, cipher, vector, vector_len - 1),
        WC_NO_ERR_TRACE(BAD_LENGTH_E));
#endif

#ifdef HAVE_AES_DECRYPT
    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, iv, AES_DECRYPTION), 0);
    ExpectIntEQ(wc_AesCbcDecrypt(aes, decrypted, cipher,
        WC_AES_BLOCK_SIZE * 2), 0);
    ExpectBufEQ(decrypted, vector, vector_len);
#ifdef WOLFSSL_AES_CBC_LENGTH_CHECKS
    ExpectIntEQ(wc_AesCbcDecrypt(aes, decrypted, cipher,
        WC_AES_BLOCK_SIZE * 2 - 1), WC_NO_ERR_TRACE(BAD_LENGTH_E));
#else
    ExpectIntEQ(wc_AesCbcDecrypt(aes, decrypted, cipher,
        WC_AES_BLOCK_SIZE * 2 - 1), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif

    ExpectIntEQ(wc_AesCbcDecryptWithKey(decrypted, cipher,
        WC_AES_BLOCK_SIZE * 2, key, keyLen, iv), 0);
    ExpectBufEQ(decrypted, vector, vector_len);

    /* Test passing in size of 0  */
    XMEMSET(decrypted, 0, WC_AES_BLOCK_SIZE * 2);
    ExpectIntEQ(wc_AesCbcDecrypt(aes, decrypted, cipher, 0), 0);
    /* Check dec was not modified */
    {
        int i;
        for (i = 0; i < (int)WC_AES_BLOCK_SIZE * 2; i++)
            ExpectIntEQ(decrypted[i], 0);
    }
#endif

    return EXPECT_RESULT();
}

static int test_wc_AesCbcEncryptDecrypt_MultiBlocks(Aes* aes, byte* key,
    word32 keyLen, byte* iv, byte* expected)
{
    EXPECT_DECLS;
#ifdef WOLFSSL_KCAPI
    (void)aes;
    (void)key;
    (void)keyLen;
    (void)iv;
    (void)expected;
#else /* !WOLFSSL_KCAPI */
    int sz;
    int cnt;
    WC_DECLARE_VAR(plain, byte, CBC_LEN, NULL);
    WC_DECLARE_VAR(cipher, byte, CBC_LEN, NULL);
    WC_DECLARE_VAR(decrypted, byte, CBC_LEN, NULL);

    WC_ALLOC_VAR(plain, byte, CBC_LEN, NULL);
    WC_ALLOC_VAR(cipher, byte, CBC_LEN, NULL);
    WC_ALLOC_VAR(decrypted, byte, CBC_LEN, NULL);

#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC
    ExpectNotNull(plain);
    ExpectNotNull(cipher);
    ExpectNotNull(decrypted);
#endif


    XMEMSET(plain, 0, CBC_LEN);
    XMEMSET(cipher, 0, CBC_LEN);
    XMEMSET(decrypted, 0, CBC_LEN);

    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, NULL, AES_ENCRYPTION), 0);
    /* Test multiple blocks. */
    for (sz = WC_AES_BLOCK_SIZE; sz <= CBC_LEN; sz += WC_AES_BLOCK_SIZE) {
        XMEMSET(cipher, 0x00, CBC_LEN);
        ExpectIntEQ(wc_AesSetIV(aes, iv), 0);
        for (cnt = 0; cnt + sz <= CBC_LEN; cnt += sz) {
            ExpectIntEQ(wc_AesCbcEncrypt(aes, cipher + cnt, plain + cnt, sz),
                0);
        }
        if (cnt < CBC_LEN) {
            ExpectIntEQ(wc_AesCbcEncrypt(aes, cipher + cnt, plain + cnt,
                CBC_LEN - cnt), 0);
        }
        ExpectBufEQ(cipher, expected, CBC_LEN);
    }
#ifdef HAVE_AES_DECRYPT
    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, NULL, AES_DECRYPTION), 0);
    for (sz = WC_AES_BLOCK_SIZE; sz <= CBC_LEN; sz += WC_AES_BLOCK_SIZE) {
        XMEMSET(decrypted, 0xff, CBC_LEN);
        ExpectIntEQ(wc_AesSetIV(aes, iv), 0);
        for (cnt = 0; cnt + sz <= CBC_LEN; cnt += sz) {
            ExpectIntEQ(wc_AesCbcDecrypt(aes, decrypted + cnt, cipher + cnt,
                sz), 0);
        }
        if (cnt < CBC_LEN) {
            ExpectIntEQ(wc_AesCbcDecrypt(aes, decrypted + cnt, cipher + cnt,
                CBC_LEN - cnt), 0);
        }
        ExpectBufEQ(decrypted, plain, CBC_LEN);
    }
#endif

    WC_FREE_VAR(plain, NULL);
    WC_FREE_VAR(cipher, NULL);
    WC_FREE_VAR(decrypted, NULL);
#endif /* !WOLFSSL_KCAPI */
    return EXPECT_RESULT();
}

static int test_wc_AesCbcEncryptDecrypt_SameBuffer(Aes* aes, byte* key,
    word32 keyLen, byte* iv, byte* expected)
{
    EXPECT_DECLS;
    WC_DECLARE_VAR(plain, byte, CBC_LEN, NULL);
    WC_DECLARE_VAR(cipher, byte, CBC_LEN, NULL);

    WC_ALLOC_VAR(plain, byte, CBC_LEN, NULL);
    WC_ALLOC_VAR(cipher, byte, CBC_LEN, NULL);

#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC
    ExpectNotNull(plain);
    ExpectNotNull(cipher);
#endif

    XMEMSET(plain, 0, CBC_LEN);

    /* Testing using same buffer for input and output. */
    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, iv, AES_ENCRYPTION), 0);
    XMEMCPY(cipher, plain, CBC_LEN);
    ExpectIntEQ(wc_AesCbcEncrypt(aes, cipher, cipher, CBC_LEN), 0);
    ExpectBufEQ(cipher, expected, CBC_LEN);
#ifdef HAVE_AES_DECRYPT
    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, iv, AES_DECRYPTION), 0);
    ExpectIntEQ(wc_AesCbcDecrypt(aes, cipher, cipher, CBC_LEN), 0);
    ExpectBufEQ(cipher, plain, CBC_LEN);
#endif

    WC_FREE_VAR(plain, NULL);
    WC_FREE_VAR(cipher, NULL);
    return EXPECT_RESULT();
}
#endif

/*
 * test function for wc_AesCbcEncrypt(), wc_AesCbcDecrypt(),
 * and wc_AesCbcDecryptWithKey()
 */
int test_wc_AesCbcEncryptDecrypt(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(HAVE_AES_CBC)
    Aes  aes;
    byte vector[] = { /* Now is the time for all good men w/o trailing 0 */
        0x4e, 0x6f, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74,
        0x68, 0x65, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20,
        0x66, 0x6f, 0x72, 0x20, 0x61, 0x6c, 0x6c, 0x20,
        0x67, 0x6f, 0x6f, 0x64, 0x20, 0x6d, 0x65, 0x6e
    };
#if defined(WOLFSSL_AES_128)
    byte key16[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    byte vector_enc16[] = {
        0x26, 0x5b, 0x55, 0xf1, 0xcc, 0x77, 0xc0, 0x9a,
        0x60, 0x77, 0x99, 0x1d, 0x52, 0xf1, 0xc0, 0x3a,
        0x0f, 0x16, 0xae, 0x62, 0xf1, 0x71, 0xf5, 0x95,
        0xb6, 0x74, 0x98, 0x2a, 0x6b, 0x7c, 0x7c, 0x39
    };
#endif
#if defined(WOLFSSL_AES_192)
    byte key24[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    byte vector_enc24[] = {
        0xdb, 0x96, 0xfa, 0x55, 0x90, 0x1e, 0x0c, 0x4f,
        0xe4, 0x0f, 0xde, 0x16, 0x33, 0x44, 0xca, 0xa5,
        0xe6, 0xa8, 0xbd, 0xd4, 0x88, 0xe5, 0x2f, 0x88,
        0xfd, 0x61, 0x0f, 0x88, 0x6d, 0xf1, 0xf6, 0xa5
    };
#endif
#if defined(WOLFSSL_AES_256)
    byte key32[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    byte vector_enc32[] = {
        0xd7, 0xd6, 0x04, 0x5b, 0x4d, 0xc4, 0x90, 0xdf,
        0x4a, 0x82, 0xed, 0x61, 0x26, 0x4e, 0x23, 0xb3,
        0xe4, 0xb5, 0x85, 0x30, 0x29, 0x4c, 0x9d, 0xcf,
        0x73, 0xc9, 0x46, 0xd1, 0xaa, 0xc8, 0xcb, 0x62,
    };
#endif
#ifdef WOLFSSL_AES_128
    byte expected16[CBC_LEN] = {
        0x46, 0x1a, 0x5f, 0xfd, 0x9d, 0xf7, 0x91, 0x71,
        0x35, 0x8e, 0x9e, 0x01, 0x77, 0xd8, 0x4e, 0xaa,
        0x34, 0x28, 0xba, 0x95, 0x76, 0xa5, 0x60, 0xeb,
        0xbf, 0x6e, 0x89, 0xf5, 0x9a, 0x03, 0x7a, 0x7e,
        0x07, 0xc5, 0xec, 0x60, 0xe1, 0x9b, 0x7a, 0x35,
        0x9c, 0x29, 0x74, 0x6c, 0x2b, 0x1c, 0xff, 0x1b,
        0xa0, 0xd5, 0xf3, 0x5b, 0x23, 0x86, 0x31, 0xbe,
        0x1a, 0x20, 0x2c, 0x57, 0xf4, 0x9e, 0x81, 0x67,
        0xb8, 0xf2, 0x60, 0x28, 0x36, 0x50, 0x6c, 0x06,
        0x69, 0xa8, 0xec, 0x36, 0x46, 0x2a, 0xc9, 0x12,
        0x54, 0xc8, 0xeb, 0x73, 0x8d, 0xe8, 0x0f, 0x0c,
        0xd6, 0x53, 0x8b, 0xd2, 0x24, 0xdb, 0x08, 0xf7,
        0x1e, 0x2e, 0x34, 0x8d, 0x27, 0x6d, 0x77, 0x8f,
        0x00, 0xa5, 0x8e, 0xc3, 0x0d, 0x07, 0x61, 0xd4,
        0xe0, 0x54, 0x9b, 0xfe, 0x71, 0x4f, 0x25, 0x75,
        0x9f, 0x7a, 0x2c, 0xa4, 0x0e, 0x47, 0x1f, 0xef,
        0x85, 0x19, 0x36, 0x65, 0x3b, 0x28, 0x20, 0x3a,
        0xf9, 0x7f, 0x13, 0xe8, 0x24, 0xd7, 0x64, 0x27,
    };
#elif defined(WOLFSSL_AES_192)
    byte expected24[CBC_LEN] = {
        0x7b, 0xde, 0x53, 0xac, 0x88, 0x24, 0xe6, 0xde,
        0x68, 0xd4, 0x64, 0x18, 0x20, 0x96, 0x62, 0x68,
        0xd0, 0x04, 0x81, 0x50, 0x73, 0xe7, 0x6d, 0x8e,
        0x14, 0x44, 0x87, 0xad, 0x6d, 0x44, 0xf9, 0xc3,
        0xe9, 0x82, 0x2e, 0x2d, 0x17, 0x16, 0x43, 0xa6,
        0x29, 0xe3, 0x9d, 0x7f, 0x84, 0x2e, 0x9a, 0x14,
        0x69, 0xe9, 0x7b, 0x38, 0xfd, 0xec, 0x71, 0x4a,
        0xf7, 0x0f, 0xbf, 0x6e, 0x4d, 0x46, 0x7e, 0xad,
        0x83, 0xcb, 0xfa, 0x20, 0x25, 0xf8, 0x13, 0xc6,
        0x75, 0xdd, 0x12, 0x1f, 0xed, 0xfa, 0x3a, 0x1c,
        0x01, 0x68, 0x02, 0x12, 0x69, 0x4c, 0xe7, 0x00,
        0xf1, 0x9c, 0x40, 0xed, 0x7d, 0x64, 0x16, 0x1c,
        0x63, 0x07, 0x87, 0x37, 0xb3, 0x5b, 0x59, 0x97,
        0xc9, 0xe4, 0x86, 0xfd, 0xd2, 0xae, 0x5b, 0x59,
        0x5a, 0xe9, 0xf5, 0x0b, 0xa0, 0x87, 0xf4, 0xb5,
        0x65, 0x9c, 0x98, 0x0f, 0xbf, 0x11, 0xa4, 0x7d,
        0x06, 0x80, 0xb5, 0x27, 0x9c, 0xd5, 0x09, 0x7a,
        0xa1, 0x42, 0xbd, 0x87, 0x6b, 0x85, 0x2f, 0x6e,
    };
#else
    byte expected32[CBC_LEN] = {
        0x18, 0x5a, 0x48, 0xfd, 0xb7, 0xd5, 0x35, 0xf3,
        0x3f, 0xb9, 0x14, 0x16, 0xf3, 0x05, 0xf3, 0x71,
        0xea, 0x4e, 0x22, 0xcd, 0x15, 0x3a, 0xcc, 0xba,
        0x3f, 0x5b, 0x85, 0x15, 0xdf, 0x07, 0xf6, 0xa4,
        0xf4, 0x41, 0xe7, 0x08, 0x30, 0x9b, 0x09, 0x2d,
        0xd4, 0x3e, 0x68, 0xea, 0x45, 0x3d, 0x3a, 0xe3,
        0x7c, 0x68, 0x00, 0xda, 0xeb, 0x87, 0xd7, 0x11,
        0x2a, 0x0b, 0x7c, 0x48, 0xe5, 0xef, 0xae, 0x6d,
        0x61, 0x04, 0xa4, 0x16, 0xc7, 0xb6, 0x0f, 0xab,
        0x24, 0x0c, 0x74, 0x0b, 0x4f, 0xfe, 0xfd, 0xd1,
        0x38, 0xae, 0x92, 0x18, 0x57, 0xdd, 0x20, 0x90,
        0x74, 0x0a, 0xdf, 0x7b, 0x06, 0x2d, 0x8a, 0xe8,
        0x43, 0x77, 0x0d, 0x18, 0x25, 0x8b, 0x04, 0x98,
        0xf4, 0x4c, 0x43, 0x19, 0x99, 0x16, 0x5a, 0xac,
        0x7f, 0x52, 0x0f, 0x79, 0xd2, 0x10, 0xa5, 0xf3,
        0x88, 0xf3, 0x79, 0x0a, 0x05, 0x22, 0xb8, 0xb2,
        0xb7, 0xd4, 0x8e, 0x17, 0x80, 0x1b, 0x4d, 0xcb,
        0x99, 0xa7, 0x30, 0x1b, 0xe0, 0xee, 0xd5, 0xd3,
    };
#endif
    byte    iv[]   = "1234567890abcdef";
    byte* key;
    word32 keyLen;
    byte* expected;

#if defined(WOLFSSL_AES_128)
    key = key16;
    keyLen = (word32)sizeof(key16) / sizeof(byte);
    expected = expected16;
#elif defined(WOLFSSL_AES_192)
    key = key24;
    keyLen = (word32)sizeof(key24) / sizeof(byte);
    expected = expected24;
#else
    key = key32;
    keyLen = (word32)sizeof(key32) / sizeof(byte);
    expected = expected32;
#endif

    /* Init stack variables. */
    XMEMSET(&aes, 0, sizeof(Aes));

    ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);

    EXPECT_TEST(test_wc_AesCbcEncryptDecrypt_BadArgs(&aes, key, keyLen, iv));

#ifdef WOLFSSL_AES_128
    EXPECT_TEST(test_wc_AesCbcEncryptDecrypt_WithKey(&aes, key16,
        (word32)sizeof(key16) / sizeof(byte), iv, vector, vector_enc16,
        (word32)sizeof(vector) / sizeof(byte)));
#endif
#ifdef WOLFSSL_AES_192
    EXPECT_TEST(test_wc_AesCbcEncryptDecrypt_WithKey(&aes, key24,
        (word32)sizeof(key24) / sizeof(byte), iv, vector, vector_enc24,
        (word32)sizeof(vector) / sizeof(byte)));
#endif
#ifdef WOLFSSL_AES_256
    EXPECT_TEST(test_wc_AesCbcEncryptDecrypt_WithKey(&aes, key32,
        (word32)sizeof(key32) / sizeof(byte), iv, vector, vector_enc32,
        (word32)sizeof(vector) / sizeof(byte)));
#endif

    EXPECT_TEST(test_wc_AesCbcEncryptDecrypt_MultiBlocks(&aes, key, keyLen, iv,
        expected));
    EXPECT_TEST(test_wc_AesCbcEncryptDecrypt_SameBuffer(&aes, key, keyLen, iv,
        expected));

    wc_AesFree(&aes);
#endif
    return EXPECT_RESULT();
} /* END test_wc_AesCbcEncryptDecrypt */

/*******************************************************************************
 * AES-CBC unaligned buffers
 ******************************************************************************/

/*
 * Verify that wc_AesCbcEncrypt / wc_AesCbcDecrypt produce correct results
 * when the input and output buffers are byte-offset (unaligned).  Tests
 * offsets 1, 2, and 3 to cover all misalignment residues mod 4.
 */
int test_wc_AesCbcEncryptDecrypt_UnalignedBuffers(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_128)
    Aes aes;
    /* NIST SP 800-38A F.2.1 key and IV (AES-128 CBC) */
    static const byte key[AES_128_KEY_SIZE] = {
        0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
        0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
    };
    static const byte iv[AES_IV_SIZE] = {
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
    };
    /* Two AES blocks of plaintext */
    static const byte plain[32] = {
        0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
        0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
        0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
        0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51
    };
    byte ref_ct[sizeof(plain)];
    byte in_buf[sizeof(plain) + 3];
    byte out_buf[sizeof(plain) + 3];
    int off;

    XMEMSET(&aes, 0, sizeof(aes));
    ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);

    /* Reference ciphertext with naturally-aligned buffers */
    ExpectIntEQ(wc_AesSetKey(&aes, key, sizeof(key), iv, AES_ENCRYPTION), 0);
    ExpectIntEQ(wc_AesCbcEncrypt(&aes, ref_ct, plain, sizeof(plain)), 0);

    /* Encrypt with byte offsets 1, 2, 3 on both in and out */
    for (off = 1; off <= 3 && EXPECT_SUCCESS(); off++) {
        XMEMCPY(in_buf + off, plain, sizeof(plain));
        XMEMSET(out_buf, 0, sizeof(out_buf));
        ExpectIntEQ(wc_AesSetKey(&aes, key, sizeof(key), iv, AES_ENCRYPTION), 0);
        ExpectIntEQ(wc_AesCbcEncrypt(&aes, out_buf + off, in_buf + off,
            sizeof(plain)), 0);
        ExpectBufEQ(out_buf + off, ref_ct, sizeof(plain));
    }

#ifdef HAVE_AES_DECRYPT
    /* Decrypt with byte offsets 1, 2, 3 on both in and out */
    for (off = 1; off <= 3 && EXPECT_SUCCESS(); off++) {
        XMEMCPY(in_buf + off, ref_ct, sizeof(plain));
        XMEMSET(out_buf, 0, sizeof(out_buf));
        ExpectIntEQ(wc_AesSetKey(&aes, key, sizeof(key), iv, AES_DECRYPTION), 0);
        ExpectIntEQ(wc_AesCbcDecrypt(&aes, out_buf + off, in_buf + off,
            sizeof(plain)), 0);
        ExpectBufEQ(out_buf + off, plain, sizeof(plain));
    }
#endif

    wc_AesFree(&aes);
#endif
    return EXPECT_RESULT();
} /* END test_wc_AesCbcEncryptDecrypt_UnalignedBuffers */

/*
 * Cross-cipher test: CBC mode is equivalent to block-by-block ECB encryption
 * with XOR chaining.  C[i] = ECB_Encrypt(K, P[i] XOR C[i-1]),  C[-1] = IV.
 *
 * This test verifies that relationship directly: encrypt with CBC, then
 * independently compute the same ciphertext using ECB + XOR, and compare.
 */
int test_wc_AesCbc_CrossCipher(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(HAVE_AES_ECB) && \
    defined(WOLFSSL_AES_128)
    Aes aes;
    /* NIST SP 800-38A F.2.1 (first two plaintext blocks) */
    static const byte key[AES_128_KEY_SIZE] = {
        0x2b,0x7e,0x15,0x16, 0x28,0xae,0xd2,0xa6,
        0xab,0xf7,0x15,0x88, 0x09,0xcf,0x4f,0x3c
    };
    static const byte iv[WC_AES_BLOCK_SIZE] = {
        0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07,
        0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f
    };
    static const byte plain[2 * WC_AES_BLOCK_SIZE] = {
        0x6b,0xc1,0xbe,0xe2, 0x2e,0x40,0x9f,0x96,
        0xe9,0x3d,0x7e,0x11, 0x73,0x93,0x17,0x2a,
        0xae,0x2d,0x8a,0x57, 0x1e,0x03,0xac,0x9c,
        0x9e,0xb7,0x6f,0xac, 0x45,0xaf,0x8e,0x51
    };
    byte cbc_ct[sizeof(plain)];
    byte ecb_ct[sizeof(plain)];
    byte xored[WC_AES_BLOCK_SIZE];
    int  i;

    XMEMSET(&aes, 0, sizeof(aes));
    ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);

    /* CBC ciphertext via the API */
    ExpectIntEQ(wc_AesSetKey(&aes, key, sizeof(key), iv, AES_ENCRYPTION), 0);
    ExpectIntEQ(wc_AesCbcEncrypt(&aes, cbc_ct, plain, sizeof(plain)), 0);

    /* Manually compute CBC via ECB + XOR chaining */
    ExpectIntEQ(wc_AesSetKey(&aes, key, sizeof(key), NULL, AES_ENCRYPTION), 0);

    /* Block 0: xor plaintext with IV, then ECB-encrypt */
    for (i = 0; i < WC_AES_BLOCK_SIZE; i++)
        xored[i] = plain[i] ^ iv[i];
    ExpectIntEQ(wc_AesEcbEncrypt(&aes, ecb_ct, xored, WC_AES_BLOCK_SIZE), 0);

    /* Block 1: xor plaintext with C[0], then ECB-encrypt */
    for (i = 0; i < WC_AES_BLOCK_SIZE; i++)
        xored[i] = plain[WC_AES_BLOCK_SIZE + i] ^ ecb_ct[i];
    ExpectIntEQ(wc_AesEcbEncrypt(&aes, ecb_ct + WC_AES_BLOCK_SIZE, xored,
        WC_AES_BLOCK_SIZE), 0);

    /* CBC ciphertext must equal the manually-chained ECB ciphertext */
    ExpectBufEQ(cbc_ct, ecb_ct, sizeof(plain));

    wc_AesFree(&aes);
#endif
    return EXPECT_RESULT();
} /* END test_wc_AesCbc_CrossCipher */

/*******************************************************************************
 * AES-CFB
 ******************************************************************************/

#if !defined(NO_AES) && defined(WOLFSSL_AES_CFB)
#define CFB_LEN     (5 * WC_AES_BLOCK_SIZE)

static int test_wc_AesCfbEncryptDecrypt_BadArgs(Aes* aes, byte* key,
    word32 keyLen, byte* iv)
{
    EXPECT_DECLS;
    byte plain[WC_AES_BLOCK_SIZE];
    byte cipher[WC_AES_BLOCK_SIZE];
#ifdef HAVE_AES_DECRYPT
    byte decrypted[WC_AES_BLOCK_SIZE];
#endif

    XMEMSET(plain, 0x00, WC_AES_BLOCK_SIZE);
    XMEMSET(cipher, 0x00, WC_AES_BLOCK_SIZE);

    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, NULL, AES_ENCRYPTION), 0);

    ExpectIntEQ(wc_AesSetIV(aes, iv), 0);
    ExpectIntEQ(wc_AesCfbEncrypt(NULL, NULL, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCfbEncrypt(aes, NULL, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCfbEncrypt(NULL, cipher, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCfbEncrypt(NULL, NULL, plain, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCfbEncrypt(aes, cipher, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCfbEncrypt(aes, NULL, plain, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCfbEncrypt(NULL, cipher, plain, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));

#ifdef HAVE_AES_DECRYPT
    ExpectIntEQ(wc_AesSetIV(aes, iv), 0);
    ExpectIntEQ(wc_AesCfbDecrypt(NULL, NULL, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCfbDecrypt(aes, NULL, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCfbDecrypt(NULL, decrypted, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCfbDecrypt(NULL, NULL, cipher, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCfbDecrypt(aes, decrypted, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCfbDecrypt(aes, NULL, cipher, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCfbDecrypt(NULL, decrypted, cipher, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif

    return EXPECT_RESULT();
}

static int test_wc_AesCfbEncryptDecrypt_WithKey(Aes* aes, byte* key,
    word32 keyLen, byte* iv, byte* expected)
{
    EXPECT_DECLS;
    WC_DECLARE_VAR(plain, byte, CFB_LEN, NULL);
    WC_DECLARE_VAR(cipher, byte, CFB_LEN, NULL);
#ifdef HAVE_AES_DECRYPT
    WC_DECLARE_VAR(decrypted, byte, CFB_LEN, NULL);
#endif

    WC_ALLOC_VAR(plain, byte, CFB_LEN, NULL);
    WC_ALLOC_VAR(cipher, byte, CFB_LEN, NULL);
#ifdef HAVE_AES_DECRYPT
    WC_ALLOC_VAR(decrypted, byte, CFB_LEN, NULL);
#endif

#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC
    ExpectNotNull(plain);
    ExpectNotNull(cipher);
#ifdef HAVE_AES_DECRYPT
    ExpectNotNull(decrypted);
#endif
#endif

    XMEMSET(plain, 0xa5, CFB_LEN);

    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, NULL, AES_ENCRYPTION), 0);

    ExpectIntEQ(wc_AesSetIV(aes, iv), 0);
    ExpectIntEQ(wc_AesCfbEncrypt(aes, cipher, plain, WC_AES_BLOCK_SIZE), 0);
    ExpectBufEQ(cipher, expected, WC_AES_BLOCK_SIZE);

#ifdef HAVE_AES_DECRYPT
    ExpectIntEQ(wc_AesSetIV(aes, iv), 0);
    ExpectIntEQ(wc_AesCfbDecrypt(aes, decrypted, cipher, WC_AES_BLOCK_SIZE),
        0);
    ExpectBufEQ(decrypted, plain, WC_AES_BLOCK_SIZE);
#endif

    ExpectIntEQ(wc_AesSetIV(aes, iv), 0);
    ExpectIntEQ(wc_AesCfbEncrypt(aes, cipher, plain, CFB_LEN), 0);
    ExpectBufEQ(cipher, expected, CFB_LEN);
#ifdef HAVE_AES_DECRYPT
    ExpectIntEQ(wc_AesSetIV(aes, iv), 0);
    ExpectIntEQ(wc_AesCfbDecrypt(aes, decrypted, cipher, CFB_LEN), 0);
    ExpectBufEQ(decrypted, plain, CFB_LEN);
#endif

    WC_FREE_VAR(plain, NULL);
    WC_FREE_VAR(cipher, NULL);
#ifdef HAVE_AES_DECRYPT
    WC_FREE_VAR(decrypted, NULL);
#endif
    return EXPECT_RESULT();
}

static int test_wc_AesCfbEncryptDecrypt_Chunking(Aes* aes, byte* key,
    word32 keyLen, byte* iv, byte* expected)
{
    EXPECT_DECLS;
    int sz;
    int cnt;
    WC_DECLARE_VAR(plain, byte, CFB_LEN, NULL);
    WC_DECLARE_VAR(cipher, byte, CFB_LEN, NULL);
#ifdef HAVE_AES_DECRYPT
    WC_DECLARE_VAR(decrypted, byte, CFB_LEN, NULL);
#endif

    WC_ALLOC_VAR(plain, byte, CFB_LEN, NULL);
    WC_ALLOC_VAR(cipher, byte, CFB_LEN, NULL);
#ifdef HAVE_AES_DECRYPT
    WC_ALLOC_VAR(decrypted, byte, CFB_LEN, NULL);
#endif

#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC
    ExpectNotNull(plain);
    ExpectNotNull(cipher);
#ifdef HAVE_AES_DECRYPT
    ExpectNotNull(decrypted);
#endif
#endif

    XMEMSET(plain, 0xa5, CFB_LEN);

    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, NULL, AES_ENCRYPTION), 0);

    for (sz = 1; sz < CFB_LEN; sz++) {
        ExpectIntEQ(wc_AesSetIV(aes, iv), 0);
        XMEMSET(cipher, 0, CFB_LEN);
        for (cnt = 0; cnt + sz <= CFB_LEN; cnt += sz) {
            ExpectIntEQ(wc_AesCfbEncrypt(aes, cipher + cnt, plain + cnt, sz),
                0);
        }
        if (cnt < CFB_LEN) {
            ExpectIntEQ(wc_AesCfbEncrypt(aes, cipher + cnt, plain + cnt,
                CFB_LEN - cnt), 0);
        }
        ExpectBufEQ(cipher, expected, CFB_LEN);
    }
#ifdef HAVE_AES_DECRYPT
    for (sz = 1; sz < CFB_LEN; sz++) {
        ExpectIntEQ(wc_AesSetIV(aes, iv), 0);
        XMEMSET(decrypted, 0xff, CFB_LEN);
        for (cnt = 0; cnt + sz <= CFB_LEN; cnt += sz) {
            ExpectIntEQ(wc_AesCfbDecrypt(aes, decrypted + cnt, cipher + cnt,
                sz), 0);
        }
        if (cnt < CFB_LEN) {
            ExpectIntEQ(wc_AesCfbDecrypt(aes, decrypted + cnt, cipher + cnt,
                CFB_LEN - cnt), 0);
        }
        ExpectBufEQ(decrypted, plain, CFB_LEN);
    }
#endif

    WC_FREE_VAR(plain, NULL);
    WC_FREE_VAR(cipher, NULL);
#ifdef HAVE_AES_DECRYPT
    WC_FREE_VAR(decrypted, NULL);
#endif
    return EXPECT_RESULT();
}

#if (!defined(HAVE_FIPS) || !defined(HAVE_FIPS_VERSION) || \
        (HAVE_FIPS_VERSION > 6)) && !defined(HAVE_SELFTEST)
static int test_wc_AesCfbEncryptDecrypt_SameBuffer(Aes* aes, byte* key,
    word32 keyLen, byte* iv, byte* expected)
{
    EXPECT_DECLS;
    WC_DECLARE_VAR(plain, byte, CFB_LEN, NULL);
    WC_DECLARE_VAR(cipher, byte, CFB_LEN, NULL);

    WC_ALLOC_VAR(plain, byte, CBC_LEN, NULL);
    WC_ALLOC_VAR(cipher, byte, CBC_LEN, NULL);

#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC
    ExpectNotNull(plain);
    ExpectNotNull(cipher);
#endif

    XMEMSET(plain, 0xa5, CFB_LEN);

    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, NULL, AES_ENCRYPTION), 0);

    /* Testing using same buffer for input and output. */
    XMEMCPY(cipher, plain, CFB_LEN);
    ExpectIntEQ(wc_AesSetIV(aes, iv), 0);
    ExpectIntEQ(wc_AesCfbEncrypt(aes, cipher, cipher, CFB_LEN), 0);
    ExpectBufEQ(cipher, expected, CFB_LEN);
#ifdef HAVE_AES_DECRYPT
    ExpectIntEQ(wc_AesSetIV(aes, iv), 0);
    ExpectIntEQ(wc_AesCfbDecrypt(aes, cipher, cipher, CFB_LEN), 0);
    ExpectBufEQ(cipher, plain, CFB_LEN);
#endif

    WC_FREE_VAR(plain, NULL);
    WC_FREE_VAR(cipher, NULL);
    return EXPECT_RESULT();
}
#endif
#endif

int test_wc_AesCfbEncryptDecrypt(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(WOLFSSL_AES_CFB)
    Aes aes;
#if defined(WOLFSSL_AES_128)
    byte key16[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    byte expected16[CFB_LEN] = {
        0xe3, 0xbf, 0xfa, 0x58, 0x38, 0x52, 0x34, 0xd4,
        0x90, 0x2b, 0x3b, 0xa4, 0xd2, 0x7d, 0xeb, 0x0f,
        0x01, 0x1f, 0xb4, 0x51, 0xa3, 0x6b, 0x21, 0x0c,
        0x17, 0xb0, 0xb2, 0xbf, 0x33, 0x3d, 0xe4, 0x3f,
        0xf9, 0x50, 0xcc, 0x2b, 0xab, 0xb7, 0x30, 0xaa,
        0xaf, 0x56, 0xad, 0xdb, 0xca, 0x73, 0x4b, 0x13,
        0x3b, 0xe2, 0xef, 0x8a, 0xb9, 0x1c, 0xfe, 0xfa,
        0x79, 0xcd, 0x92, 0x34, 0x27, 0xae, 0x6c, 0xe9,
        0x18, 0x60, 0x05, 0x44, 0xdd, 0x87, 0xe5, 0xfa,
        0x87, 0x64, 0xd0, 0x4c, 0x21, 0x00, 0xe9, 0x8d,
    };
#endif
#if defined(WOLFSSL_AES_192)
    byte key24[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    byte expected24[CFB_LEN] = {
        0xde, 0x7b, 0xf6, 0x09, 0x2d, 0x81, 0x43, 0x7b,
        0xcd, 0x71, 0xc1, 0xbd, 0x85, 0x33, 0xc7, 0xcd,
        0x23, 0xb2, 0x9f, 0xf8, 0x69, 0xe5, 0x77, 0xbf,
        0x5a, 0x7f, 0xad, 0x5d, 0x98, 0x8f, 0x17, 0x70,
        0x65, 0xf6, 0x18, 0x90, 0x95, 0x5f, 0x85, 0xfd,
        0xfb, 0xc4, 0xed, 0xf2, 0x85, 0x6a, 0x3f, 0x62,
        0x8c, 0x33, 0x08, 0x42, 0x5d, 0x29, 0x51, 0xec,
        0xaa, 0x37, 0x7c, 0x57, 0x51, 0xa0, 0xde, 0xf8,
        0x68, 0x12, 0xf7, 0x73, 0x1c, 0x0c, 0xc7, 0xa6,
        0xb1, 0x82, 0x0e, 0xc8, 0xbd, 0xe3, 0x48, 0x3c,
    };
#endif
#if defined(WOLFSSL_AES_256)
    byte key32[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    byte expected32[CFB_LEN] = {
        0xbd, 0xff, 0xed, 0x58, 0x12, 0x70, 0x90, 0x56,
        0x9a, 0x1c, 0xb1, 0xb3, 0x56, 0xa0, 0x56, 0xd4,
        0x97, 0xb3, 0x9c, 0xf9, 0xeb, 0x2a, 0xb6, 0x23,
        0x11, 0x0c, 0x8d, 0x15, 0x2d, 0x03, 0x66, 0x76,
        0x4a, 0x7f, 0xb4, 0xf4, 0xe6, 0x7c, 0xec, 0x8b,
        0xe9, 0xa9, 0x40, 0x2b, 0x97, 0xec, 0x0e, 0x24,
        0xfe, 0x4b, 0xa1, 0xd6, 0xfc, 0x8f, 0x9c, 0x79,
        0x0c, 0x84, 0x18, 0x67, 0x14, 0x7d, 0x8c, 0x5a,
        0x78, 0x4f, 0x18, 0xb1, 0x04, 0xd9, 0x41, 0x79,
        0x72, 0x92, 0x5e, 0x91, 0xe8, 0xa9, 0xe7, 0xe9,
    };
#endif
    byte iv[]   = "1234567890abcdef";
    byte* key;
    word32 keyLen;
    byte* expected;

#if defined(WOLFSSL_AES_128)
    key = key16;
    keyLen = (word32)sizeof(key16) / sizeof(byte);
    expected = expected16;
#elif defined(WOLFSSL_AES_192)
    key = key24;
    keyLen = (word32)sizeof(key24) / sizeof(byte);
    expected = expected24;
#else
    key = key32;
    keyLen = (word32)sizeof(key32) / sizeof(byte);
    expected = expected32;
#endif

    XMEMSET(&aes, 0, sizeof(Aes));
    ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);

    EXPECT_TEST(test_wc_AesCfbEncryptDecrypt_BadArgs(&aes, key, keyLen, iv));

#if defined(WOLFSSL_AES_128)
    EXPECT_TEST(test_wc_AesCfbEncryptDecrypt_WithKey(&aes, key16,
        (word32)sizeof(key16) / sizeof(byte), iv, expected16));
#endif
#if defined(WOLFSSL_AES_192)
    EXPECT_TEST(test_wc_AesCfbEncryptDecrypt_WithKey(&aes, key24,
        (word32)sizeof(key24) / sizeof(byte), iv, expected24));
#endif
#if defined(WOLFSSL_AES_256)
    EXPECT_TEST(test_wc_AesCfbEncryptDecrypt_WithKey(&aes, key32,
        (word32)sizeof(key32) / sizeof(byte), iv, expected32));
#endif

    EXPECT_TEST(test_wc_AesCfbEncryptDecrypt_Chunking(&aes, key, keyLen, iv,
        expected));
#if (!defined(HAVE_FIPS) || !defined(HAVE_FIPS_VERSION) || \
        (HAVE_FIPS_VERSION > 6)) && !defined(HAVE_SELFTEST)
    EXPECT_TEST(test_wc_AesCfbEncryptDecrypt_SameBuffer(&aes, key, keyLen, iv,
        expected));
#endif

    wc_AesFree(&aes);
#endif
    return EXPECT_RESULT();
} /* END test_wc_AesCfbEncryptDecrypt */

/*
 * Cross-cipher test: CFB128 encrypts by first running ECB on the previous
 * ciphertext block (or IV for the first block), then XOR-ing the result with
 * the plaintext.
 * C[i] = ECB_Encrypt(K, C[i-1]) XOR P[i],  C[-1] = IV.
 *
 * This test verifies that relationship: encrypt with CFB, then independently
 * compute the same ciphertext using ECB + feedback, and compare.
 */
int test_wc_AesCfb_CrossCipher(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(WOLFSSL_AES_CFB) && defined(HAVE_AES_ECB) && \
    defined(WOLFSSL_AES_128)
    Aes aes;
    /* NIST SP 800-38A F.3.13 (first two plaintext blocks, CFB128) */
    static const byte key[AES_128_KEY_SIZE] = {
        0x2b,0x7e,0x15,0x16, 0x28,0xae,0xd2,0xa6,
        0xab,0xf7,0x15,0x88, 0x09,0xcf,0x4f,0x3c
    };
    static const byte iv[WC_AES_BLOCK_SIZE] = {
        0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07,
        0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f
    };
    static const byte plain[2 * WC_AES_BLOCK_SIZE] = {
        0x6b,0xc1,0xbe,0xe2, 0x2e,0x40,0x9f,0x96,
        0xe9,0x3d,0x7e,0x11, 0x73,0x93,0x17,0x2a,
        0xae,0x2d,0x8a,0x57, 0x1e,0x03,0xac,0x9c,
        0x9e,0xb7,0x6f,0xac, 0x45,0xaf,0x8e,0x51
    };
    byte cfb_ct[sizeof(plain)];
    byte ecb_ct[sizeof(plain)];
    byte ks[WC_AES_BLOCK_SIZE];
    int  i;

    XMEMSET(&aes, 0, sizeof(aes));
    ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);

    /* CFB ciphertext via the API */
    ExpectIntEQ(wc_AesSetKey(&aes, key, sizeof(key), NULL, AES_ENCRYPTION), 0);
    ExpectIntEQ(wc_AesSetIV(&aes, iv), 0);
    ExpectIntEQ(wc_AesCfbEncrypt(&aes, cfb_ct, plain, sizeof(plain)), 0);

    /* Manually compute CFB via ECB + ciphertext feedback */
    ExpectIntEQ(wc_AesSetKey(&aes, key, sizeof(key), NULL, AES_ENCRYPTION), 0);

    /* Block 0: encrypt IV to get keystream, then XOR with plaintext */
    ExpectIntEQ(wc_AesEcbEncrypt(&aes, ks, iv, WC_AES_BLOCK_SIZE), 0);
    if (EXPECT_SUCCESS()) {
        for (i = 0; i < WC_AES_BLOCK_SIZE; i++)
            ecb_ct[i] = plain[i] ^ ks[i];
    }

    /* Block 1: encrypt C[0] to get keystream, then XOR with plaintext */
    ExpectIntEQ(wc_AesEcbEncrypt(&aes, ks, ecb_ct, WC_AES_BLOCK_SIZE), 0);
    if (EXPECT_SUCCESS()) {
        for (i = 0; i < WC_AES_BLOCK_SIZE; i++)
            ecb_ct[WC_AES_BLOCK_SIZE + i] = plain[WC_AES_BLOCK_SIZE + i] ^
                                            ks[i];
    }

    /* CFB ciphertext must equal the manually computed ECB+feedback ciphertext */
    ExpectBufEQ(cfb_ct, ecb_ct, sizeof(plain));

    wc_AesFree(&aes);
#endif
    return EXPECT_RESULT();
} /* END test_wc_AesCfb_CrossCipher */

/*******************************************************************************
 * AES-OFB
 ******************************************************************************/

#if !defined(NO_AES) && defined(WOLFSSL_AES_OFB)
#define OFB_LEN     (5 * WC_AES_BLOCK_SIZE)

static int test_wc_AesOfbEncryptDecrypt_BadArgs(Aes* aes, byte* key,
    word32 keyLen, byte* iv)
{
    EXPECT_DECLS;
    byte plain[WC_AES_BLOCK_SIZE];
    byte cipher[WC_AES_BLOCK_SIZE];
#ifdef HAVE_AES_DECRYPT
    byte decrypted[WC_AES_BLOCK_SIZE];
#endif

    XMEMSET(plain, 0x00, WC_AES_BLOCK_SIZE);
    XMEMSET(cipher, 0x00, WC_AES_BLOCK_SIZE);

    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, NULL, AES_ENCRYPTION), 0);

    ExpectIntEQ(wc_AesSetIV(aes, iv), 0);
    ExpectIntEQ(wc_AesOfbEncrypt(NULL, NULL, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesOfbEncrypt(aes, NULL, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesOfbEncrypt(NULL, cipher, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesOfbEncrypt(NULL, NULL, plain, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesOfbEncrypt(aes, cipher, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesOfbEncrypt(aes, NULL, plain, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesOfbEncrypt(NULL, cipher, plain, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));

#ifdef HAVE_AES_DECRYPT
    ExpectIntEQ(wc_AesSetIV(aes, iv), 0);
    ExpectIntEQ(wc_AesOfbDecrypt(NULL, NULL, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesOfbDecrypt(aes, NULL, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesOfbDecrypt(NULL, decrypted, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesOfbDecrypt(NULL, NULL, cipher, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesOfbDecrypt(aes, decrypted, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesOfbDecrypt(aes, NULL, cipher, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesOfbDecrypt(NULL, decrypted, cipher, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif

    return EXPECT_RESULT();
}

static int test_wc_AesOfbEncryptDecrypt_WithKey(Aes* aes, byte* key,
    word32 keyLen, byte* iv, byte* expected)
{
    EXPECT_DECLS;
    WC_DECLARE_VAR(plain, byte, OFB_LEN, NULL);
    WC_DECLARE_VAR(cipher, byte, OFB_LEN, NULL);
#ifdef HAVE_AES_DECRYPT
    WC_DECLARE_VAR(decrypted, byte, OFB_LEN, NULL);
#endif

    WC_ALLOC_VAR(plain, byte, OFB_LEN, NULL);
    WC_ALLOC_VAR(cipher, byte, OFB_LEN, NULL);
#ifdef HAVE_AES_DECRYPT
    WC_ALLOC_VAR(decrypted, byte, OFB_LEN, NULL);
#endif

    XMEMSET(plain, 0xa5, OFB_LEN);

    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, NULL, AES_ENCRYPTION), 0);

    ExpectIntEQ(wc_AesSetIV(aes, iv), 0);
    ExpectIntEQ(wc_AesOfbEncrypt(aes, cipher, plain, WC_AES_BLOCK_SIZE), 0);
    ExpectBufEQ(cipher, expected, WC_AES_BLOCK_SIZE);

#ifdef HAVE_AES_DECRYPT
    ExpectIntEQ(wc_AesSetIV(aes, iv), 0);
    ExpectIntEQ(wc_AesOfbDecrypt(aes, decrypted, cipher, WC_AES_BLOCK_SIZE),
        0);
    ExpectBufEQ(decrypted, plain, WC_AES_BLOCK_SIZE);
#endif

    ExpectIntEQ(wc_AesSetIV(aes, iv), 0);
    ExpectIntEQ(wc_AesOfbEncrypt(aes, cipher, plain, OFB_LEN), 0);
    ExpectBufEQ(cipher, expected, OFB_LEN);
#ifdef HAVE_AES_DECRYPT
    ExpectIntEQ(wc_AesSetIV(aes, iv), 0);
    ExpectIntEQ(wc_AesOfbDecrypt(aes, decrypted, cipher, OFB_LEN), 0);
    ExpectBufEQ(decrypted, plain, OFB_LEN);
#endif

    WC_FREE_VAR(plain, NULL);
    WC_FREE_VAR(cipher, NULL);
#ifdef HAVE_AES_DECRYPT
    WC_FREE_VAR(decrypted, NULL);
#endif
    return EXPECT_RESULT();
}

static int test_wc_AesOfbEncryptDecrypt_Chunking(Aes* aes, byte* key,
    word32 keyLen, byte* iv, byte* expected)
{
    EXPECT_DECLS;
    int sz;
    int cnt;
    WC_DECLARE_VAR(plain, byte, OFB_LEN, NULL);
    WC_DECLARE_VAR(cipher, byte, OFB_LEN, NULL);
#ifdef HAVE_AES_DECRYPT
    WC_DECLARE_VAR(decrypted, byte, OFB_LEN, NULL);
#endif

    WC_ALLOC_VAR(plain, byte, OFB_LEN, NULL);
    WC_ALLOC_VAR(cipher, byte, OFB_LEN, NULL);
#ifdef HAVE_AES_DECRYPT
    WC_ALLOC_VAR(decrypted, byte, OFB_LEN, NULL);
#endif

#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC
    ExpectNotNull(plain);
    ExpectNotNull(cipher);
#ifdef HAVE_AES_DECRYPT
    ExpectNotNull(decrypted);
#endif
#endif

    XMEMSET(plain, 0xa5, OFB_LEN);

    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, NULL, AES_ENCRYPTION), 0);

    for (sz = 1; sz < OFB_LEN; sz++) {
        ExpectIntEQ(wc_AesSetIV(aes, iv), 0);
        XMEMSET(cipher, 0, OFB_LEN);
        for (cnt = 0; cnt + sz <= OFB_LEN; cnt += sz) {
            ExpectIntEQ(wc_AesOfbEncrypt(aes, cipher + cnt, plain + cnt, sz),
                0);
        }
        if (cnt < OFB_LEN) {
            ExpectIntEQ(wc_AesOfbEncrypt(aes, cipher + cnt, plain + cnt,
                OFB_LEN - cnt), 0);
        }
        ExpectBufEQ(cipher, expected, OFB_LEN);
    }
#ifdef HAVE_AES_DECRYPT
    for (sz = 1; sz < OFB_LEN; sz++) {
        ExpectIntEQ(wc_AesSetIV(aes, iv), 0);
        XMEMSET(decrypted, 0xff, OFB_LEN);
        for (cnt = 0; cnt + sz <= OFB_LEN; cnt += sz) {
            ExpectIntEQ(wc_AesOfbDecrypt(aes, decrypted + cnt, cipher + cnt,
                sz), 0);
        }
        if (cnt < OFB_LEN) {
            ExpectIntEQ(wc_AesOfbDecrypt(aes, decrypted + cnt, cipher + cnt,
                OFB_LEN - cnt), 0);
        }
        ExpectBufEQ(decrypted, plain, OFB_LEN);
    }
#endif

    WC_FREE_VAR(plain, NULL);
    WC_FREE_VAR(cipher, NULL);
#ifdef HAVE_AES_DECRYPT
    WC_FREE_VAR(decrypted, NULL);
#endif
    return EXPECT_RESULT();
}

static int test_wc_AesOfbEncryptDecrypt_SameBuffer(Aes* aes, byte* key,
    word32 keyLen, byte* iv, byte* expected)
{
    EXPECT_DECLS;
    WC_DECLARE_VAR(plain, byte, OFB_LEN, NULL);
    WC_DECLARE_VAR(cipher, byte, OFB_LEN, NULL);

    WC_ALLOC_VAR(plain, byte, OFB_LEN, NULL);
    WC_ALLOC_VAR(cipher, byte, OFB_LEN, NULL);

#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC
    ExpectNotNull(plain);
    ExpectNotNull(cipher);
#endif
    XMEMSET(plain, 0xa5, OFB_LEN);

    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, NULL, AES_ENCRYPTION), 0);

    /* Testing using same buffer for input and output. */
    XMEMCPY(cipher, plain, OFB_LEN);
    ExpectIntEQ(wc_AesSetIV(aes, iv), 0);
    ExpectIntEQ(wc_AesOfbEncrypt(aes, cipher, cipher, OFB_LEN), 0);
    ExpectBufEQ(cipher, expected, OFB_LEN);
#ifdef HAVE_AES_DECRYPT
    ExpectIntEQ(wc_AesSetIV(aes, iv), 0);
    ExpectIntEQ(wc_AesOfbDecrypt(aes, cipher, cipher, OFB_LEN), 0);
    ExpectBufEQ(cipher, plain, OFB_LEN);
#endif

    WC_FREE_VAR(plain, NULL);
    WC_FREE_VAR(cipher, NULL);
    return EXPECT_RESULT();
}
#endif

int test_wc_AesOfbEncryptDecrypt(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(WOLFSSL_AES_OFB)
    Aes aes;
#if defined(WOLFSSL_AES_128)
    byte key16[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    byte expected16[OFB_LEN] = {
        0xe3, 0xbf, 0xfa, 0x58, 0x38, 0x52, 0x34, 0xd4,
        0x90, 0x2b, 0x3b, 0xa4, 0xd2, 0x7d, 0xeb, 0x0f,
        0x91, 0x8d, 0x1f, 0x30, 0xd3, 0x00, 0xc5, 0x4e,
        0x1a, 0xcb, 0x2c, 0x50, 0x3f, 0xa6, 0xdf, 0xdb,
        0xa2, 0x60, 0x49, 0xc5, 0x44, 0x3e, 0xdf, 0x90,
        0x39, 0x8c, 0xd1, 0xc9, 0x8e, 0xb9, 0x5a, 0xbe,
        0x05, 0x70, 0x56, 0xfe, 0x86, 0x23, 0x94, 0x1b,
        0xbf, 0x85, 0x89, 0xf2, 0x51, 0x3b, 0x24, 0xc2,
        0x1d, 0x57, 0xc5, 0x8d, 0x93, 0xf5, 0xc9, 0xa3,
        0xcc, 0x0d, 0x49, 0x93, 0xe3, 0x8f, 0x6c, 0xb7,
    };
#endif
#if defined(WOLFSSL_AES_192)
    byte key24[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    byte expected24[OFB_LEN] = {
        0xde, 0x7b, 0xf6, 0x09, 0x2d, 0x81, 0x43, 0x7b,
        0xcd, 0x71, 0xc1, 0xbd, 0x85, 0x33, 0xc7, 0xcd,
        0x75, 0xa1, 0x24, 0xf5, 0xd6, 0x42, 0xc8, 0x2b,
        0xb1, 0xe1, 0x22, 0x08, 0xc8, 0xe1, 0x5c, 0x66,
        0x4c, 0x27, 0x8b, 0x88, 0xb2, 0xb3, 0xe6, 0x03,
        0x8c, 0x46, 0x38, 0xda, 0x21, 0x8b, 0x3f, 0xb1,
        0xcc, 0x4c, 0xde, 0x9d, 0x58, 0x49, 0xd4, 0xef,
        0x52, 0xaa, 0x1a, 0xcb, 0xe8, 0xe3, 0xdb, 0x08,
        0x26, 0x6e, 0x5f, 0x85, 0x80, 0x5d, 0xb6, 0x63,
        0xd0, 0x78, 0xb7, 0xba, 0x48, 0x5f, 0x9f, 0xb9,
    };
#endif
#if defined(WOLFSSL_AES_256)
    byte key32[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    byte expected32[OFB_LEN] = {
        0xbd, 0xff, 0xed, 0x58, 0x12, 0x70, 0x90, 0x56,
        0x9a, 0x1c, 0xb1, 0xb3, 0x56, 0xa0, 0x56, 0xd4,
        0x4f, 0xeb, 0x87, 0x68, 0xb0, 0x9f, 0x69, 0x1f,
        0x9a, 0xfe, 0x20, 0xb0, 0x7a, 0xa2, 0x53, 0x01,
        0x51, 0xe4, 0x42, 0xad, 0x95, 0x3e, 0xac, 0x88,
        0x71, 0x9b, 0xcd, 0x4f, 0xe0, 0x98, 0x9f, 0x46,
        0xd9, 0xcd, 0xa5, 0x7f, 0x4e, 0x22, 0x72, 0xb4,
        0x8f, 0xae, 0xd9, 0xed, 0x40, 0x4a, 0x0b, 0xc8,
        0xc4, 0xa1, 0x01, 0xb3, 0x62, 0x13, 0xaa, 0x0e,
        0x81, 0xa9, 0xd1, 0xae, 0xea, 0x5b, 0x58, 0x74,
    };
#endif
    byte iv[]   = "1234567890abcdef";
    byte* key;
    word32 keyLen;
    byte* expected;

#if defined(WOLFSSL_AES_128)
    key = key16;
    keyLen = (word32)sizeof(key16) / sizeof(byte);
    expected = expected16;
#elif defined(WOLFSSL_AES_192)
    key = key24;
    keyLen = (word32)sizeof(key24) / sizeof(byte);
    expected = expected24;
#else
    key = key32;
    keyLen = (word32)sizeof(key32) / sizeof(byte);
    expected = expected32;
#endif

    XMEMSET(&aes, 0, sizeof(Aes));
    ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);

    EXPECT_TEST(test_wc_AesOfbEncryptDecrypt_BadArgs(&aes, key, keyLen, iv));

#if defined(WOLFSSL_AES_128)
    EXPECT_TEST(test_wc_AesOfbEncryptDecrypt_WithKey(&aes, key16,
        (word32)sizeof(key16) / sizeof(byte), iv, expected16));
#endif
#if defined(WOLFSSL_AES_192)
    EXPECT_TEST(test_wc_AesOfbEncryptDecrypt_WithKey(&aes, key24,
        (word32)sizeof(key24) / sizeof(byte), iv, expected24));
#endif
#if defined(WOLFSSL_AES_256)
    EXPECT_TEST(test_wc_AesOfbEncryptDecrypt_WithKey(&aes, key32,
        (word32)sizeof(key32) / sizeof(byte), iv, expected32));
#endif

    EXPECT_TEST(test_wc_AesOfbEncryptDecrypt_Chunking(&aes, key, keyLen, iv,
        expected));
    EXPECT_TEST(test_wc_AesOfbEncryptDecrypt_SameBuffer(&aes, key, keyLen, iv,
        expected));

    wc_AesFree(&aes);
#endif
    return EXPECT_RESULT();
} /* END test_wc_AesOfbEncryptDecrypt */

/*
 * Cross-cipher test: OFB mode generates a keystream by repeatedly ECB-
 * encrypting the previous output block, starting from the IV.
 * O[0] = ECB_Encrypt(K, IV);   C[0] = P[0] XOR O[0]
 * O[1] = ECB_Encrypt(K, O[0]); C[1] = P[1] XOR O[1]
 *
 * Unlike CFB, the feedback is taken from the keystream output, not the
 * ciphertext, making OFB a synchronous stream cipher.
 */
int test_wc_AesOfb_CrossCipher(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(WOLFSSL_AES_OFB) && defined(HAVE_AES_ECB) && \
    defined(WOLFSSL_AES_128)
    Aes aes;
    /* NIST SP 800-38A F.4.1 (first two plaintext blocks, OFB) */
    static const byte key[AES_128_KEY_SIZE] = {
        0x2b,0x7e,0x15,0x16, 0x28,0xae,0xd2,0xa6,
        0xab,0xf7,0x15,0x88, 0x09,0xcf,0x4f,0x3c
    };
    static const byte iv[WC_AES_BLOCK_SIZE] = {
        0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07,
        0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f
    };
    static const byte plain[2 * WC_AES_BLOCK_SIZE] = {
        0x6b,0xc1,0xbe,0xe2, 0x2e,0x40,0x9f,0x96,
        0xe9,0x3d,0x7e,0x11, 0x73,0x93,0x17,0x2a,
        0xae,0x2d,0x8a,0x57, 0x1e,0x03,0xac,0x9c,
        0x9e,0xb7,0x6f,0xac, 0x45,0xaf,0x8e,0x51
    };
    byte ofb_ct[sizeof(plain)];
    byte ecb_ct[sizeof(plain)];
    byte o0[WC_AES_BLOCK_SIZE]; /* output-feedback block 0 */
    byte o1[WC_AES_BLOCK_SIZE]; /* output-feedback block 1 */
    int  i;

    XMEMSET(&aes, 0, sizeof(aes));
    ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);

    /* OFB ciphertext via the API */
    ExpectIntEQ(wc_AesSetKey(&aes, key, sizeof(key), NULL, AES_ENCRYPTION), 0);
    ExpectIntEQ(wc_AesSetIV(&aes, iv), 0);
    ExpectIntEQ(wc_AesOfbEncrypt(&aes, ofb_ct, plain, sizeof(plain)), 0);

    /* Manually compute OFB via ECB + output feedback */
    ExpectIntEQ(wc_AesSetKey(&aes, key, sizeof(key), NULL, AES_ENCRYPTION), 0);

    /* O[0] = ECB_E(K, IV);  C[0] = P[0] XOR O[0] */
    ExpectIntEQ(wc_AesEcbEncrypt(&aes, o0, iv, WC_AES_BLOCK_SIZE), 0);
    if (EXPECT_SUCCESS()) {
        for (i = 0; i < WC_AES_BLOCK_SIZE; i++)
            ecb_ct[i] = plain[i] ^ o0[i];
    }

    /* O[1] = ECB_E(K, O[0]);  C[1] = P[1] XOR O[1] */
    ExpectIntEQ(wc_AesEcbEncrypt(&aes, o1, o0, WC_AES_BLOCK_SIZE), 0);
    if (EXPECT_SUCCESS()) {
        for (i = 0; i < WC_AES_BLOCK_SIZE; i++)
            ecb_ct[WC_AES_BLOCK_SIZE + i] = plain[WC_AES_BLOCK_SIZE + i] ^
                                            o1[i];
    }

    /* OFB ciphertext must equal the manually computed ECB+output-feedback */
    ExpectBufEQ(ofb_ct, ecb_ct, sizeof(plain));

    wc_AesFree(&aes);
#endif
    return EXPECT_RESULT();
} /* END test_wc_AesOfb_CrossCipher */

/*******************************************************************************
 * AES-CTS
 ******************************************************************************/

int test_wc_AesCtsEncryptDecrypt(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(WOLFSSL_AES_CTS) && \
    defined(HAVE_AES_DECRYPT) && defined(WOLFSSL_AES_128)
    /* Test vectors taken form RFC3962 Appendix B */
    const struct {
        const char* input;
        const char* output;
        size_t inLen;
        size_t outLen;
    } vects[] = {
        {
            "\x49\x20\x77\x6f\x75\x6c\x64\x20\x6c\x69\x6b\x65\x20\x74\x68\x65"
            "\x20",
            "\xc6\x35\x35\x68\xf2\xbf\x8c\xb4\xd8\xa5\x80\x36\x2d\xa7\xff\x7f"
            "\x97",
            17, 17
        },
        {
            "\x49\x20\x77\x6f\x75\x6c\x64\x20\x6c\x69\x6b\x65\x20\x74\x68\x65"
            "\x20\x47\x65\x6e\x65\x72\x61\x6c\x20\x47\x61\x75\x27\x73\x20",
            "\xfc\x00\x78\x3e\x0e\xfd\xb2\xc1\xd4\x45\xd4\xc8\xef\xf7\xed\x22"
            "\x97\x68\x72\x68\xd6\xec\xcc\xc0\xc0\x7b\x25\xe2\x5e\xcf\xe5",
            31, 31
        },
        {
            "\x49\x20\x77\x6f\x75\x6c\x64\x20\x6c\x69\x6b\x65\x20\x74\x68\x65"
            "\x20\x47\x65\x6e\x65\x72\x61\x6c\x20\x47\x61\x75\x27\x73\x20\x43",
            "\x39\x31\x25\x23\xa7\x86\x62\xd5\xbe\x7f\xcb\xcc\x98\xeb\xf5\xa8"
            "\x97\x68\x72\x68\xd6\xec\xcc\xc0\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84",
            32, 32
        },
        {
            "\x49\x20\x77\x6f\x75\x6c\x64\x20\x6c\x69\x6b\x65\x20\x74\x68\x65"
            "\x20\x47\x65\x6e\x65\x72\x61\x6c\x20\x47\x61\x75\x27\x73\x20\x43"
            "\x68\x69\x63\x6b\x65\x6e\x2c\x20\x70\x6c\x65\x61\x73\x65\x2c",
            "\x97\x68\x72\x68\xd6\xec\xcc\xc0\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84"
            "\xb3\xff\xfd\x94\x0c\x16\xa1\x8c\x1b\x55\x49\xd2\xf8\x38\x02\x9e"
            "\x39\x31\x25\x23\xa7\x86\x62\xd5\xbe\x7f\xcb\xcc\x98\xeb\xf5",
            47, 47
        },
        {
            "\x49\x20\x77\x6f\x75\x6c\x64\x20\x6c\x69\x6b\x65\x20\x74\x68\x65"
            "\x20\x47\x65\x6e\x65\x72\x61\x6c\x20\x47\x61\x75\x27\x73\x20\x43"
            "\x68\x69\x63\x6b\x65\x6e\x2c\x20\x70\x6c\x65\x61\x73\x65\x2c\x20",
            "\x97\x68\x72\x68\xd6\xec\xcc\xc0\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84"
            "\x9d\xad\x8b\xbb\x96\xc4\xcd\xc0\x3b\xc1\x03\xe1\xa1\x94\xbb\xd8"
            "\x39\x31\x25\x23\xa7\x86\x62\xd5\xbe\x7f\xcb\xcc\x98\xeb\xf5\xa8",
            48, 48
        },
        {
            "\x49\x20\x77\x6f\x75\x6c\x64\x20\x6c\x69\x6b\x65\x20\x74\x68\x65"
            "\x20\x47\x65\x6e\x65\x72\x61\x6c\x20\x47\x61\x75\x27\x73\x20\x43"
            "\x68\x69\x63\x6b\x65\x6e\x2c\x20\x70\x6c\x65\x61\x73\x65\x2c\x20"
            "\x61\x6e\x64\x20\x77\x6f\x6e\x74\x6f\x6e\x20\x73\x6f\x75\x70\x2e",
            "\x97\x68\x72\x68\xd6\xec\xcc\xc0\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84"
            "\x39\x31\x25\x23\xa7\x86\x62\xd5\xbe\x7f\xcb\xcc\x98\xeb\xf5\xa8"
            "\x48\x07\xef\xe8\x36\xee\x89\xa5\x26\x73\x0d\xbc\x2f\x7b\xc8\x40"
            "\x9d\xad\x8b\xbb\x96\xc4\xcd\xc0\x3b\xc1\x03\xe1\xa1\x94\xbb\xd8",
            64, 64
        }
    };
    const byte keyBytes[AES_128_KEY_SIZE] = {
        0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
        0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69
    };
    byte tmp[64]; /* Largest vector size */
    size_t i;
    byte iv[AES_IV_SIZE]; /* All-zero IV for all cases */

    XMEMSET(iv, 0, sizeof(iv));
    for (i = 0; i < XELEM_CNT(vects) && EXPECT_SUCCESS(); i++) {
        /* One-shot encrypt */
        XMEMSET(tmp, 0, sizeof(tmp));
        ExpectIntEQ(wc_AesCtsEncrypt(keyBytes, sizeof(keyBytes), tmp,
                 (const byte*)vects[i].input, (word32)vects[i].inLen, iv), 0);
        ExpectBufEQ(tmp, vects[i].output, vects[i].outLen);
        XMEMSET(tmp, 0, sizeof(tmp));
        ExpectIntEQ(wc_AesCtsDecrypt(keyBytes, sizeof(keyBytes), tmp,
                 (const byte*)vects[i].output, (word32)vects[i].outLen, iv), 0);
        ExpectBufEQ(tmp, vects[i].input, vects[i].inLen);
    }
    /* Execute all branches */
    {
        Aes* aes = NULL;
        int result_code = 0;
        const byte* in = (const byte*)vects[5].input;
        byte* out = tmp;
        word32 outSz = (word32)vects[5].outLen;
        word32 remSz = (word32)vects[5].outLen;

        XMEMSET(tmp, 0, sizeof(tmp));
        ExpectNotNull(aes = wc_AesNew(NULL, INVALID_DEVID, &result_code));
        ExpectIntEQ(wc_AesSetKey(aes, keyBytes, sizeof(keyBytes), iv,
                                 AES_ENCRYPTION), 0);
        ExpectIntEQ(wc_AesCtsEncryptUpdate(aes, out, &outSz, in, 1), 0);
        in += 1; out += outSz; remSz -= outSz; outSz = remSz;
        ExpectIntEQ(wc_AesCtsEncryptUpdate(aes, out, &outSz, in, 31), 0);
        in += 31; out += outSz; remSz -= outSz; outSz = remSz;
        ExpectIntEQ(wc_AesCtsEncryptUpdate(aes, out, &outSz, in, 32), 0);
        in += 32; out += outSz; remSz -= outSz; outSz = remSz;
        ExpectIntEQ(wc_AesCtsEncryptFinal(aes, out, &outSz), 0);
        remSz -= outSz;
        ExpectIntEQ(remSz, 0);
        ExpectBufEQ(tmp, vects[5].output, vects[5].outLen);
        ExpectIntEQ(wc_AesDelete(aes, &aes), 0);
    }
    {
        Aes* aes = NULL;
        int result_code = 0;
        const byte* in = (const byte*)vects[5].input;
        byte* out = tmp;
        word32 outSz = (word32)vects[5].outLen;
        word32 remSz = (word32)vects[5].outLen;

        ExpectNotNull(aes = wc_AesNew(NULL, INVALID_DEVID, &result_code));
        ExpectIntEQ(wc_AesSetKey(aes, keyBytes, sizeof(keyBytes), iv,
                                 AES_ENCRYPTION), 0);
        ExpectIntEQ(wc_AesCtsEncryptUpdate(aes, out, &outSz, in, 1), 0);
        in += 1; out += outSz; remSz -= outSz; outSz = remSz;
        ExpectIntEQ(wc_AesCtsEncryptUpdate(aes, out, &outSz, in, 63), 0);
        in += 63; out += outSz; remSz -= outSz; outSz = remSz;
        ExpectIntEQ(wc_AesCtsEncryptFinal(aes, out, &outSz), 0);
        remSz -= outSz;
        ExpectIntEQ(remSz, 0);
        ExpectBufEQ(tmp, vects[5].output, vects[5].outLen);
        ExpectIntEQ(wc_AesDelete(aes, &aes), 0);
    }
    {
        Aes* aes = NULL;
        int result_code = 0;
        const byte* in = (const byte*)vects[2].input;
        byte* out = tmp;
        word32 outSz = (word32)vects[2].outLen;
        word32 remSz = (word32)vects[2].outLen;

        ExpectNotNull(aes = wc_AesNew(NULL, INVALID_DEVID, &result_code));
        ExpectIntEQ(wc_AesSetKey(aes, keyBytes, sizeof(keyBytes), iv,
                                 AES_ENCRYPTION), 0);
        ExpectIntEQ(wc_AesCtsEncryptUpdate(aes, out, &outSz, in, 16), 0);
        in += 16; out += outSz; remSz -= outSz; outSz = remSz;
        ExpectIntEQ(wc_AesCtsEncryptUpdate(aes, out, &outSz, in, 16), 0);
        in += 16; out += outSz; remSz -= outSz; outSz = remSz;
        ExpectIntEQ(wc_AesCtsEncryptFinal(aes, out, &outSz), 0);
        remSz -= outSz;
        ExpectIntEQ(remSz, 0);
        ExpectBufEQ(tmp, vects[2].output, vects[2].outLen);
        ExpectIntEQ(wc_AesDelete(aes, &aes), 0);
    }
    {
        Aes* aes = NULL;
        int result_code = 0;
        const byte* in = (const byte*)vects[5].output;
        byte* out = tmp;
        word32 outSz = (word32)vects[5].inLen;
        word32 remSz = (word32)vects[5].inLen;

        XMEMSET(tmp, 0, sizeof(tmp));
        ExpectNotNull(aes = wc_AesNew(NULL, INVALID_DEVID, &result_code));
        ExpectIntEQ(wc_AesSetKey(aes, keyBytes, sizeof(keyBytes), iv,
                                 AES_DECRYPTION), 0);
        ExpectIntEQ(wc_AesCtsDecryptUpdate(aes, out, &outSz, in, 1), 0);
        in += 1; out += outSz; remSz -= outSz; outSz = remSz;
        ExpectIntEQ(wc_AesCtsDecryptUpdate(aes, out, &outSz, in, 31), 0);
        in += 31; out += outSz; remSz -= outSz; outSz = remSz;
        ExpectIntEQ(wc_AesCtsDecryptUpdate(aes, out, &outSz, in, 32), 0);
        in += 32; out += outSz; remSz -= outSz; outSz = remSz;
        ExpectIntEQ(wc_AesCtsDecryptFinal(aes, out, &outSz), 0);
        remSz -= outSz;
        ExpectIntEQ(remSz, 0);
        ExpectBufEQ(tmp, vects[5].input, vects[5].inLen);
        ExpectIntEQ(wc_AesDelete(aes, &aes), 0);
    }
    {
        Aes* aes = NULL;
        int result_code = 0;
        const byte* in = (const byte*)vects[5].output;
        byte* out = tmp;
        word32 outSz = (word32)vects[5].inLen;
        word32 remSz = (word32)vects[5].inLen;

        ExpectNotNull(aes = wc_AesNew(NULL, INVALID_DEVID, &result_code));
        ExpectIntEQ(wc_AesSetKey(aes, keyBytes, sizeof(keyBytes), iv,
                                 AES_DECRYPTION), 0);
        ExpectIntEQ(wc_AesCtsDecryptUpdate(aes, out, &outSz, in, 1), 0);
        in += 1; out += outSz; remSz -= outSz; outSz = remSz;
        ExpectIntEQ(wc_AesCtsDecryptUpdate(aes, out, &outSz, in, 63), 0);
        in += 63; out += outSz; remSz -= outSz; outSz = remSz;
        ExpectIntEQ(wc_AesCtsDecryptFinal(aes, out, &outSz), 0);
        remSz -= outSz;
        ExpectIntEQ(remSz, 0);
        ExpectBufEQ(tmp, vects[5].input, vects[5].inLen);
        ExpectIntEQ(wc_AesDelete(aes, &aes), 0);
    }
    {
        Aes* aes = NULL;
        int result_code = 0;
        const byte* in = (const byte*)vects[2].output;
        byte* out = tmp;
        word32 outSz = (word32)vects[2].inLen;
        word32 remSz = (word32)vects[2].inLen;

        ExpectNotNull(aes = wc_AesNew(NULL, INVALID_DEVID, &result_code));
        ExpectIntEQ(wc_AesSetKey(aes, keyBytes, sizeof(keyBytes), iv,
                                 AES_DECRYPTION), 0);
        ExpectIntEQ(wc_AesCtsDecryptUpdate(aes, out, &outSz, in, 16), 0);
        in += 16; out += outSz; remSz -= outSz; outSz = remSz;
        ExpectIntEQ(wc_AesCtsDecryptUpdate(aes, out, &outSz, in, 16), 0);
        in += 16; out += outSz; remSz -= outSz; outSz = remSz;
        ExpectIntEQ(wc_AesCtsDecryptFinal(aes, out, &outSz), 0);
        remSz -= outSz;
        ExpectIntEQ(remSz, 0);
        ExpectBufEQ(tmp, vects[2].input, vects[2].inLen);
        ExpectIntEQ(wc_AesDelete(aes, &aes), 0);
    }
#endif
    return EXPECT_RESULT();
}

/*******************************************************************************
 * AES-CTS overlapping (in-place) buffers
 ******************************************************************************/

/*
 * Verify that wc_AesCtsEncrypt / wc_AesCtsDecrypt correctly handle an
 * in-place call (out == in).  RFC 3962 Appendix B test vector 5 (48 bytes,
 * three full AES blocks) is used because the CTS one-shot API buffers input
 * internally before writing output, so it is safe for in-place use.
 */
int test_wc_AesCtsEncryptDecrypt_InPlace(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(WOLFSSL_AES_CTS) && \
    defined(HAVE_AES_DECRYPT) && defined(WOLFSSL_AES_128)
    static const byte key[AES_128_KEY_SIZE] = {
        0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
        0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69
    };
    /* RFC 3962 plaintext vector 5 (48 bytes):
     * "I would like the General Gau's Chicken, please, " */
    static const byte plain[48] = {
        0x49, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20,
        0x6c, 0x69, 0x6b, 0x65, 0x20, 0x74, 0x68, 0x65,
        0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c,
        0x20, 0x47, 0x61, 0x75, 0x27, 0x73, 0x20, 0x43,
        0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x2c, 0x20,
        0x70, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x2c, 0x20
    };
    byte iv[AES_IV_SIZE];
    byte ref_ct[sizeof(plain)];
    byte buf[sizeof(plain)];

    /* Reference ciphertext with separate in/out buffers */
    XMEMSET(iv, 0, sizeof(iv));
    ExpectIntEQ(wc_AesCtsEncrypt(key, sizeof(key), ref_ct, plain,
        sizeof(plain), iv), 0);

    /* Encrypt in-place (out == in) - must produce the same ciphertext */
    XMEMSET(iv, 0, sizeof(iv));
    XMEMCPY(buf, plain, sizeof(buf));
    ExpectIntEQ(wc_AesCtsEncrypt(key, sizeof(key), buf, buf,
        sizeof(buf), iv), 0);
    ExpectBufEQ(buf, ref_ct, sizeof(buf));

    /* Decrypt in-place - must recover original plaintext */
    XMEMSET(iv, 0, sizeof(iv));
    ExpectIntEQ(wc_AesCtsDecrypt(key, sizeof(key), buf, buf,
        sizeof(buf), iv), 0);
    ExpectBufEQ(buf, plain, sizeof(buf));
#endif
    return EXPECT_RESULT();
} /* END test_wc_AesCtsEncryptDecrypt_InPlace */

/*******************************************************************************
 * AES-CTS unaligned buffers
 ******************************************************************************/

/*
 * Verify that wc_AesCtsEncrypt / wc_AesCtsDecrypt produce correct results
 * when the input and output buffers are byte-offset (unaligned).  Tests
 * offsets 1, 2, and 3 to cover all misalignment residues mod 4.
 */
int test_wc_AesCtsEncryptDecrypt_UnalignedBuffers(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(WOLFSSL_AES_CTS) && \
    defined(HAVE_AES_DECRYPT) && defined(WOLFSSL_AES_128)
    /* RFC 3962 Appendix B test vector 5 - same as InPlace test */
    static const byte key[AES_128_KEY_SIZE] = {
        0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
        0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69
    };
    static const byte plain[48] = {
        0x49, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20,
        0x6c, 0x69, 0x6b, 0x65, 0x20, 0x74, 0x68, 0x65,
        0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c,
        0x20, 0x47, 0x61, 0x75, 0x27, 0x73, 0x20, 0x43,
        0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x2c, 0x20,
        0x70, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x2c, 0x20
    };
    byte iv[AES_IV_SIZE];
    byte ref_ct[sizeof(plain)];
    byte in_buf[sizeof(plain) + 3];
    byte out_buf[sizeof(plain) + 3];
    int off;

    /* Reference ciphertext with naturally-aligned buffers */
    XMEMSET(iv, 0, sizeof(iv));
    ExpectIntEQ(wc_AesCtsEncrypt(key, sizeof(key), ref_ct, plain,
        sizeof(plain), iv), 0);

    /* Encrypt with byte offsets 1, 2, 3 on both in and out */
    for (off = 1; off <= 3 && EXPECT_SUCCESS(); off++) {
        XMEMSET(iv, 0, sizeof(iv));
        XMEMCPY(in_buf + off, plain, sizeof(plain));
        XMEMSET(out_buf, 0, sizeof(out_buf));
        ExpectIntEQ(wc_AesCtsEncrypt(key, sizeof(key), out_buf + off,
            in_buf + off, sizeof(plain), iv), 0);
        ExpectBufEQ(out_buf + off, ref_ct, sizeof(plain));
    }

    /* Decrypt with byte offsets 1, 2, 3 on both in and out */
    for (off = 1; off <= 3 && EXPECT_SUCCESS(); off++) {
        XMEMSET(iv, 0, sizeof(iv));
        XMEMCPY(in_buf + off, ref_ct, sizeof(plain));
        XMEMSET(out_buf, 0, sizeof(out_buf));
        ExpectIntEQ(wc_AesCtsDecrypt(key, sizeof(key), out_buf + off,
            in_buf + off, sizeof(plain), iv), 0);
        ExpectBufEQ(out_buf + off, plain, sizeof(plain));
    }
#endif
    return EXPECT_RESULT();
} /* END test_wc_AesCtsEncryptDecrypt_UnalignedBuffers */

/*******************************************************************************
 * AES-CTR
 ******************************************************************************/

#if !defined(NO_AES) && defined(WOLFSSL_AES_COUNTER) && \
    (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0)) && \
    !defined(HAVE_SELFTEST) && !defined(WOLFSSL_AFALG) && \
    !defined(WOLFSSL_KCAPI)
static int test_wc_AesCtrSetKey_BadArgs(Aes* aes, byte* key, word32 keyLen,
    byte* iv)
{
    EXPECT_DECLS;

    ExpectIntEQ(wc_AesCtrSetKey(NULL, NULL, keyLen, iv, AES_ENCRYPTION),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCtrSetKey(NULL, key , keyLen, iv, AES_ENCRYPTION),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCtrSetKey(aes , key , 48    , iv, AES_ENCRYPTION),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    return EXPECT_RESULT();
}

static int test_wc_AesCtrSetKey_WithKey(Aes* aes, byte* key, word32 keyLen,
    byte* iv, int ret)
{
    EXPECT_DECLS;

    ExpectIntEQ(wc_AesCtrSetKey(aes, key, keyLen, iv, AES_ENCRYPTION), ret);
    ExpectIntEQ(wc_AesCtrSetKey(aes, key, keyLen, NULL, AES_DECRYPTION), ret);

    return EXPECT_RESULT();
}
#endif /* !NO_AES && WOLFSSL_AES_COUNTER &&       */
       /* (!HAVE_FIPS || FIPS_VERSION_GE(7,0)) && */
       /* !HAVE_SELFTEST && !WOLFSSL_AFALG &&     */
       /* !WOLFSSL_KCAPI */

/*
 * Testing function for wc_AesCtrSetKey().
 */
int test_wc_AesCtrSetKey(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(WOLFSSL_AES_COUNTER) && \
    (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0)) && \
    !defined(HAVE_SELFTEST) && !defined(WOLFSSL_AFALG) && \
    !defined(WOLFSSL_KCAPI)
    Aes  aes;
    byte key16[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    byte key24[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37
    };
    byte key32[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    byte badKey16[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65
    };
    byte iv[] = "1234567890abcdef";
    byte* key;
    word32 keyLen;

#if defined(WOLFSSL_AES_128)
    key = key16;
    keyLen = (word32)sizeof(key16) / sizeof(byte);
#elif defined(WOLFSSL_AES_192)
    key = key24;
    keyLen = (word32)sizeof(key24) / sizeof(byte);
#else
    key = key32;
    keyLen = (word32)sizeof(key32) / sizeof(byte);
#endif

    XMEMSET(&aes, 0, sizeof(Aes));

    ExpectIntEQ(wc_AesInit(NULL, NULL, INVALID_DEVID),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);

    EXPECT_TEST(test_wc_AesCtrSetKey_BadArgs(&aes, key, keyLen, iv));

#ifdef WOLFSSL_AES_128
    EXPECT_TEST(test_wc_AesCtrSetKey_WithKey(&aes, key16,
        (word32)sizeof(key16) / sizeof(byte), iv, 0));
#else
    EXPECT_TEST(test_wc_AesCtrSetKey_WithKey(&aes, key16,
        (word32)sizeof(key16) / sizeof(byte), iv, BAD_FUNC_ARG));
#endif
#ifdef WOLFSSL_AES_192
    EXPECT_TEST(test_wc_AesCtrSetKey_WithKey(&aes, key24,
        (word32)sizeof(key24) / sizeof(byte), iv, 0));
#else
    EXPECT_TEST(test_wc_AesCtrSetKey_WithKey(&aes, key24,
        (word32)sizeof(key24) / sizeof(byte), iv, BAD_FUNC_ARG));
#endif
#ifdef WOLFSSL_AES_256
    EXPECT_TEST(test_wc_AesCtrSetKey_WithKey(&aes, key32,
        (word32)sizeof(key32) / sizeof(byte), iv, 0));
#else
    EXPECT_TEST(test_wc_AesCtrSetKey_WithKey(&aes, key32,
        (word32)sizeof(key32) / sizeof(byte), iv, BAD_FUNC_ARG));
#endif

    ExpectIntEQ(wc_AesCtrSetKey(&aes, badKey16,
        (word32)sizeof(badKey16) / sizeof(byte), iv, AES_ENCRYPTION),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    wc_AesFree(&aes);
#endif /* !NO_AES && WOLFSSL_AES_COUNTER &&       */
       /* (!HAVE_FIPS || FIPS_VERSION_GE(7,0)) && */
       /* !HAVE_SELFTEST && !WOLFSSL_AFALG &&     */
       /* !WOLFSSL_KCAPI */

    return EXPECT_RESULT();
} /* END test_wc_AesCtrSetKey */

#if !defined(NO_AES) && defined(WOLFSSL_AES_COUNTER)
/* Assembly code doing 8 iterations at a time. */
#define CTR_LEN     (15 * WC_AES_BLOCK_SIZE)

static int test_wc_AesCtrEncrypt_BadArgs(Aes* aes, byte* key,
    word32 keyLen, byte* iv)
{
    EXPECT_DECLS;
    byte    plain[WC_AES_BLOCK_SIZE];
    byte    cipher[WC_AES_BLOCK_SIZE];
    byte    decrypted[WC_AES_BLOCK_SIZE];

    XMEMSET(plain, 0, WC_AES_BLOCK_SIZE);
    XMEMSET(cipher, 0, WC_AES_BLOCK_SIZE);
    XMEMSET(decrypted, 0, WC_AES_BLOCK_SIZE);

#if (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0)) && \
    !defined(HAVE_SELFTEST) && !defined(WOLFSSL_AFALG) && \
    !defined(WOLFSSL_KCAPI)
    ExpectIntEQ(wc_AesCtrSetKey(aes, key, keyLen, iv, AES_ENCRYPTION), 0);
#else
    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, iv, AES_ENCRYPTION), 0);
#endif
    ExpectIntEQ(wc_AesCtrEncrypt(NULL, NULL, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCtrEncrypt(aes, NULL, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCtrEncrypt(NULL, cipher, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCtrEncrypt(NULL, NULL, plain, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCtrEncrypt(aes, cipher, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCtrEncrypt(aes, NULL, plain, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCtrEncrypt(NULL, cipher, plain, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    return EXPECT_RESULT();
}

static int test_wc_AesCtrEncrypt_WithKey(Aes* aes, byte* key,
    word32 keyLen, byte* iv, byte* vector, byte* vector_enc, word32 vector_len)
{
    EXPECT_DECLS;
    byte    plain[WC_AES_BLOCK_SIZE * 2];
    byte    cipher[WC_AES_BLOCK_SIZE * 2];
    byte    decrypted[WC_AES_BLOCK_SIZE * 2];

    XMEMSET(plain, 0, WC_AES_BLOCK_SIZE * 2);
    XMEMSET(cipher, 0, WC_AES_BLOCK_SIZE * 2);
    XMEMSET(decrypted, 0, WC_AES_BLOCK_SIZE * 2);

#if (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0)) && \
    !defined(HAVE_SELFTEST) && !defined(WOLFSSL_AFALG) && \
    !defined(WOLFSSL_KCAPI)
    ExpectIntEQ(wc_AesCtrSetKey(aes, key, keyLen, iv, AES_ENCRYPTION), 0);
#else
    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, iv, AES_ENCRYPTION), 0);
#endif
    ExpectIntEQ(wc_AesCtrEncrypt(aes, cipher, vector, vector_len), 0);
    ExpectBufEQ(cipher, vector_enc, vector_len);
    /* Decrypt with wc_AesCtrEncrypt() */
#if (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0)) && \
    !defined(HAVE_SELFTEST) && !defined(WOLFSSL_AFALG) && \
    !defined(WOLFSSL_KCAPI)
    ExpectIntEQ(wc_AesCtrSetKey(aes, key, keyLen, iv, AES_ENCRYPTION), 0);
#else
    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, iv, AES_ENCRYPTION), 0);
#endif
    ExpectIntEQ(wc_AesCtrEncrypt(aes, decrypted, cipher, vector_len), 0);
    ExpectBufEQ(decrypted, vector, vector_len);

    return EXPECT_RESULT();
}

static int test_wc_AesCtrEncrypt_Chunking(Aes* aes, byte* key,
    word32 keyLen, byte* iv, byte* expected)
{
    EXPECT_DECLS;
#if defined(WOLFSSL_AFALG) || defined(WOLFSSL_KCAPI)
    (void)aes;
    (void)key;
    (void)keyLen;
    (void)iv;
    (void)expected;
#else
    int sz;
    int cnt;
    WC_DECLARE_VAR(plain, byte, CTR_LEN, NULL);
    WC_DECLARE_VAR(cipher, byte, CTR_LEN, NULL);
#ifdef HAVE_AES_DECRYPT
    WC_DECLARE_VAR(decrypted, byte, CTR_LEN, NULL);
#endif

    WC_ALLOC_VAR(plain, byte, CTR_LEN, NULL);
    WC_ALLOC_VAR(cipher, byte, CTR_LEN, NULL);
#ifdef HAVE_AES_DECRYPT
    WC_ALLOC_VAR(decrypted, byte, CTR_LEN, NULL);
#endif

#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC
    ExpectNotNull(plain);
    ExpectNotNull(cipher);
#ifdef HAVE_AES_DECRYPT
    ExpectNotNull(decrypted);
#endif
#endif

    XMEMSET(plain, 0, CTR_LEN);
    XMEMSET(cipher, 0, CTR_LEN);
    XMEMSET(decrypted, 0, CTR_LEN);

#if (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0)) && \
    !defined(HAVE_SELFTEST)
    ExpectIntEQ(wc_AesCtrSetKey(aes, key, keyLen, NULL, AES_ENCRYPTION), 0);
#else
    ExpectIntEQ(wc_AesSetKey(aes, key, keyLen, NULL, AES_ENCRYPTION), 0);
#endif
    /* Test multiple blocks. */
    for (sz = 1; sz <= CTR_LEN; sz++) {
        XMEMSET(cipher, 0x00, CTR_LEN);
        ExpectIntEQ(wc_AesSetIV(aes, iv), 0);
        for (cnt = 0; cnt + sz <= CTR_LEN; cnt += sz) {
            ExpectIntEQ(wc_AesCtrEncrypt(aes, cipher + cnt, plain + cnt, sz),
                0);
        }
        if (cnt < CTR_LEN) {
            ExpectIntEQ(wc_AesCtrEncrypt(aes, cipher + cnt, plain + cnt,
                CTR_LEN - cnt), 0);
        }
        ExpectBufEQ(cipher, expected, CTR_LEN);
    }

    WC_FREE_VAR(plain, NULL);
    WC_FREE_VAR(cipher, NULL);
#ifdef HAVE_AES_DECRYPT
    WC_FREE_VAR(decrypted, NULL);
#endif
#endif /* !WOLFSSL_AFALG && !WOLFSSL_KCAPI */
    return EXPECT_RESULT();
}

#if (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0)) && \
    !defined(HAVE_SELFTEST) && !defined(WOLFSSL_AFALG) && \
    !defined(WOLFSSL_KCAPI)
static int test_wc_AesCtrEncrypt_SameBuffer(Aes* aes, byte* key,
    word32 keyLen, byte* iv, byte* expected)
{
    EXPECT_DECLS;
    WC_DECLARE_VAR(plain, byte, CTR_LEN, NULL);
    WC_DECLARE_VAR(cipher, byte, CTR_LEN, NULL);

    WC_ALLOC_VAR(plain, byte, CTR_LEN, NULL);
    WC_ALLOC_VAR(cipher, byte, CTR_LEN, NULL);

#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC
    ExpectNotNull(plain);
    ExpectNotNull(cipher);
#endif

    XMEMSET(plain, 0, CTR_LEN);

    /* Testing using same buffer for input and output. */
    ExpectIntEQ(wc_AesCtrSetKey(aes, key, keyLen, iv, AES_ENCRYPTION), 0);
    XMEMCPY(cipher, plain, CTR_LEN);
    ExpectIntEQ(wc_AesCtrEncrypt(aes, cipher, cipher, CTR_LEN), 0);
    ExpectBufEQ(cipher, expected, CTR_LEN);

    WC_FREE_VAR(plain, NULL);
    WC_FREE_VAR(cipher, NULL);
    return EXPECT_RESULT();
}
#endif
#endif

/*******************************************************************************
 * AES-CTR counter overflow
 ******************************************************************************/

/*
 * Verify that AES-CTR counter carry-propagation works across byte boundaries
 * when the counter wraps around.  We encrypt three blocks starting from a
 * near-overflow IV (last four bytes = 0xFF,0xFF,0xFF,0xFE) in a single call,
 * then re-encrypt each block individually with the expected IV value for that
 * block position, and confirm the outputs match.
 *
 *  block 0 IV: ...0xFF,0xFF,0xFF,0xFE
 *  block 1 IV: ...0xFF,0xFF,0xFF,0xFF
 *  block 2 IV: ...0x01,0x00,0x00,0x00,0x00  (carry propagated through four FFs)
 */
int test_wc_AesCtrCounterOverflow(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(WOLFSSL_AES_COUNTER) && \
    defined(WOLFSSL_AES_128) && \
    (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0)) && \
    !defined(HAVE_SELFTEST) && !defined(WOLFSSL_AFALG) && \
    !defined(WOLFSSL_KCAPI)
    Aes enc;
    /* IV with last four bytes = 0xFF,0xFF,0xFF,0xFE  (one before two-step
     * overflow: 0xFE->0xFF is a normal increment; 0xFF->0x00 carries through
     * all four bytes into byte[11]). */
    static const byte iv_start[WC_AES_BLOCK_SIZE] = {
        0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00, 0xFF,0xFF,0xFF,0xFE
    };
    /* Expected IV for block 1: last byte incremented 0xFE->0xFF */
    static const byte iv_b1[WC_AES_BLOCK_SIZE] = {
        0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00, 0xFF,0xFF,0xFF,0xFF
    };
    /* Expected IV for block 2: carry propagates all four 0xFF bytes ->
     * byte[11] increments 0x00->0x01, bytes[12..15] all become 0x00. */
    static const byte iv_b2[WC_AES_BLOCK_SIZE] = {
        0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x01, 0x00,0x00,0x00,0x00
    };
    static const byte key[16] = {
        0x2b,0x7e,0x15,0x16, 0x28,0xae,0xd2,0xa6,
        0xab,0xf7,0x15,0x88, 0x09,0xcf,0x4f,0x3c
    };
    /* Three blocks of all-zero plaintext - simplifies comparison. */
    static const byte plain[3 * WC_AES_BLOCK_SIZE] = { 0 };

    byte cipher_combined[3 * WC_AES_BLOCK_SIZE];
    byte cipher_b0[WC_AES_BLOCK_SIZE];
    byte cipher_b1[WC_AES_BLOCK_SIZE];
    byte cipher_b2[WC_AES_BLOCK_SIZE];
    byte decrypted[3 * WC_AES_BLOCK_SIZE];

    XMEMSET(&enc, 0, sizeof(enc));
    ExpectIntEQ(wc_AesInit(&enc, NULL, INVALID_DEVID), 0);

    /* Encrypt three blocks in one call, spanning the carry-propagation
     * boundary. */
    ExpectIntEQ(wc_AesCtrSetKey(&enc, key, sizeof(key), iv_start,
        AES_ENCRYPTION), 0);
    ExpectIntEQ(wc_AesCtrEncrypt(&enc, cipher_combined, plain,
        sizeof(plain)), 0);

    /* Block 0: starts at iv_start. */
    ExpectIntEQ(wc_AesCtrSetKey(&enc, key, sizeof(key), iv_start,
        AES_ENCRYPTION), 0);
    ExpectIntEQ(wc_AesCtrEncrypt(&enc, cipher_b0, plain,
        WC_AES_BLOCK_SIZE), 0);

    /* Block 1: counter incremented once (0xFFFFFFFE -> 0xFFFFFFFF). */
    ExpectIntEQ(wc_AesCtrSetKey(&enc, key, sizeof(key), iv_b1,
        AES_ENCRYPTION), 0);
    ExpectIntEQ(wc_AesCtrEncrypt(&enc, cipher_b1, plain + WC_AES_BLOCK_SIZE,
        WC_AES_BLOCK_SIZE), 0);

    /* Block 2: counter wrapped (0xFFFFFFFF -> 0x00000000 with carry into
     * the next byte group). */
    ExpectIntEQ(wc_AesCtrSetKey(&enc, key, sizeof(key), iv_b2,
        AES_ENCRYPTION), 0);
    ExpectIntEQ(wc_AesCtrEncrypt(&enc, cipher_b2,
        plain + 2 * WC_AES_BLOCK_SIZE, WC_AES_BLOCK_SIZE), 0);

    /* Combined output must match per-block results. */
    ExpectBufEQ(cipher_combined, cipher_b0, WC_AES_BLOCK_SIZE);
    ExpectBufEQ(cipher_combined + WC_AES_BLOCK_SIZE, cipher_b1,
        WC_AES_BLOCK_SIZE);
    ExpectBufEQ(cipher_combined + 2 * WC_AES_BLOCK_SIZE, cipher_b2,
        WC_AES_BLOCK_SIZE);

    /* Blocks 1 and 2 must differ - different counter values produce different
     * key-stream blocks. */
    ExpectIntNE(XMEMCMP(cipher_b1, cipher_b2, WC_AES_BLOCK_SIZE), 0);

    /* Decrypt round-trip. */
    ExpectIntEQ(wc_AesCtrSetKey(&enc, key, sizeof(key), iv_start,
        AES_ENCRYPTION), 0);
    ExpectIntEQ(wc_AesCtrEncrypt(&enc, decrypted, cipher_combined,
        sizeof(cipher_combined)), 0);
    ExpectBufEQ(decrypted, plain, sizeof(plain));

    wc_AesFree(&enc);
#endif
    return EXPECT_RESULT();
}

/*
 * Testing wc_AesCtrEncrypt
 * Decrypt is an encrypt.
 */
int test_wc_AesCtrEncryptDecrypt(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(WOLFSSL_AES_COUNTER)
    Aes aes;
    byte vector[] = { /* Now is the time for all w/o trailing 0 */
        0x4e,0x6f,0x77,0x20,0x69,0x73,0x20,0x74,
        0x68,0x65,0x20,0x74,0x69,0x6d,0x65,0x20,
        0x66,0x6f,0x72,0x20,0x61,0x6c,0x6c,0x20
    };
#if defined(WOLFSSL_AES_128)
    byte key16[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    byte vector_enc16[] = {
        0x08, 0x75, 0x28, 0xdd, 0xf4, 0x84, 0xb1, 0x05,
        0x5d, 0xeb, 0xbe, 0x75, 0x1e, 0xb5, 0x2b, 0x8a,
        0x39, 0x70, 0x64, 0x06, 0x98, 0xa1, 0x82, 0x35,
    };
#endif
#if defined(WOLFSSL_AES_192)
    byte key24[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    byte vector_enc24[] = {
        0x35, 0xb1, 0x24, 0x8c, 0xe1, 0x57, 0xc6, 0xaa,
        0x00, 0xb1, 0x44, 0x6c, 0x49, 0xfb, 0x07, 0x48,
        0xd2, 0xa7, 0x1e, 0x81, 0xcf, 0xa0, 0x72, 0x54,
    };
#endif
#if defined(WOLFSSL_AES_256)
    byte key32[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    byte vector_enc32[] = {
        0x56, 0x35, 0x3f, 0xdd, 0xde, 0xa6, 0x15, 0x87,
        0x57, 0xdc, 0x34, 0x62, 0x9a, 0x68, 0x96, 0x51,
        0x14, 0xeb, 0xfa, 0xba, 0x30, 0x8e, 0xfb, 0x8a,
    };
#endif
#if defined(WOLFSSL_AES_128)
    byte expected16[CTR_LEN] = {
        0x46, 0x1a, 0x5f, 0xfd, 0x9d, 0xf7, 0x91, 0x71,
        0x35, 0x8e, 0x9e, 0x01, 0x77, 0xd8, 0x4e, 0xaa,
        0x5f, 0x1f, 0x16, 0x26, 0xf9, 0xcd, 0xee, 0x15,
        0xce, 0x4d, 0x4d, 0x3d, 0x17, 0x56, 0xa1, 0x48,
        0x36, 0x0b, 0x0e, 0x8b, 0x3d, 0x3b, 0x70, 0x02,
        0x2e, 0xd1, 0x0b, 0x61, 0x51, 0x05, 0xd6, 0x2b,
        0x4b, 0xb9, 0xaf, 0x26, 0x27, 0xed, 0x41, 0x50,
        0x08, 0xaf, 0xdd, 0xbf, 0x5b, 0x12, 0x4b, 0xb2,
        0x80, 0xd5, 0xba, 0x31, 0x31, 0x70, 0xfa, 0xfd,
        0x15, 0x19, 0x1e, 0x35, 0xc9, 0x10, 0x96, 0x6c,
        0xe4, 0x38, 0x61, 0xd8, 0x95, 0x30, 0x4d, 0xca,
        0xd8, 0x68, 0xc9, 0xdc, 0x6f, 0x8b, 0x86, 0x26,
        0x11, 0xee, 0x2d, 0x01, 0xd3, 0x0e, 0x35, 0xa2,
        0x4b, 0x26, 0x22, 0x8c, 0xd0, 0x4e, 0xda, 0x5d,
        0x49, 0x1e, 0x6d, 0xfa, 0x33, 0xcb, 0xa0, 0x0f,
        0x86, 0x8f, 0x83, 0xff, 0x3d, 0xbe, 0x6e, 0xfa,
        0xd2, 0x2b, 0x3e, 0x70, 0x21, 0x1c, 0xe8, 0x7b,
        0xe4, 0x01, 0x2c, 0xd0, 0x82, 0xe2, 0x7a, 0x4a,
        0xcf, 0x67, 0x82, 0x1c, 0x80, 0x79, 0x85, 0x5e,
        0xe5, 0xf9, 0x3a, 0x0d, 0x1a, 0xa7, 0x89, 0x29,
        0xee, 0xe7, 0x2b, 0xd6, 0x29, 0xac, 0xfa, 0xca,
        0xc8, 0xcb, 0x4e, 0x6c, 0x1f, 0x30, 0x5e, 0x95,
        0xa5, 0xa2, 0x17, 0xe2, 0x93, 0xd3, 0xe6, 0xbe,
        0x91, 0x37, 0x84, 0x01, 0xdb, 0x44, 0x4c, 0x60,
        0x1c, 0x2c, 0x64, 0x7d, 0xb7, 0x73, 0x12, 0x11,
        0xc2, 0x6a, 0xfd, 0xac, 0x6d, 0x85, 0xd8, 0xeb,
        0x0e, 0x70, 0xd3, 0x82, 0x93, 0x65, 0xff, 0x18,
        0x4e, 0x22, 0x07, 0x8a, 0xf6, 0xfd, 0x36, 0x9d,
        0x5c, 0x15, 0x1c, 0x84, 0x69, 0x13, 0x68, 0x78,
        0xf1, 0x04, 0x02, 0x66, 0xec, 0x37, 0xcc, 0x0d,
    };
#elif defined(WOLFSSL_AES_192)
    byte expected24[CTR_LEN] = {
        0x7b, 0xde, 0x53, 0xac, 0x88, 0x24, 0xe6, 0xde,
        0x68, 0xd4, 0x64, 0x18, 0x20, 0x96, 0x62, 0x68,
        0xb4, 0xc8, 0x6c, 0xa1, 0xae, 0xcc, 0x1e, 0x74,
        0x2a, 0xd6, 0x69, 0x5c, 0x71, 0x76, 0x92, 0x5b,
        0xd8, 0x61, 0xfa, 0x70, 0x8c, 0x80, 0x3e, 0xfc,
        0xdc, 0xd8, 0xbb, 0x31, 0x22, 0x47, 0x78, 0x02,
        0x5b, 0xa2, 0xb5, 0xb1, 0x41, 0x88, 0xc4, 0x84,
        0x82, 0xd7, 0x20, 0x11, 0xdc, 0x58, 0xea, 0xf9,
        0x2c, 0x43, 0x50, 0xc2, 0x33, 0x15, 0x58, 0x14,
        0xd0, 0xf3, 0xe5, 0xe1, 0x17, 0x86, 0x4b, 0xfb,
        0xdd, 0x83, 0xa3, 0xdd, 0x3a, 0xcc, 0x82, 0x05,
        0xb9, 0xf2, 0xfd, 0x8d, 0x3c, 0x08, 0x5f, 0xd9,
        0x79, 0x2d, 0xa3, 0xa0, 0xeb, 0xa3, 0xa2, 0xfe,
        0x7b, 0x2b, 0xf9, 0x5d, 0x32, 0x52, 0xeb, 0xee,
        0xe1, 0x68, 0xff, 0xe7, 0xb3, 0x0c, 0x08, 0x74,
        0x8d, 0x3b, 0xa9, 0x17, 0x4c, 0x2a, 0xc7, 0x97,
        0x99, 0xb7, 0xaf, 0x86, 0x17, 0xf9, 0xe4, 0x2c,
        0x5a, 0x4d, 0x6d, 0x7f, 0xfe, 0xb8, 0xaa, 0x9b,
        0xf8, 0xb6, 0xcb, 0x6f, 0x2f, 0xa4, 0x57, 0x61,
        0x88, 0x6c, 0x94, 0xaa, 0xf7, 0x97, 0xcf, 0xcd,
        0x19, 0x29, 0x9e, 0xf3, 0x30, 0xb8, 0xaa, 0x56,
        0x49, 0xcb, 0xf0, 0x56, 0xdd, 0xac, 0x4b, 0x41,
        0x00, 0xb3, 0x19, 0xdd, 0xef, 0x69, 0xd0, 0x9c,
        0xd1, 0x67, 0x48, 0x62, 0x9f, 0x56, 0x21, 0x2d,
        0x05, 0xb3, 0x4d, 0x0b, 0xac, 0xb6, 0x63, 0xf4,
        0x44, 0xfc, 0x43, 0xc0, 0xa9, 0x8c, 0x37, 0xd6,
        0xc3, 0x8c, 0xa4, 0x42, 0x68, 0x08, 0x2c, 0x1e,
        0xe7, 0xcc, 0xe4, 0x1f, 0x82, 0x9a, 0xe0, 0xfb,
        0x18, 0x84, 0x55, 0xaf, 0x02, 0xcc, 0x55, 0x13,
        0x7e, 0xc7, 0x05, 0xb8, 0xb9, 0x5e, 0x90, 0xc3,
    };
#else
    byte expected32[CTR_LEN] = {
        0x18, 0x5a, 0x48, 0xfd, 0xb7, 0xd5, 0x35, 0xf3,
        0x3f, 0xb9, 0x14, 0x16, 0xf3, 0x05, 0xf3, 0x71,
        0x72, 0x84, 0x88, 0x9a, 0x51, 0xe2, 0x97, 0xaa,
        0x65, 0xc1, 0x3c, 0x0b, 0x1e, 0x9f, 0x29, 0xb8,
        0xf4, 0xc8, 0x16, 0x9c, 0x47, 0x42, 0x0a, 0x9e,
        0xae, 0xf0, 0x75, 0x9b, 0x54, 0xdd, 0x8a, 0xa4,
        0x28, 0x97, 0xc1, 0x5a, 0xbb, 0x08, 0x52, 0x73,
        0xf7, 0x67, 0xa4, 0xb8, 0xc9, 0x37, 0x8d, 0x9e,
        0x23, 0x27, 0x68, 0xca, 0x2b, 0xb5, 0xd0, 0x1c,
        0x11, 0xe2, 0x2e, 0x7e, 0x17, 0x6b, 0x38, 0x99,
        0x82, 0x0c, 0x65, 0xed, 0x33, 0xd8, 0xa4, 0x47,
        0x43, 0x9c, 0x16, 0xa6, 0xab, 0x5d, 0x39, 0xad,
        0x88, 0x6a, 0x50, 0x86, 0xd4, 0x95, 0x1b, 0x91,
        0xb3, 0x91, 0x7d, 0x06, 0xe0, 0xfc, 0x5e, 0xd1,
        0xaf, 0x4c, 0xb3, 0xdb, 0x01, 0x01, 0xc9, 0x09,
        0xf1, 0x7b, 0x2b, 0x87, 0xe4, 0xcd, 0x93, 0x22,
        0x07, 0xdc, 0x35, 0x46, 0x8a, 0x1d, 0xf5, 0xe4,
        0x23, 0x01, 0x67, 0x00, 0x66, 0x7b, 0xd6, 0x56,
        0x0d, 0x57, 0x4f, 0x6f, 0x45, 0x82, 0x91, 0x58,
        0x81, 0x37, 0xcc, 0xb4, 0xa4, 0xa3, 0x3c, 0x57,
        0x42, 0x05, 0x95, 0xa3, 0x04, 0x1f, 0xfd, 0x32,
        0xb7, 0xc8, 0xbb, 0x14, 0xe7, 0xf1, 0xc1, 0x1f,
        0xe9, 0x33, 0x6a, 0xb0, 0x10, 0x0d, 0xfb, 0x91,
        0x88, 0xca, 0x20, 0x29, 0xeb, 0xcd, 0x9c, 0x71,
        0x07, 0xfd, 0x3f, 0x6b, 0x1f, 0xb3, 0x76, 0xb7,
        0x6b, 0xa1, 0xad, 0xbe, 0xd3, 0x45, 0xb5, 0xe9,
        0x04, 0x9a, 0xfd, 0x6a, 0x85, 0xa2, 0xbc, 0x4e,
        0xca, 0xdb, 0x84, 0xbc, 0x0e, 0x0c, 0x96, 0x65,
        0xc9, 0x95, 0x2b, 0xcb, 0x98, 0x8c, 0xd2, 0x78,
        0x85, 0x7e, 0x1a, 0xa2, 0x6a, 0x73, 0x90, 0x80,
    };
#endif
    byte    iv[]   = "1234567890abcdef";
    byte* key;
    word32 keyLen;
    byte* expected;

#if defined(WOLFSSL_AES_128)
    key = key16;
    keyLen = (word32)sizeof(key16) / sizeof(byte);
    expected = expected16;
#elif defined(WOLFSSL_AES_192)
    key = key24;
    keyLen = (word32)sizeof(key24) / sizeof(byte);
    expected = expected24;
#else
    key = key32;
    keyLen = (word32)sizeof(key32) / sizeof(byte);
    expected = expected32;
#endif

    /* Init stack variables. */
    XMEMSET(&aes, 0, sizeof(Aes));

    ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);

    EXPECT_TEST(test_wc_AesCtrEncrypt_BadArgs(&aes, key, keyLen, iv));

#ifdef WOLFSSL_AES_128
    EXPECT_TEST(test_wc_AesCtrEncrypt_WithKey(&aes, key16,
        (word32)sizeof(key16) / sizeof(byte), iv, vector, vector_enc16,
        (word32)sizeof(vector) / sizeof(byte)));
#endif
#ifdef WOLFSSL_AES_192
    EXPECT_TEST(test_wc_AesCtrEncrypt_WithKey(&aes, key24,
        (word32)sizeof(key24) / sizeof(byte), iv, vector, vector_enc24,
        (word32)sizeof(vector) / sizeof(byte)));
#endif
#ifdef WOLFSSL_AES_256
    EXPECT_TEST(test_wc_AesCtrEncrypt_WithKey(&aes, key32,
        (word32)sizeof(key32) / sizeof(byte), iv, vector, vector_enc32,
        (word32)sizeof(vector) / sizeof(byte)));
#endif

    EXPECT_TEST(test_wc_AesCtrEncrypt_Chunking(&aes, key, keyLen, iv,
        expected));
#if (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0)) && \
    !defined(HAVE_SELFTEST) && !defined(WOLFSSL_AFALG) && \
    !defined(WOLFSSL_KCAPI)
    EXPECT_TEST(test_wc_AesCtrEncrypt_SameBuffer(&aes, key, keyLen, iv,
        expected));
#endif

    wc_AesFree(&aes);
#endif
    return EXPECT_RESULT();
} /* END test_wc_AesCtrEncryptDecrypt */

/*******************************************************************************
 * AES-CTR unaligned buffers
 ******************************************************************************/

/*
 * Verify that wc_AesCtrEncrypt produces correct results when the input and
 * output buffers are byte-offset (unaligned).  Tests offsets 1, 2, and 3.
 * A 35-byte plaintext is used to exercise both the full-block path and the
 * partial-block leftover (35 = 2*16 + 3).
 */
int test_wc_AesCtrEncryptDecrypt_UnalignedBuffers(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(WOLFSSL_AES_COUNTER) && \
    defined(WOLFSSL_AES_128) && \
    (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0)) && \
    !defined(HAVE_SELFTEST) && !defined(WOLFSSL_AFALG) && \
    !defined(WOLFSSL_KCAPI)
    Aes aes;
    static const byte key[AES_128_KEY_SIZE] = {
        0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
        0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
    };
    static const byte iv[AES_IV_SIZE] = {
        0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
        0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
    };
    /* 35 bytes: two full blocks + 3-byte tail */
    static const byte plain[35] = {
        0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
        0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
        0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
        0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
        0x30, 0xc8, 0x1c
    };
    byte ref_ct[sizeof(plain)];
    byte in_buf[sizeof(plain) + 3];
    byte out_buf[sizeof(plain) + 3];
    int off;

    XMEMSET(&aes, 0, sizeof(aes));
    ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);

    /* Reference ciphertext with naturally-aligned buffers */
    ExpectIntEQ(wc_AesCtrSetKey(&aes, key, sizeof(key), iv, AES_ENCRYPTION), 0);
    ExpectIntEQ(wc_AesCtrEncrypt(&aes, ref_ct, plain, sizeof(plain)), 0);

    /* Encrypt with byte offsets 1, 2, 3 on both in and out */
    for (off = 1; off <= 3 && EXPECT_SUCCESS(); off++) {
        XMEMCPY(in_buf + off, plain, sizeof(plain));
        XMEMSET(out_buf, 0, sizeof(out_buf));
        ExpectIntEQ(wc_AesCtrSetKey(&aes, key, sizeof(key), iv,
            AES_ENCRYPTION), 0);
        ExpectIntEQ(wc_AesCtrEncrypt(&aes, out_buf + off, in_buf + off,
            sizeof(plain)), 0);
        ExpectBufEQ(out_buf + off, ref_ct, sizeof(plain));
    }

    /* Decrypt (CTR is symmetric: encrypt again to recover plaintext) */
    for (off = 1; off <= 3 && EXPECT_SUCCESS(); off++) {
        XMEMCPY(in_buf + off, ref_ct, sizeof(plain));
        XMEMSET(out_buf, 0, sizeof(out_buf));
        ExpectIntEQ(wc_AesCtrSetKey(&aes, key, sizeof(key), iv,
            AES_ENCRYPTION), 0);
        ExpectIntEQ(wc_AesCtrEncrypt(&aes, out_buf + off, in_buf + off,
            sizeof(plain)), 0);
        ExpectBufEQ(out_buf + off, plain, sizeof(plain));
    }

    wc_AesFree(&aes);
#endif
    return EXPECT_RESULT();
} /* END test_wc_AesCtrEncryptDecrypt_UnalignedBuffers */

/*
 * Cross-cipher test: CTR mode generates a keystream by ECB-encrypting the
 * counter block.  The counter starts at the IV value and increments as a
 * 128-bit big-endian integer after each block.
 * KS[i] = ECB_Encrypt(K, counter[i]);  C[i] = P[i] XOR KS[i]
 *
 * This test verifies that relationship: encrypt with CTR, then independently
 * compute the same ciphertext using ECB + counter increment, and compare.
 */
int test_wc_AesCtr_CrossCipher(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(WOLFSSL_AES_COUNTER) && defined(HAVE_AES_ECB) && \
    defined(WOLFSSL_AES_128) && \
    (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0)) && \
    !defined(HAVE_SELFTEST) && !defined(WOLFSSL_AFALG) && \
    !defined(WOLFSSL_KCAPI)
    Aes aes;
    /* NIST SP 800-38A F.5.1 (first two plaintext blocks, CTR) */
    static const byte key[AES_128_KEY_SIZE] = {
        0x2b,0x7e,0x15,0x16, 0x28,0xae,0xd2,0xa6,
        0xab,0xf7,0x15,0x88, 0x09,0xcf,0x4f,0x3c
    };
    static const byte iv[WC_AES_BLOCK_SIZE] = {
        0xf0,0xf1,0xf2,0xf3, 0xf4,0xf5,0xf6,0xf7,
        0xf8,0xf9,0xfa,0xfb, 0xfc,0xfd,0xfe,0xff
    };
    static const byte plain[2 * WC_AES_BLOCK_SIZE] = {
        0x6b,0xc1,0xbe,0xe2, 0x2e,0x40,0x9f,0x96,
        0xe9,0x3d,0x7e,0x11, 0x73,0x93,0x17,0x2a,
        0xae,0x2d,0x8a,0x57, 0x1e,0x03,0xac,0x9c,
        0x9e,0xb7,0x6f,0xac, 0x45,0xaf,0x8e,0x51
    };
    byte ctr_ct[sizeof(plain)];
    byte ecb_ct[sizeof(plain)];
    byte counter[WC_AES_BLOCK_SIZE];
    byte ks[WC_AES_BLOCK_SIZE];
    int  i, j;

    XMEMSET(&aes, 0, sizeof(aes));
    ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);

    /* CTR ciphertext via the API */
    ExpectIntEQ(wc_AesCtrSetKey(&aes, key, sizeof(key), iv, AES_ENCRYPTION), 0);
    ExpectIntEQ(wc_AesCtrEncrypt(&aes, ctr_ct, plain, sizeof(plain)), 0);

    /* Manually compute CTR via ECB + big-endian counter increment */
    ExpectIntEQ(wc_AesSetKey(&aes, key, sizeof(key), NULL, AES_ENCRYPTION), 0);
    XMEMCPY(counter, iv, WC_AES_BLOCK_SIZE);

    for (i = 0; i < 2; i++) {
        /* KS[i] = ECB_E(K, counter[i]) */
        ExpectIntEQ(wc_AesEcbEncrypt(&aes, ks, counter, WC_AES_BLOCK_SIZE), 0);
        if (EXPECT_SUCCESS()) {
            /* C[i] = P[i] XOR KS[i] */
            for (j = 0; j < WC_AES_BLOCK_SIZE; j++)
                ecb_ct[i * WC_AES_BLOCK_SIZE + j] =
                    plain[i * WC_AES_BLOCK_SIZE + j] ^ ks[j];
            /* Increment 128-bit counter big-endian (carry from last byte
             * upward) */
            for (j = WC_AES_BLOCK_SIZE - 1; j >= 0 && (++counter[j]) == 0; j--)
                ;
        }
    }

    /* CTR ciphertext must equal the manually computed ECB+counter ciphertext */
    ExpectBufEQ(ctr_ct, ecb_ct, sizeof(plain));

    wc_AesFree(&aes);
#endif
    return EXPECT_RESULT();
} /* END test_wc_AesCtr_CrossCipher */

/*******************************************************************************
 * AES-GCM
 ******************************************************************************/

/*
 * test function for wc_AesGcmSetKey()
 */
int test_wc_AesGcmSetKey(void)
{
    EXPECT_DECLS;
#if  !defined(NO_AES) && defined(HAVE_AESGCM)
    Aes aes;
#ifdef WOLFSSL_AES_128
    byte key16[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
#endif
#ifdef WOLFSSL_AES_192
    byte key24[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37
    };
#endif
#ifdef WOLFSSL_AES_256
    byte key32[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
#endif
    byte badKey16[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65
    };
    byte badKey24[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36
    };
    byte badKey32[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x37, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65
    };
    byte* key;
    word32 keyLen;

#ifdef WOLFSSL_AES_128
    key = key16;
    keyLen = sizeof(key16)/sizeof(byte);
#elif defined(WOLFSSL_AES_192)
    key = key24;
    keyLen = sizeof(key24)/sizeof(byte);
#else
    key = key32;
    keyLen = sizeof(key32)/sizeof(byte);
#endif

    ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);

#ifdef WOLFSSL_AES_128
    ExpectIntEQ(wc_AesGcmSetKey(&aes, key16, sizeof(key16)/sizeof(byte)), 0);
#endif
#ifdef WOLFSSL_AES_192
    ExpectIntEQ(wc_AesGcmSetKey(&aes, key24, sizeof(key24)/sizeof(byte)), 0);
#endif
#ifdef WOLFSSL_AES_256
    ExpectIntEQ(wc_AesGcmSetKey(&aes, key32, sizeof(key32)/sizeof(byte)), 0);
#endif

    /* Pass in bad args. */
    ExpectIntEQ(wc_AesGcmSetKey(NULL, NULL, keyLen),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmSetKey(NULL, key, keyLen),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#if (!defined(HAVE_FIPS) || !defined(HAVE_FIPS_VERSION) || \
        (HAVE_FIPS_VERSION > 6)) && !defined(HAVE_SELFTEST)
    ExpectIntEQ(wc_AesGcmSetKey(&aes, NULL, keyLen),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
    ExpectIntEQ(wc_AesGcmSetKey(&aes, badKey16, sizeof(badKey16)/sizeof(byte)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmSetKey(&aes, badKey24, sizeof(badKey24)/sizeof(byte)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmSetKey(&aes, badKey32, sizeof(badKey32)/sizeof(byte)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    wc_AesFree(&aes);
#endif
    return EXPECT_RESULT();
} /* END test_wc_AesGcmSetKey */

int test_wc_AesGcmEncryptDecrypt_Sizes(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(HAVE_AESGCM) && defined(WOLFSSL_AES_256) && \
    !defined(WOLFSSL_AFALG) && !defined(WOLFSSL_KCAPI)
    #define GCM_LEN     (WC_AES_BLOCK_SIZE * 16)
    byte expTagShort[WC_AES_BLOCK_SIZE][WC_AES_BLOCK_SIZE] = {
        {
            0x41, 0x5d, 0x72, 0x1e, 0xe0, 0x17, 0x7c, 0xe2,
            0x33, 0xfb, 0x0e, 0xab, 0x5a, 0x08, 0x4c, 0xb0,
        },
        {
            0x26, 0xe8, 0xc0, 0x9f, 0xbc, 0x70, 0x1d, 0x7e,
            0x22, 0x43, 0x26, 0x1b, 0x21, 0x9d, 0x2c, 0x5b,
        },
        {
            0x94, 0x8f, 0x24, 0xeb, 0xd1, 0x5b, 0x3d, 0x2a,
            0x31, 0xf2, 0xe4, 0xf9, 0x07, 0xc8, 0xe7, 0x63,
        },
        {
            0x62, 0xa9, 0x79, 0x97, 0x6c, 0x93, 0x77, 0x52,
            0x2f, 0xbf, 0x51, 0xb2, 0xc2, 0xf7, 0xe5, 0xf4,
        },
        {
            0xa5, 0x44, 0xfd, 0x3c, 0x16, 0x2a, 0x05, 0x7a,
            0x52, 0xe1, 0xed, 0x13, 0x49, 0x81, 0x93, 0x7a,
        },
        {
            0xe5, 0x3b, 0xd4, 0xc9, 0x9f, 0x9e, 0xf0, 0x55,
            0xcd, 0x80, 0xb7, 0x42, 0xa4, 0xaf, 0x33, 0x88,
        },
        {
            0x65, 0xa8, 0xc9, 0xa7, 0x8b, 0xdb, 0x80, 0xfe,
            0x40, 0xfe, 0xb6, 0xe4, 0x00, 0xf9, 0x23, 0x72,
        },
        {
            0xe0, 0x1e, 0xec, 0x38, 0x45, 0xf0, 0x9c, 0x82,
            0x72, 0xac, 0x2f, 0xec, 0x3b, 0x2b, 0xfe, 0x75,
        },
        {
            0xea, 0xb4, 0x5b, 0x4d, 0x76, 0x98, 0xc8, 0x34,
            0x07, 0x1d, 0x7b, 0xaf, 0x36, 0xfa, 0x72, 0x9b,
        },
        {
            0xcf, 0x2b, 0x12, 0x7a, 0x5a, 0x5a, 0x73, 0x73,
            0xb5, 0xb6, 0xb6, 0xb0, 0x42, 0xa5, 0xc0, 0x23,
        },
        {
            0xc1, 0x14, 0x52, 0xd0, 0xd0, 0x1d, 0xca, 0xce,
            0x2e, 0x4c, 0xd8, 0x94, 0x62, 0x92, 0xf6, 0x9c,
        },
        {
            0x5b, 0xd9, 0xa6, 0x8c, 0x34, 0x0e, 0x81, 0xaf,
            0x09, 0xc3, 0x44, 0x74, 0x35, 0xce, 0x89, 0x92,
        },
        {
            0xdc, 0x9f, 0xd0, 0xd5, 0xaa, 0x38, 0xe2, 0xce,
            0x75, 0x88, 0x64, 0xee, 0x7a, 0x5d, 0x44, 0xa4,
        },
        {
            0xc3, 0x35, 0xfe, 0xa9, 0x9d, 0x3d, 0x75, 0xb7,
            0xba, 0xdd, 0x9e, 0xa5, 0x5d, 0xd3, 0x65, 0x80,
        },
        {
            0x1d, 0x1a, 0x04, 0x99, 0xb5, 0x8b, 0xe8, 0xec,
            0x81, 0xd1, 0xde, 0xd3, 0x3a, 0x09, 0xb4, 0x9f,
        },
        {
            0xb8, 0x14, 0x0a, 0xc3, 0x8b, 0x88, 0x87, 0xa1,
            0xdf, 0xfa, 0x6d, 0x15, 0x70, 0xde, 0xff, 0x3b,
        },
    };
    byte expected[GCM_LEN] = {
        0x9a, 0x10, 0xb2, 0x60, 0x38, 0x65, 0x46, 0x81,
        0xc0, 0xa7, 0x0d, 0x3f, 0x5b, 0x4f, 0x27,
    };
    byte expTagLong[][WC_AES_BLOCK_SIZE] = {
        {
            0xdd, 0x1c, 0x3d, 0x12, 0xa4, 0x16, 0xa5, 0xf7,
            0x67, 0xc5, 0x58, 0xb8, 0xda, 0x22, 0x6c, 0x22,
        },
        {
            0xbe, 0x5e, 0x04, 0x61, 0xae, 0x36, 0x61, 0xfb,
            0x86, 0x66, 0xda, 0x62, 0xaa, 0x36, 0x7e, 0x22,
        },
        {
            0x18, 0xc3, 0xf5, 0xcf, 0x76, 0x24, 0xd4, 0x5c,
            0xbb, 0xeb, 0xb3, 0x0a, 0x7a, 0x53, 0x64, 0x9b,
        },
        {
            0xe0, 0xaa, 0xe9, 0x10, 0x41, 0x16, 0x72, 0x1b,
            0x16, 0xd6, 0xd9, 0xcd, 0x2f, 0xe4, 0xd2, 0xe8,
        },
        {
            0xfa, 0xdc, 0x28, 0x4a, 0x65, 0x96, 0xe0, 0x73,
            0xfb, 0xcd, 0x2b, 0x35, 0xa0, 0x68, 0xde, 0x60,
        },
    };
    byte key32[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    Aes aes;
    byte tag[WC_AES_BLOCK_SIZE];
    byte iv[] = "1234567890a";
    word32 ivLen = (word32)sizeof(iv)/sizeof(byte);
    int sz;
    int i;
    WC_DECLARE_VAR(plain, byte, GCM_LEN, NULL);
    WC_DECLARE_VAR(cipher, byte, GCM_LEN, NULL);
#ifdef HAVE_AES_DECRYPT
    WC_DECLARE_VAR(decrypted, byte, GCM_LEN, NULL);
#endif

    WC_ALLOC_VAR(plain, byte, GCM_LEN, NULL);
    WC_ALLOC_VAR(cipher, byte, GCM_LEN, NULL);
#ifdef HAVE_AES_DECRYPT
    WC_ALLOC_VAR(decrypted, byte, GCM_LEN, NULL);
#endif

#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC
    ExpectNotNull(plain);
    ExpectNotNull(cipher);
#ifdef HAVE_AES_DECRYPT
    ExpectNotNull(decrypted);
#endif
#endif

    XMEMSET(&aes, 0, sizeof(Aes));
    XMEMSET(plain, 0xa5, GCM_LEN);

    ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);

    ExpectIntEQ(wc_AesGcmSetKey(&aes, key32, sizeof(key32)/sizeof(byte)), 0);
    for (sz = 0; sz < WC_AES_BLOCK_SIZE; sz++) {
        XMEMSET(cipher, 0, GCM_LEN);
        ExpectIntEQ(wc_AesGcmEncrypt(&aes, cipher, plain, sz, iv, ivLen, tag,
            sizeof(tag), NULL, 0), 0);
        ExpectBufEQ(cipher, expected, sz);
        ExpectBufEQ(tag, expTagShort[sz], WC_AES_BLOCK_SIZE);

#ifdef HAVE_AES_DECRYPT
        XMEMSET(decrypted, 0xff, GCM_LEN);
        ExpectIntEQ(wc_AesGcmDecrypt(&aes, decrypted, cipher, sz, iv, ivLen,
            tag, sizeof(tag), NULL, 0), 0);
        ExpectBufEQ(decrypted, plain, sz);
#endif
    }

    i = 0;
    for (sz = WC_AES_BLOCK_SIZE; sz <= GCM_LEN; sz *= 2) {
        XMEMSET(cipher, 0, GCM_LEN);
        ExpectIntEQ(wc_AesGcmEncrypt(&aes, cipher, plain, sz, iv, ivLen, tag,
            sizeof(tag), NULL, 0), 0);
        ExpectBufEQ(tag, expTagLong[i], WC_AES_BLOCK_SIZE);
        i++;

#ifdef HAVE_AES_DECRYPT
        XMEMSET(decrypted, 0xff, GCM_LEN);
        ExpectIntEQ(wc_AesGcmDecrypt(&aes, decrypted, cipher, sz, iv, ivLen,
            tag, sizeof(tag), NULL, 0), 0);
        ExpectBufEQ(decrypted, plain, sz);
#endif
    }

    wc_AesFree(&aes);
    WC_FREE_VAR(plain, NULL);
    WC_FREE_VAR(cipher, NULL);
#ifdef HAVE_AES_DECRYPT
    WC_FREE_VAR(decrypted, NULL);
#endif
#endif
    return EXPECT_RESULT();
}

/*
 * test function for wc_AesGcmEncrypt and wc_AesGcmDecrypt
 */
int test_wc_AesGcmEncryptDecrypt(void)
{
    EXPECT_DECLS;
    /* WOLFSSL_AFALG requires 12 byte IV */
#if !defined(NO_AES) && defined(HAVE_AESGCM) && defined(WOLFSSL_AES_256) && \
    !defined(WOLFSSL_AFALG) && !defined(WOLFSSL_DEVCRYPTO_AES)
    Aes  aes;
    byte key32[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    byte vector[] = { /* Now is the time for all w/o trailing 0 */
        0x4e,0x6f,0x77,0x20,0x69,0x73,0x20,0x74,
        0x68,0x65,0x20,0x74,0x69,0x6d,0x65,0x20,
        0x66,0x6f,0x72,0x20,0x61,0x6c,0x6c,0x20
    };
    const byte a[] = {
        0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
        0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
        0xab, 0xad, 0xda, 0xd2
    };
    byte iv[] = "1234567890a";
    byte longIV[] = "1234567890abcdefghij";
    byte enc[sizeof(vector)];
    byte resultT[WC_AES_BLOCK_SIZE];
    byte dec[sizeof(vector)];

    /* Init stack variables. */
    XMEMSET(&aes, 0, sizeof(Aes));
    XMEMSET(enc, 0, sizeof(vector));
    XMEMSET(dec, 0, sizeof(vector));
    XMEMSET(resultT, 0, WC_AES_BLOCK_SIZE);

    ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);

    ExpectIntEQ(wc_AesGcmSetKey(&aes, key32, sizeof(key32)/sizeof(byte)), 0);
    ExpectIntEQ(wc_AesGcmEncrypt(&aes, enc, vector, sizeof(vector), iv,
        sizeof(iv)/sizeof(byte), resultT, sizeof(resultT), a, sizeof(a)), 0);
    ExpectIntEQ(wc_AesGcmDecrypt(&aes, dec, enc, sizeof(vector), iv,
        sizeof(iv)/sizeof(byte), resultT, sizeof(resultT), a, sizeof(a)), 0);
    ExpectIntEQ(XMEMCMP(vector, dec, sizeof(vector)), 0);

    /* Test bad args for wc_AesGcmEncrypt and wc_AesGcmDecrypt */
    ExpectIntEQ(wc_AesGcmEncrypt(NULL, enc, vector, sizeof(vector), iv,
        sizeof(iv)/sizeof(byte), resultT, sizeof(resultT), a, sizeof(a)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmEncrypt(&aes, enc, vector, sizeof(vector), iv,
        sizeof(iv)/sizeof(byte), resultT, sizeof(resultT) + 1, a, sizeof(a)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmEncrypt(&aes, enc, vector, sizeof(vector), iv,
        sizeof(iv)/sizeof(byte), resultT, sizeof(resultT) - 5, a, sizeof(a)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));

#if (defined(HAVE_FIPS) && defined(HAVE_FIPS_VERSION) && \
        (HAVE_FIPS_VERSION == 2)) || defined(HAVE_SELFTEST) || \
        defined(WOLFSSL_AES_GCM_FIXED_IV_AAD)
        /* FIPS does not check the lower bound of ivSz */
#else
        ExpectIntEQ(wc_AesGcmEncrypt(&aes, enc, vector, sizeof(vector), iv, 0,
            resultT, sizeof(resultT), a, sizeof(a)),
            WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif

    /* This case is now considered good. Long IVs are now allowed.
     * Except for the original FIPS release, it still has an upper
     * bound on the IV length. */
#if (!defined(HAVE_FIPS) || \
    (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))) && \
    !defined(WOLFSSL_AES_GCM_FIXED_IV_AAD)
    ExpectIntEQ(wc_AesGcmEncrypt(&aes, enc, vector, sizeof(vector), longIV,
        sizeof(longIV)/sizeof(byte), resultT, sizeof(resultT), a, sizeof(a)),
        0);
#else
    (void)longIV;
#endif /* Old FIPS */
    /* END wc_AesGcmEncrypt */

#ifdef HAVE_AES_DECRYPT
    ExpectIntEQ(wc_AesGcmDecrypt(NULL, dec, enc, sizeof(enc)/sizeof(byte), iv,
        sizeof(iv)/sizeof(byte), resultT, sizeof(resultT), a, sizeof(a)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmDecrypt(&aes, NULL, enc, sizeof(enc)/sizeof(byte), iv,
        sizeof(iv)/sizeof(byte), resultT, sizeof(resultT), a, sizeof(a)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmDecrypt(&aes, dec, NULL, sizeof(enc)/sizeof(byte), iv,
        sizeof(iv)/sizeof(byte), resultT, sizeof(resultT), a, sizeof(a)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmDecrypt(&aes, dec, enc, sizeof(enc)/sizeof(byte), NULL,
        sizeof(iv)/sizeof(byte), resultT, sizeof(resultT), a, sizeof(a)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmDecrypt(&aes, dec, enc, sizeof(enc)/sizeof(byte), iv,
        sizeof(iv)/sizeof(byte), NULL, sizeof(resultT), a, sizeof(a)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    #if (defined(HAVE_FIPS) && FIPS_VERSION_LE(2,0) && defined(WOLFSSL_ARMASM))
    ExpectIntEQ(wc_AesGcmDecrypt(&aes, dec, enc, sizeof(enc)/sizeof(byte), iv,
        sizeof(iv)/sizeof(byte), resultT, sizeof(resultT) + 1, a, sizeof(a)),
        WC_NO_ERR_TRACE(AES_GCM_AUTH_E));
    #else
    ExpectIntEQ(wc_AesGcmDecrypt(&aes, dec, enc, sizeof(enc)/sizeof(byte), iv,
        sizeof(iv)/sizeof(byte), resultT, sizeof(resultT) + 1, a, sizeof(a)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    #endif
    #if ((defined(HAVE_FIPS) && defined(HAVE_FIPS_VERSION) && \
            (HAVE_FIPS_VERSION == 2)) || defined(HAVE_SELFTEST)) && \
            !defined(WOLFSSL_AES_GCM_FIXED_IV_AAD)
            /* FIPS does not check the lower bound of ivSz */
    #else
        ExpectIntEQ(wc_AesGcmDecrypt(&aes, dec, enc, sizeof(enc)/sizeof(byte),
            iv, 0, resultT, sizeof(resultT), a, sizeof(a)),
            WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    #endif
#endif /* HAVE_AES_DECRYPT */

    wc_AesFree(&aes);
#endif
    return EXPECT_RESULT();

} /* END test_wc_AesGcmEncryptDecrypt */

/*******************************************************************************
 * AES-GCM overlapping (in-place) buffers
 ******************************************************************************/

/*
 * Verify that wc_AesGcmEncrypt / wc_AesGcmDecrypt work correctly when the
 * plaintext/ciphertext pointer is the same buffer (in == out).  AES-GCM uses
 * CTR mode for encryption (XOR keystream), so in-place operation is safe.
 * The auth tag is always a separate buffer, so it is not affected.
 *
 * McGrew & Viega Test Case 4 (AES-128) is used for the key and IV; a 24-byte
 * slice of the test-case plaintext provides a non-block-aligned length.
 */
int test_wc_AesGcmEncryptDecrypt_InPlace(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(HAVE_AESGCM) && defined(WOLFSSL_AES_128) && \
    !defined(WOLFSSL_AFALG) && !defined(WOLFSSL_DEVCRYPTO_AES)
    Aes aes;
    static const byte key[AES_128_KEY_SIZE] = {
        0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
        0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08
    };
    static const byte iv[GCM_NONCE_MID_SZ] = {
        0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
        0xde, 0xca, 0xf8, 0x88
    };
    static const byte aad[20] = {
        0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
        0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
        0xab, 0xad, 0xda, 0xd2
    };
    static const byte plain[24] = {
        0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
        0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
        0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda
    };
    byte ref_ct[sizeof(plain)], ref_tag[WC_AES_BLOCK_SIZE];
    byte buf[sizeof(plain)],    tag[WC_AES_BLOCK_SIZE];

    XMEMSET(&aes, 0, sizeof(aes));
    ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesGcmSetKey(&aes, key, sizeof(key)), 0);

    /* Reference ciphertext with separate in/out buffers */
    XMEMSET(ref_ct,  0, sizeof(ref_ct));
    XMEMSET(ref_tag, 0, sizeof(ref_tag));
    ExpectIntEQ(wc_AesGcmEncrypt(&aes, ref_ct, plain, sizeof(plain),
        iv, sizeof(iv), ref_tag, sizeof(ref_tag), aad, sizeof(aad)), 0);

    /* Encrypt in-place (out == in) - must produce the same ciphertext/tag */
    XMEMSET(tag, 0, sizeof(tag));
    XMEMCPY(buf, plain, sizeof(buf));
    ExpectIntEQ(wc_AesGcmEncrypt(&aes, buf, buf, sizeof(buf),
        iv, sizeof(iv), tag, sizeof(tag), aad, sizeof(aad)), 0);
    ExpectBufEQ(buf, ref_ct,  sizeof(buf));
    ExpectBufEQ(tag, ref_tag, sizeof(tag));

#ifdef HAVE_AES_DECRYPT
    /* Decrypt in-place - must recover original plaintext */
    ExpectIntEQ(wc_AesGcmDecrypt(&aes, buf, buf, sizeof(buf),
        iv, sizeof(iv), tag, sizeof(tag), aad, sizeof(aad)), 0);
    ExpectBufEQ(buf, plain, sizeof(buf));
#endif

    wc_AesFree(&aes);
#endif
    return EXPECT_RESULT();
} /* END test_wc_AesGcmEncryptDecrypt_InPlace */

/*******************************************************************************
 * AES-GCM unaligned buffers
 ******************************************************************************/

/*
 * Verify that wc_AesGcmEncrypt / wc_AesGcmDecrypt produce correct results
 * when plaintext, ciphertext, and AAD buffers are byte-offset (unaligned).
 * Tests offsets 1, 2, and 3.  Exercises the GHASH path as well as the CTR
 * encryption, both of which may use SIMD intrinsics sensitive to alignment.
 */
int test_wc_AesGcmEncryptDecrypt_UnalignedBuffers(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(HAVE_AESGCM) && defined(WOLFSSL_AES_128) && \
    !defined(WOLFSSL_AFALG) && !defined(WOLFSSL_DEVCRYPTO_AES)
    Aes aes;
    /* Same key / IV / AAD as InPlace test (McGrew TC4, AES-128) */
    static const byte key[AES_128_KEY_SIZE] = {
        0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
        0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08
    };
    static const byte iv[GCM_NONCE_MID_SZ] = {
        0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
        0xde, 0xca, 0xf8, 0x88
    };
    static const byte aad[20] = {
        0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
        0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
        0xab, 0xad, 0xda, 0xd2
    };
    static const byte plain[24] = {
        0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
        0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
        0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda
    };
    byte ref_ct[sizeof(plain)], ref_tag[WC_AES_BLOCK_SIZE];
    byte in_buf[sizeof(plain) + 3], out_buf[sizeof(plain) + 3];
    byte aad_buf[sizeof(aad) + 3];
    byte tag[WC_AES_BLOCK_SIZE];
    int off;

    XMEMSET(&aes, 0, sizeof(aes));
    ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesGcmSetKey(&aes, key, sizeof(key)), 0);

    /* Reference ciphertext/tag with naturally-aligned buffers */
    XMEMSET(ref_ct,  0, sizeof(ref_ct));
    XMEMSET(ref_tag, 0, sizeof(ref_tag));
    ExpectIntEQ(wc_AesGcmEncrypt(&aes, ref_ct, plain, sizeof(plain),
        iv, sizeof(iv), ref_tag, sizeof(ref_tag), aad, sizeof(aad)), 0);

    /* Encrypt with byte offsets 1, 2, 3 on plaintext, ciphertext, and AAD */
    for (off = 1; off <= 3 && EXPECT_SUCCESS(); off++) {
        XMEMCPY(in_buf  + off, plain, sizeof(plain));
        XMEMCPY(aad_buf + off, aad,   sizeof(aad));
        XMEMSET(out_buf, 0, sizeof(out_buf));
        XMEMSET(tag,     0, sizeof(tag));
        ExpectIntEQ(wc_AesGcmEncrypt(&aes, out_buf + off, in_buf + off,
            sizeof(plain), iv, sizeof(iv), tag, sizeof(tag),
            aad_buf + off, sizeof(aad)), 0);
        ExpectBufEQ(out_buf + off, ref_ct,  sizeof(plain));
        ExpectBufEQ(tag,           ref_tag, sizeof(tag));
    }

#ifdef HAVE_AES_DECRYPT
    /* Decrypt with byte offsets 1, 2, 3 */
    for (off = 1; off <= 3 && EXPECT_SUCCESS(); off++) {
        XMEMCPY(in_buf  + off, ref_ct, sizeof(plain));
        XMEMCPY(aad_buf + off, aad,    sizeof(aad));
        XMEMSET(out_buf, 0, sizeof(out_buf));
        ExpectIntEQ(wc_AesGcmDecrypt(&aes, out_buf + off, in_buf + off,
            sizeof(plain), iv, sizeof(iv), ref_tag, sizeof(ref_tag),
            aad_buf + off, sizeof(aad)), 0);
        ExpectBufEQ(out_buf + off, plain, sizeof(plain));
    }
#endif

    wc_AesFree(&aes);
#endif
    return EXPECT_RESULT();
} /* END test_wc_AesGcmEncryptDecrypt_UnalignedBuffers */

/*
 * Cross-cipher test: AES-GCM encrypts plaintext using AES-CTR starting at the
 * counter block J0+1.  For a 12-byte nonce, J0 = nonce || 0x00000001, so the
 * first counter block used for data is nonce || 0x00000002.
 *
 * This test verifies that the ciphertext portion of a GCM encrypt equals the
 * output of AES-CTR with the initial counter set to nonce || 0x00000002.
 */
int test_wc_AesGcm_CrossCipher(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(HAVE_AESGCM) && defined(WOLFSSL_AES_COUNTER) && \
    defined(WOLFSSL_AES_128) && !defined(WOLFSSL_AFALG) && \
    !defined(WOLFSSL_DEVCRYPTO_AES) && \
    (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0)) && \
    !defined(HAVE_SELFTEST) && !defined(WOLFSSL_KCAPI)
    Aes aes;
    /* McGrew/Viega GCM test case 4 (128-bit key, 12-byte nonce) */
    static const byte key[AES_128_KEY_SIZE] = {
        0xfe,0xff,0xe9,0x92, 0x86,0x65,0x73,0x1c,
        0x6d,0x6a,0x8f,0x94, 0x67,0x30,0x83,0x08
    };
    static const byte nonce[GCM_NONCE_MID_SZ] = {
        0xca,0xfe,0xba,0xbe, 0xfa,0xce,0xdb,0xad,
        0xde,0xca,0xf8,0x88
    };
    static const byte aad[20] = {
        0xfe,0xed,0xfa,0xce, 0xde,0xad,0xbe,0xef,
        0xfe,0xed,0xfa,0xce, 0xde,0xad,0xbe,0xef,
        0xab,0xad,0xda,0xd2
    };
    static const byte plain[24] = {
        0xd9,0x31,0x32,0x25, 0xf8,0x84,0x06,0xe5,
        0xa5,0x59,0x09,0xc5, 0xaf,0xf5,0x26,0x9a,
        0x86,0xa7,0xa9,0x53, 0x15,0x34,0xf7,0xda
    };
    /* CTR initial counter = nonce || 0x00000002  (GCM's J0+1) */
    byte ctr_iv[WC_AES_BLOCK_SIZE];
    byte gcm_ct[sizeof(plain)], gcm_tag[WC_AES_BLOCK_SIZE];
    byte ctr_ct[sizeof(plain)];

    XMEMSET(&aes, 0, sizeof(aes));
    ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);

    /* GCM ciphertext */
    ExpectIntEQ(wc_AesGcmSetKey(&aes, key, sizeof(key)), 0);
    ExpectIntEQ(wc_AesGcmEncrypt(&aes, gcm_ct, plain, sizeof(plain),
        nonce, sizeof(nonce), gcm_tag, sizeof(gcm_tag), aad, sizeof(aad)), 0);

    /* CTR ciphertext starting at J0+1: nonce || 0x00000002 */
    XMEMCPY(ctr_iv, nonce, sizeof(nonce));
    ctr_iv[12] = 0x00; ctr_iv[13] = 0x00; ctr_iv[14] = 0x00; ctr_iv[15] = 0x02;
    ExpectIntEQ(wc_AesCtrSetKey(&aes, key, sizeof(key), ctr_iv,
        AES_ENCRYPTION), 0);
    ExpectIntEQ(wc_AesCtrEncrypt(&aes, ctr_ct, plain, sizeof(plain)), 0);

    /* GCM ciphertext portion must equal the CTR ciphertext */
    ExpectBufEQ(gcm_ct, ctr_ct, sizeof(plain));

    wc_AesFree(&aes);
#endif
    return EXPECT_RESULT();
} /* END test_wc_AesGcm_CrossCipher */

/*
 * test function for mixed (one-shot encryption + stream decryption) AES GCM
 * using a long IV (older FIPS does NOT support long IVs).  Relates to zd15423
 */
int test_wc_AesGcmMixedEncDecLongIV(void)
{
    EXPECT_DECLS;
#if  (!defined(HAVE_FIPS) || \
      (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))) && \
     !defined(NO_AES) && defined(HAVE_AESGCM) && defined(WOLFSSL_AES_256) && \
     defined(WOLFSSL_AESGCM_STREAM)
    const byte key[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    const byte in[] = {
        0x4e,0x6f,0x77,0x20,0x69,0x73,0x20,0x74,
        0x68,0x65,0x20,0x74,0x69,0x6d,0x65,0x20,
        0x66,0x6f,0x72,0x20,0x61,0x6c,0x6c,0x20
    };
    const byte aad[] = {
        0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
        0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
        0xab, 0xad, 0xda, 0xd2
    };
    Aes aesEnc;
    Aes aesDec;
    byte iv[] = "1234567890abcdefghij";
    byte out[sizeof(in)];
    byte plain[sizeof(in)];
    byte tag[WC_AES_BLOCK_SIZE];

    XMEMSET(&aesEnc, 0, sizeof(Aes));
    XMEMSET(&aesDec, 0, sizeof(Aes));
    XMEMSET(out, 0, sizeof(out));
    XMEMSET(plain, 0, sizeof(plain));
    XMEMSET(tag, 0, sizeof(tag));

    /* Perform one-shot encryption using long IV */
    ExpectIntEQ(wc_AesInit(&aesEnc, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesGcmSetKey(&aesEnc, key, sizeof(key)), 0);
    ExpectIntEQ(wc_AesGcmEncrypt(&aesEnc, out, in, sizeof(in), iv, sizeof(iv),
        tag, sizeof(tag), aad, sizeof(aad)), 0);

    /* Perform streaming decryption using long IV */
    ExpectIntEQ(wc_AesInit(&aesDec, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesGcmInit(&aesDec, key, sizeof(key), iv, sizeof(iv)), 0);
    ExpectIntEQ(wc_AesGcmDecryptUpdate(&aesDec, plain, out, sizeof(out), aad,
        sizeof(aad)), 0);
    ExpectIntEQ(wc_AesGcmDecryptFinal(&aesDec, tag, sizeof(tag)), 0);
    ExpectIntEQ(XMEMCMP(plain, in, sizeof(in)), 0);

    /* Free resources */
    wc_AesFree(&aesEnc);
    wc_AesFree(&aesDec);
#endif
    return EXPECT_RESULT();

} /* END wc_AesGcmMixedEncDecLongIV */

/*******************************************************************************
 * AES-GCM non-standard nonce lengths
 ******************************************************************************/

/*
 * Non-standard (non-96-bit) nonce tests for AES-GCM.
 *
 * NIST SP 800-38D requires a different counter-derivation path when
 * len(IV) != 96 bits (12 bytes): J0 = GHASH_H(IV || pad || len64(IV)).
 * Most hardware accelerators only support the 12-byte fast path, so these
 * tests are skipped on FIPS builds and hardware-only backends.
 *
 * Three sections:
 *  1. 1-byte IV  - FIPS CAVS example vector (AES-128).
 *  2. 60-byte IV - McGrew & Viega Test Case 12 (AES-192).
 *  3. Variable IV length loop (1..GCM_NONCE_MAX_SZ, AES-128): roundtrip and
 *     uniqueness - each distinct IV length must produce distinct ciphertext.
 *  4. Zero-length IV must be rejected with an error.
 */
int test_wc_AesGcmNonStdNonce(void)
{
    EXPECT_DECLS;
/* Hardware accelerators and FIPS mode only support the 12-byte IV fast path
 * and cannot exercise the GHASH-based counter derivation. */
#if !defined(NO_AES) && defined(HAVE_AESGCM) && \
    !defined(HAVE_FIPS) && \
    !defined(WOLFSSL_AFALG) && !defined(WOLFSSL_KCAPI)

    /* ------------------------------------------------------------------
     * Section 1: 1-byte IV, AES-128
     * Key, IV, plaintext, AAD, ciphertext, and tag are taken directly from
     * the FIPS CAVS non-96-bit-IV example vectors, also present in
     * wolfcrypt/test/test.c (variable k3/iv3/p3/a3/c3/t3).
     * ------------------------------------------------------------------ */
#ifdef WOLFSSL_AES_128
    {
        static const byte key_1b[AES_128_KEY_SIZE] = {
            0xbb,0x01,0xd7,0x03, 0x81,0x1c,0x10,0x1a,
            0x35,0xe0,0xff,0xd2, 0x91,0xba,0xf2,0x4b
        };
        static const byte iv_1b[1] = { 0xca };
        static const byte pt_1b[AES_128_KEY_SIZE] = {
            0x57,0xce,0x45,0x1f, 0xa5,0xe2,0x35,0xa5,
            0x8e,0x1a,0xa2,0x3b, 0x77,0xcb,0xaf,0xe2
        };
        static const byte aad_1b[AES_128_KEY_SIZE] = {
            0x40,0xfc,0xdc,0xd7, 0x4a,0xd7,0x8b,0xf1,
            0x3e,0x7c,0x60,0x55, 0x50,0x51,0xdd,0x54
        };
        static const byte expCt_1b[AES_128_KEY_SIZE] = {
            0x6b,0x5f,0xb3,0x9d, 0xc1,0xc5,0x7a,0x4f,
            0xf3,0x51,0x4d,0xc2, 0xd5,0xf0,0xd0,0x07
        };
        static const byte expTag_1b[WC_AES_BLOCK_SIZE] = {
            0x06,0x90,0xed,0x01, 0x34,0xdd,0xc6,0x95,
            0x31,0x2e,0x2a,0xf9, 0x57,0x7a,0x1e,0xa6
        };
        Aes enc;
#ifdef HAVE_AES_DECRYPT
        Aes dec;
#endif
        byte ct[AES_128_KEY_SIZE];
        byte tag[WC_AES_BLOCK_SIZE];
#ifdef HAVE_AES_DECRYPT
        byte pt[AES_128_KEY_SIZE];
#endif

        XMEMSET(&enc, 0, sizeof(enc));
        ExpectIntEQ(wc_AesInit(&enc, NULL, INVALID_DEVID), 0);
        ExpectIntEQ(wc_AesGcmSetKey(&enc, key_1b, sizeof(key_1b)), 0);
        ExpectIntEQ(wc_AesGcmEncrypt(&enc, ct, pt_1b, sizeof(pt_1b),
            iv_1b, sizeof(iv_1b), tag, sizeof(tag),
            aad_1b, sizeof(aad_1b)), 0);
        ExpectBufEQ(ct,  expCt_1b,  sizeof(expCt_1b));
        ExpectBufEQ(tag, expTag_1b, sizeof(expTag_1b));

#ifdef HAVE_AES_DECRYPT
        XMEMSET(&dec, 0, sizeof(dec));
        ExpectIntEQ(wc_AesInit(&dec, NULL, INVALID_DEVID), 0);
        ExpectIntEQ(wc_AesGcmSetKey(&dec, key_1b, sizeof(key_1b)), 0);
        ExpectIntEQ(wc_AesGcmDecrypt(&dec, pt, ct, sizeof(ct),
            iv_1b, sizeof(iv_1b), tag, sizeof(tag),
            aad_1b, sizeof(aad_1b)), 0);
        ExpectBufEQ(pt, pt_1b, sizeof(pt_1b));
        wc_AesFree(&dec);
#endif
        wc_AesFree(&enc);
    }
#endif /* WOLFSSL_AES_128 */

    /* ------------------------------------------------------------------
     * Section 2: 60-byte IV, AES-192
     * McGrew & Viega Test Case 12 - uses the shared 60-byte plaintext and
     * 20-byte AAD from Test Case 16, but with a 60-byte (non-96-bit) IV.
     * Reference: wolfcrypt/test/test.c vectors k2/iv2/p/a/c2/t2.
     * ------------------------------------------------------------------ */
#ifdef WOLFSSL_AES_192
    {
        static const byte key_60b[AES_192_KEY_SIZE] = {
            0xfe,0xff,0xe9,0x92, 0x86,0x65,0x73,0x1c,
            0x6d,0x6a,0x8f,0x94, 0x67,0x30,0x83,0x08,
            0xfe,0xff,0xe9,0x92, 0x86,0x65,0x73,0x1c
        };
        static const byte iv_60b[60] = {
            0x93,0x13,0x22,0x5d, 0xf8,0x84,0x06,0xe5,
            0x55,0x90,0x9c,0x5a, 0xff,0x52,0x69,0xaa,
            0x6a,0x7a,0x95,0x38, 0x53,0x4f,0x7d,0xa1,
            0xe4,0xc3,0x03,0xd2, 0xa3,0x18,0xa7,0x28,
            0xc3,0xc0,0xc9,0x51, 0x56,0x80,0x95,0x39,
            0xfc,0xf0,0xe2,0x42, 0x9a,0x6b,0x52,0x54,
            0x16,0xae,0xdb,0xf5, 0xa0,0xde,0x6a,0x57,
            0xa6,0x37,0xb3,0x9b
        };
        static const byte pt_60b[60] = {
            0xd9,0x31,0x32,0x25, 0xf8,0x84,0x06,0xe5,
            0xa5,0x59,0x09,0xc5, 0xaf,0xf5,0x26,0x9a,
            0x86,0xa7,0xa9,0x53, 0x15,0x34,0xf7,0xda,
            0x2e,0x4c,0x30,0x3d, 0x8a,0x31,0x8a,0x72,
            0x1c,0x3c,0x0c,0x95, 0x95,0x68,0x09,0x53,
            0x2f,0xcf,0x0e,0x24, 0x49,0xa6,0xb5,0x25,
            0xb1,0x6a,0xed,0xf5, 0xaa,0x0d,0xe6,0x57,
            0xba,0x63,0x7b,0x39
        };
        static const byte aad_60b[20] = {
            0xfe,0xed,0xfa,0xce, 0xde,0xad,0xbe,0xef,
            0xfe,0xed,0xfa,0xce, 0xde,0xad,0xbe,0xef,
            0xab,0xad,0xda,0xd2
        };
        static const byte expCt_60b[60] = {
            0xd2,0x7e,0x88,0x68, 0x1c,0xe3,0x24,0x3c,
            0x48,0x30,0x16,0x5a, 0x8f,0xdc,0xf9,0xff,
            0x1d,0xe9,0xa1,0xd8, 0xe6,0xb4,0x47,0xef,
            0x6e,0xf7,0xb7,0x98, 0x28,0x66,0x6e,0x45,
            0x81,0xe7,0x90,0x12, 0xaf,0x34,0xdd,0xd9,
            0xe2,0xf0,0x37,0x58, 0x9b,0x29,0x2d,0xb3,
            0xe6,0x7c,0x03,0x67, 0x45,0xfa,0x22,0xe7,
            0xe9,0xb7,0x37,0x3b
        };
        static const byte expTag_60b[WC_AES_BLOCK_SIZE] = {
            0xdc,0xf5,0x66,0xff, 0x29,0x1c,0x25,0xbb,
            0xb8,0x56,0x8f,0xc3, 0xd3,0x76,0xa6,0xd9
        };
        Aes enc;
#ifdef HAVE_AES_DECRYPT
        Aes dec;
#endif
        byte ct[60];
        byte tag[WC_AES_BLOCK_SIZE];
#ifdef HAVE_AES_DECRYPT
        byte pt[60];
#endif

        XMEMSET(&enc, 0, sizeof(enc));
        ExpectIntEQ(wc_AesInit(&enc, NULL, INVALID_DEVID), 0);
        ExpectIntEQ(wc_AesGcmSetKey(&enc, key_60b, sizeof(key_60b)), 0);
        ExpectIntEQ(wc_AesGcmEncrypt(&enc, ct, pt_60b, sizeof(pt_60b),
            iv_60b, sizeof(iv_60b), tag, sizeof(tag),
            aad_60b, sizeof(aad_60b)), 0);
        ExpectBufEQ(ct,  expCt_60b,  sizeof(expCt_60b));
        ExpectBufEQ(tag, expTag_60b, sizeof(expTag_60b));

#ifdef HAVE_AES_DECRYPT
        XMEMSET(&dec, 0, sizeof(dec));
        ExpectIntEQ(wc_AesInit(&dec, NULL, INVALID_DEVID), 0);
        ExpectIntEQ(wc_AesGcmSetKey(&dec, key_60b, sizeof(key_60b)), 0);
        ExpectIntEQ(wc_AesGcmDecrypt(&dec, pt, ct, sizeof(ct),
            iv_60b, sizeof(iv_60b), tag, sizeof(tag),
            aad_60b, sizeof(aad_60b)), 0);
        ExpectBufEQ(pt, pt_60b, sizeof(pt_60b));
        wc_AesFree(&dec);
#endif
        wc_AesFree(&enc);
    }
#endif /* WOLFSSL_AES_192 */

    /* ------------------------------------------------------------------
     * Section 3: Variable IV length loop, AES-128
     * Iterates IV lengths 1..GCM_NONCE_MAX_SZ.  For each length:
     *  - Encrypt succeeds and produces a full-length ciphertext.
     *  - Decrypt recovers the original plaintext (auth-tag verification).
     *  - Adjacent IV lengths produce different ciphertext (uniqueness).
     * ------------------------------------------------------------------ */
#ifdef WOLFSSL_AES_128
    {
        static const byte key_var[AES_128_KEY_SIZE] = {
            0xfe,0xff,0xe9,0x92, 0x86,0x65,0x73,0x1c,
            0x6d,0x6a,0x8f,0x94, 0x67,0x30,0x83,0x08
        };
        /* IV material: reuse the key bytes, take the first ivLen bytes. */
        static const byte ivMat[GCM_NONCE_MAX_SZ] = {
            0xfe,0xff,0xe9,0x92, 0x86,0x65,0x73,0x1c,
            0x6d,0x6a,0x8f,0x94, 0x67,0x30,0x83,0x08
        };
        static const byte plain_var[AES_128_KEY_SIZE] = {
            0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07,
            0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f
        };
        Aes enc;
        byte ct[AES_128_KEY_SIZE];
        byte ctPrev[AES_128_KEY_SIZE]; /* ciphertext from previous ivLen */
        byte tag[WC_AES_BLOCK_SIZE];
#ifdef HAVE_AES_DECRYPT
        byte ptOut[AES_128_KEY_SIZE];
#endif
        word32 ivLen;
        int hasPrev = 0;

        XMEMSET(&enc, 0, sizeof(enc));
        ExpectIntEQ(wc_AesInit(&enc, NULL, INVALID_DEVID), 0);
        ExpectIntEQ(wc_AesGcmSetKey(&enc, key_var, sizeof(key_var)), 0);

        for (ivLen = 1;
             ivLen <= GCM_NONCE_MAX_SZ && EXPECT_SUCCESS();
             ivLen++) {
            XMEMSET(ct,  0, sizeof(ct));
            XMEMSET(tag, 0, sizeof(tag));

            ExpectIntEQ(wc_AesGcmEncrypt(&enc, ct, plain_var,
                sizeof(plain_var), ivMat, ivLen, tag, sizeof(tag),
                NULL, 0), 0);

            /* Adjacent IV lengths must produce distinct ciphertext. */
            if (hasPrev) {
                ExpectIntNE(XMEMCMP(ct, ctPrev, sizeof(ct)), 0);
            }
            XMEMCPY(ctPrev, ct, sizeof(ct));
            hasPrev = 1;

#ifdef HAVE_AES_DECRYPT
            XMEMSET(ptOut, 0, sizeof(ptOut));
            ExpectIntEQ(wc_AesGcmDecrypt(&enc, ptOut, ct, sizeof(ct),
                ivMat, ivLen, tag, sizeof(tag), NULL, 0), 0);
            ExpectBufEQ(ptOut, plain_var, sizeof(plain_var));
#endif
        }
        wc_AesFree(&enc);
    }
#endif /* WOLFSSL_AES_128 */

    /* ------------------------------------------------------------------
     * Section 4: Zero-length IV must be rejected.
     * ------------------------------------------------------------------ */
#ifdef WOLFSSL_AES_128
    {
        static const byte key_z[AES_128_KEY_SIZE] = { 0 };
        static const byte pt_z[1] = { 0 };
        Aes enc;
        byte ct[1];
        byte tag[WC_AES_BLOCK_SIZE];

        XMEMSET(&enc, 0, sizeof(enc));
        ExpectIntEQ(wc_AesInit(&enc, NULL, INVALID_DEVID), 0);
        ExpectIntEQ(wc_AesGcmSetKey(&enc, key_z, sizeof(key_z)), 0);
#ifdef HAVE_SELFTEST
        ExpectIntEQ(wc_AesGcmEncrypt(&enc, ct, pt_z, sizeof(pt_z),
            NULL, 0, tag, sizeof(tag), NULL, 0), 0);
#else
        ExpectIntNE(wc_AesGcmEncrypt(&enc, ct, pt_z, sizeof(pt_z),
            NULL, 0, tag, sizeof(tag), NULL, 0), 0);
#endif
        wc_AesFree(&enc);
    }
#endif

#endif /* !NO_AES && HAVE_AESGCM && !HAVE_FIPS && !HW */
    return EXPECT_RESULT();
} /* END test_wc_AesGcmNonStdNonce */

/*
 * Testing streaming AES-GCM API.
 */
int test_wc_AesGcmStream(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(WOLFSSL_AES_128) && defined(HAVE_AESGCM) && \
    defined(WOLFSSL_AESGCM_STREAM)
    int i;
    WC_RNG rng[1];
    Aes aesEnc[1];
    Aes aesDec[1];
    byte tag[WC_AES_BLOCK_SIZE];
    byte in[WC_AES_BLOCK_SIZE * 3 + 2] = { 0, };
    byte out[WC_AES_BLOCK_SIZE * 3 + 2];
    byte plain[WC_AES_BLOCK_SIZE * 3 + 2];
    byte aad[WC_AES_BLOCK_SIZE * 3 + 2] = { 0, };
    byte key[AES_128_KEY_SIZE] = { 0, };
    byte iv[AES_IV_SIZE] = { 1, };
    byte ivOut[AES_IV_SIZE];
    static const byte expTagAAD1[WC_AES_BLOCK_SIZE] = {
        0x6c, 0x35, 0xe6, 0x7f, 0x59, 0x9e, 0xa9, 0x2f,
        0x27, 0x2d, 0x5f, 0x8e, 0x7e, 0x42, 0xd3, 0x05
    };
    static const byte expTagPlain1[WC_AES_BLOCK_SIZE] = {
        0x24, 0xba, 0x57, 0x95, 0xd0, 0x27, 0x9e, 0x78,
        0x3a, 0x88, 0x4c, 0x0a, 0x5d, 0x50, 0x23, 0xd1
    };
    static const byte expTag[WC_AES_BLOCK_SIZE] = {
        0x22, 0x91, 0x70, 0xad, 0x42, 0xc3, 0xad, 0x96,
        0xe0, 0x31, 0x57, 0x60, 0xb7, 0x92, 0xa3, 0x6d
    };

    XMEMSET(&rng, 0, sizeof(WC_RNG));
    XMEMSET(&aesEnc, 0, sizeof(Aes));
    XMEMSET(&aesDec, 0, sizeof(Aes));

    /* Create a random for generating IV/nonce. */
    ExpectIntEQ(wc_InitRng(rng), 0);

    /* Initialize data structures. */
    ExpectIntEQ(wc_AesInit(aesEnc, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesInit(aesDec, NULL, INVALID_DEVID), 0);

    /* BadParameters to streaming init. */
    ExpectIntEQ(wc_AesGcmEncryptInit(NULL, NULL, 0, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmDecryptInit(NULL, NULL, 0, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmDecryptInit(aesEnc, NULL, AES_128_KEY_SIZE, NULL,
        0), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmDecryptInit(aesEnc, NULL, 0, NULL, GCM_NONCE_MID_SZ),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    /* Bad parameters to encrypt update. */
    ExpectIntEQ(wc_AesGcmEncryptUpdate(NULL, NULL, NULL, 0, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmEncryptUpdate(aesEnc, NULL, NULL, 1, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmEncryptUpdate(aesEnc, NULL, in, 1, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmEncryptUpdate(aesEnc, out, NULL, 1, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmEncryptUpdate(aesEnc, NULL, NULL, 0, NULL, 1),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    /* Bad parameters to decrypt update. */
    ExpectIntEQ(wc_AesGcmDecryptUpdate(NULL, NULL, NULL, 0, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmDecryptUpdate(aesDec, NULL, NULL, 1, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmDecryptUpdate(aesDec, NULL, in, 1, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmDecryptUpdate(aesDec, out, NULL, 1, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmDecryptUpdate(aesDec, NULL, NULL, 0, NULL, 1),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    /* Bad parameters to encrypt final. */
    ExpectIntEQ(wc_AesGcmEncryptFinal(NULL, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmEncryptFinal(NULL, tag, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmEncryptFinal(NULL, NULL, WC_AES_BLOCK_SIZE),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmEncryptFinal(aesEnc, tag, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmEncryptFinal(aesEnc, NULL, WC_AES_BLOCK_SIZE),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmEncryptFinal(aesEnc, tag, WC_AES_BLOCK_SIZE + 1),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    /* Bad parameters to decrypt final. */
    ExpectIntEQ(wc_AesGcmDecryptFinal(NULL, NULL, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmDecryptFinal(NULL, tag, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmDecryptFinal(NULL, NULL, WC_AES_BLOCK_SIZE),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmDecryptFinal(aesDec, tag, 0),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmDecryptFinal(aesDec, NULL, WC_AES_BLOCK_SIZE),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesGcmDecryptFinal(aesDec, tag, WC_AES_BLOCK_SIZE + 1),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    /* Check calling final before setting key fails. */
    ExpectIntEQ(wc_AesGcmEncryptFinal(aesEnc, tag, sizeof(tag)),
        WC_NO_ERR_TRACE(MISSING_KEY));
    ExpectIntEQ(wc_AesGcmEncryptFinal(aesDec, tag, sizeof(tag)),
        WC_NO_ERR_TRACE(MISSING_KEY));
    /* Check calling update before setting key else fails. */
    ExpectIntEQ(wc_AesGcmEncryptUpdate(aesEnc, NULL, NULL, 0, aad, 1),
        WC_NO_ERR_TRACE(MISSING_KEY));
    ExpectIntEQ(wc_AesGcmDecryptUpdate(aesDec, NULL, NULL, 0, aad, 1),
        WC_NO_ERR_TRACE(MISSING_KEY));

    /* Set key but not IV. */
    ExpectIntEQ(wc_AesGcmInit(aesEnc, key, sizeof(key), NULL, 0), 0);
    ExpectIntEQ(wc_AesGcmInit(aesDec, key, sizeof(key), NULL, 0), 0);
    /* Check calling final before setting IV fails. */
    ExpectIntEQ(wc_AesGcmEncryptFinal(aesEnc, tag, sizeof(tag)),
        WC_NO_ERR_TRACE(MISSING_IV));
    ExpectIntEQ(wc_AesGcmEncryptFinal(aesDec, tag, sizeof(tag)),
        WC_NO_ERR_TRACE(MISSING_IV));
    /* Check calling update before setting IV else fails. */
    ExpectIntEQ(wc_AesGcmEncryptUpdate(aesEnc, NULL, NULL, 0, aad, 1),
        WC_NO_ERR_TRACE(MISSING_IV));
    ExpectIntEQ(wc_AesGcmDecryptUpdate(aesDec, NULL, NULL, 0, aad, 1),
        WC_NO_ERR_TRACE(MISSING_IV));

    /* Set IV using fixed part IV and external IV APIs. */
    ExpectIntEQ(wc_AesGcmSetIV(aesEnc, GCM_NONCE_MID_SZ, iv, AES_IV_FIXED_SZ,
        rng), 0);
    ExpectIntEQ(wc_AesGcmEncryptInit_ex(aesEnc, NULL, 0, ivOut,
        GCM_NONCE_MID_SZ), 0);
    ExpectIntEQ(wc_AesGcmSetExtIV(aesDec, ivOut, GCM_NONCE_MID_SZ), 0);
    ExpectIntEQ(wc_AesGcmInit(aesDec, NULL, 0, NULL, 0), 0);
    /* Encrypt and decrypt data. */
    ExpectIntEQ(wc_AesGcmEncryptUpdate(aesEnc, out, in, 1, aad, 1), 0);
    ExpectIntEQ(wc_AesGcmDecryptUpdate(aesDec, plain, out, 1, aad, 1), 0);
    ExpectIntEQ(XMEMCMP(plain, in, 1), 0);
    /* Finalize and check tag matches. */
    ExpectIntEQ(wc_AesGcmEncryptFinal(aesEnc, tag, WC_AES_BLOCK_SIZE), 0);
    ExpectIntEQ(wc_AesGcmDecryptFinal(aesDec, tag, WC_AES_BLOCK_SIZE), 0);

    /* Set key and IV through streaming init API. */
    wc_AesFree(aesEnc);
    wc_AesFree(aesDec);
    ExpectIntEQ(wc_AesInit(aesEnc, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesInit(aesDec, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesGcmInit(aesEnc, key, sizeof(key), iv, AES_IV_SIZE), 0);
    ExpectIntEQ(wc_AesGcmInit(aesDec, key, sizeof(key), iv, AES_IV_SIZE), 0);
    /* Encrypt/decrypt one block and AAD of one block. */
    ExpectIntEQ(wc_AesGcmEncryptUpdate(aesEnc, out, in, WC_AES_BLOCK_SIZE, aad,
        WC_AES_BLOCK_SIZE), 0);
    ExpectIntEQ(wc_AesGcmDecryptUpdate(aesDec, plain, out, WC_AES_BLOCK_SIZE,
        aad, WC_AES_BLOCK_SIZE), 0);
    ExpectIntEQ(XMEMCMP(plain, in, WC_AES_BLOCK_SIZE), 0);
    /* Finalize and check tag matches. */
    ExpectIntEQ(wc_AesGcmEncryptFinal(aesEnc, tag, WC_AES_BLOCK_SIZE), 0);
    ExpectIntEQ(wc_AesGcmDecryptFinal(aesDec, tag, WC_AES_BLOCK_SIZE), 0);

    /* Set key and IV through streaming init API. */
    wc_AesFree(aesEnc);
    wc_AesFree(aesDec);
    ExpectIntEQ(wc_AesInit(aesEnc, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesInit(aesDec, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesGcmInit(aesEnc, key, sizeof(key), iv, AES_IV_SIZE), 0);
    ExpectIntEQ(wc_AesGcmInit(aesDec, key, sizeof(key), iv, AES_IV_SIZE), 0);
    /* No data to encrypt/decrypt one byte of AAD. */
    ExpectIntEQ(wc_AesGcmEncryptUpdate(aesEnc, NULL, NULL, 0, aad, 1), 0);
    ExpectIntEQ(wc_AesGcmDecryptUpdate(aesDec, NULL, NULL, 0, aad, 1), 0);
    /* Finalize and check tag matches. */
    ExpectIntEQ(wc_AesGcmEncryptFinal(aesEnc, tag, WC_AES_BLOCK_SIZE), 0);
    ExpectIntEQ(XMEMCMP(tag, expTagAAD1, WC_AES_BLOCK_SIZE), 0);
    ExpectIntEQ(wc_AesGcmDecryptFinal(aesDec, tag, WC_AES_BLOCK_SIZE), 0);

    /* Set key and IV through streaming init API. */
    wc_AesFree(aesEnc);
    wc_AesFree(aesDec);
    ExpectIntEQ(wc_AesInit(aesEnc, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesInit(aesDec, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesGcmInit(aesEnc, key, sizeof(key), iv, AES_IV_SIZE), 0);
    ExpectIntEQ(wc_AesGcmInit(aesDec, key, sizeof(key), iv, AES_IV_SIZE), 0);
    /* Encrypt/decrypt one byte and no AAD. */
    ExpectIntEQ(wc_AesGcmEncryptUpdate(aesEnc, out, in, 1, NULL, 0), 0);
    ExpectIntEQ(wc_AesGcmDecryptUpdate(aesDec, plain, out, 1, NULL, 0), 0);
    ExpectIntEQ(XMEMCMP(plain, in, 1), 0);
    /* Finalize and check tag matches. */
    ExpectIntEQ(wc_AesGcmEncryptFinal(aesEnc, tag, WC_AES_BLOCK_SIZE), 0);
    ExpectIntEQ(XMEMCMP(tag, expTagPlain1, WC_AES_BLOCK_SIZE), 0);
    ExpectIntEQ(wc_AesGcmDecryptFinal(aesDec, tag, WC_AES_BLOCK_SIZE), 0);

    /* Set key and IV through streaming init API. */
    wc_AesFree(aesEnc);
    wc_AesFree(aesDec);
    ExpectIntEQ(wc_AesInit(aesEnc, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesInit(aesDec, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesGcmInit(aesEnc, key, sizeof(key), iv, AES_IV_SIZE), 0);
    ExpectIntEQ(wc_AesGcmInit(aesDec, key, sizeof(key), iv, AES_IV_SIZE), 0);
    /* Encryption AES is one byte at a time */
    for (i = 0; i < (int)sizeof(aad); i++) {
        ExpectIntEQ(wc_AesGcmEncryptUpdate(aesEnc, NULL, NULL, 0, aad + i, 1),
            0);
    }
    for (i = 0; i < (int)sizeof(in); i++) {
        ExpectIntEQ(wc_AesGcmEncryptUpdate(aesEnc, out + i, in + i, 1, NULL, 0),
            0);
    }
    /* Decryption AES is two bytes at a time */
    for (i = 0; i < (int)sizeof(aad); i += 2) {
        ExpectIntEQ(wc_AesGcmDecryptUpdate(aesDec, NULL, NULL, 0, aad + i, 2),
            0);
    }
    for (i = 0; i < (int)sizeof(aad); i += 2) {
        ExpectIntEQ(wc_AesGcmDecryptUpdate(aesDec, plain + i, out + i, 2, NULL,
            0), 0);
    }
    ExpectIntEQ(XMEMCMP(plain, in, sizeof(in)), 0);
    /* Finalize and check tag matches. */
    ExpectIntEQ(wc_AesGcmEncryptFinal(aesEnc, tag, WC_AES_BLOCK_SIZE), 0);
    ExpectIntEQ(XMEMCMP(tag, expTag, WC_AES_BLOCK_SIZE), 0);
    ExpectIntEQ(wc_AesGcmDecryptFinal(aesDec, tag, WC_AES_BLOCK_SIZE), 0);

    /* Check streaming encryption can be decrypted with one shot. */
    wc_AesFree(aesDec);
    ExpectIntEQ(wc_AesInit(aesDec, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesGcmInit(aesDec, key, sizeof(key), iv, AES_IV_SIZE), 0);
    ExpectIntEQ(wc_AesGcmSetKey(aesDec, key, sizeof(key)), 0);
    ExpectIntEQ(wc_AesGcmDecrypt(aesDec, plain, out, sizeof(in), iv,
        AES_IV_SIZE, tag, WC_AES_BLOCK_SIZE, aad, sizeof(aad)), 0);
    ExpectIntEQ(XMEMCMP(plain, in, sizeof(in)), 0);

    wc_AesFree(aesEnc);
    wc_AesFree(aesDec);
    wc_FreeRng(rng);
#endif
    return EXPECT_RESULT();
} /* END test_wc_AesGcmStream */

/*******************************************************************************
 * AES-GCM streaming mid-stream state corruption
 ******************************************************************************/

/*
 * Verify that the AES-GCM streaming API enforces its state flags even when
 * they are cleared after a streaming session has already been started.
 *
 * The state is represented by three bitfields in struct Aes:
 *   gcmKeySet  - set by wc_AesGcmInit/SetKey
 *   nonceSet   - set by wc_AesGcmInit (when an IV is provided)
 *   ctrSet     - set once the keystream counter has been initialised
 *
 * Clearing these fields mid-stream simulates either a software bug or a
 * deliberate tampering attempt, and the API must detect and reject it.
 */
int test_wc_AesGcmStream_MidStreamState(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(HAVE_AESGCM) && defined(WOLFSSL_AES_128) && \
    defined(WOLFSSL_AESGCM_STREAM)
    static const byte key[AES_128_KEY_SIZE] = { 0 };
    static const byte iv[GCM_NONCE_MID_SZ]  = { 1 };
    static const byte aad[4] = { 0xfe, 0xed, 0xfa, 0xce };
    static const byte in[4]  = { 0x00, 0x01, 0x02, 0x03 };
    Aes aes[1];
    byte out[4];
    byte tag[WC_AES_BLOCK_SIZE];

    XMEMSET(aes, 0, sizeof(Aes));
    ExpectIntEQ(wc_AesInit(aes, NULL, INVALID_DEVID), 0);

    /* ------------------------------------------------------------------
     * Test 1: clear gcmKeySet after streaming has started -> MISSING_KEY
     * ------------------------------------------------------------------ */
    ExpectIntEQ(wc_AesGcmInit(aes, key, sizeof(key), iv, sizeof(iv)), 0);
    ExpectIntEQ(wc_AesGcmEncryptUpdate(aes, out, in, sizeof(in),
        aad, sizeof(aad)), 0);
    /* Corrupt the key-set flag mid-stream. */
    aes->gcmKeySet = 0;
    ExpectIntEQ(wc_AesGcmEncryptFinal(aes, tag, sizeof(tag)),
        WC_NO_ERR_TRACE(MISSING_KEY));

    /* ------------------------------------------------------------------
     * Test 2: clear nonceSet after streaming has started -> MISSING_IV
     * ------------------------------------------------------------------ */
    ExpectIntEQ(wc_AesGcmInit(aes, key, sizeof(key), iv, sizeof(iv)), 0);
    ExpectIntEQ(wc_AesGcmEncryptUpdate(aes, out, in, sizeof(in),
        aad, sizeof(aad)), 0);
    /* Corrupt the nonce-set flag mid-stream. */
    aes->nonceSet = 0;
    ExpectIntEQ(wc_AesGcmEncryptFinal(aes, tag, sizeof(tag)),
        WC_NO_ERR_TRACE(MISSING_IV));

#ifdef HAVE_AES_DECRYPT
    /* ------------------------------------------------------------------
     * Test 3: clear gcmKeySet during a decrypt session -> MISSING_KEY
     * ------------------------------------------------------------------ */
    ExpectIntEQ(wc_AesGcmDecryptInit(aes, key, sizeof(key), iv, sizeof(iv)), 0);
    ExpectIntEQ(wc_AesGcmDecryptUpdate(aes, out, in, sizeof(in),
        aad, sizeof(aad)), 0);
    aes->gcmKeySet = 0;
    ExpectIntEQ(wc_AesGcmDecryptFinal(aes, tag, sizeof(tag)),
        WC_NO_ERR_TRACE(MISSING_KEY));
#endif

    wc_AesFree(aes);
#endif
    return EXPECT_RESULT();
} /* END test_wc_AesGcmStream_MidStreamState */

/*******************************************************************************
 * AES-GCM streaming re-initialization after Final
 ******************************************************************************/

/*
 * Verify that an AES-GCM streaming context can be re-initialized and reused
 * after wc_AesGcmEncryptFinal / wc_AesGcmDecryptFinal.
 *
 * wc_AesGcmInit resets the GHASH accumulator and running-length counters
 * (aSz, cSz, over) and re-initialises the keystream counter, so calling it
 * again after Final must produce a clean new session.
 *
 *  1. Re-init with the same key and IV produces identical ciphertext and tag.
 *  2. Re-init with a different IV produces different ciphertext and tag.
 *  3. Re-init after an abandoned session (Init but no Final) also works.
 *  4. Decrypt re-init: re-initialise the decrypt context and recover plaintext.
 */
int test_wc_AesGcmStream_ReinitAfterFinal(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(HAVE_AESGCM) && defined(WOLFSSL_AES_128) && \
    defined(WOLFSSL_AESGCM_STREAM)
    static const byte key[AES_128_KEY_SIZE] = {
        0xfe,0xff,0xe9,0x92, 0x86,0x65,0x73,0x1c,
        0x6d,0x6a,0x8f,0x94, 0x67,0x30,0x83,0x08
    };
    static const byte iv1[GCM_NONCE_MID_SZ] = {
        0xca,0xfe,0xba,0xbe, 0xfa,0xce,0xdb,0xad,
        0xde,0xca,0xf8,0x88
    };
    /* Different IV - last byte changed. */
    static const byte iv2[GCM_NONCE_MID_SZ] = {
        0xca,0xfe,0xba,0xbe, 0xfa,0xce,0xdb,0xad,
        0xde,0xca,0xf8,0x89
    };
    static const byte aad[20] = {
        0xfe,0xed,0xfa,0xce, 0xde,0xad,0xbe,0xef,
        0xfe,0xed,0xfa,0xce, 0xde,0xad,0xbe,0xef,
        0xab,0xad,0xda,0xd2
    };
    static const byte plain[16] = {
        0xd9,0x31,0x32,0x25, 0xf8,0x84,0x06,0xe5,
        0xa5,0x59,0x09,0xc5, 0xaf,0xf5,0x26,0x9a
    };
    Aes enc[1];
#ifdef HAVE_AES_DECRYPT
    Aes dec[1];
#endif
    byte ct1[sizeof(plain)], ct2[sizeof(plain)], ct3[sizeof(plain)];
    byte tag1[WC_AES_BLOCK_SIZE], tag2[WC_AES_BLOCK_SIZE],
         tag3[WC_AES_BLOCK_SIZE];
#ifdef HAVE_AES_DECRYPT
    byte pt[sizeof(plain)];
#endif

    XMEMSET(enc, 0, sizeof(Aes));
    ExpectIntEQ(wc_AesInit(enc, NULL, INVALID_DEVID), 0);

    /* ---- Session 1: baseline ---- */
    ExpectIntEQ(wc_AesGcmInit(enc, key, sizeof(key), iv1, sizeof(iv1)), 0);
    ExpectIntEQ(wc_AesGcmEncryptUpdate(enc, ct1, plain, sizeof(plain),
        aad, sizeof(aad)), 0);
    ExpectIntEQ(wc_AesGcmEncryptFinal(enc, tag1, sizeof(tag1)), 0);

    /* ---- Session 2: re-init with same key and IV -> must match ---- */
    ExpectIntEQ(wc_AesGcmInit(enc, key, sizeof(key), iv1, sizeof(iv1)), 0);
    ExpectIntEQ(wc_AesGcmEncryptUpdate(enc, ct2, plain, sizeof(plain),
        aad, sizeof(aad)), 0);
    ExpectIntEQ(wc_AesGcmEncryptFinal(enc, tag2, sizeof(tag2)), 0);
    ExpectBufEQ(ct2,  ct1,  sizeof(ct1));
    ExpectBufEQ(tag2, tag1, sizeof(tag1));

    /* ---- Session 3: re-init with different IV -> must differ ---- */
    ExpectIntEQ(wc_AesGcmInit(enc, key, sizeof(key), iv2, sizeof(iv2)), 0);
    ExpectIntEQ(wc_AesGcmEncryptUpdate(enc, ct3, plain, sizeof(plain),
        aad, sizeof(aad)), 0);
    ExpectIntEQ(wc_AesGcmEncryptFinal(enc, tag3, sizeof(tag3)), 0);
    ExpectIntNE(XMEMCMP(ct3,  ct1,  sizeof(ct1)),  0);
    ExpectIntNE(XMEMCMP(tag3, tag1, sizeof(tag1)), 0);

    /* ---- Session 4: re-init after abandoned session ----
     * Start a session (Init + Update) but never call Final, then re-init. */
    ExpectIntEQ(wc_AesGcmInit(enc, key, sizeof(key), iv2, sizeof(iv2)), 0);
    /* partial update - abandon without Final */
    ExpectIntEQ(wc_AesGcmEncryptUpdate(enc, ct3, plain, sizeof(plain),
        aad, sizeof(aad)), 0);
    /* Re-init with iv1 - must produce session-1 output. */
    ExpectIntEQ(wc_AesGcmInit(enc, key, sizeof(key), iv1, sizeof(iv1)), 0);
    ExpectIntEQ(wc_AesGcmEncryptUpdate(enc, ct2, plain, sizeof(plain),
        aad, sizeof(aad)), 0);
    ExpectIntEQ(wc_AesGcmEncryptFinal(enc, tag2, sizeof(tag2)), 0);
    ExpectBufEQ(ct2,  ct1,  sizeof(ct1));
    ExpectBufEQ(tag2, tag1, sizeof(tag1));

    wc_AesFree(enc);

#ifdef HAVE_AES_DECRYPT
    /* ---- Decrypt: re-init recovers plaintext on each session ---- */
    XMEMSET(dec, 0, sizeof(Aes));
    ExpectIntEQ(wc_AesInit(dec, NULL, INVALID_DEVID), 0);

    /* Session A: decrypt ct1 with iv1 -> plaintext. */
    ExpectIntEQ(wc_AesGcmDecryptInit(dec, key, sizeof(key), iv1, sizeof(iv1)), 0);
    ExpectIntEQ(wc_AesGcmDecryptUpdate(dec, pt, ct1, sizeof(ct1),
        aad, sizeof(aad)), 0);
    ExpectIntEQ(wc_AesGcmDecryptFinal(dec, tag1, sizeof(tag1)), 0);
    ExpectBufEQ(pt, plain, sizeof(plain));

    /* Session B: re-init and decrypt again -> same plaintext. */
    ExpectIntEQ(wc_AesGcmDecryptInit(dec, key, sizeof(key), iv1, sizeof(iv1)), 0);
    ExpectIntEQ(wc_AesGcmDecryptUpdate(dec, pt, ct1, sizeof(ct1),
        aad, sizeof(aad)), 0);
    ExpectIntEQ(wc_AesGcmDecryptFinal(dec, tag1, sizeof(tag1)), 0);
    ExpectBufEQ(pt, plain, sizeof(plain));

    wc_AesFree(dec);
#endif
#endif
    return EXPECT_RESULT();
} /* END test_wc_AesGcmStream_ReinitAfterFinal */

int test_wc_AesGcmStream_BadAuthTag(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(HAVE_AESGCM) && defined(HAVE_AES_DECRYPT) && \
    defined(WOLFSSL_AES_128) && defined(WOLFSSL_AESGCM_STREAM)
    static const byte key[AES_128_KEY_SIZE] = {
        0xfe,0xff,0xe9,0x92, 0x86,0x65,0x73,0x1c,
        0x6d,0x6a,0x8f,0x94, 0x67,0x30,0x83,0x08
    };
    static const byte iv[GCM_NONCE_MID_SZ] = {
        0xca,0xfe,0xba,0xbe, 0xfa,0xce,0xdb,0xad,
        0xde,0xca,0xf8,0x88
    };
    static const byte aad[20] = {
        0xfe,0xed,0xfa,0xce, 0xde,0xad,0xbe,0xef,
        0xfe,0xed,0xfa,0xce, 0xde,0xad,0xbe,0xef,
        0xab,0xad,0xda,0xd2
    };
    static const byte plain[16] = {
        0xd9,0x31,0x32,0x25, 0xf8,0x84,0x06,0xe5,
        0xa5,0x59,0x09,0xc5, 0xaf,0xf5,0x26,0x9a
    };
    Aes enc[1];
    Aes dec[1];
    byte ct[sizeof(plain)];
    byte pt[sizeof(plain)];
    byte tag[WC_AES_BLOCK_SIZE];
    byte bad_aad[sizeof(aad)];

    XMEMSET(enc, 0, sizeof(Aes));
    XMEMSET(dec, 0, sizeof(Aes));
    XMEMSET(tag, 0, sizeof(tag));

    ExpectIntEQ(wc_AesInit(enc, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesGcmInit(enc, key, sizeof(key), iv, sizeof(iv)), 0);
    ExpectIntEQ(wc_AesGcmEncryptUpdate(enc, ct, plain, sizeof(plain),
        aad, sizeof(aad)), 0);
    ExpectIntEQ(wc_AesGcmEncryptFinal(enc, tag, sizeof(tag)), 0);
    wc_AesFree(enc);

    tag[0] ^= 0x01;

    ExpectIntEQ(wc_AesInit(dec, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesGcmDecryptInit(dec, key, sizeof(key), iv, sizeof(iv)), 0);
    ExpectIntEQ(wc_AesGcmDecryptUpdate(dec, pt, ct, sizeof(ct),
        aad, sizeof(aad)), 0);
    ExpectIntEQ(wc_AesGcmDecryptFinal(dec, tag, sizeof(tag)),
        WC_NO_ERR_TRACE(AES_GCM_AUTH_E));
    wc_AesFree(dec);

    tag[0] ^= 0x01;
    XMEMCPY(bad_aad, aad, sizeof(aad));
    bad_aad[0] ^= 0x01;
    ExpectIntEQ(wc_AesInit(dec, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesGcmDecryptInit(dec, key, sizeof(key), iv, sizeof(iv)), 0);
    ExpectIntEQ(wc_AesGcmDecryptUpdate(dec, pt, ct, sizeof(ct),
        bad_aad, sizeof(bad_aad)), 0);
    ExpectIntEQ(wc_AesGcmDecryptFinal(dec, tag, sizeof(tag)),
        WC_NO_ERR_TRACE(AES_GCM_AUTH_E));
    wc_AesFree(dec);
#endif
    return EXPECT_RESULT();
}

/*******************************************************************************
 * GMAC
 ******************************************************************************/

/*
 * unit test for wc_GmacSetKey()
 */
int test_wc_GmacSetKey(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(HAVE_AESGCM)
    Gmac gmac;
    byte key16[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
#ifdef WOLFSSL_AES_192
    byte key24[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37
    };
#endif
#ifdef WOLFSSL_AES_256
    byte key32[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
#endif
    byte badKey16[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x66
    };
    byte badKey24[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37
    };
    byte badKey32[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };

    XMEMSET(&gmac, 0, sizeof(Gmac));

    ExpectIntEQ(wc_AesInit(&gmac.aes, NULL, INVALID_DEVID), 0);

#ifdef WOLFSSL_AES_128
    ExpectIntEQ(wc_GmacSetKey(&gmac, key16, sizeof(key16)/sizeof(byte)), 0);
#endif
#ifdef WOLFSSL_AES_192
    ExpectIntEQ(wc_GmacSetKey(&gmac, key24, sizeof(key24)/sizeof(byte)), 0);
#endif
#ifdef WOLFSSL_AES_256
    ExpectIntEQ(wc_GmacSetKey(&gmac, key32, sizeof(key32)/sizeof(byte)), 0);
#endif

    /* Pass in bad args. */
    ExpectIntEQ(wc_GmacSetKey(NULL, key16, sizeof(key16)/sizeof(byte)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_GmacSetKey(&gmac, NULL, sizeof(key16)/sizeof(byte)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_GmacSetKey(&gmac, badKey16, sizeof(badKey16)/sizeof(byte)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_GmacSetKey(&gmac, badKey24, sizeof(badKey24)/sizeof(byte)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_GmacSetKey(&gmac, badKey32, sizeof(badKey32)/sizeof(byte)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    wc_AesFree(&gmac.aes);
#endif
    return EXPECT_RESULT();
} /* END test_wc_GmacSetKey */

/*
 * unit test for wc_GmacUpdate
 */
int test_wc_GmacUpdate(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(HAVE_AESGCM)
    Gmac gmac;
#ifdef WOLFSSL_AES_128
    const byte key16[] = {
        0x89, 0xc9, 0x49, 0xe9, 0xc8, 0x04, 0xaf, 0x01,
        0x4d, 0x56, 0x04, 0xb3, 0x94, 0x59, 0xf2, 0xc8
    };
#endif
#ifdef WOLFSSL_AES_192
    byte key24[] = {
        0x41, 0xc5, 0xda, 0x86, 0x67, 0xef, 0x72, 0x52,
        0x20, 0xff, 0xe3, 0x9a, 0xe0, 0xac, 0x59, 0x0a,
        0xc9, 0xfc, 0xa7, 0x29, 0xab, 0x60, 0xad, 0xa0
    };
#endif
#ifdef WOLFSSL_AES_256
   byte key32[] = {
        0x78, 0xdc, 0x4e, 0x0a, 0xaf, 0x52, 0xd9, 0x35,
        0xc3, 0xc0, 0x1e, 0xea, 0x57, 0x42, 0x8f, 0x00,
        0xca, 0x1f, 0xd4, 0x75, 0xf5, 0xda, 0x86, 0xa4,
        0x9c, 0x8d, 0xd7, 0x3d, 0x68, 0xc8, 0xe2, 0x23
    };
#endif
#ifdef WOLFSSL_AES_128
    const byte authIn[] = {
        0x82, 0xad, 0xcd, 0x63, 0x8d, 0x3f, 0xa9, 0xd9,
        0xf3, 0xe8, 0x41, 0x00, 0xd6, 0x1e, 0x07, 0x77
    };
#endif
#ifdef WOLFSSL_AES_192
    const byte authIn2[] = {
       0x8b, 0x5c, 0x12, 0x4b, 0xef, 0x6e, 0x2f, 0x0f,
       0xe4, 0xd8, 0xc9, 0x5c, 0xd5, 0xfa, 0x4c, 0xf1
    };
#endif
    const byte authIn3[] = {
        0xb9, 0x6b, 0xaa, 0x8c, 0x1c, 0x75, 0xa6, 0x71,
        0xbf, 0xb2, 0xd0, 0x8d, 0x06, 0xbe, 0x5f, 0x36
    };
#ifdef WOLFSSL_AES_128
    const byte tag1[] = { /* Known. */
        0x88, 0xdb, 0x9d, 0x62, 0x17, 0x2e, 0xd0, 0x43,
        0xaa, 0x10, 0xf1, 0x6d, 0x22, 0x7d, 0xc4, 0x1b
    };
#endif
#ifdef WOLFSSL_AES_192
    const byte tag2[] = { /* Known */
        0x20, 0x4b, 0xdb, 0x1b, 0xd6, 0x21, 0x54, 0xbf,
        0x08, 0x92, 0x2a, 0xaa, 0x54, 0xee, 0xd7, 0x05
    };
#endif
    const byte tag3[] = { /* Known */
        0x3e, 0x5d, 0x48, 0x6a, 0xa2, 0xe3, 0x0b, 0x22,
        0xe0, 0x40, 0xb8, 0x57, 0x23, 0xa0, 0x6e, 0x76
    };
#ifdef WOLFSSL_AES_128
    const byte iv[] = {
        0xd1, 0xb1, 0x04, 0xc8, 0x15, 0xbf, 0x1e, 0x94,
        0xe2, 0x8c, 0x8f, 0x16
    };
#endif
#ifdef WOLFSSL_AES_192
    const byte iv2[] = {
        0x05, 0xad, 0x13, 0xa5, 0xe2, 0xc2, 0xab, 0x66,
        0x7e, 0x1a, 0x6f, 0xbc
    };
#endif
    const byte iv3[] = {
        0xd7, 0x9c, 0xf2, 0x2d, 0x50, 0x4c, 0xc7, 0x93,
        0xc3, 0xfb, 0x6c, 0x8a
    };
    byte tagOut[16];
    byte tagOut2[24];
    byte tagOut3[32];

    /* Init stack variables. */
    XMEMSET(&gmac, 0, sizeof(Gmac));
    XMEMSET(tagOut, 0, sizeof(tagOut));
    XMEMSET(tagOut2, 0, sizeof(tagOut2));
    XMEMSET(tagOut3, 0, sizeof(tagOut3));

#ifdef WOLFSSL_AES_128
    ExpectIntEQ(wc_AesInit(&gmac.aes, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_GmacSetKey(&gmac, key16, sizeof(key16)), 0);
    ExpectIntEQ(wc_GmacUpdate(&gmac, iv, sizeof(iv), authIn, sizeof(authIn),
        tagOut, sizeof(tag1)), 0);
    ExpectIntEQ(XMEMCMP(tag1, tagOut, sizeof(tag1)), 0);
    wc_AesFree(&gmac.aes);
#endif

#ifdef WOLFSSL_AES_192
    ExpectNotNull(XMEMSET(&gmac, 0, sizeof(Gmac)));
    ExpectIntEQ(wc_AesInit(&gmac.aes, HEAP_HINT, INVALID_DEVID), 0);
    ExpectIntEQ(wc_GmacSetKey(&gmac, key24, sizeof(key24)/sizeof(byte)), 0);
    ExpectIntEQ(wc_GmacUpdate(&gmac, iv2, sizeof(iv2), authIn2, sizeof(authIn2),
        tagOut2, sizeof(tag2)), 0);
    ExpectIntEQ(XMEMCMP(tagOut2, tag2, sizeof(tag2)), 0);
    wc_AesFree(&gmac.aes);
#endif

#ifdef WOLFSSL_AES_256
    ExpectNotNull(XMEMSET(&gmac, 0, sizeof(Gmac)));
    ExpectIntEQ(wc_AesInit(&gmac.aes, HEAP_HINT, INVALID_DEVID), 0);
    ExpectIntEQ(wc_GmacSetKey(&gmac, key32, sizeof(key32)/sizeof(byte)), 0);
    ExpectIntEQ(wc_GmacUpdate(&gmac, iv3, sizeof(iv3), authIn3, sizeof(authIn3),
        tagOut3, sizeof(tag3)), 0);
    ExpectIntEQ(XMEMCMP(tag3, tagOut3, sizeof(tag3)), 0);
    wc_AesFree(&gmac.aes);
#endif

    /* Pass bad args. */
    ExpectIntEQ(wc_AesInit(&gmac.aes, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_GmacUpdate(NULL, iv3, sizeof(iv3), authIn3, sizeof(authIn3),
        tagOut3, sizeof(tag3)), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_GmacUpdate(&gmac, iv3, sizeof(iv3), authIn3, sizeof(authIn3),
        tagOut3, sizeof(tag3) - 5), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_GmacUpdate(&gmac, iv3, sizeof(iv3), authIn3, sizeof(authIn3),
        tagOut3, sizeof(tag3) + 1),  WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    wc_AesFree(&gmac.aes);

#endif
    return EXPECT_RESULT();
} /* END test_wc_GmacUpdate */

/*******************************************************************************
 * AES-CCM
 ******************************************************************************/

/*
 * unit test for wc_AesCcmSetKey
 */
int test_wc_AesCcmSetKey(void)
{
    EXPECT_DECLS;
#ifdef HAVE_AESCCM
    Aes aes;
    const byte key16[] = {
        0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
        0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf
    };
    const byte key24[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37
    };
    const byte key32[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };

    XMEMSET(&aes, 0, sizeof(Aes));

    ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);

#ifdef WOLFSSL_AES_128
    ExpectIntEQ(wc_AesCcmSetKey(&aes, key16, sizeof(key16)), 0);
#endif
#ifdef WOLFSSL_AES_192
    ExpectIntEQ(wc_AesCcmSetKey(&aes, key24, sizeof(key24)), 0);
#endif
#ifdef WOLFSSL_AES_256
    ExpectIntEQ(wc_AesCcmSetKey(&aes, key32, sizeof(key32)), 0);
#endif

    /* Test bad args. */
   ExpectIntEQ(wc_AesCcmSetKey(&aes, key16, sizeof(key16) - 1),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
   ExpectIntEQ(wc_AesCcmSetKey(&aes, key24, sizeof(key24) - 1),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
   ExpectIntEQ(wc_AesCcmSetKey(&aes, key32, sizeof(key32) - 1),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    wc_AesFree(&aes);
#endif
    return EXPECT_RESULT();

} /* END test_wc_AesCcmSetKey */

/*
 * Unit test function for wc_AesCcmEncrypt and wc_AesCcmDecrypt
 */
int test_wc_AesCcmEncryptDecrypt(void)
{
    EXPECT_DECLS;
#if defined(HAVE_AESCCM) && defined(WOLFSSL_AES_128)
    Aes aes;
    const byte key16[] = {
        0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
        0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf
    };
    /* plaintext */
    const byte plainT[] = {
        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
        0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e
    };
    /* nonce */
    const byte iv[] = {
        0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0xa0,
        0xa1, 0xa2, 0xa3, 0xa4, 0xa5
    };
    const byte c[] = { /* cipher text. */
        0x58, 0x8c, 0x97, 0x9a, 0x61, 0xc6, 0x63, 0xd2,
        0xf0, 0x66, 0xd0, 0xc2, 0xc0, 0xf9, 0x89, 0x80,
        0x6d, 0x5f, 0x6b, 0x61, 0xda, 0xc3, 0x84
    };
    const byte t[] = { /* Auth tag */
        0x17, 0xe8, 0xd1, 0x2c, 0xfd, 0xf9, 0x26, 0xe0
    };
    const byte authIn[] = {
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
    };
    byte cipherOut[sizeof(plainT)];
    byte authTag[sizeof(t)];
#ifdef HAVE_AES_DECRYPT
    byte plainOut[sizeof(cipherOut)];
#endif

    XMEMSET(&aes, 0, sizeof(Aes));

    ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesCcmSetKey(&aes, key16, sizeof(key16)), 0);

    ExpectIntEQ(wc_AesCcmEncrypt(&aes, cipherOut, plainT, sizeof(cipherOut),
        iv, sizeof(iv), authTag, sizeof(authTag), authIn , sizeof(authIn)), 0);
    ExpectIntEQ(XMEMCMP(cipherOut, c, sizeof(c)), 0);
    ExpectIntEQ(XMEMCMP(t, authTag, sizeof(t)), 0);
#ifdef HAVE_AES_DECRYPT
    ExpectIntEQ(wc_AesCcmDecrypt(&aes, plainOut, cipherOut, sizeof(plainOut),
        iv, sizeof(iv), authTag, sizeof(authTag), authIn, sizeof(authIn)), 0);
    ExpectIntEQ(XMEMCMP(plainOut, plainT, sizeof(plainT)), 0);
#endif

    /* Pass in bad args. Encrypt*/
    ExpectIntEQ(wc_AesCcmEncrypt(NULL, cipherOut, plainT, sizeof(cipherOut),
        iv, sizeof(iv), authTag, sizeof(authTag), authIn , sizeof(authIn)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCcmEncrypt(&aes, NULL, plainT, sizeof(cipherOut),
        iv, sizeof(iv), authTag, sizeof(authTag), authIn , sizeof(authIn)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCcmEncrypt(&aes, cipherOut, NULL, sizeof(cipherOut),
        iv, sizeof(iv), authTag, sizeof(authTag), authIn , sizeof(authIn)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCcmEncrypt(&aes, cipherOut, plainT, sizeof(cipherOut),
        NULL, sizeof(iv), authTag, sizeof(authTag), authIn , sizeof(authIn)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCcmEncrypt(&aes, cipherOut, plainT, sizeof(cipherOut),
        iv, sizeof(iv), NULL, sizeof(authTag), authIn , sizeof(authIn)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCcmEncrypt(&aes, cipherOut, plainT, sizeof(cipherOut),
        iv, sizeof(iv) + 1, authTag, sizeof(authTag), authIn , sizeof(authIn)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCcmEncrypt(&aes, cipherOut, plainT, sizeof(cipherOut),
        iv, sizeof(iv) - 7, authTag, sizeof(authTag), authIn , sizeof(authIn)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));

#ifdef HAVE_AES_DECRYPT
    /* Pass in bad args. Decrypt*/
    ExpectIntEQ(wc_AesCcmDecrypt(NULL, plainOut, cipherOut, sizeof(plainOut),
        iv, sizeof(iv), authTag, sizeof(authTag), authIn, sizeof(authIn)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCcmDecrypt(&aes, NULL, cipherOut, sizeof(plainOut),
        iv, sizeof(iv), authTag, sizeof(authTag), authIn, sizeof(authIn)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCcmDecrypt(&aes, plainOut, NULL, sizeof(plainOut),
        iv, sizeof(iv), authTag, sizeof(authTag), authIn, sizeof(authIn)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCcmDecrypt(&aes, plainOut, cipherOut, sizeof(plainOut),
        NULL, sizeof(iv), authTag, sizeof(authTag), authIn, sizeof(authIn)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCcmDecrypt(&aes, plainOut, cipherOut, sizeof(plainOut),
        iv, sizeof(iv), NULL, sizeof(authTag), authIn, sizeof(authIn)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCcmDecrypt(&aes, plainOut, cipherOut, sizeof(plainOut),
        iv, sizeof(iv) + 1, authTag, sizeof(authTag), authIn, sizeof(authIn)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesCcmDecrypt(&aes, plainOut, cipherOut, sizeof(plainOut),
        iv, sizeof(iv) - 7, authTag, sizeof(authTag), authIn, sizeof(authIn)),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    #endif

    wc_AesFree(&aes);
#endif  /* HAVE_AESCCM */
    return EXPECT_RESULT();
} /* END test_wc_AesCcmEncryptDecrypt */

/*******************************************************************************
 * AES-CCM overlapping (in-place) buffers
 ******************************************************************************/

/*
 * Verify that wc_AesCcmEncrypt / wc_AesCcmDecrypt work correctly when the
 * plaintext/ciphertext pointer is the same buffer (in == out).  AES-CCM uses
 * CTR mode for encryption (XOR keystream), so in-place operation is safe.
 *
 * Vectors are the IEEE 802.15.4 / RFC 3610 test case used in
 * test_wc_AesCcmEncryptDecrypt.
 */
int test_wc_AesCcmEncryptDecrypt_InPlace(void)
{
    EXPECT_DECLS;
#if defined(HAVE_AESCCM) && defined(WOLFSSL_AES_128) && defined(HAVE_AES_DECRYPT)
    Aes aes;
    static const byte key[AES_128_KEY_SIZE] = {
        0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
        0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf
    };
    static const byte nonce[13] = {
        0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0xa0,
        0xa1, 0xa2, 0xa3, 0xa4, 0xa5
    };
    static const byte aad[8] = {
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
    };
    static const byte plain[23] = {
        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
        0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e
    };
    byte ref_ct[sizeof(plain)], ref_tag[8];
    byte buf[sizeof(plain)],    tag[8];

    XMEMSET(&aes, 0, sizeof(aes));
    ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesCcmSetKey(&aes, key, sizeof(key)), 0);

    /* Reference ciphertext with separate in/out buffers */
    ExpectIntEQ(wc_AesCcmEncrypt(&aes, ref_ct, plain, sizeof(plain),
        nonce, sizeof(nonce), ref_tag, sizeof(ref_tag),
        aad, sizeof(aad)), 0);

    /* Encrypt in-place (out == in) - must produce the same ciphertext/tag */
    XMEMCPY(buf, plain, sizeof(buf));
    ExpectIntEQ(wc_AesCcmEncrypt(&aes, buf, buf, sizeof(buf),
        nonce, sizeof(nonce), tag, sizeof(tag),
        aad, sizeof(aad)), 0);
    ExpectBufEQ(buf, ref_ct,  sizeof(buf));
    ExpectBufEQ(tag, ref_tag, sizeof(tag));

    /* Decrypt in-place - must recover original plaintext */
    ExpectIntEQ(wc_AesCcmDecrypt(&aes, buf, buf, sizeof(buf),
        nonce, sizeof(nonce), tag, sizeof(tag),
        aad, sizeof(aad)), 0);
    ExpectBufEQ(buf, plain, sizeof(buf));

    wc_AesFree(&aes);
#endif
    return EXPECT_RESULT();
} /* END test_wc_AesCcmEncryptDecrypt_InPlace */

/*******************************************************************************
 * AES-CCM unaligned buffers
 ******************************************************************************/

/*
 * Verify that wc_AesCcmEncrypt / wc_AesCcmDecrypt produce correct results
 * when plaintext, ciphertext, and AAD buffers are byte-offset (unaligned).
 * Tests offsets 1, 2, and 3.  Same vectors as the InPlace test.
 */
int test_wc_AesCcmEncryptDecrypt_UnalignedBuffers(void)
{
    EXPECT_DECLS;
#if defined(HAVE_AESCCM) && defined(WOLFSSL_AES_128) && defined(HAVE_AES_DECRYPT)
    Aes aes;
    static const byte key[AES_128_KEY_SIZE] = {
        0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
        0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf
    };
    static const byte nonce[13] = {
        0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0xa0,
        0xa1, 0xa2, 0xa3, 0xa4, 0xa5
    };
    static const byte aad[8] = {
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
    };
    static const byte plain[23] = {
        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
        0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e
    };
    byte ref_ct[sizeof(plain)], ref_tag[8];
    byte in_buf[sizeof(plain) + 3], out_buf[sizeof(plain) + 3];
    byte aad_buf[sizeof(aad) + 3];
    byte tag[8];
    int off;

    XMEMSET(&aes, 0, sizeof(aes));
    ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesCcmSetKey(&aes, key, sizeof(key)), 0);

    /* Reference ciphertext/tag with naturally-aligned buffers */
    ExpectIntEQ(wc_AesCcmEncrypt(&aes, ref_ct, plain, sizeof(plain),
        nonce, sizeof(nonce), ref_tag, sizeof(ref_tag),
        aad, sizeof(aad)), 0);

    /* Encrypt with byte offsets 1, 2, 3 on plaintext, ciphertext, and AAD */
    for (off = 1; off <= 3 && EXPECT_SUCCESS(); off++) {
        XMEMCPY(in_buf  + off, plain, sizeof(plain));
        XMEMCPY(aad_buf + off, aad,   sizeof(aad));
        XMEMSET(out_buf, 0, sizeof(out_buf));
        ExpectIntEQ(wc_AesCcmEncrypt(&aes, out_buf + off, in_buf + off,
            sizeof(plain), nonce, sizeof(nonce), tag, sizeof(tag),
            aad_buf + off, sizeof(aad)), 0);
        ExpectBufEQ(out_buf + off, ref_ct,  sizeof(plain));
        ExpectBufEQ(tag,           ref_tag, sizeof(tag));
    }

    /* Decrypt with byte offsets 1, 2, 3 */
    for (off = 1; off <= 3 && EXPECT_SUCCESS(); off++) {
        XMEMCPY(in_buf  + off, ref_ct, sizeof(plain));
        XMEMCPY(aad_buf + off, aad,    sizeof(aad));
        XMEMSET(out_buf, 0, sizeof(out_buf));
        ExpectIntEQ(wc_AesCcmDecrypt(&aes, out_buf + off, in_buf + off,
            sizeof(plain), nonce, sizeof(nonce), ref_tag, sizeof(ref_tag),
            aad_buf + off, sizeof(aad)), 0);
        ExpectBufEQ(out_buf + off, plain, sizeof(plain));
    }

    wc_AesFree(&aes);
#endif
    return EXPECT_RESULT();
} /* END test_wc_AesCcmEncryptDecrypt_UnalignedBuffers */

/*
 * AES-CCM AEAD edge cases:
 *   - invalid auth tag rejection
 *   - empty AAD (NULL / 0-length)
 *   - empty plaintext with non-empty AAD
 */
int test_wc_AesCcmAeadEdgeCases(void)
{
    EXPECT_DECLS;
#if defined(HAVE_AESCCM) && defined(WOLFSSL_AES_128)
    static const byte key[] = {
        0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
        0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf
    };
    static const byte nonce[] = {
        0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0xa0,
        0xa1, 0xa2, 0xa3, 0xa4, 0xa5
    };
    static const byte plainT[] = {
        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
        0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e
    };
    static const byte authIn[] = {
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
    };
    Aes  aes;
    byte cipherOut[sizeof(plainT)];
    byte authTag[8];
#ifdef HAVE_AES_DECRYPT
    byte plainOut[sizeof(plainT)];
#endif

    XMEMSET(&aes, 0, sizeof(aes));
    ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesCcmSetKey(&aes, key, sizeof(key)), 0);

    /* --- Empty AAD (NULL/0): encrypt with no additional data --- */
    XMEMSET(cipherOut, 0, sizeof(cipherOut));
    XMEMSET(authTag,   0, sizeof(authTag));
    ExpectIntEQ(wc_AesCcmEncrypt(&aes, cipherOut, plainT, sizeof(plainT),
        nonce, sizeof(nonce), authTag, sizeof(authTag), NULL, 0), 0);
#ifdef HAVE_AES_DECRYPT
    XMEMSET(plainOut, 0, sizeof(plainOut));
    ExpectIntEQ(wc_AesCcmDecrypt(&aes, plainOut, cipherOut, sizeof(cipherOut),
        nonce, sizeof(nonce), authTag, sizeof(authTag), NULL, 0), 0);
    ExpectBufEQ(plainOut, plainT, sizeof(plainT));
#endif /* HAVE_AES_DECRYPT */

    /* --- Empty plaintext with non-empty AAD --- */
    XMEMSET(authTag, 0, sizeof(authTag));
#if defined(HAVE_SELFTEST) || (defined(HAVE_FIPS_VERSION) && \
    (HAVE_FIPS_VERSION <= 2))
    ExpectIntEQ(wc_AesCcmEncrypt(&aes, NULL, NULL, 0,
        nonce, sizeof(nonce), authTag, sizeof(authTag),
        authIn, sizeof(authIn)), BAD_FUNC_ARG);
#else
    ExpectIntEQ(wc_AesCcmEncrypt(&aes, NULL, NULL, 0,
        nonce, sizeof(nonce), authTag, sizeof(authTag),
        authIn, sizeof(authIn)), 0);
#ifdef HAVE_AES_DECRYPT
    /* Correct tag must pass */
    ExpectIntEQ(wc_AesCcmDecrypt(&aes, NULL, NULL, 0,
        nonce, sizeof(nonce), authTag, sizeof(authTag),
        authIn, sizeof(authIn)), 0);
    /* Tampered tag must fail */
    authTag[0] ^= 0xff;
    ExpectIntEQ(wc_AesCcmDecrypt(&aes, NULL, NULL, 0,
        nonce, sizeof(nonce), authTag, sizeof(authTag),
        authIn, sizeof(authIn)),
        WC_NO_ERR_TRACE(AES_CCM_AUTH_E));
#endif /* HAVE_AES_DECRYPT */
#endif

    /* --- Invalid tag rejection: encrypt then tamper auth tag --- */
    XMEMSET(cipherOut, 0, sizeof(cipherOut));
    XMEMSET(authTag,   0, sizeof(authTag));
    ExpectIntEQ(wc_AesCcmEncrypt(&aes, cipherOut, plainT, sizeof(plainT),
        nonce, sizeof(nonce), authTag, sizeof(authTag),
        authIn, sizeof(authIn)), 0);
#ifdef HAVE_AES_DECRYPT
    authTag[0] ^= 0xff;
    ExpectIntEQ(wc_AesCcmDecrypt(&aes, plainOut, cipherOut, sizeof(cipherOut),
        nonce, sizeof(nonce), authTag, sizeof(authTag),
        authIn, sizeof(authIn)),
        WC_NO_ERR_TRACE(AES_CCM_AUTH_E));
#endif /* HAVE_AES_DECRYPT */

    wc_AesFree(&aes);
#endif /* HAVE_AESCCM && WOLFSSL_AES_128 */
    return EXPECT_RESULT();
} /* END test_wc_AesCcmAeadEdgeCases */

/*******************************************************************************
 * AES-XTS
 ******************************************************************************/

/*
 * test function for wc_AesXtsSetKey()
 */
int test_wc_AesXtsSetKey(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(WOLFSSL_AES_XTS)
    XtsAes aes;
#ifdef WOLFSSL_AES_128
    byte key16[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
    };
#endif
#if defined(WOLFSSL_AES_192) && !defined(HAVE_FIPS)
    byte key24[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
#endif
#ifdef WOLFSSL_AES_256
    byte key32[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
#endif
    byte badKey16[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65
    };
    byte badKey24[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36
    };
    byte badKey32[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x37, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65
    };
    byte* key;
    word32 keyLen;

#ifdef WOLFSSL_AES_128
    key = key16;
    keyLen = sizeof(key16)/sizeof(byte);
#elif defined(WOLFSSL_AES_192)
    key = key24;
    keyLen = sizeof(key24)/sizeof(byte);
#else
    key = key32;
    keyLen = sizeof(key32)/sizeof(byte);
#endif

#ifdef WOLFSSL_AES_128
    ExpectIntEQ(wc_AesXtsSetKey(&aes, key16, sizeof(key16)/sizeof(byte),
        AES_ENCRYPTION, NULL, INVALID_DEVID), 0);
    wc_AesXtsFree(&aes);
#endif
#if defined(WOLFSSL_AES_192) && !defined(HAVE_FIPS)
    ExpectIntEQ(wc_AesXtsSetKey(&aes, key24, sizeof(key24)/sizeof(byte),
        AES_ENCRYPTION, NULL, INVALID_DEVID), 0);
    wc_AesXtsFree(&aes);
#endif
#ifdef WOLFSSL_AES_256
    ExpectIntEQ(wc_AesXtsSetKey(&aes, key32, sizeof(key32)/sizeof(byte),
        AES_ENCRYPTION, NULL, INVALID_DEVID), 0);
    wc_AesXtsFree(&aes);
#endif

    /* Pass in bad args. */
    ExpectIntEQ(wc_AesXtsSetKey(NULL, NULL, keyLen, AES_ENCRYPTION, NULL,
        INVALID_DEVID), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesXtsSetKey(NULL, key, keyLen, AES_ENCRYPTION, NULL,
        INVALID_DEVID), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesXtsSetKey(&aes, NULL, keyLen, AES_ENCRYPTION, NULL,
        INVALID_DEVID), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesXtsSetKey(&aes, badKey16, sizeof(badKey16)/sizeof(byte),
        AES_ENCRYPTION, NULL, INVALID_DEVID), WC_NO_ERR_TRACE(WC_KEY_SIZE_E));
    ExpectIntEQ(wc_AesXtsSetKey(&aes, badKey24, sizeof(badKey24)/sizeof(byte),
        AES_ENCRYPTION, NULL, INVALID_DEVID), WC_NO_ERR_TRACE(WC_KEY_SIZE_E));
    ExpectIntEQ(wc_AesXtsSetKey(&aes, badKey32, sizeof(badKey32)/sizeof(byte),
        AES_ENCRYPTION, NULL, INVALID_DEVID), WC_NO_ERR_TRACE(WC_KEY_SIZE_E));
    ExpectIntEQ(wc_AesXtsSetKey(&aes, key, keyLen, -2, NULL, INVALID_DEVID),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif
    return EXPECT_RESULT();
} /* END test_wc_AesXtsSetKey */

int test_wc_AesXtsEncryptDecrypt_Sizes(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(WOLFSSL_AES_XTS) && \
    defined(WOLFSSL_AES_256) && !defined(WOLFSSL_AFALG) && \
    !defined(WOLFSSL_KCAPI)
    #define XTS_LEN     (WC_AES_BLOCK_SIZE * 16)
    byte key32[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    byte tweak[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
    };
    XtsAes aes;
    word32 tweakLen = (word32)sizeof(tweak)/sizeof(byte);
    int sz;
    WC_DECLARE_VAR(plain, byte, XTS_LEN, NULL);
    WC_DECLARE_VAR(cipher, byte, XTS_LEN, NULL);
#ifdef HAVE_AES_DECRYPT
    WC_DECLARE_VAR(decrypted, byte, XTS_LEN, NULL);
#endif

    WC_ALLOC_VAR(plain, byte, XTS_LEN, NULL);
    WC_ALLOC_VAR(cipher, byte, XTS_LEN, NULL);
#ifdef HAVE_AES_DECRYPT
    WC_ALLOC_VAR(decrypted, byte, XTS_LEN, NULL);
#endif

#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC
    ExpectNotNull(plain);
    ExpectNotNull(cipher);
#ifdef HAVE_AES_DECRYPT
    ExpectNotNull(decrypted);
#endif
#endif

    XMEMSET(&aes, 0, sizeof(Aes));
    XMEMSET(plain, 0xa5, XTS_LEN);

    for (sz = WC_AES_BLOCK_SIZE; sz <= XTS_LEN; sz *= 2) {
        ExpectIntEQ(wc_AesXtsSetKey(&aes, key32, sizeof(key32)/sizeof(byte),
            AES_ENCRYPTION, NULL, INVALID_DEVID), 0);
        XMEMSET(cipher, 0, XTS_LEN);
        ExpectIntEQ(wc_AesXtsEncrypt(&aes, cipher, plain, sz, tweak, tweakLen),
            0);
        wc_AesXtsFree(&aes);

#ifdef HAVE_AES_DECRYPT
        ExpectIntEQ(wc_AesXtsSetKey(&aes, key32, sizeof(key32)/sizeof(byte),
            AES_DECRYPTION, NULL, INVALID_DEVID), 0);
        XMEMSET(decrypted, 0xff, XTS_LEN);
        ExpectIntEQ(wc_AesXtsDecrypt(&aes, decrypted, cipher, sz, tweak,
            tweakLen), 0);
        ExpectBufEQ(decrypted, plain, sz);
        wc_AesXtsFree(&aes);
#endif
    }

    WC_FREE_VAR(plain, NULL);
    WC_FREE_VAR(cipher, NULL);
#ifdef HAVE_AES_DECRYPT
    WC_FREE_VAR(decrypted, NULL);
#endif
#endif
    return EXPECT_RESULT();
}

/*
 * test function for wc_AesXtsEncrypt and wc_AesXtsDecrypt
 */
int test_wc_AesXtsEncryptDecrypt(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(WOLFSSL_AES_XTS) && \
    defined(WOLFSSL_AES_256)
    XtsAes  aes;
    byte key32[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    byte vector[] = { /* Now is the time for all w/o trailing 0 */
        0x4e,0x6f,0x77,0x20,0x69,0x73,0x20,0x74,
        0x68,0x65,0x20,0x74,0x69,0x6d,0x65,0x20,
        0x66,0x6f,0x72,0x20,0x61,0x6c,0x6c,0x20
    };
    byte tweak[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
    };
    word32 tweakLen = (word32)sizeof(tweak)/sizeof(byte);
    byte enc[sizeof(vector)];
    byte resultT[WC_AES_BLOCK_SIZE];
    byte dec[sizeof(vector)];

    /* Init stack variables. */
    XMEMSET(&aes, 0, sizeof(Aes));
    XMEMSET(enc, 0, sizeof(vector));
    XMEMSET(dec, 0, sizeof(vector));
    XMEMSET(resultT, 0, WC_AES_BLOCK_SIZE);

    ExpectIntEQ(wc_AesXtsSetKey(&aes, key32, sizeof(key32)/sizeof(byte),
        AES_ENCRYPTION, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesXtsEncrypt(&aes, enc, vector, sizeof(vector), tweak,
        tweakLen), 0);
    wc_AesXtsFree(&aes);
    ExpectIntEQ(wc_AesXtsSetKey(&aes, key32, sizeof(key32)/sizeof(byte),
        AES_DECRYPTION, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesXtsDecrypt(&aes, dec, enc, sizeof(vector), tweak,
        tweakLen), 0);
    ExpectIntEQ(XMEMCMP(vector, dec, sizeof(vector)), 0);
    wc_AesXtsFree(&aes);

    ExpectIntEQ(wc_AesXtsSetKey(&aes, key32, sizeof(key32)/sizeof(byte),
        AES_ENCRYPTION, NULL, INVALID_DEVID), 0);
    /* Test bad args for wc_AesXtsEncrypt and wc_AesXtsDecrypt */
    ExpectIntEQ(wc_AesXtsEncrypt(NULL, enc, vector, sizeof(vector), tweak,
        tweakLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesXtsEncrypt(&aes, NULL, vector, sizeof(vector), tweak,
        tweakLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesXtsEncrypt(&aes, enc, NULL, sizeof(vector), tweak,
        tweakLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    wc_AesXtsFree(&aes);
    /* END wc_AesXtsEncrypt */

#ifdef HAVE_AES_DECRYPT
    ExpectIntEQ(wc_AesXtsSetKey(&aes, key32, sizeof(key32)/sizeof(byte),
        AES_DECRYPTION, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesXtsDecrypt(NULL, dec, enc, sizeof(enc)/sizeof(byte),
        tweak, tweakLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesXtsDecrypt(&aes, NULL, enc, sizeof(enc)/sizeof(byte),
        tweak, tweakLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesXtsDecrypt(&aes, dec, NULL, sizeof(enc)/sizeof(byte),
        tweak, tweakLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    wc_AesXtsFree(&aes);
#endif /* HAVE_AES_DECRYPT */
#endif

    return EXPECT_RESULT();
} /* END test_wc_AesXtsEncryptDecrypt */

/*******************************************************************************
 * AES-XTS overlapping (in-place) buffers
 ******************************************************************************/

/*
 * Verify that wc_AesXtsEncrypt / wc_AesXtsDecrypt work correctly when the
 * plaintext/ciphertext pointer is the same buffer (in == out).  The software
 * path explicitly handles this case by reading each input block into a local
 * copy before XOR-and-encrypt, so in-place operation is safe.
 */
int test_wc_AesXtsEncryptDecrypt_InPlace(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(WOLFSSL_AES_XTS) && \
    defined(WOLFSSL_AES_256) && !defined(WOLFSSL_AFALG) && \
    !defined(WOLFSSL_KCAPI)
    XtsAes aes;
    static const byte key64[64] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    static const byte tweak[WC_AES_BLOCK_SIZE] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    /* 24 bytes: one full block + 8-byte partial block (CTS-style steal) */
    static const byte plain[24] = {
        0x4e, 0x6f, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74,
        0x68, 0x65, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20,
        0x66, 0x6f, 0x72, 0x20, 0x61, 0x6c, 0x6c, 0x20
    };
    byte ref_ct[sizeof(plain)];
    byte buf[sizeof(plain)];

    XMEMSET(&aes, 0, sizeof(aes));

    /* Reference ciphertext with separate in/out buffers */
    ExpectIntEQ(wc_AesXtsSetKey(&aes, key64, sizeof(key64),
        AES_ENCRYPTION, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesXtsEncrypt(&aes, ref_ct, plain, sizeof(plain),
        tweak, sizeof(tweak)), 0);
    wc_AesXtsFree(&aes);

    /* Encrypt in-place (out == in) - must produce the same ciphertext */
    XMEMCPY(buf, plain, sizeof(buf));
    ExpectIntEQ(wc_AesXtsSetKey(&aes, key64, sizeof(key64),
        AES_ENCRYPTION, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesXtsEncrypt(&aes, buf, buf, sizeof(buf),
        tweak, sizeof(tweak)), 0);
    wc_AesXtsFree(&aes);
    ExpectBufEQ(buf, ref_ct, sizeof(buf));

#ifdef HAVE_AES_DECRYPT
    /* Decrypt in-place - must recover original plaintext */
    ExpectIntEQ(wc_AesXtsSetKey(&aes, key64, sizeof(key64),
        AES_DECRYPTION, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesXtsDecrypt(&aes, buf, buf, sizeof(buf),
        tweak, sizeof(tweak)), 0);
    wc_AesXtsFree(&aes);
    ExpectBufEQ(buf, plain, sizeof(buf));
#endif
#endif
    return EXPECT_RESULT();
} /* END test_wc_AesXtsEncryptDecrypt_InPlace */

/*******************************************************************************
 * AES-XTS unaligned buffers
 ******************************************************************************/

/*
 * Verify that wc_AesXtsEncrypt / wc_AesXtsDecrypt produce correct results
 * when plaintext and ciphertext buffers are byte-offset (unaligned).  Tests
 * offsets 1, 2, and 3.  Same key/tweak/plain as InPlace test.
 */
int test_wc_AesXtsEncryptDecrypt_UnalignedBuffers(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(WOLFSSL_AES_XTS) && \
    defined(WOLFSSL_AES_256) && !defined(WOLFSSL_AFALG) && \
    !defined(WOLFSSL_KCAPI)
    XtsAes aes;
    static const byte key64[64] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    static const byte tweak[WC_AES_BLOCK_SIZE] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    static const byte plain[24] = {
        0x4e, 0x6f, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74,
        0x68, 0x65, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20,
        0x66, 0x6f, 0x72, 0x20, 0x61, 0x6c, 0x6c, 0x20
    };
    byte ref_ct[sizeof(plain)];
    byte in_buf[sizeof(plain) + 3], out_buf[sizeof(plain) + 3];
    int off;

    XMEMSET(&aes, 0, sizeof(aes));

    /* Reference ciphertext with naturally-aligned buffers */
    ExpectIntEQ(wc_AesXtsSetKey(&aes, key64, sizeof(key64),
        AES_ENCRYPTION, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesXtsEncrypt(&aes, ref_ct, plain, sizeof(plain),
        tweak, sizeof(tweak)), 0);
    wc_AesXtsFree(&aes);

    /* Encrypt with byte offsets 1, 2, 3 on both in and out */
    for (off = 1; off <= 3 && EXPECT_SUCCESS(); off++) {
        XMEMCPY(in_buf + off, plain, sizeof(plain));
        XMEMSET(out_buf, 0, sizeof(out_buf));
        ExpectIntEQ(wc_AesXtsSetKey(&aes, key64, sizeof(key64),
            AES_ENCRYPTION, NULL, INVALID_DEVID), 0);
        ExpectIntEQ(wc_AesXtsEncrypt(&aes, out_buf + off, in_buf + off,
            sizeof(plain), tweak, sizeof(tweak)), 0);
        wc_AesXtsFree(&aes);
        ExpectBufEQ(out_buf + off, ref_ct, sizeof(plain));
    }

#ifdef HAVE_AES_DECRYPT
    /* Decrypt with byte offsets 1, 2, 3 */
    for (off = 1; off <= 3 && EXPECT_SUCCESS(); off++) {
        XMEMCPY(in_buf + off, ref_ct, sizeof(plain));
        XMEMSET(out_buf, 0, sizeof(out_buf));
        ExpectIntEQ(wc_AesXtsSetKey(&aes, key64, sizeof(key64),
            AES_DECRYPTION, NULL, INVALID_DEVID), 0);
        ExpectIntEQ(wc_AesXtsDecrypt(&aes, out_buf + off, in_buf + off,
            sizeof(plain), tweak, sizeof(tweak)), 0);
        wc_AesXtsFree(&aes);
        ExpectBufEQ(out_buf + off, plain, sizeof(plain));
    }
#endif
#endif
    return EXPECT_RESULT();
} /* END test_wc_AesXtsEncryptDecrypt_UnalignedBuffers */

/*******************************************************************************
 * AES-XTS streaming (Init/Update/Final)
 ******************************************************************************/

/*
 * test function for AES-XTS streaming encrypt/decrypt
 */
int test_wc_AesXtsStream(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(WOLFSSL_AES_XTS) && \
    defined(WOLFSSL_AES_256) && defined(WOLFSSL_AESXTS_STREAM) && \
    !defined(WOLFSSL_AFALG) && !defined(WOLFSSL_KCAPI)
    /* Same key as test_wc_AesXtsEncryptDecrypt */
    static const byte key32[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    static const byte tweak[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    /* Non-block-aligned plaintext from test_wc_AesXtsEncryptDecrypt (24 bytes) */
    static const byte vector[] = {
        0x4e, 0x6f, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74,
        0x68, 0x65, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20,
        0x66, 0x6f, 0x72, 0x20, 0x61, 0x6c, 0x6c, 0x20
    };
    const word32 tweakLen = (word32)sizeof(tweak);
    XtsAes aes;
    XtsAesStreamData xtsStream;
    byte plain3[WC_AES_BLOCK_SIZE * 3];  /* block-aligned plaintext */
    byte expEnc[sizeof(vector)];          /* expected ciphertext (non-aligned) */
    byte expEnc3[WC_AES_BLOCK_SIZE * 3];  /* expected ciphertext (3 blocks) */
    byte enc[WC_AES_BLOCK_SIZE * 3];
    byte dec[WC_AES_BLOCK_SIZE * 3];

    XMEMSET(&aes, 0, sizeof(aes));
    XMEMSET(plain3, 0xa5, sizeof(plain3));

    /* Get expected ciphertext for non-aligned vector via single-shot */
    ExpectIntEQ(wc_AesXtsSetKey(&aes, key32, sizeof(key32),
        AES_ENCRYPTION, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesXtsEncrypt(&aes, expEnc, vector, sizeof(vector), tweak,
        tweakLen), 0);
    wc_AesXtsFree(&aes);

    /* Get expected ciphertext for 3-block plain via single-shot */
    ExpectIntEQ(wc_AesXtsSetKey(&aes, key32, sizeof(key32),
        AES_ENCRYPTION, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesXtsEncrypt(&aes, expEnc3, plain3, sizeof(plain3), tweak,
        tweakLen), 0);
    wc_AesXtsFree(&aes);

    /* --- Stream encrypt: Init + Final(non-aligned, 24 bytes) --- */
    XMEMSET(enc, 0, sizeof(enc));
    XMEMSET(&xtsStream, 0, sizeof(xtsStream));
    ExpectIntEQ(wc_AesXtsSetKey(&aes, key32, sizeof(key32),
        AES_ENCRYPTION, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesXtsEncryptInit(&aes, tweak, tweakLen, &xtsStream), 0);
    ExpectIntEQ(wc_AesXtsEncryptFinal(&aes, enc, vector, sizeof(vector),
        &xtsStream), 0);
    ExpectBufEQ(enc, expEnc, sizeof(expEnc));
    wc_AesXtsFree(&aes);

    /* --- Stream encrypt: Init + Update(2 blocks) + Final(1 block) --- */
    XMEMSET(enc, 0, sizeof(enc));
    XMEMSET(&xtsStream, 0, sizeof(xtsStream));
    ExpectIntEQ(wc_AesXtsSetKey(&aes, key32, sizeof(key32),
        AES_ENCRYPTION, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesXtsEncryptInit(&aes, tweak, tweakLen, &xtsStream), 0);
    ExpectIntEQ(wc_AesXtsEncryptUpdate(&aes, enc, plain3,
        WC_AES_BLOCK_SIZE * 2, &xtsStream), 0);
    ExpectIntEQ(wc_AesXtsEncryptFinal(&aes,
        enc + WC_AES_BLOCK_SIZE * 2,
        plain3 + WC_AES_BLOCK_SIZE * 2,
        WC_AES_BLOCK_SIZE, &xtsStream), 0);
    ExpectBufEQ(enc, expEnc3, sizeof(expEnc3));
    wc_AesXtsFree(&aes);

    /* --- Stream encrypt: Init + Update(1 block) x3 via individual calls +
     *     Final(0 bytes) --- */
    XMEMSET(enc, 0, sizeof(enc));
    XMEMSET(&xtsStream, 0, sizeof(xtsStream));
    ExpectIntEQ(wc_AesXtsSetKey(&aes, key32, sizeof(key32),
        AES_ENCRYPTION, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesXtsEncryptInit(&aes, tweak, tweakLen, &xtsStream), 0);
    ExpectIntEQ(wc_AesXtsEncryptUpdate(&aes, enc,
        plain3, WC_AES_BLOCK_SIZE, &xtsStream), 0);
    ExpectIntEQ(wc_AesXtsEncryptUpdate(&aes,
        enc + WC_AES_BLOCK_SIZE,
        plain3 + WC_AES_BLOCK_SIZE, WC_AES_BLOCK_SIZE, &xtsStream), 0);
    ExpectIntEQ(wc_AesXtsEncryptUpdate(&aes,
        enc + WC_AES_BLOCK_SIZE * 2,
        plain3 + WC_AES_BLOCK_SIZE * 2, WC_AES_BLOCK_SIZE, &xtsStream), 0);
    ExpectIntEQ(wc_AesXtsEncryptFinal(&aes, NULL, NULL, 0, &xtsStream), 0);
    ExpectBufEQ(enc, expEnc3, sizeof(expEnc3));
    wc_AesXtsFree(&aes);

#ifdef HAVE_AES_DECRYPT
    /* --- Stream decrypt: Init + Final(non-aligned, 24 bytes) --- */
    XMEMSET(dec, 0, sizeof(dec));
    XMEMSET(&xtsStream, 0, sizeof(xtsStream));
    ExpectIntEQ(wc_AesXtsSetKey(&aes, key32, sizeof(key32),
        AES_DECRYPTION, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesXtsDecryptInit(&aes, tweak, tweakLen, &xtsStream), 0);
    ExpectIntEQ(wc_AesXtsDecryptFinal(&aes, dec, expEnc, sizeof(expEnc),
        &xtsStream), 0);
    ExpectBufEQ(dec, vector, sizeof(vector));
    wc_AesXtsFree(&aes);

    /* --- Stream decrypt: Init + Update(2 blocks) + Final(1 block) --- */
    XMEMSET(dec, 0, sizeof(dec));
    XMEMSET(&xtsStream, 0, sizeof(xtsStream));
    ExpectIntEQ(wc_AesXtsSetKey(&aes, key32, sizeof(key32),
        AES_DECRYPTION, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesXtsDecryptInit(&aes, tweak, tweakLen, &xtsStream), 0);
    ExpectIntEQ(wc_AesXtsDecryptUpdate(&aes, dec, expEnc3,
        WC_AES_BLOCK_SIZE * 2, &xtsStream), 0);
    ExpectIntEQ(wc_AesXtsDecryptFinal(&aes,
        dec + WC_AES_BLOCK_SIZE * 2,
        expEnc3 + WC_AES_BLOCK_SIZE * 2,
        WC_AES_BLOCK_SIZE, &xtsStream), 0);
    ExpectBufEQ(dec, plain3, sizeof(plain3));
    wc_AesXtsFree(&aes);
#endif /* HAVE_AES_DECRYPT */

    /* --- Bad args --- */
    XMEMSET(&xtsStream, 0, sizeof(xtsStream));
    /* NULL aes */
    ExpectIntEQ(wc_AesXtsEncryptInit(NULL, tweak, tweakLen, &xtsStream),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    /* NULL tweak */
    ExpectIntEQ(wc_AesXtsEncryptInit(&aes, NULL, tweakLen, &xtsStream),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    /* NULL stream */
    ExpectIntEQ(wc_AesXtsEncryptInit(&aes, tweak, tweakLen, NULL),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    /* sz not a multiple of block size */
    ExpectIntEQ(wc_AesXtsEncryptUpdate(&aes, enc, plain3, 1, &xtsStream),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    /* NULL stream to Update */
    ExpectIntEQ(wc_AesXtsEncryptUpdate(&aes, enc, plain3,
        WC_AES_BLOCK_SIZE, NULL),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    /* NULL stream to Final */
    ExpectIntEQ(wc_AesXtsEncryptFinal(&aes, enc, vector, sizeof(vector), NULL),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifdef HAVE_AES_DECRYPT
    ExpectIntEQ(wc_AesXtsDecryptInit(NULL, tweak, tweakLen, &xtsStream),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesXtsDecryptInit(&aes, NULL, tweakLen, &xtsStream),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesXtsDecryptInit(&aes, tweak, tweakLen, NULL),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesXtsDecryptUpdate(&aes, dec, expEnc3,
        WC_AES_BLOCK_SIZE, NULL),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesXtsDecryptFinal(&aes, dec, expEnc3, sizeof(plain3), NULL),
        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif /* HAVE_AES_DECRYPT */
#endif
    return EXPECT_RESULT();
} /* END test_wc_AesXtsStream */

/*******************************************************************************
 * AES-XTS streaming mid-stream state corruption
 ******************************************************************************/

/*
 * Verify that calling wc_AesXtsEncryptUpdate / wc_AesXtsDecryptUpdate after
 * wc_AesXtsEncryptFinal / wc_AesXtsDecryptFinal is rejected.
 *
 * AES-XTS tracks state through stream->bytes_crypted_with_this_tweak.  After
 * a Final call that processed a non-block-aligned chunk, this field is left
 * with a value whose low bits are non-zero.  A subsequent Update call checks
 * this condition and returns BAD_FUNC_ARG to prevent reuse of a completed
 * streaming session.
 */
int test_wc_AesXtsStream_MidStreamState(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(WOLFSSL_AES_XTS) && \
    defined(WOLFSSL_AES_256) && defined(WOLFSSL_AESXTS_STREAM) && \
    !defined(WOLFSSL_AFALG) && !defined(WOLFSSL_KCAPI)
    static const byte key64[64] = {
        0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37,
        0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37,
        0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37,
        0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37,
        0x38,0x39,0x61,0x62, 0x63,0x64,0x65,0x66,
        0x38,0x39,0x61,0x62, 0x63,0x64,0x65,0x66,
        0x38,0x39,0x61,0x62, 0x63,0x64,0x65,0x66,
        0x38,0x39,0x61,0x62, 0x63,0x64,0x65,0x66
    };
    static const byte tweak[WC_AES_BLOCK_SIZE] = {
        0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37,
        0x38,0x39,0x61,0x62, 0x63,0x64,0x65,0x66
    };
    /* 24-byte (non-block-aligned) vector - ensures Final leaves
     * bytes_crypted_with_this_tweak with a value whose low 4 bits are
     * non-zero, triggering the guard on the next Update call. */
    static const byte plain24[24] = {
        0x4e,0x6f,0x77,0x20, 0x69,0x73,0x20,0x74,
        0x68,0x65,0x20,0x74, 0x69,0x6d,0x65,0x20,
        0x66,0x6f,0x72,0x20, 0x61,0x6c,0x6c,0x20
    };
    /* One full block for the subsequent (illegal) Update call. */
    static const byte oneBlock[WC_AES_BLOCK_SIZE] = { 0 };
    XtsAes aes;
    XtsAesStreamData xtsStream;
    byte enc[24];
    byte dummy[WC_AES_BLOCK_SIZE];

    XMEMSET(&aes, 0, sizeof(aes));

    /* ------------------------------------------------------------------
     * Encrypt: Init -> Final (non-aligned 24 B) -> Update must fail
     * ------------------------------------------------------------------ */
    ExpectIntEQ(wc_AesXtsSetKey(&aes, key64, sizeof(key64),
        AES_ENCRYPTION, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesXtsEncryptInit(&aes, tweak, sizeof(tweak), &xtsStream), 0);
    /* Final processes all 24 bytes; bytes_crypted_with_this_tweak becomes 24
     * (not a multiple of WC_AES_BLOCK_SIZE=16). */
    ExpectIntEQ(wc_AesXtsEncryptFinal(&aes, enc, plain24, sizeof(plain24),
        &xtsStream), 0);
    /* The subsequent Update must be rejected because the stream is "done". */
    ExpectIntEQ(wc_AesXtsEncryptUpdate(&aes, dummy, oneBlock, sizeof(oneBlock),
        &xtsStream), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    wc_AesXtsFree(&aes);

#ifdef HAVE_AES_DECRYPT
    /* ------------------------------------------------------------------
     * Decrypt: Init -> Final (non-aligned 24 B) -> Update must fail
     * ------------------------------------------------------------------ */
    XMEMSET(&aes, 0, sizeof(aes));
    ExpectIntEQ(wc_AesXtsSetKey(&aes, key64, sizeof(key64),
        AES_DECRYPTION, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesXtsDecryptInit(&aes, tweak, sizeof(tweak), &xtsStream), 0);
    ExpectIntEQ(wc_AesXtsDecryptFinal(&aes, enc, enc, sizeof(enc),
        &xtsStream), 0);
    ExpectIntEQ(wc_AesXtsDecryptUpdate(&aes, dummy, oneBlock, sizeof(oneBlock),
        &xtsStream), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    wc_AesXtsFree(&aes);
#endif
#endif
    return EXPECT_RESULT();
} /* END test_wc_AesXtsStream_MidStreamState */

/*******************************************************************************
 * AES-XTS streaming re-initialization after Final
 ******************************************************************************/

/*
 * Verify that an AES-XTS streaming context can be re-initialized and reused
 * after wc_AesXtsEncryptFinal / wc_AesXtsDecryptFinal.
 *
 * wc_AesXtsEncryptInit unconditionally resets stream->bytes_crypted_with_this_tweak
 * to 0 and reloads the tweak, so it is safe to call it again after Final.
 *
 *  1. Re-init with the same key and tweak produces identical ciphertext.
 *  2. Re-init with a different tweak produces different ciphertext.
 *  3. Re-init after an abandoned session (Init + Update but no Final) works.
 *  4. Decrypt re-init: recover plaintext across two separate sessions.
 */
int test_wc_AesXtsStream_ReinitAfterFinal(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(WOLFSSL_AES_XTS) && \
    defined(WOLFSSL_AES_256) && defined(WOLFSSL_AESXTS_STREAM) && \
    !defined(WOLFSSL_AFALG) && !defined(WOLFSSL_KCAPI)
    static const byte key64[64] = {
        0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37,
        0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37,
        0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37,
        0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37,
        0x38,0x39,0x61,0x62, 0x63,0x64,0x65,0x66,
        0x38,0x39,0x61,0x62, 0x63,0x64,0x65,0x66,
        0x38,0x39,0x61,0x62, 0x63,0x64,0x65,0x66,
        0x38,0x39,0x61,0x62, 0x63,0x64,0x65,0x66
    };
    /* Two distinct tweaks (sector numbers). */
    static const byte tweak1[WC_AES_BLOCK_SIZE] = {
        0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37,
        0x38,0x39,0x61,0x62, 0x63,0x64,0x65,0x66
    };
    static const byte tweak2[WC_AES_BLOCK_SIZE] = {
        0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37,
        0x38,0x39,0x61,0x62, 0x63,0x64,0x65,0x67  /* last byte differs */
    };
    /* Two-block-aligned plaintext + a partial tail (40 bytes total). */
    static const byte plain[40] = {
        0x4e,0x6f,0x77,0x20, 0x69,0x73,0x20,0x74,
        0x68,0x65,0x20,0x74, 0x69,0x6d,0x65,0x20,
        0x66,0x6f,0x72,0x20, 0x61,0x6c,0x6c,0x20,
        0x67,0x6f,0x6f,0x64, 0x20,0x6d,0x65,0x6e,
        0x20,0x74,0x6f,0x20, 0x63,0x6f,0x6d,0x65
    };
    XtsAes aes;
    XtsAesStreamData xtsStream;
    byte ct1[sizeof(plain)], ct2[sizeof(plain)], ct3[sizeof(plain)];
#ifdef HAVE_AES_DECRYPT
    byte pt[sizeof(plain)];
#endif

    XMEMSET(&aes, 0, sizeof(aes));
    ExpectIntEQ(wc_AesXtsSetKey(&aes, key64, sizeof(key64),
        AES_ENCRYPTION, NULL, INVALID_DEVID), 0);

    /* ---- Session 1: baseline ----
     * One full block via Update, the remaining 24 bytes via Final.
     * Note: AesXtsEncryptFinal forwards to the Update path, so the Final
     * size must be >= WC_AES_BLOCK_SIZE when sz > 0. */
    ExpectIntEQ(wc_AesXtsEncryptInit(&aes, tweak1, sizeof(tweak1), &xtsStream), 0);
    ExpectIntEQ(wc_AesXtsEncryptUpdate(&aes, ct1, plain,
        WC_AES_BLOCK_SIZE, &xtsStream), 0);
    ExpectIntEQ(wc_AesXtsEncryptFinal(&aes, ct1 + WC_AES_BLOCK_SIZE,
        plain + WC_AES_BLOCK_SIZE,
        sizeof(plain) - WC_AES_BLOCK_SIZE, &xtsStream), 0);

    /* ---- Session 2: re-init with same tweak -> must match ---- */
    ExpectIntEQ(wc_AesXtsEncryptInit(&aes, tweak1, sizeof(tweak1), &xtsStream), 0);
    ExpectIntEQ(wc_AesXtsEncryptUpdate(&aes, ct2, plain,
        WC_AES_BLOCK_SIZE, &xtsStream), 0);
    ExpectIntEQ(wc_AesXtsEncryptFinal(&aes, ct2 + WC_AES_BLOCK_SIZE,
        plain + WC_AES_BLOCK_SIZE,
        sizeof(plain) - WC_AES_BLOCK_SIZE, &xtsStream), 0);
    ExpectBufEQ(ct2, ct1, sizeof(ct1));

    /* ---- Session 3: re-init with different tweak -> must differ ---- */
    ExpectIntEQ(wc_AesXtsEncryptInit(&aes, tweak2, sizeof(tweak2), &xtsStream), 0);
    ExpectIntEQ(wc_AesXtsEncryptUpdate(&aes, ct3, plain,
        WC_AES_BLOCK_SIZE, &xtsStream), 0);
    ExpectIntEQ(wc_AesXtsEncryptFinal(&aes, ct3 + WC_AES_BLOCK_SIZE,
        plain + WC_AES_BLOCK_SIZE,
        sizeof(plain) - WC_AES_BLOCK_SIZE, &xtsStream), 0);
    ExpectIntNE(XMEMCMP(ct3, ct1, sizeof(ct1)), 0);

    /* ---- Session 4: re-init after abandoned (no Final) session ---- */
    ExpectIntEQ(wc_AesXtsEncryptInit(&aes, tweak2, sizeof(tweak2), &xtsStream), 0);
    ExpectIntEQ(wc_AesXtsEncryptUpdate(&aes, ct3, plain,
        WC_AES_BLOCK_SIZE, &xtsStream), 0);
    /* Abandon - re-init with tweak1, must give session-1 output. */
    ExpectIntEQ(wc_AesXtsEncryptInit(&aes, tweak1, sizeof(tweak1), &xtsStream), 0);
    ExpectIntEQ(wc_AesXtsEncryptUpdate(&aes, ct2, plain,
        WC_AES_BLOCK_SIZE, &xtsStream), 0);
    ExpectIntEQ(wc_AesXtsEncryptFinal(&aes, ct2 + WC_AES_BLOCK_SIZE,
        plain + WC_AES_BLOCK_SIZE,
        sizeof(plain) - WC_AES_BLOCK_SIZE, &xtsStream), 0);
    ExpectBufEQ(ct2, ct1, sizeof(ct1));

    wc_AesXtsFree(&aes);

#ifdef HAVE_AES_DECRYPT
    /* ---- Decrypt: re-init recovers plaintext on each session ---- */
    XMEMSET(&aes, 0, sizeof(aes));
    ExpectIntEQ(wc_AesXtsSetKey(&aes, key64, sizeof(key64),
        AES_DECRYPTION, NULL, INVALID_DEVID), 0);

    /* Session A: decrypt ct1 with tweak1 -> plaintext. */
    ExpectIntEQ(wc_AesXtsDecryptInit(&aes, tweak1, sizeof(tweak1), &xtsStream), 0);
    ExpectIntEQ(wc_AesXtsDecryptUpdate(&aes, pt, ct1,
        WC_AES_BLOCK_SIZE, &xtsStream), 0);
    ExpectIntEQ(wc_AesXtsDecryptFinal(&aes, pt + WC_AES_BLOCK_SIZE,
        ct1 + WC_AES_BLOCK_SIZE,
        sizeof(ct1) - WC_AES_BLOCK_SIZE, &xtsStream), 0);
    ExpectBufEQ(pt, plain, sizeof(plain));

    /* Session B: re-init and decrypt again -> same plaintext. */
    ExpectIntEQ(wc_AesXtsDecryptInit(&aes, tweak1, sizeof(tweak1), &xtsStream), 0);
    ExpectIntEQ(wc_AesXtsDecryptUpdate(&aes, pt, ct1,
        WC_AES_BLOCK_SIZE, &xtsStream), 0);
    ExpectIntEQ(wc_AesXtsDecryptFinal(&aes, pt + WC_AES_BLOCK_SIZE,
        ct1 + WC_AES_BLOCK_SIZE,
        sizeof(ct1) - WC_AES_BLOCK_SIZE, &xtsStream), 0);
    ExpectBufEQ(pt, plain, sizeof(plain));

    wc_AesXtsFree(&aes);
#endif
#endif
    return EXPECT_RESULT();
} /* END test_wc_AesXtsStream_ReinitAfterFinal */

/*******************************************************************************
 * AES-XTS sector APIs
 ******************************************************************************/

/*
 * test function for wc_AesXtsEncryptSector, wc_AesXtsDecryptSector,
 * wc_AesXtsEncryptConsecutiveSectors, and wc_AesXtsDecryptConsecutiveSectors
 */
int test_wc_AesXtsEncryptDecryptSector(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(WOLFSSL_AES_XTS) && \
    defined(WOLFSSL_AES_256) && !defined(WOLFSSL_AFALG) && \
    !defined(WOLFSSL_KCAPI)
    /* Sector size used for consecutive-sector tests (2 AES blocks) */
    #define SECTOR_SZ   (WC_AES_BLOCK_SIZE * 2)
    #define NUM_SECTORS  3
    #define TOTAL_SZ    (SECTOR_SZ * NUM_SECTORS)

    static const byte key32[] = {
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
        0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
    };
    XtsAes aes;
    byte plain[TOTAL_SZ];
    byte enc[TOTAL_SZ];
    byte dec[TOTAL_SZ];
    byte encRef[TOTAL_SZ];   /* sector-by-sector reference */
    byte zeroTweak[WC_AES_BLOCK_SIZE];
    byte encZeroTweak[SECTOR_SZ];
    byte encSector0[SECTOR_SZ];
    byte encSector1[SECTOR_SZ];
    int i;

    XMEMSET(&aes, 0, sizeof(aes));
    XMEMSET(zeroTweak, 0, sizeof(zeroTweak));

    /* Fill plaintext with a recognisable pattern */
    for (i = 0; i < (int)sizeof(plain); i++)
        plain[i] = (byte)i;

    /*
     * 1. wc_AesXtsEncryptSector / wc_AesXtsDecryptSector
     */

    /* Encrypt sector 0 and verify it matches wc_AesXtsEncrypt with zero tweak */
    ExpectIntEQ(wc_AesXtsSetKey(&aes, key32, sizeof(key32),
        AES_ENCRYPTION, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesXtsEncryptSector(&aes, encSector0, plain,
        SECTOR_SZ, 0), 0);
    ExpectIntEQ(wc_AesXtsEncrypt(&aes, encZeroTweak, plain, SECTOR_SZ,
        zeroTweak, WC_AES_BLOCK_SIZE), 0);
    ExpectBufEQ(encSector0, encZeroTweak, SECTOR_SZ);
    wc_AesXtsFree(&aes);

    /* Encrypt sector 1 and verify it differs from sector 0 */
    ExpectIntEQ(wc_AesXtsSetKey(&aes, key32, sizeof(key32),
        AES_ENCRYPTION, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesXtsEncryptSector(&aes, encSector1, plain,
        SECTOR_SZ, 1), 0);
    ExpectIntNE(XMEMCMP(encSector0, encSector1, SECTOR_SZ), 0);
    wc_AesXtsFree(&aes);

#ifdef HAVE_AES_DECRYPT
    /* Decrypt sector 0 and verify roundtrip */
    XMEMSET(dec, 0, sizeof(dec));
    ExpectIntEQ(wc_AesXtsSetKey(&aes, key32, sizeof(key32),
        AES_DECRYPTION, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesXtsDecryptSector(&aes, dec, encSector0,
        SECTOR_SZ, 0), 0);
    ExpectBufEQ(dec, plain, SECTOR_SZ);
    wc_AesXtsFree(&aes);

    /* Decrypt sector 1 and verify roundtrip */
    XMEMSET(dec, 0, sizeof(dec));
    ExpectIntEQ(wc_AesXtsSetKey(&aes, key32, sizeof(key32),
        AES_DECRYPTION, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesXtsDecryptSector(&aes, dec, encSector1,
        SECTOR_SZ, 1), 0);
    ExpectBufEQ(dec, plain, SECTOR_SZ);
    wc_AesXtsFree(&aes);
#endif /* HAVE_AES_DECRYPT */

    /*
     * 2. wc_AesXtsEncryptConsecutiveSectors
     */

    /* Build reference ciphertext by encrypting each sector individually */
    ExpectIntEQ(wc_AesXtsSetKey(&aes, key32, sizeof(key32),
        AES_ENCRYPTION, NULL, INVALID_DEVID), 0);
    for (i = 0; i < NUM_SECTORS; i++) {
        ExpectIntEQ(wc_AesXtsEncryptSector(&aes,
            encRef + i * SECTOR_SZ,
            plain  + i * SECTOR_SZ,
            SECTOR_SZ, (word64)(5 + i)), 0);
    }
    wc_AesXtsFree(&aes);

    /* Encrypt all sectors in one call and compare against reference */
    XMEMSET(enc, 0, sizeof(enc));
    ExpectIntEQ(wc_AesXtsSetKey(&aes, key32, sizeof(key32),
        AES_ENCRYPTION, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesXtsEncryptConsecutiveSectors(&aes, enc, plain,
        TOTAL_SZ, 5, SECTOR_SZ), 0);
    ExpectBufEQ(enc, encRef, TOTAL_SZ);
    wc_AesXtsFree(&aes);

#ifdef HAVE_AES_DECRYPT
    /* Decrypt all sectors at once and verify roundtrip */
    XMEMSET(dec, 0, sizeof(dec));
    ExpectIntEQ(wc_AesXtsSetKey(&aes, key32, sizeof(key32),
        AES_DECRYPTION, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesXtsDecryptConsecutiveSectors(&aes, dec, enc,
        TOTAL_SZ, 5, SECTOR_SZ), 0);
    ExpectBufEQ(dec, plain, TOTAL_SZ);
    wc_AesXtsFree(&aes);
#endif /* HAVE_AES_DECRYPT */

    /*
     * 3. ConsecutiveSectors with a remainder (total not a multiple of sectorSz)
     *    TOTAL_SZ + WC_AES_BLOCK_SIZE bytes: NUM_SECTORS full sectors plus one
     *    partial sector of exactly WC_AES_BLOCK_SIZE bytes.
     */
    {
        #define REMAINDER_SZ  (TOTAL_SZ + WC_AES_BLOCK_SIZE)
        byte plainR[REMAINDER_SZ];
        byte encR[REMAINDER_SZ];
        byte decR[REMAINDER_SZ];
        byte encRref[REMAINDER_SZ];

        for (i = 0; i < (int)sizeof(plainR); i++)
            plainR[i] = (byte)(i ^ 0xA5);

        /* Build reference: NUM_SECTORS full + 1 partial */
        ExpectIntEQ(wc_AesXtsSetKey(&aes, key32, sizeof(key32),
            AES_ENCRYPTION, NULL, INVALID_DEVID), 0);
        for (i = 0; i < NUM_SECTORS; i++) {
            ExpectIntEQ(wc_AesXtsEncryptSector(&aes,
                encRref + i * SECTOR_SZ,
                plainR  + i * SECTOR_SZ,
                SECTOR_SZ, (word64)(10 + i)), 0);
        }
        /* Partial final sector */
        ExpectIntEQ(wc_AesXtsEncryptSector(&aes,
            encRref + TOTAL_SZ,
            plainR  + TOTAL_SZ,
            WC_AES_BLOCK_SIZE, (word64)(10 + NUM_SECTORS)), 0);
        wc_AesXtsFree(&aes);

        /* ConsecutiveSectors with same data */
        XMEMSET(encR, 0, sizeof(encR));
        ExpectIntEQ(wc_AesXtsSetKey(&aes, key32, sizeof(key32),
            AES_ENCRYPTION, NULL, INVALID_DEVID), 0);
        ExpectIntEQ(wc_AesXtsEncryptConsecutiveSectors(&aes, encR, plainR,
            REMAINDER_SZ, 10, SECTOR_SZ), 0);
        ExpectBufEQ(encR, encRref, REMAINDER_SZ);
        wc_AesXtsFree(&aes);

#ifdef HAVE_AES_DECRYPT
        XMEMSET(decR, 0, sizeof(decR));
        ExpectIntEQ(wc_AesXtsSetKey(&aes, key32, sizeof(key32),
            AES_DECRYPTION, NULL, INVALID_DEVID), 0);
        ExpectIntEQ(wc_AesXtsDecryptConsecutiveSectors(&aes, decR, encR,
            REMAINDER_SZ, 10, SECTOR_SZ), 0);
        ExpectBufEQ(decR, plainR, REMAINDER_SZ);
        wc_AesXtsFree(&aes);
#endif /* HAVE_AES_DECRYPT */

        #undef REMAINDER_SZ
    }

    /*
     * 4. Bad args for ConsecutiveSectors
     */
    ExpectIntEQ(wc_AesXtsEncryptConsecutiveSectors(NULL, enc, plain,
        TOTAL_SZ, 0, SECTOR_SZ), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesXtsEncryptConsecutiveSectors(&aes, NULL, plain,
        TOTAL_SZ, 0, SECTOR_SZ), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesXtsEncryptConsecutiveSectors(&aes, enc, NULL,
        TOTAL_SZ, 0, SECTOR_SZ), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    /* sectorSz == 0 */
    ExpectIntEQ(wc_AesXtsEncryptConsecutiveSectors(&aes, enc, plain,
        TOTAL_SZ, 0, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    /* sz < WC_AES_BLOCK_SIZE */
    ExpectIntEQ(wc_AesXtsEncryptConsecutiveSectors(&aes, enc, plain,
        WC_AES_BLOCK_SIZE - 1, 0, SECTOR_SZ), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifdef HAVE_AES_DECRYPT
    ExpectIntEQ(wc_AesXtsDecryptConsecutiveSectors(NULL, dec, enc,
        TOTAL_SZ, 0, SECTOR_SZ), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesXtsDecryptConsecutiveSectors(&aes, NULL, enc,
        TOTAL_SZ, 0, SECTOR_SZ), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesXtsDecryptConsecutiveSectors(&aes, dec, NULL,
        TOTAL_SZ, 0, SECTOR_SZ), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesXtsDecryptConsecutiveSectors(&aes, dec, enc,
        TOTAL_SZ, 0, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesXtsDecryptConsecutiveSectors(&aes, dec, enc,
        WC_AES_BLOCK_SIZE - 1, 0, SECTOR_SZ), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#endif /* HAVE_AES_DECRYPT */

    #undef SECTOR_SZ
    #undef NUM_SECTORS
    #undef TOTAL_SZ
#endif
    return EXPECT_RESULT();
} /* END test_wc_AesXtsEncryptDecryptSector */

#if defined(WOLFSSL_AES_EAX) && defined(WOLFSSL_AES_256) && \
    (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5, 3)) && !defined(HAVE_SELFTEST)

/*******************************************************************************
 * AES-EAX
 ******************************************************************************/

/*
 * Testing test_wc_AesEaxVectors()
 */
int test_wc_AesEaxVectors(void)
{
    EXPECT_DECLS;

    typedef struct {
        byte key[AES_256_KEY_SIZE];
        int key_length;
        byte iv[WC_AES_BLOCK_SIZE];
        int iv_length;
        byte aad[WC_AES_BLOCK_SIZE * 2];
        int aad_length;
        byte msg[WC_AES_BLOCK_SIZE * 5];
        int msg_length;
        byte ct[WC_AES_BLOCK_SIZE * 5];
        int ct_length;
        byte tag[WC_AES_BLOCK_SIZE];
        int tag_length;
        int valid;
    } AadVector;

    /*  Test vectors obtained from Google wycheproof project
     *  https://github.com/google/wycheproof
     *  from testvectors/aes_eax_test.json
     */
    const AadVector vectors[] = {
    #ifdef WOLFSSL_AES_128
        {
            /* key, key length  */
            {0x23, 0x39, 0x52, 0xde, 0xe4, 0xd5, 0xed, 0x5f,
             0x9b, 0x9c, 0x6d, 0x6f, 0xf8, 0x0f, 0xf4, 0x78}, 16,
            /* iv, iv length  */
            {0x62, 0xec, 0x67, 0xf9, 0xc3, 0xa4, 0xa4, 0x07,
             0xfc, 0xb2, 0xa8, 0xc4, 0x90, 0x31, 0xa8, 0xb3}, 16,
            /* aad, aad length  */
            {0x6b, 0xfb, 0x91, 0x4f, 0xd0, 0x7e, 0xae, 0x6b}, 8,
            /* msg, msg length  */
            {0x00}, 0,
            /* ct, ct length  */
            {0x00}, 0,
            /* tag, tag length  */
            {0xe0, 0x37, 0x83, 0x0e, 0x83, 0x89, 0xf2, 0x7b,
             0x02, 0x5a, 0x2d, 0x65, 0x27, 0xe7, 0x9d, 0x01}, 16,
            /* valid */
            1,
        },
        {
            /* key, key length  */
            {0x91, 0x94, 0x5d, 0x3f, 0x4d, 0xcb, 0xee, 0x0b,
             0xf4, 0x5e, 0xf5, 0x22, 0x55, 0xf0, 0x95, 0xa4}, 16,
            /* iv, iv length  */
            {0xbe, 0xca, 0xf0, 0x43, 0xb0, 0xa2, 0x3d, 0x84,
             0x31, 0x94, 0xba, 0x97, 0x2c, 0x66, 0xde, 0xbd}, 16,
            /* aad, aad length  */
            {0xfa, 0x3b, 0xfd, 0x48, 0x06, 0xeb, 0x53, 0xfa}, 8,
            /* msg, msg length  */
            {0xf7, 0xfb}, 2,
            /* ct, ct length  */
            {0x19, 0xdd}, 2,
            /* tag, tag length  */
            {0x5c, 0x4c, 0x93, 0x31, 0x04, 0x9d, 0x0b, 0xda,
             0xb0, 0x27, 0x74, 0x08, 0xf6, 0x79, 0x67, 0xe5}, 16,
            /* valid */
            1,
        },
        {
            /* key, key length  */
            {0x01, 0xf7, 0x4a, 0xd6, 0x40, 0x77, 0xf2, 0xe7,
             0x04, 0xc0, 0xf6, 0x0a, 0xda, 0x3d, 0xd5, 0x23}, 16,
            /* iv, iv length  */
            {0x70, 0xc3, 0xdb, 0x4f, 0x0d, 0x26, 0x36, 0x84,
             0x00, 0xa1, 0x0e, 0xd0, 0x5d, 0x2b, 0xff, 0x5e}, 16,
            /* aad, aad length  */
            {0x23, 0x4a, 0x34, 0x63, 0xc1, 0x26, 0x4a, 0xc6}, 8,
            /* msg, msg length  */
            {0x1a, 0x47, 0xcb, 0x49, 0x33}, 5,
            /* ct, ct length  */
            {0xd8, 0x51, 0xd5, 0xba, 0xe0}, 5,
            /* tag, tag length  */
            {0x3a, 0x59, 0xf2, 0x38, 0xa2, 0x3e, 0x39, 0x19,
             0x9d, 0xc9, 0x26, 0x66, 0x26, 0xc4, 0x0f, 0x80}, 16,
            /* valid */
            1,
        },
        {
            /* key, key length  */
            {0xd0, 0x7c, 0xf6, 0xcb, 0xb7, 0xf3, 0x13, 0xbd,
             0xde, 0x66, 0xb7, 0x27, 0xaf, 0xd3, 0xc5, 0xe8}, 16,
            /* iv, iv length  */
            {0x84, 0x08, 0xdf, 0xff, 0x3c, 0x1a, 0x2b, 0x12,
             0x92, 0xdc, 0x19, 0x9e, 0x46, 0xb7, 0xd6, 0x17}, 16,
            /* aad, aad length  */
            {0x33, 0xcc, 0xe2, 0xea, 0xbf, 0xf5, 0xa7, 0x9d}, 8,
            /* msg, msg length  */
            {0x48, 0x1c, 0x9e, 0x39, 0xb1}, 5,
            /* ct, ct length  */
            {0x63, 0x2a, 0x9d, 0x13, 0x1a}, 5,
            /* tag, tag length  */
            {0xd4, 0xc1, 0x68, 0xa4, 0x22, 0x5d, 0x8e, 0x1f,
             0xf7, 0x55, 0x93, 0x99, 0x74, 0xa7, 0xbe, 0xde}, 16,
            /* valid */
            1,
        },
        {
            /* key, key length  */
            {0x35, 0xb6, 0xd0, 0x58, 0x00, 0x05, 0xbb, 0xc1,
             0x2b, 0x05, 0x87, 0x12, 0x45, 0x57, 0xd2, 0xc2}, 16,
            /* iv, iv length  */
            {0xfd, 0xb6, 0xb0, 0x66, 0x76, 0xee, 0xdc, 0x5c,
             0x61, 0xd7, 0x42, 0x76, 0xe1, 0xf8, 0xe8, 0x16}, 16,
            /* aad, aad length  */
            {0xae, 0xb9, 0x6e, 0xae, 0xbe, 0x29, 0x70, 0xe9}, 8,
            /* msg, msg length  */
            {0x40, 0xd0, 0xc0, 0x7d, 0xa5, 0xe4}, 6,
            /* ct, ct length  */
            {0x07, 0x1d, 0xfe, 0x16, 0xc6, 0x75}, 6,
            /* tag, tag length  */
            {0xcb, 0x06, 0x77, 0xe5, 0x36, 0xf7, 0x3a, 0xfe,
             0x6a, 0x14, 0xb7, 0x4e, 0xe4, 0x98, 0x44, 0xdd}, 16,
            /* valid */
            1,
        },
        {
            /* key, key length  */
            {0xbd, 0x8e, 0x6e, 0x11, 0x47, 0x5e, 0x60, 0xb2,
             0x68, 0x78, 0x4c, 0x38, 0xc6, 0x2f, 0xeb, 0x22}, 16,
            /* iv, iv length  */
            {0x6e, 0xac, 0x5c, 0x93, 0x07, 0x2d, 0x8e, 0x85,
             0x13, 0xf7, 0x50, 0x93, 0x5e, 0x46, 0xda, 0x1b}, 16,
            /* aad, aad length  */
            {0xd4, 0x48, 0x2d, 0x1c, 0xa7, 0x8d, 0xce, 0x0f}, 8,
            /* msg, msg length  */
            {0x4d, 0xe3, 0xb3, 0x5c, 0x3f, 0xc0, 0x39, 0x24,
             0x5b, 0xd1, 0xfb, 0x7d}, 12,
            /* ct, ct length  */
            {0x83, 0x5b, 0xb4, 0xf1, 0x5d, 0x74, 0x3e, 0x35,
             0x0e, 0x72, 0x84, 0x14}, 12,
            /* tag, tag length  */
            {0xab, 0xb8, 0x64, 0x4f, 0xd6, 0xcc, 0xb8, 0x69,
             0x47, 0xc5, 0xe1, 0x05, 0x90, 0x21, 0x0a, 0x4f}, 16,
            /* valid */
            1,
        },
        {
            /* key, key length  */
            {0x7c, 0x77, 0xd6, 0xe8, 0x13, 0xbe, 0xd5, 0xac,
             0x98, 0xba, 0xa4, 0x17, 0x47, 0x7a, 0x2e, 0x7d}, 16,
            /* iv, iv length  */
            {0x1a, 0x8c, 0x98, 0xdc, 0xd7, 0x3d, 0x38, 0x39,
             0x3b, 0x2b, 0xf1, 0x56, 0x9d, 0xee, 0xfc, 0x19}, 16,
            /* aad, aad length  */
            {0x65, 0xd2, 0x01, 0x79, 0x90, 0xd6, 0x25, 0x28}, 8,
            /* msg, msg length  */
            {0x8b, 0x0a, 0x79, 0x30, 0x6c, 0x9c, 0xe7, 0xed,
             0x99, 0xda, 0xe4, 0xf8, 0x7f, 0x8d, 0xd6, 0x16,
             0x36}, 17,
            /* ct, ct length  */
            {0x02, 0x08, 0x3e, 0x39, 0x79, 0xda, 0x01, 0x48,
             0x12, 0xf5, 0x9f, 0x11, 0xd5, 0x26, 0x30, 0xda,
             0x30}, 17,
            /* tag, tag length  */
            {0x13, 0x73, 0x27, 0xd1, 0x06, 0x49, 0xb0, 0xaa,
             0x6e, 0x1c, 0x18, 0x1d, 0xb6, 0x17, 0xd7, 0xf2}, 16,
            /* valid */
            1,
        },
        {
            /* key, key length  */
            {0x5f, 0xff, 0x20, 0xca, 0xfa, 0xb1, 0x19, 0xca,
             0x2f, 0xc7, 0x35, 0x49, 0xe2, 0x0f, 0x5b, 0x0d}, 16,
            /* iv, iv length  */
            {0xdd, 0xe5, 0x9b, 0x97, 0xd7, 0x22, 0x15, 0x6d,
             0x4d, 0x9a, 0xff, 0x2b, 0xc7, 0x55, 0x98, 0x26}, 16,
            /* aad, aad length  */
            {0x54, 0xb9, 0xf0, 0x4e, 0x6a, 0x09, 0x18, 0x9a}, 8,
            /* msg, msg length  */
            {0x1b, 0xda, 0x12, 0x2b, 0xce, 0x8a, 0x8d, 0xba,
             0xf1, 0x87, 0x7d, 0x96, 0x2b, 0x85, 0x92, 0xdd,
             0x2d, 0x56}, 18,
            /* ct, ct length  */
            {0x2e, 0xc4, 0x7b, 0x2c, 0x49, 0x54, 0xa4, 0x89,
             0xaf, 0xc7, 0xba, 0x48, 0x97, 0xed, 0xcd, 0xae,
             0x8c, 0xc3}, 18,
            /* tag, tag length  */
            {0x3b, 0x60, 0x45, 0x05, 0x99, 0xbd, 0x02, 0xc9,
             0x63, 0x82, 0x90, 0x2a, 0xef, 0x7f, 0x83, 0x2a}, 16,
            /* valid */
            1,
        },
        {
            /* key, key length  */
            {0xa4, 0xa4, 0x78, 0x2b, 0xcf, 0xfd, 0x3e, 0xc5,
             0xe7, 0xef, 0x6d, 0x8c, 0x34, 0xa5, 0x61, 0x23}, 16,
            /* iv, iv length  */
            {0xb7, 0x81, 0xfc, 0xf2, 0xf7, 0x5f, 0xa5, 0xa8,
             0xde, 0x97, 0xa9, 0xca, 0x48, 0xe5, 0x22, 0xec}, 16,
            /* aad, aad length  */
            {0x89, 0x9a, 0x17, 0x58, 0x97, 0x56, 0x1d, 0x7e}, 8,
            /* msg, msg length  */
            {0x6c, 0xf3, 0x67, 0x20, 0x87, 0x2b, 0x85, 0x13,
             0xf6, 0xea, 0xb1, 0xa8, 0xa4, 0x44, 0x38, 0xd5,
             0xef, 0x11}, 18,
            /* ct, ct length  */
            {0x0d, 0xe1, 0x8f, 0xd0, 0xfd, 0xd9, 0x1e, 0x7a,
             0xf1, 0x9f, 0x1d, 0x8e, 0xe8, 0x73, 0x39, 0x38,
             0xb1, 0xe8}, 18,
            /* tag, tag length  */
            {0xe7, 0xf6, 0xd2, 0x23, 0x16, 0x18, 0x10, 0x2f,
             0xdb, 0x7f, 0xe5, 0x5f, 0xf1, 0x99, 0x17, 0x00}, 16,
            /* valid */
            1,
        },
        {
            /* key, key length  */
            {0x83, 0x95, 0xfc, 0xf1, 0xe9, 0x5b, 0xeb, 0xd6,
             0x97, 0xbd, 0x01, 0x0b, 0xc7, 0x66, 0xaa, 0xc3}, 16,
            /* iv, iv length  */
            {0x22, 0xe7, 0xad, 0xd9, 0x3c, 0xfc, 0x63, 0x93,
             0xc5, 0x7e, 0xc0, 0xb3, 0xc1, 0x7d, 0x6b, 0x44}, 16,
            /* aad, aad length  */
            {0x12, 0x67, 0x35, 0xfc, 0xc3, 0x20, 0xd2, 0x5a}, 8,
            /* msg, msg length  */
            {0xca, 0x40, 0xd7, 0x44, 0x6e, 0x54, 0x5f, 0xfa,
             0xed, 0x3b, 0xd1, 0x2a, 0x74, 0x0a, 0x65, 0x9f,
             0xfb, 0xbb, 0x3c, 0xea, 0xb7}, 21,
            /* ct, ct length  */
            {0xcb, 0x89, 0x20, 0xf8, 0x7a, 0x6c, 0x75, 0xcf,
             0xf3, 0x96, 0x27, 0xb5, 0x6e, 0x3e, 0xd1, 0x97,
             0xc5, 0x52, 0xd2, 0x95, 0xa7}, 21,
            /* tag, tag length  */
            {0xcf, 0xc4, 0x6a, 0xfc, 0x25, 0x3b, 0x46, 0x52,
             0xb1, 0xaf, 0x37, 0x95, 0xb1, 0x24, 0xab, 0x6e}, 16,
            /* valid */
            1,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x3c, 0x8c, 0xc2, 0x97, 0x0a, 0x00, 0x8f, 0x75,
             0xcc, 0x5b, 0xea, 0xe2, 0x84, 0x72, 0x58, 0xc2}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
             0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 32,
            /* ct, ct length  */
            {0x3c, 0x44, 0x1f, 0x32, 0xce, 0x07, 0x82, 0x23,
             0x64, 0xd7, 0xa2, 0x99, 0x0e, 0x50, 0xbb, 0x13,
             0xd7, 0xb0, 0x2a, 0x26, 0x96, 0x9e, 0x4a, 0x93,
             0x7e, 0x5e, 0x90, 0x73, 0xb0, 0xd9, 0xc9, 0x68}, 32,
            /* tag, tag length  */
            {0xdb, 0x90, 0xbd, 0xb3, 0xda, 0x3d, 0x00, 0xaf,
             0xd0, 0xfc, 0x6a, 0x83, 0x55, 0x1d, 0xa9, 0x5e}, 16,
            /* valid */
            1,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0xae, 0xf0, 0x3d, 0x00, 0x59, 0x84, 0x94, 0xe9,
             0xfb, 0x03, 0xcd, 0x7d, 0x8b, 0x59, 0x08, 0x66}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
             0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 32,
            /* ct, ct length  */
            {0xd1, 0x9a, 0xc5, 0x98, 0x49, 0x02, 0x6a, 0x91,
             0xaa, 0x1b, 0x9a, 0xec, 0x29, 0xb1, 0x1a, 0x20,
             0x2a, 0x4d, 0x73, 0x9f, 0xd8, 0x6c, 0x28, 0xe3,
             0xae, 0x3d, 0x58, 0x8e, 0xa2, 0x1d, 0x70, 0xc6}, 32,
            /* tag, tag length  */
            {0xc3, 0x0f, 0x6c, 0xd9, 0x20, 0x20, 0x74, 0xed,
             0x6e, 0x2a, 0x2a, 0x36, 0x0e, 0xac, 0x8c, 0x47}, 16,
            /* valid */
            1,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x55, 0xd1, 0x25, 0x11, 0xc6, 0x96, 0xa8, 0x0d,
             0x05, 0x14, 0xd1, 0xff, 0xba, 0x49, 0xca, 0xda}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
             0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 32,
            /* ct, ct length  */
            {0x21, 0x08, 0x55, 0x8a, 0xc4, 0xb2, 0xc2, 0xd5,
             0xcc, 0x66, 0xce, 0xa5, 0x1d, 0x62, 0x10, 0xe0,
             0x46, 0x17, 0x7a, 0x67, 0x63, 0x1c, 0xd2, 0xdd,
             0x8f, 0x09, 0x46, 0x97, 0x33, 0xac, 0xb5, 0x17}, 32,
            /* tag, tag length  */
            {0xfc, 0x35, 0x5e, 0x87, 0xa2, 0x67, 0xbe, 0x3a,
             0xe3, 0xe4, 0x4c, 0x0b, 0xf3, 0xf9, 0x9b, 0x2b}, 16,
            /* valid */
            1,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x79, 0x42, 0x2d, 0xdd, 0x91, 0xc4, 0xee, 0xe2,
             0xde, 0xae, 0xf1, 0xf9, 0x68, 0x30, 0x53, 0x04}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
             0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 32,
            /* ct, ct length  */
            {0x4d, 0x2c, 0x15, 0x24, 0xca, 0x4b, 0xaa, 0x4e,
             0xef, 0xcc, 0xe6, 0xb9, 0x1b, 0x22, 0x7e, 0xe8,
             0x3a, 0xba, 0xff, 0x81, 0x05, 0xdc, 0xaf, 0xa2,
             0xab, 0x19, 0x1f, 0x5d, 0xf2, 0x57, 0x50, 0x35}, 32,
            /* tag, tag length  */
            {0xe2, 0xc8, 0x65, 0xce, 0x2d, 0x7a, 0xbd, 0xac,
             0x02, 0x4c, 0x6f, 0x99, 0x1a, 0x84, 0x83, 0x90}, 16,
            /* valid */
            1,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x0a, 0xf5, 0xaa, 0x7a, 0x76, 0x76, 0xe2, 0x83,
             0x06, 0x30, 0x6b, 0xcd, 0x9b, 0xf2, 0x00, 0x3a}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
             0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 32,
            /* ct, ct length  */
            {0x8e, 0xb0, 0x1e, 0x62, 0x18, 0x5d, 0x78, 0x2e,
             0xb9, 0x28, 0x7a, 0x34, 0x1a, 0x68, 0x62, 0xac,
             0x52, 0x57, 0xd6, 0xf9, 0xad, 0xc9, 0x9e, 0xe0,
             0xa2, 0x4d, 0x9c, 0x22, 0xb3, 0xe9, 0xb3, 0x8a}, 32,
            /* tag, tag length  */
            {0x39, 0xc3, 0x39, 0xbc, 0x8a, 0x74, 0xc7, 0x5e,
             0x2c, 0x65, 0xc6, 0x11, 0x95, 0x44, 0xd6, 0x1e}, 16,
            /* valid */
            1,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0xaf, 0x5a, 0x03, 0xae, 0x7e, 0xdd, 0x73, 0x47,
             0x1b, 0xdc, 0xdf, 0xac, 0x5e, 0x19, 0x4a, 0x60}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
             0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 32,
            /* ct, ct length  */
            {0x94, 0xc5, 0xd2, 0xac, 0xa6, 0xdb, 0xbc, 0xe8,
             0xc2, 0x45, 0x13, 0xa2, 0x5e, 0x09, 0x5c, 0x0e,
             0x54, 0xa9, 0x42, 0x86, 0x0d, 0x32, 0x7a, 0x22,
             0x2a, 0x81, 0x5c, 0xc7, 0x13, 0xb1, 0x63, 0xb4}, 32,
            /* tag, tag length  */
            {0xf5, 0x0b, 0x30, 0x30, 0x4e, 0x45, 0xc9, 0xd4,
             0x11, 0xe8, 0xdf, 0x45, 0x08, 0xa9, 0x86, 0x12}, 16,
            /* valid */
            1,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0xb3, 0x70, 0x87, 0x68, 0x0f, 0x0e, 0xdd, 0x5a,
             0x52, 0x22, 0x8b, 0x8c, 0x7a, 0xae, 0xa6, 0x64}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
             0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
             0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
             0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
             0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
             0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33}, 64,
            /* ct, ct length  */
            {0x3b, 0xb6, 0x17, 0x3e, 0x37, 0x72, 0xd4, 0xb6,
             0x2e, 0xef, 0x37, 0xf9, 0xef, 0x07, 0x81, 0xf3,
             0x60, 0xb6, 0xc7, 0x4b, 0xe3, 0xbf, 0x6b, 0x37,
             0x10, 0x67, 0xbc, 0x1b, 0x09, 0x0d, 0x9d, 0x66,
             0x22, 0xa1, 0xfb, 0xec, 0x6a, 0xc4, 0x71, 0xb3,
             0x34, 0x9c, 0xd4, 0x27, 0x7a, 0x10, 0x1d, 0x40,
             0x89, 0x0f, 0xbf, 0x27, 0xdf, 0xdc, 0xd0, 0xb4,
             0xe3, 0x78, 0x1f, 0x98, 0x06, 0xda, 0xab, 0xb6}, 64,
            /* tag, tag length  */
            {0xa0, 0x49, 0x87, 0x45, 0xe5, 0x99, 0x99, 0xdd,
             0xc3, 0x2d, 0x5b, 0x14, 0x02, 0x41, 0x12, 0x4e}, 16,
            /* valid */
            1,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x4f, 0x80, 0x2d, 0xa6, 0x2a, 0x38, 0x45, 0x55,
             0xa1, 0x9b, 0xc2, 0xb3, 0x82, 0xeb, 0x25, 0xaf}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
             0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
             0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
             0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
             0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
             0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
             0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
             0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44}, 80,
            /* ct, ct length  */
            {0xe9, 0xb0, 0xbb, 0x88, 0x57, 0x81, 0x8c, 0xe3,
             0x20, 0x1c, 0x36, 0x90, 0xd2, 0x1d, 0xaa, 0x7f,
             0x26, 0x4f, 0xb8, 0xee, 0x93, 0xcc, 0x7a, 0x46,
             0x74, 0xea, 0x2f, 0xc3, 0x2b, 0xf1, 0x82, 0xfb,
             0x2a, 0x7e, 0x8a, 0xd5, 0x15, 0x07, 0xad, 0x4f,
             0x31, 0xce, 0xfc, 0x23, 0x56, 0xfe, 0x79, 0x36,
             0xa7, 0xf6, 0xe1, 0x9f, 0x95, 0xe8, 0x8f, 0xdb,
             0xf1, 0x76, 0x20, 0x91, 0x6d, 0x3a, 0x6f, 0x3d,
             0x01, 0xfc, 0x17, 0xd3, 0x58, 0x67, 0x2f, 0x77,
             0x7f, 0xd4, 0x09, 0x92, 0x46, 0xe4, 0x36, 0xe1}, 80,
            /* tag, tag length  */
            {0x67, 0x91, 0x0b, 0xe7, 0x44, 0xb8, 0x31, 0x5a,
             0xe0, 0xeb, 0x61, 0x24, 0x59, 0x0c, 0x5d, 0x8b}, 16,
            /* valid */
            1,
        },
        {
            /* key, key length  */
            {0xb6, 0x7b, 0x1a, 0x6e, 0xfd, 0xd4, 0x0d, 0x37,
             0x08, 0x0f, 0xbe, 0x8f, 0x80, 0x47, 0xae, 0xb9}, 16,
            /* iv, iv length  */
            {0xfa, 0x29, 0x4b, 0x12, 0x99, 0x72, 0xf7, 0xfc,
             0x5b, 0xbd, 0x5b, 0x96, 0xbb, 0xa8, 0x37, 0xc9}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x00}, 0,
            /* ct, ct length  */
            {0x00}, 0,
            /* tag, tag length  */
            {0xb1, 0x4b, 0x64, 0xfb, 0x58, 0x98, 0x99, 0x69,
             0x95, 0x70, 0xcc, 0x91, 0x60, 0xe3, 0x98, 0x96}, 16,
            /* valid */
            1,
        },
        {
            /* key, key length  */
            {0x20, 0x9e, 0x6d, 0xbf, 0x2a, 0xd2, 0x6a, 0x10,
             0x54, 0x45, 0xfc, 0x02, 0x07, 0xcd, 0x9e, 0x9a}, 16,
            /* iv, iv length  */
            {0x94, 0x77, 0x84, 0x9d, 0x6c, 0xcd, 0xfc, 0xa1,
             0x12, 0xd9, 0x2e, 0x53, 0xfa, 0xe4, 0xa7, 0xca}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x01}, 1,
            /* ct, ct length  */
            {0x1d}, 1,
            /* tag, tag length  */
            {0x52, 0xa5, 0xf6, 0x00, 0xfe, 0x53, 0x38, 0x02,
             0x6a, 0x7c, 0xb0, 0x9c, 0x11, 0x64, 0x00, 0x82}, 16,
            /* valid */
            1,
        },
        {
            /* key, key length  */
            {0xa5, 0x49, 0x44, 0x2e, 0x35, 0x15, 0x40, 0x32,
             0xd0, 0x7c, 0x86, 0x66, 0x00, 0x6a, 0xa6, 0xa2}, 16,
            /* iv, iv length  */
            {0x51, 0x71, 0x52, 0x45, 0x68, 0xe8, 0x1d, 0x97,
             0xe8, 0xc4, 0xde, 0x4b, 0xa5, 0x6c, 0x10, 0xa0}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x11, 0x82, 0xe9, 0x35, 0x96, 0xca, 0xc5, 0x60,
             0x89, 0x46, 0x40, 0x0b, 0xc7, 0x3f, 0x3a}, 15,
            /* ct, ct length  */
            {0xd7, 0xb8, 0xa6, 0xb4, 0x3d, 0x2e, 0x9f, 0x98,
             0xc2, 0xb4, 0x4c, 0xe5, 0xe3, 0xcf, 0xdb}, 15,
            /* tag, tag length  */
            {0x1b, 0xdd, 0x52, 0xfc, 0x98, 0x7d, 0xaf, 0x0e,
             0xe1, 0x92, 0x34, 0xc9, 0x05, 0xea, 0x64, 0x5f}, 16,
            /* valid */
            1,
        },
        {
            /* key, key length  */
            {0x95, 0x8b, 0xcd, 0xb6, 0x6a, 0x39, 0x52, 0xb5,
             0x37, 0x01, 0x58, 0x2a, 0x68, 0xa0, 0xe4, 0x74}, 16,
            /* iv, iv length  */
            {0x0e, 0x6e, 0xc8, 0x79, 0xb0, 0x2c, 0x6f, 0x51,
             0x69, 0x76, 0xe3, 0x58, 0x98, 0x42, 0x8d, 0xa7}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x14, 0x04, 0x15, 0x82, 0x3e, 0xcc, 0x89, 0x32,
             0xa0, 0x58, 0x38, 0x4b, 0x73, 0x8e, 0xa6, 0xea,
             0x6d, 0x4d, 0xfe, 0x3b, 0xbe, 0xee}, 22,
            /* ct, ct length  */
            {0x73, 0xe5, 0xc6, 0xf0, 0xe7, 0x03, 0xa5, 0x2d,
             0x02, 0xf7, 0xf7, 0xfa, 0xeb, 0x1b, 0x77, 0xfd,
             0x4f, 0xd0, 0xcb, 0x42, 0x1e, 0xaf}, 22,
            /* tag, tag length  */
            {0x6c, 0x15, 0x4a, 0x85, 0x96, 0x8e, 0xdd, 0x74,
             0x77, 0x65, 0x75, 0xa4, 0x45, 0x0b, 0xd8, 0x97}, 16,
            /* valid */
            1,
        },
        {
            /* key, key length  */
            {0x96, 0x5b, 0x75, 0x7b, 0xa5, 0x01, 0x8a, 0x8d,
             0x66, 0xed, 0xc7, 0x8e, 0x0c, 0xee, 0xe8, 0x6b}, 16,
            /* iv, iv length  */
            {0x2e, 0x35, 0x90, 0x1a, 0xe7, 0xd4, 0x91, 0xee,
             0xcc, 0x88, 0x38, 0xfe, 0xdd, 0x63, 0x14, 0x05}, 16,
            /* aad, aad length  */
            {0xdf, 0x10, 0xd0, 0xd2, 0x12, 0x24, 0x24, 0x50}, 8,
            /* msg, msg length  */
            {0x36, 0xe5, 0x7a, 0x76, 0x39, 0x58, 0xb0, 0x2c,
             0xea, 0x9d, 0x6a, 0x67, 0x6e, 0xbc, 0xe8, 0x1f}, 16,
            /* ct, ct length  */
            {0x93, 0x6b, 0x69, 0xb6, 0xc9, 0x55, 0xad, 0xfd,
             0x15, 0x53, 0x9b, 0x9b, 0xe4, 0x98, 0x9c, 0xb6}, 16,
            /* tag, tag length  */
            {0xee, 0x15, 0xa1, 0x45, 0x4e, 0x88, 0xfa, 0xad,
             0x8e, 0x48, 0xa8, 0xdf, 0x29, 0x83, 0xb4, 0x25}, 16,
            /* valid */
            1,
        },
        {
            /* key, key length  */
            {0x88, 0xd0, 0x20, 0x33, 0x78, 0x1c, 0x7b, 0x41,
             0x64, 0x71, 0x1a, 0x05, 0x42, 0x0f, 0x25, 0x6e}, 16,
            /* iv, iv length  */
            {0x7f, 0x29, 0x85, 0x29, 0x63, 0x15, 0x50, 0x7a,
             0xa4, 0xc0, 0xa9, 0x3d, 0x5c, 0x12, 0xbd, 0x77}, 16,
            /* aad, aad length  */
            {0x7c, 0x57, 0x1d, 0x2f, 0xbb, 0x5f, 0x62, 0x52,
             0x3c, 0x0e, 0xb3, 0x38, 0xbe, 0xf9, 0xa9}, 15,
            /* msg, msg length  */
            {0xd9, 0x8a, 0xdc, 0x03, 0xd9, 0xd5, 0x82, 0x73,
             0x2e, 0xb0, 0x7d, 0xf2, 0x3d, 0x7b, 0x9f, 0x74}, 16,
            /* ct, ct length  */
            {0x67, 0xca, 0xac, 0x35, 0x44, 0x3a, 0x31, 0x38,
             0xd2, 0xcb, 0x81, 0x1f, 0x0c, 0xe0, 0x4d, 0xd2}, 16,
            /* tag, tag length  */
            {0xb7, 0x96, 0x8e, 0x0b, 0x56, 0x40, 0xe3, 0xb2,
             0x36, 0x56, 0x96, 0x53, 0x20, 0x8b, 0x9d, 0xeb}, 16,
            /* valid */
            1,
        },
        {
            /* key, key length  */
            {0x51, 0x58, 0x40, 0xcf, 0x67, 0xd2, 0xe4, 0x0e,
             0xb6, 0x5e, 0x54, 0xa2, 0x4c, 0x72, 0xcb, 0xf2}, 16,
            /* iv, iv length  */
            {0xbf, 0x47, 0xaf, 0xdf, 0xd4, 0x92, 0x13, 0x7a,
             0x24, 0x23, 0x6b, 0xc3, 0x67, 0x97, 0xa8, 0x8e}, 16,
            /* aad, aad length  */
            {0x16, 0x84, 0x3c, 0x09, 0x1d, 0x43, 0xb0, 0xa1,
             0x91, 0xd0, 0xc7, 0x3d, 0x15, 0x60, 0x1b, 0xe9}, 16,
            /* msg, msg length  */
            {0xc8, 0x34, 0x58, 0x8c, 0xb6, 0xda, 0xf9, 0xf0,
             0x6d, 0xd2, 0x35, 0x19, 0xf4, 0xbe, 0x9f, 0x56}, 16,
            /* ct, ct length  */
            {0x20, 0x0a, 0xc4, 0x51, 0xfb, 0xeb, 0x0f, 0x61,
             0x51, 0xd6, 0x15, 0x83, 0xa4, 0x3b, 0x73, 0x43}, 16,
            /* tag, tag length  */
            {0x2a, 0xd4, 0x3e, 0x4c, 0xaa, 0x51, 0x98, 0x3a,
             0x9d, 0x4d, 0x24, 0x48, 0x1b, 0xf4, 0xc8, 0x39}, 16,
            /* valid */
            1,
        },
        {
            /* key, key length  */
            {0x2e, 0x44, 0x92, 0xd4, 0x44, 0xe5, 0xb6, 0xf4,
             0xce, 0xc8, 0xc2, 0xd3, 0x61, 0x5a, 0xc8, 0x58}, 16,
            /* iv, iv length  */
            {0xd0, 0x2b, 0xf0, 0x76, 0x3a, 0x9f, 0xef, 0xbf,
             0x70, 0xc3, 0x3a, 0xee, 0x1e, 0x9d, 0xa1, 0xd6}, 16,
            /* aad, aad length  */
            {0x90, 0x4d, 0x86, 0xf1, 0x33, 0xce, 0xc1, 0x5a,
             0x0c, 0x3c, 0xaf, 0x14, 0xd7, 0xe0, 0x29, 0xc8,
             0x2a, 0x07, 0x70, 0x5a, 0x23, 0xf0, 0xd0, 0x80}, 24,
            /* msg, msg length  */
            {0x9e, 0x62, 0xd6, 0x51, 0x1b, 0x0b, 0xda, 0x7d,
             0xd7, 0x74, 0x0b, 0x61, 0x4d, 0x97, 0xba, 0xe0}, 16,
            /* ct, ct length  */
            {0x27, 0xc6, 0xe9, 0xa6, 0x53, 0xc5, 0x25, 0x3c,
             0xa1, 0xc5, 0x67, 0x3f, 0x97, 0xb9, 0xb3, 0x3e}, 16,
            /* tag, tag length  */
            {0x2d, 0x58, 0x12, 0x71, 0xe1, 0xfa, 0x9e, 0x36,
             0x86, 0x13, 0x6c, 0xaa, 0x8f, 0x4d, 0x6c, 0x8e}, 16,
            /* valid */
            1,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
             0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, 16,
            /* ct, ct length  */
            {0x29, 0xa0, 0x91, 0x4f, 0xec, 0x4b, 0xef, 0x54,
             0xba, 0xbf, 0x66, 0x13, 0xa9, 0xf9, 0xcd, 0x70}, 16,
            /* tag, tag length  */
            {0xe7, 0x0e, 0x7c, 0x50, 0x13, 0xa6, 0xdb, 0xf2,
             0x52, 0x98, 0xb1, 0x92, 0x9b, 0xc3, 0x56, 0xa7}, 16,
            /* valid */
            0,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
             0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, 16,
            /* ct, ct length  */
            {0x29, 0xa0, 0x91, 0x4f, 0xec, 0x4b, 0xef, 0x54,
             0xba, 0xbf, 0x66, 0x13, 0xa9, 0xf9, 0xcd, 0x70}, 16,
            /* tag, tag length  */
            {0xe4, 0x0e, 0x7c, 0x50, 0x13, 0xa6, 0xdb, 0xf2,
             0x52, 0x98, 0xb1, 0x92, 0x9b, 0xc3, 0x56, 0xa7}, 16,
            /* valid */
            0,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
             0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, 16,
            /* ct, ct length  */
            {0x29, 0xa0, 0x91, 0x4f, 0xec, 0x4b, 0xef, 0x54,
             0xba, 0xbf, 0x66, 0x13, 0xa9, 0xf9, 0xcd, 0x70}, 16,
            /* tag, tag length  */
            {0x66, 0x0e, 0x7c, 0x50, 0x13, 0xa6, 0xdb, 0xf2,
             0x52, 0x98, 0xb1, 0x92, 0x9b, 0xc3, 0x56, 0xa7}, 16,
            /* valid */
            0,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
             0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, 16,
            /* ct, ct length  */
            {0x29, 0xa0, 0x91, 0x4f, 0xec, 0x4b, 0xef, 0x54,
             0xba, 0xbf, 0x66, 0x13, 0xa9, 0xf9, 0xcd, 0x70}, 16,
            /* tag, tag length  */
            {0xe6, 0x0f, 0x7c, 0x50, 0x13, 0xa6, 0xdb, 0xf2,
             0x52, 0x98, 0xb1, 0x92, 0x9b, 0xc3, 0x56, 0xa7}, 16,
            /* valid */
            0,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
             0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, 16,
            /* ct, ct length  */
            {0x29, 0xa0, 0x91, 0x4f, 0xec, 0x4b, 0xef, 0x54,
             0xba, 0xbf, 0x66, 0x13, 0xa9, 0xf9, 0xcd, 0x70}, 16,
            /* tag, tag length  */
            {0xe6, 0x0e, 0x7c, 0xd0, 0x13, 0xa6, 0xdb, 0xf2,
             0x52, 0x98, 0xb1, 0x92, 0x9b, 0xc3, 0x56, 0xa7}, 16,
            /* valid */
            0,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
             0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, 16,
            /* ct, ct length  */
            {0x29, 0xa0, 0x91, 0x4f, 0xec, 0x4b, 0xef, 0x54,
             0xba, 0xbf, 0x66, 0x13, 0xa9, 0xf9, 0xcd, 0x70}, 16,
            /* tag, tag length  */
            {0xe6, 0x0e, 0x7c, 0x50, 0x12, 0xa6, 0xdb, 0xf2,
             0x52, 0x98, 0xb1, 0x92, 0x9b, 0xc3, 0x56, 0xa7}, 16,
            /* valid */
            0,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
             0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, 16,
            /* ct, ct length  */
            {0x29, 0xa0, 0x91, 0x4f, 0xec, 0x4b, 0xef, 0x54,
             0xba, 0xbf, 0x66, 0x13, 0xa9, 0xf9, 0xcd, 0x70}, 16,
            /* tag, tag length  */
            {0xe6, 0x0e, 0x7c, 0x50, 0x11, 0xa6, 0xdb, 0xf2,
             0x52, 0x98, 0xb1, 0x92, 0x9b, 0xc3, 0x56, 0xa7}, 16,
            /* valid */
            0,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
             0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, 16,
            /* ct, ct length  */
            {0x29, 0xa0, 0x91, 0x4f, 0xec, 0x4b, 0xef, 0x54,
             0xba, 0xbf, 0x66, 0x13, 0xa9, 0xf9, 0xcd, 0x70}, 16,
            /* tag, tag length  */
            {0xe6, 0x0e, 0x7c, 0x50, 0x13, 0xa6, 0xdb, 0x72,
             0x52, 0x98, 0xb1, 0x92, 0x9b, 0xc3, 0x56, 0xa7}, 16,
            /* valid */
            0,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
             0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, 16,
            /* ct, ct length  */
            {0x29, 0xa0, 0x91, 0x4f, 0xec, 0x4b, 0xef, 0x54,
             0xba, 0xbf, 0x66, 0x13, 0xa9, 0xf9, 0xcd, 0x70}, 16,
            /* tag, tag length  */
            {0xe6, 0x0e, 0x7c, 0x50, 0x13, 0xa6, 0xdb, 0xf2,
             0x53, 0x98, 0xb1, 0x92, 0x9b, 0xc3, 0x56, 0xa7}, 16,
            /* valid */
            0,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
             0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, 16,
            /* ct, ct length  */
            {0x29, 0xa0, 0x91, 0x4f, 0xec, 0x4b, 0xef, 0x54,
             0xba, 0xbf, 0x66, 0x13, 0xa9, 0xf9, 0xcd, 0x70}, 16,
            /* tag, tag length  */
            {0xe6, 0x0e, 0x7c, 0x50, 0x13, 0xa6, 0xdb, 0xf2,
             0xd2, 0x98, 0xb1, 0x92, 0x9b, 0xc3, 0x56, 0xa7}, 16,
            /* valid */
            0,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
             0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, 16,
            /* ct, ct length  */
            {0x29, 0xa0, 0x91, 0x4f, 0xec, 0x4b, 0xef, 0x54,
             0xba, 0xbf, 0x66, 0x13, 0xa9, 0xf9, 0xcd, 0x70}, 16,
            /* tag, tag length  */
            {0xe6, 0x0e, 0x7c, 0x50, 0x13, 0xa6, 0xdb, 0xf2,
             0x52, 0xb8, 0xb1, 0x92, 0x9b, 0xc3, 0x56, 0xa7}, 16,
            /* valid */
            0,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
             0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, 16,
            /* ct, ct length  */
            {0x29, 0xa0, 0x91, 0x4f, 0xec, 0x4b, 0xef, 0x54,
             0xba, 0xbf, 0x66, 0x13, 0xa9, 0xf9, 0xcd, 0x70}, 16,
            /* tag, tag length  */
            {0xe6, 0x0e, 0x7c, 0x50, 0x13, 0xa6, 0xdb, 0xf2,
             0x52, 0x98, 0xb0, 0x92, 0x9b, 0xc3, 0x56, 0xa7}, 16,
            /* valid */
            0,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
             0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, 16,
            /* ct, ct length  */
            {0x29, 0xa0, 0x91, 0x4f, 0xec, 0x4b, 0xef, 0x54,
             0xba, 0xbf, 0x66, 0x13, 0xa9, 0xf9, 0xcd, 0x70}, 16,
            /* tag, tag length  */
            {0xe6, 0x0e, 0x7c, 0x50, 0x13, 0xa6, 0xdb, 0xf2,
             0x52, 0x98, 0xb1, 0x92, 0x9a, 0xc3, 0x56, 0xa7}, 16,
            /* valid */
            0,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
             0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, 16,
            /* ct, ct length  */
            {0x29, 0xa0, 0x91, 0x4f, 0xec, 0x4b, 0xef, 0x54,
             0xba, 0xbf, 0x66, 0x13, 0xa9, 0xf9, 0xcd, 0x70}, 16,
            /* tag, tag length  */
            {0xe6, 0x0e, 0x7c, 0x50, 0x13, 0xa6, 0xdb, 0xf2,
             0x52, 0x98, 0xb1, 0x92, 0x99, 0xc3, 0x56, 0xa7}, 16,
            /* valid */
            0,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
             0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, 16,
            /* ct, ct length  */
            {0x29, 0xa0, 0x91, 0x4f, 0xec, 0x4b, 0xef, 0x54,
             0xba, 0xbf, 0x66, 0x13, 0xa9, 0xf9, 0xcd, 0x70}, 16,
            /* tag, tag length  */
            {0xe6, 0x0e, 0x7c, 0x50, 0x13, 0xa6, 0xdb, 0xf2,
             0x52, 0x98, 0xb1, 0x92, 0x1b, 0xc3, 0x56, 0xa7}, 16,
            /* valid */
            0,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
             0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, 16,
            /* ct, ct length  */
            {0x29, 0xa0, 0x91, 0x4f, 0xec, 0x4b, 0xef, 0x54,
             0xba, 0xbf, 0x66, 0x13, 0xa9, 0xf9, 0xcd, 0x70}, 16,
            /* tag, tag length  */
            {0xe6, 0x0e, 0x7c, 0x50, 0x13, 0xa6, 0xdb, 0xf2,
             0x52, 0x98, 0xb1, 0x92, 0x9b, 0xc3, 0x56, 0xa6}, 16,
            /* valid */
            0,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
             0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, 16,
            /* ct, ct length  */
            {0x29, 0xa0, 0x91, 0x4f, 0xec, 0x4b, 0xef, 0x54,
             0xba, 0xbf, 0x66, 0x13, 0xa9, 0xf9, 0xcd, 0x70}, 16,
            /* tag, tag length  */
            {0xe6, 0x0e, 0x7c, 0x50, 0x13, 0xa6, 0xdb, 0xf2,
             0x52, 0x98, 0xb1, 0x92, 0x9b, 0xc3, 0x56, 0xa5}, 16,
            /* valid */
            0,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
             0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, 16,
            /* ct, ct length  */
            {0x29, 0xa0, 0x91, 0x4f, 0xec, 0x4b, 0xef, 0x54,
             0xba, 0xbf, 0x66, 0x13, 0xa9, 0xf9, 0xcd, 0x70}, 16,
            /* tag, tag length  */
            {0xe6, 0x0e, 0x7c, 0x50, 0x13, 0xa6, 0xdb, 0xf2,
             0x52, 0x98, 0xb1, 0x92, 0x9b, 0xc3, 0x56, 0xe7}, 16,
            /* valid */
            0,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
             0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, 16,
            /* ct, ct length  */
            {0x29, 0xa0, 0x91, 0x4f, 0xec, 0x4b, 0xef, 0x54,
             0xba, 0xbf, 0x66, 0x13, 0xa9, 0xf9, 0xcd, 0x70}, 16,
            /* tag, tag length  */
            {0xe6, 0x0e, 0x7c, 0x50, 0x13, 0xa6, 0xdb, 0xf2,
             0x52, 0x98, 0xb1, 0x92, 0x9b, 0xc3, 0x56, 0x27}, 16,
            /* valid */
            0,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
             0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, 16,
            /* ct, ct length  */
            {0x29, 0xa0, 0x91, 0x4f, 0xec, 0x4b, 0xef, 0x54,
             0xba, 0xbf, 0x66, 0x13, 0xa9, 0xf9, 0xcd, 0x70}, 16,
            /* tag, tag length  */
            {0xe7, 0x0e, 0x7c, 0x50, 0x13, 0xa6, 0xdb, 0xf2,
             0x53, 0x98, 0xb1, 0x92, 0x9b, 0xc3, 0x56, 0xa7}, 16,
            /* valid */
            0,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
             0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, 16,
            /* ct, ct length  */
            {0x29, 0xa0, 0x91, 0x4f, 0xec, 0x4b, 0xef, 0x54,
             0xba, 0xbf, 0x66, 0x13, 0xa9, 0xf9, 0xcd, 0x70}, 16,
            /* tag, tag length  */
            {0xe6, 0x0e, 0x7c, 0xd0, 0x13, 0xa6, 0xdb, 0x72,
             0x52, 0x98, 0xb1, 0x92, 0x9b, 0xc3, 0x56, 0xa7}, 16,
            /* valid */
            0,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
             0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, 16,
            /* ct, ct length  */
            {0x29, 0xa0, 0x91, 0x4f, 0xec, 0x4b, 0xef, 0x54,
             0xba, 0xbf, 0x66, 0x13, 0xa9, 0xf9, 0xcd, 0x70}, 16,
            /* tag, tag length  */
            {0xe6, 0x0e, 0x7c, 0x50, 0x13, 0xa6, 0xdb, 0x72,
             0x52, 0x98, 0xb1, 0x92, 0x9b, 0xc3, 0x56, 0x27}, 16,
            /* valid */
            0,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
             0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, 16,
            /* ct, ct length  */
            {0x29, 0xa0, 0x91, 0x4f, 0xec, 0x4b, 0xef, 0x54,
             0xba, 0xbf, 0x66, 0x13, 0xa9, 0xf9, 0xcd, 0x70}, 16,
            /* tag, tag length  */
            {0x19, 0xf1, 0x83, 0xaf, 0xec, 0x59, 0x24, 0x0d,
             0xad, 0x67, 0x4e, 0x6d, 0x64, 0x3c, 0xa9, 0x58}, 16,
            /* valid */
            0,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
             0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, 16,
            /* ct, ct length  */
            {0x29, 0xa0, 0x91, 0x4f, 0xec, 0x4b, 0xef, 0x54,
             0xba, 0xbf, 0x66, 0x13, 0xa9, 0xf9, 0xcd, 0x70}, 16,
            /* tag, tag length  */
            {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 16,
            /* valid */
            0,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
             0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, 16,
            /* ct, ct length  */
            {0x29, 0xa0, 0x91, 0x4f, 0xec, 0x4b, 0xef, 0x54,
             0xba, 0xbf, 0x66, 0x13, 0xa9, 0xf9, 0xcd, 0x70}, 16,
            /* tag, tag length  */
            {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
             0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 16,
            /* valid */
            0,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
             0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, 16,
            /* ct, ct length  */
            {0x29, 0xa0, 0x91, 0x4f, 0xec, 0x4b, 0xef, 0x54,
             0xba, 0xbf, 0x66, 0x13, 0xa9, 0xf9, 0xcd, 0x70}, 16,
            /* tag, tag length  */
            {0x66, 0x8e, 0xfc, 0xd0, 0x93, 0x26, 0x5b, 0x72,
             0xd2, 0x18, 0x31, 0x12, 0x1b, 0x43, 0xd6, 0x27}, 16,
            /* valid */
            0,
        },
        {
            /* key, key length  */
            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, 16,
            /* iv, iv length  */
            {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
             0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f}, 16,
            /* aad, aad length  */
            {0x00}, 0,
            /* msg, msg length  */
            {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}, 16,
            /* ct, ct length  */
            {0x29, 0xa0, 0x91, 0x4f, 0xec, 0x4b, 0xef, 0x54,
             0xba, 0xbf, 0x66, 0x13, 0xa9, 0xf9, 0xcd, 0x70}, 16,
            /* tag, tag length  */
            {0xe7, 0x0f, 0x7d, 0x51, 0x12, 0xa7, 0xda, 0xf3,
             0x53, 0x99, 0xb0, 0x93, 0x9a, 0xc2, 0x57, 0xa6}, 16,
            /* valid */
            0,
        },
    #endif
    };

    byte ciphertext[sizeof(vectors[0].ct)];
    byte authtag[sizeof(vectors[0].tag)];
    int i;
    int len;
    int ret;


    for (i = 0; i < (int)(sizeof(vectors)/sizeof(vectors[0])); i++) {

        XMEMSET(ciphertext, 0, sizeof(ciphertext));

        len = sizeof(authtag);
        ExpectIntEQ(wc_AesEaxEncryptAuth(vectors[i].key, vectors[i].key_length,
                                         ciphertext,
                                         vectors[i].msg, vectors[i].msg_length,
                                         vectors[i].iv, vectors[i].iv_length,
                                         authtag, len,
                                         vectors[i].aad, vectors[i].aad_length),
                                         0);

        /* check ciphertext matches vector */
        ExpectIntEQ(XMEMCMP(ciphertext, vectors[i].ct, vectors[i].ct_length),
                    0);

        /* check that computed tag matches vector only for vectors marked asx
         * valid */
        ret = XMEMCMP(authtag, vectors[i].tag, len);
        if (vectors[i].valid) {
            ExpectIntEQ(ret, 0);
        }
        else {
            ExpectIntNE(ret, 0);
        }

        XMEMSET(ciphertext, 0, sizeof(ciphertext));

        /* Decrypt, checking that the computed auth tags match */
        ExpectIntEQ(wc_AesEaxDecryptAuth(vectors[i].key, vectors[i].key_length,
                                         ciphertext,
                                         vectors[i].ct, vectors[i].ct_length,
                                         vectors[i].iv, vectors[i].iv_length,
                                         authtag, len,
                                         vectors[i].aad, vectors[i].aad_length),
                                         0);

        /* check decrypted ciphertext matches vector plaintext */
        ExpectIntEQ(XMEMCMP(ciphertext, vectors[i].msg, vectors[i].msg_length),
                    0);
    }
    return EXPECT_RESULT();
} /* END test_wc_AesEaxVectors */

/*
 * Testing test_wc_AesEaxEncryptAuth()
 */
int test_wc_AesEaxEncryptAuth(void)
{
    EXPECT_DECLS;

    const byte key[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
                        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
                        0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F};
    const byte iv[]  = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
                        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
                        0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F};
    const byte aad[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
    const byte msg[] = {0x00, 0x01, 0x02, 0x03, 0x04};

    byte ciphertext[sizeof(msg)];
    byte authtag[WC_AES_BLOCK_SIZE];
    int i;
    int len;

    len = sizeof(authtag);
    ExpectIntEQ(wc_AesEaxEncryptAuth(key, sizeof(key),
                                     ciphertext,
                                     msg, sizeof(msg),
                                     iv, sizeof(iv),
                                     authtag, (word32)len,
                                     aad, sizeof(aad)),
                                     0);

    /* Test null checking */
    ExpectIntEQ(wc_AesEaxEncryptAuth(NULL, sizeof(key),
                                     ciphertext,
                                     msg, sizeof(msg),
                                     iv, sizeof(iv),
                                     authtag, (word32)len,
                                     aad, sizeof(aad)),
                                     WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesEaxEncryptAuth(key, sizeof(key),
                                     NULL,
                                     msg, sizeof(msg),
                                     iv, sizeof(iv),
                                     authtag, (word32)len,
                                     aad, sizeof(aad)),
                                     WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesEaxEncryptAuth(key, sizeof(key),
                                     ciphertext,
                                     NULL, sizeof(msg),
                                     iv, sizeof(iv),
                                     authtag, (word32)len,
                                     aad, sizeof(aad)),
                                     WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesEaxEncryptAuth(key, sizeof(key),
                                     ciphertext,
                                     msg, sizeof(msg),
                                     NULL, sizeof(iv),
                                     authtag, (word32)len,
                                     aad, sizeof(aad)),
                                     WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesEaxEncryptAuth(key, sizeof(key),
                                     ciphertext,
                                     msg, sizeof(msg),
                                     iv, sizeof(iv),
                                     NULL, (word32)len,
                                     aad, sizeof(aad)),
                                     WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesEaxEncryptAuth(key, sizeof(key),
                                     ciphertext,
                                     msg, sizeof(msg),
                                     iv, sizeof(iv),
                                     authtag, (word32)len,
                                     NULL, sizeof(aad)),
                                     WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    /* Test bad key lengths */
    for (i = 0; i <= 32; i++) {
        int exp_ret;
    #ifdef WOLFSSL_AES_128
        if (i == AES_128_KEY_SIZE) {
            exp_ret = 0;
        }
        else
    #endif
    #ifdef WOLFSSL_AES_192
        if (i == AES_192_KEY_SIZE) {
            exp_ret = 0;
        }
        else
    #endif
    #ifdef WOLFSSL_AES_256
        if (i == AES_256_KEY_SIZE) {
            exp_ret = 0;
        }
        else
    #endif
        {
            exp_ret = WC_NO_ERR_TRACE(BAD_FUNC_ARG);
        }

        ExpectIntEQ(wc_AesEaxEncryptAuth(key, (word32)i,
                                         ciphertext,
                                         msg, sizeof(msg),
                                         iv, sizeof(iv),
                                         authtag, (word32)len,
                                         aad, sizeof(aad)),
                                         exp_ret);
    }


    /* Test auth tag size out of range */
    len = WC_AES_BLOCK_SIZE + 1;
    ExpectIntEQ(wc_AesEaxEncryptAuth(key, sizeof(key),
                                     ciphertext,
                                     msg, sizeof(msg),
                                     iv, sizeof(iv),
                                     authtag, (word32)len,
                                     aad, sizeof(aad)),
                                     WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    return EXPECT_RESULT();
} /* END test_wc_AesEaxEncryptAuth() */

/*
 * Testing test_wc_AesEaxDecryptAuth()
 */
int test_wc_AesEaxDecryptAuth(void)
{
    EXPECT_DECLS;

    const byte key[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
                        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
                        0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F};
    const byte iv[]  = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
                        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
                        0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F};
    const byte aad[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
    const byte ct[] =  {0x00, 0x01, 0x02, 0x03, 0x04};
    /* Garbage tag that should always fail for above aad */
    const byte tag[] = {0xFE, 0xED, 0xBE, 0xEF, 0xDE, 0xAD, 0xC0, 0xDE,
                        0xCA, 0xFE, 0xBE, 0xEF, 0xDE, 0xAF, 0xBE, 0xEF};

    byte plaintext[sizeof(ct)];
    int i;
    int len;

    len = sizeof(tag);
    ExpectIntEQ(wc_AesEaxDecryptAuth(key, sizeof(key),
                                     plaintext,
                                     ct, sizeof(ct),
                                     iv, sizeof(iv),
                                     tag, (word32)len,
                                     aad, sizeof(aad)),
                                     WC_NO_ERR_TRACE(AES_EAX_AUTH_E));

    /* Test null checking */
    ExpectIntEQ(wc_AesEaxDecryptAuth(NULL, sizeof(key),
                                     plaintext,
                                     ct, sizeof(ct),
                                     iv, sizeof(iv),
                                     tag, (word32)len,
                                     aad, sizeof(aad)),
                                     WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesEaxDecryptAuth(key, sizeof(key),
                                     NULL,
                                     ct, sizeof(ct),
                                     iv, sizeof(iv),
                                     tag, (word32)len,
                                     aad, sizeof(aad)),
                                     WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesEaxDecryptAuth(key, sizeof(key),
                                     plaintext,
                                     NULL, sizeof(ct),
                                     iv, sizeof(iv),
                                     tag, (word32)len,
                                     aad, sizeof(aad)),
                                     WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesEaxDecryptAuth(key, sizeof(key),
                                     plaintext,
                                     ct, sizeof(ct),
                                     NULL, sizeof(iv),
                                     tag, (word32)len,
                                     aad, sizeof(aad)),
                                     WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesEaxDecryptAuth(key, sizeof(key),
                                     plaintext,
                                     ct, sizeof(ct),
                                     iv, sizeof(iv),
                                     NULL, (word32)len,
                                     aad, sizeof(aad)),
                                     WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesEaxDecryptAuth(key, sizeof(key),
                                     plaintext,
                                     ct, sizeof(ct),
                                     iv, sizeof(iv),
                                     tag, (word32)len,
                                     NULL, sizeof(aad)),
                                     WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    /* Test bad key lengths */
    for (i = 0; i <= 32; i++) {
        int exp_ret;
    #ifdef WOLFSSL_AES_128
        if (i == AES_128_KEY_SIZE) {
            exp_ret = WC_NO_ERR_TRACE(AES_EAX_AUTH_E);
        }
        else
    #endif
    #ifdef WOLFSSL_AES_192
        if (i == AES_192_KEY_SIZE) {
            exp_ret = WC_NO_ERR_TRACE(AES_EAX_AUTH_E);
        }
        else
    #endif
    #ifdef WOLFSSL_AES_256
        if (i == AES_256_KEY_SIZE) {
            exp_ret = WC_NO_ERR_TRACE(AES_EAX_AUTH_E);
        }
        else
    #endif
        {
            exp_ret = WC_NO_ERR_TRACE(BAD_FUNC_ARG);
        }

        ExpectIntEQ(wc_AesEaxDecryptAuth(key, (word32)i,
                                         plaintext,
                                         ct, sizeof(ct),
                                         iv, sizeof(iv),
                                         tag, (word32)len,
                                         aad, sizeof(aad)),
                                         exp_ret);
    }


    /* Test auth tag size out of range */
    len = WC_AES_BLOCK_SIZE + 1;
    ExpectIntEQ(wc_AesEaxDecryptAuth(key, sizeof(key),
                                     plaintext,
                                     ct, sizeof(ct),
                                     iv, sizeof(iv),
                                     tag, (word32)len,
                                     aad, sizeof(aad)),
                                     WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    return EXPECT_RESULT();
} /* END test_wc_AesEaxDecryptAuth() */

/*
 * Testing AES-EAX streaming (incremental) API:
 *   wc_AesEaxInit, wc_AesEaxEncryptUpdate, wc_AesEaxAuthDataUpdate,
 *   wc_AesEaxEncryptFinal, wc_AesEaxDecryptUpdate, wc_AesEaxDecryptFinal,
 *   wc_AesEaxFree
 */
int test_wc_AesEaxStream(void)
{
    EXPECT_DECLS;

#ifdef WOLFSSL_AES_128
    /* Wycheproof AES-EAX 128-bit key vectors */

    /* Vector 1: empty plaintext - AAD passed via Init */
    const byte key1[]   = {0x23, 0x39, 0x52, 0xde, 0xe4, 0xd5, 0xed, 0x5f,
                            0x9b, 0x9c, 0x6d, 0x6f, 0xf8, 0x0f, 0xf4, 0x78};
    const byte nonce1[] = {0x62, 0xec, 0x67, 0xf9, 0xc3, 0xa4, 0xa4, 0x07,
                            0xfc, 0xb2, 0xa8, 0xc4, 0x90, 0x31, 0xa8, 0xb3};
    const byte aad1[]   = {0x6b, 0xfb, 0x91, 0x4f, 0xd0, 0x7e, 0xae, 0x6b};
    const byte tag1[]   = {0xe0, 0x37, 0x83, 0x0e, 0x83, 0x89, 0xf2, 0x7b,
                            0x02, 0x5a, 0x2d, 0x65, 0x27, 0xe7, 0x9d, 0x01};

    /* Vector 2: 2-byte plaintext - AAD passed via EncryptUpdate */
    const byte key2[]   = {0x91, 0x94, 0x5d, 0x3f, 0x4d, 0xcb, 0xee, 0x0b,
                            0xf4, 0x5e, 0xf5, 0x22, 0x55, 0xf0, 0x95, 0xa4};
    const byte nonce2[] = {0xbe, 0xca, 0xf0, 0x43, 0xb0, 0xa2, 0x3d, 0x84,
                            0x31, 0x94, 0xba, 0x97, 0x2c, 0x66, 0xde, 0xbd};
    const byte aad2[]   = {0xfa, 0x3b, 0xfd, 0x48, 0x06, 0xeb, 0x53, 0xfa};
    const byte pt2[]    = {0xf7, 0xfb};
    const byte ct2[]    = {0x19, 0xdd};
    const byte tag2[]   = {0x5c, 0x4c, 0x93, 0x31, 0x04, 0x9d, 0x0b, 0xda,
                            0xb0, 0x27, 0x74, 0x08, 0xf6, 0x79, 0x67, 0xe5};

    /* Vector 3: 5-byte plaintext - multi-chunk, AAD via AuthDataUpdate */
    const byte key3[]   = {0x01, 0xf7, 0x4a, 0xd6, 0x40, 0x77, 0xf2, 0xe7,
                            0x04, 0xc0, 0xf6, 0x0a, 0xda, 0x3d, 0xd5, 0x23};
    const byte nonce3[] = {0x70, 0xc3, 0xdb, 0x4f, 0x0d, 0x26, 0x36, 0x84,
                            0x00, 0xa1, 0x0e, 0xd0, 0x5d, 0x2b, 0xff, 0x5e};
    const byte aad3[]   = {0x23, 0x4a, 0x34, 0x63, 0xc1, 0x26, 0x4a, 0xc6};
    const byte pt3[]    = {0x1a, 0x47, 0xcb, 0x49, 0x33};
    const byte ct3[]    = {0xd8, 0x51, 0xd5, 0xba, 0xe0};
    const byte tag3[]   = {0x3a, 0x59, 0xf2, 0x38, 0xa2, 0x3e, 0x39, 0x19,
                            0x9d, 0xc9, 0x26, 0x66, 0x26, 0xc4, 0x0f, 0x80};

    AesEax eax;
    byte   out[16];
    byte   tagBuf[WC_AES_BLOCK_SIZE];

    XMEMSET(&eax, 0, sizeof(eax));
    XMEMSET(out, 0, sizeof(out));
    XMEMSET(tagBuf, 0, sizeof(tagBuf));

    /* --- Test 1: empty plaintext, AAD passed to Init --- */
    ExpectIntEQ(wc_AesEaxInit(&eax, key1, sizeof(key1),
                              nonce1, sizeof(nonce1),
                              aad1, sizeof(aad1)), 0);
    ExpectIntEQ(wc_AesEaxEncryptFinal(&eax, tagBuf, sizeof(tag1)), 0);
    ExpectBufEQ(tagBuf, tag1, sizeof(tag1));
    ExpectIntEQ(wc_AesEaxFree(&eax), 0);

    /* --- Test 1d: empty plaintext decrypt --- */
    ExpectIntEQ(wc_AesEaxInit(&eax, key1, sizeof(key1),
                              nonce1, sizeof(nonce1),
                              aad1, sizeof(aad1)), 0);
    ExpectIntEQ(wc_AesEaxDecryptFinal(&eax, tag1, sizeof(tag1)), 0);
    ExpectIntEQ(wc_AesEaxFree(&eax), 0);

    /* --- Test 2: 2-byte plaintext, single EncryptUpdate with inline AAD --- */
    ExpectIntEQ(wc_AesEaxInit(&eax, key2, sizeof(key2),
                              nonce2, sizeof(nonce2),
                              NULL, 0), 0);
    ExpectIntEQ(wc_AesEaxEncryptUpdate(&eax, out, pt2, sizeof(pt2),
                                       aad2, sizeof(aad2)), 0);
    ExpectBufEQ(out, ct2, sizeof(ct2));
    ExpectIntEQ(wc_AesEaxEncryptFinal(&eax, tagBuf, sizeof(tag2)), 0);
    ExpectBufEQ(tagBuf, tag2, sizeof(tag2));
    ExpectIntEQ(wc_AesEaxFree(&eax), 0);

    /* --- Test 2d: 2-byte ciphertext, single DecryptUpdate with inline AAD --- */
    ExpectIntEQ(wc_AesEaxInit(&eax, key2, sizeof(key2),
                              nonce2, sizeof(nonce2),
                              NULL, 0), 0);
    ExpectIntEQ(wc_AesEaxDecryptUpdate(&eax, out, ct2, sizeof(ct2),
                                       aad2, sizeof(aad2)), 0);
    ExpectBufEQ(out, pt2, sizeof(pt2));
    ExpectIntEQ(wc_AesEaxDecryptFinal(&eax, tag2, sizeof(tag2)), 0);
    ExpectIntEQ(wc_AesEaxFree(&eax), 0);

    /* --- Test 3: 5-byte plaintext, multi-chunk encrypt with AuthDataUpdate --- */
    ExpectIntEQ(wc_AesEaxInit(&eax, key3, sizeof(key3),
                              nonce3, sizeof(nonce3),
                              NULL, 0), 0);
    /* Feed AAD via AuthDataUpdate split into two calls */
    ExpectIntEQ(wc_AesEaxAuthDataUpdate(&eax, aad3, 4), 0);
    ExpectIntEQ(wc_AesEaxAuthDataUpdate(&eax, aad3 + 4, sizeof(aad3) - 4), 0);
    /* Encrypt plaintext in two chunks */
    ExpectIntEQ(wc_AesEaxEncryptUpdate(&eax, out, pt3, 2, NULL, 0), 0);
    ExpectBufEQ(out, ct3, 2);
    ExpectIntEQ(wc_AesEaxEncryptUpdate(&eax, out + 2, pt3 + 2,
                                       (word32)(sizeof(pt3) - 2), NULL, 0), 0);
    ExpectBufEQ(out + 2, ct3 + 2, sizeof(ct3) - 2);
    ExpectIntEQ(wc_AesEaxEncryptFinal(&eax, tagBuf, sizeof(tag3)), 0);
    ExpectBufEQ(tagBuf, tag3, sizeof(tag3));
    ExpectIntEQ(wc_AesEaxFree(&eax), 0);

    /* --- Test 3d: 5-byte ciphertext, multi-chunk decrypt with AuthDataUpdate --- */
    ExpectIntEQ(wc_AesEaxInit(&eax, key3, sizeof(key3),
                              nonce3, sizeof(nonce3),
                              NULL, 0), 0);
    ExpectIntEQ(wc_AesEaxAuthDataUpdate(&eax, aad3, 4), 0);
    ExpectIntEQ(wc_AesEaxAuthDataUpdate(&eax, aad3 + 4, sizeof(aad3) - 4), 0);
    /* Decrypt ciphertext in two chunks */
    ExpectIntEQ(wc_AesEaxDecryptUpdate(&eax, out, ct3, 2, NULL, 0), 0);
    ExpectBufEQ(out, pt3, 2);
    ExpectIntEQ(wc_AesEaxDecryptUpdate(&eax, out + 2, ct3 + 2,
                                       (word32)(sizeof(ct3) - 2), NULL, 0), 0);
    ExpectBufEQ(out + 2, pt3 + 2, sizeof(pt3) - 2);
    ExpectIntEQ(wc_AesEaxDecryptFinal(&eax, tag3, sizeof(tag3)), 0);
    ExpectIntEQ(wc_AesEaxFree(&eax), 0);

    /* --- Bad args --- */
    /* wc_AesEaxInit */
    ExpectIntEQ(wc_AesEaxInit(NULL, key1, sizeof(key1),
                              nonce1, sizeof(nonce1), NULL, 0),
                WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesEaxInit(&eax, NULL, sizeof(key1),
                              nonce1, sizeof(nonce1), NULL, 0),
                WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesEaxInit(&eax, key1, sizeof(key1),
                              NULL, sizeof(nonce1), NULL, 0),
                WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    /* wc_AesEaxAuthDataUpdate */
    ExpectIntEQ(wc_AesEaxAuthDataUpdate(NULL, aad1, sizeof(aad1)),
                WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    /* wc_AesEaxEncryptFinal */
    ExpectIntEQ(wc_AesEaxEncryptFinal(NULL, tagBuf, WC_AES_BLOCK_SIZE),
                WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    /* wc_AesEaxDecryptFinal NULL eax */
    ExpectIntEQ(wc_AesEaxDecryptFinal(NULL, tag1, sizeof(tag1)),
                WC_NO_ERR_TRACE(BAD_FUNC_ARG));

    /* wc_AesEaxDecryptFinal authInSz > WC_AES_BLOCK_SIZE */
    ExpectIntEQ(wc_AesEaxInit(&eax, key1, sizeof(key1),
                              nonce1, sizeof(nonce1), NULL, 0), 0);
    ExpectIntEQ(wc_AesEaxDecryptFinal(&eax, tag1, WC_AES_BLOCK_SIZE + 1),
                WC_NO_ERR_TRACE(BAD_FUNC_ARG));
    ExpectIntEQ(wc_AesEaxFree(&eax), 0);

    /* wc_AesEaxFree NULL */
    ExpectIntEQ(wc_AesEaxFree(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG));

#endif /* WOLFSSL_AES_128 */

    return EXPECT_RESULT();
} /* END test_wc_AesEaxStream() */

#endif /* WOLFSSL_AES_EAX && WOLFSSL_AES_256
        * (!HAVE_FIPS || FIPS_VERSION_GE(5, 3)) && !HAVE_SELFTEST
        */

/*----------------------------------------------------------------------------*
 | AES-SIV Test
 *----------------------------------------------------------------------------*/

#if defined(WOLFSSL_AES_SIV) && defined(WOLFSSL_AES_128)

/*
 * Testing wc_AesSivEncrypt, wc_AesSivDecrypt,
 *         wc_AesSivEncrypt_ex, wc_AesSivDecrypt_ex.
 * Uses RFC 5297 Example A.1 (single assoc) and A.2 (two assocs).
 */
int test_wc_AesSivEncryptDecrypt(void)
{
    EXPECT_DECLS;

    /* RFC 5297 Example A.1: single associated data buffer */
    const byte key_a1[] = {
        0xff,0xfe,0xfd,0xfc,0xfb,0xfa,0xf9,0xf8,
        0xf7,0xf6,0xf5,0xf4,0xf3,0xf2,0xf1,0xf0,
        0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,
        0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
    };
    const byte assoc_a1[] = {
        0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
        0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
        0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27
    };
    const byte pt_a1[] = {
        0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,
        0x99,0xaa,0xbb,0xcc,0xdd,0xee
    };
    const byte siv_a1[] = {
        0x85,0x63,0x2d,0x07,0xc6,0xe8,0xf3,0x7f,
        0x95,0x0a,0xcd,0x32,0x0a,0x2e,0xcc,0x93
    };
    const byte ct_a1[] = {
        0x40,0xc0,0x2b,0x96,0x90,0xc4,0xdc,0x04,
        0xda,0xef,0x7f,0x6a,0xfe,0x5c
    };

    /* RFC 5297 Example A.2: two associated data buffers, no nonce */
    const byte key_a2[] = {
        0x7f,0x7e,0x7d,0x7c,0x7b,0x7a,0x79,0x78,
        0x77,0x76,0x75,0x74,0x73,0x72,0x71,0x70,
        0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
        0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f
    };
    const byte assoc2_1_a2[] = {
        0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
        0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff,
        0xde,0xad,0xda,0xda,0xde,0xad,0xda,0xda,
        0xff,0xee,0xdd,0xcc,0xbb,0xaa,0x99,0x88,
        0x77,0x66,0x55,0x44,0x33,0x22,0x11,0x00
    };
    const byte assoc2_2_a2[] = {
        0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80,
        0x90,0xa0
    };
    const byte nonce_a2[] = {
        0x09,0xf9,0x11,0x02,0x9d,0x74,0xe3,0x5b,
        0xd8,0x41,0x56,0xc5,0x63,0x56,0x88,0xc0
    };
    const byte pt_a2[] = {
        0x74,0x68,0x69,0x73,0x20,0x69,0x73,0x20,
        0x73,0x6f,0x6d,0x65,0x20,0x70,0x6c,0x61,
        0x69,0x6e,0x74,0x65,0x78,0x74,0x20,0x74,
        0x6f,0x20,0x65,0x6e,0x63,0x72,0x79,0x70,
        0x74,0x20,0x75,0x73,0x69,0x6e,0x67,0x20,
        0x53,0x49,0x56,0x2d,0x41,0x45,0x53
    };
    const byte siv_a2[] = {
        0x7b,0xdb,0x6e,0x3b,0x43,0x26,0x67,0xeb,
        0x06,0xf4,0xd1,0x4b,0xff,0x2f,0xbd,0x0f
    };
    const byte ct_a2[] = {
        0xcb,0x90,0x0f,0x2f,0xdd,0xbe,0x40,0x43,
        0x26,0x60,0x19,0x65,0xc8,0x89,0xbf,0x17,
        0xdb,0xa7,0x7c,0xeb,0x09,0x4f,0xa6,0x63,
        0xb7,0xa3,0xf7,0x48,0xba,0x8a,0xf8,0x29,
        0xea,0x64,0xad,0x54,0x4a,0x27,0x2e,0x9c,
        0x48,0x5b,0x62,0xa3,0xfd,0x5c,0x0d
    };

    byte siv[WC_AES_BLOCK_SIZE];
    byte ct[sizeof(pt_a2)];   /* large enough for both tests */
    byte pt[sizeof(pt_a2)];

    /* --- A.1: wc_AesSivEncrypt (single assoc, no nonce) --- */
    XMEMSET(siv, 0, sizeof(siv));
    XMEMSET(ct, 0, sizeof(ct));
    ExpectIntEQ(wc_AesSivEncrypt(key_a1, sizeof(key_a1),
                                 assoc_a1, sizeof(assoc_a1),
                                 NULL, 0,
                                 pt_a1, sizeof(pt_a1),
                                 siv, ct), 0);
    ExpectBufEQ(siv, siv_a1, sizeof(siv_a1));
    ExpectBufEQ(ct, ct_a1, sizeof(ct_a1));

    /* --- A.1: wc_AesSivDecrypt --- */
    XMEMSET(pt, 0, sizeof(pt));
    XMEMCPY(siv, siv_a1, sizeof(siv_a1));
    ExpectIntEQ(wc_AesSivDecrypt(key_a1, sizeof(key_a1),
                                 assoc_a1, sizeof(assoc_a1),
                                 NULL, 0,
                                 ct_a1, sizeof(ct_a1),
                                 siv, pt), 0);
    ExpectBufEQ(pt, pt_a1, sizeof(pt_a1));

    /* Corrupt SIV: decrypt must fail */
    siv[0] ^= 0xff;
    ExpectIntNE(wc_AesSivDecrypt(key_a1, sizeof(key_a1),
                                 assoc_a1, sizeof(assoc_a1),
                                 NULL, 0,
                                 ct_a1, sizeof(ct_a1),
                                 siv, pt), 0);

    /* --- A.2: wc_AesSivEncrypt_ex (two assocs + nonce) --- */
    {
        const AesSivAssoc assocs[2] = {
            { assoc2_1_a2, sizeof(assoc2_1_a2) },
            { assoc2_2_a2, sizeof(assoc2_2_a2) }
        };
        XMEMSET(siv, 0, sizeof(siv));
        XMEMSET(ct, 0, sizeof(ct));
        ExpectIntEQ(wc_AesSivEncrypt_ex(key_a2, sizeof(key_a2),
                                        assocs, 2,
                                        nonce_a2, sizeof(nonce_a2),
                                        pt_a2, sizeof(pt_a2),
                                        siv, ct), 0);
        ExpectBufEQ(siv, siv_a2, sizeof(siv_a2));
        ExpectBufEQ(ct, ct_a2, sizeof(ct_a2));

        /* wc_AesSivDecrypt_ex */
        XMEMSET(pt, 0, sizeof(pt));
        XMEMCPY(siv, siv_a2, sizeof(siv_a2));
        ExpectIntEQ(wc_AesSivDecrypt_ex(key_a2, sizeof(key_a2),
                                        assocs, 2,
                                        nonce_a2, sizeof(nonce_a2),
                                        ct_a2, sizeof(ct_a2),
                                        siv, pt), 0);
        ExpectBufEQ(pt, pt_a2, sizeof(pt_a2));
    }

    /* --- Bad args: wc_AesSivEncrypt --- */
    ExpectIntNE(wc_AesSivEncrypt(NULL, sizeof(key_a1),
                                 assoc_a1, sizeof(assoc_a1),
                                 NULL, 0, pt_a1, sizeof(pt_a1), siv, ct), 0);
    ExpectIntNE(wc_AesSivEncrypt(key_a1, 0,
                                 assoc_a1, sizeof(assoc_a1),
                                 NULL, 0, pt_a1, sizeof(pt_a1), siv, ct), 0);
    ExpectIntNE(wc_AesSivEncrypt(key_a1, sizeof(key_a1),
                                 assoc_a1, sizeof(assoc_a1),
                                 NULL, 0, pt_a1, sizeof(pt_a1), NULL, ct), 0);
    ExpectIntNE(wc_AesSivEncrypt(key_a1, sizeof(key_a1),
                                 assoc_a1, sizeof(assoc_a1),
                                 NULL, 0, pt_a1, sizeof(pt_a1), siv, NULL), 0);

    /* --- Bad args: wc_AesSivDecrypt --- */
    XMEMCPY(siv, siv_a1, sizeof(siv_a1));
    ExpectIntNE(wc_AesSivDecrypt(NULL, sizeof(key_a1),
                                 assoc_a1, sizeof(assoc_a1),
                                 NULL, 0, ct_a1, sizeof(ct_a1), siv, pt), 0);
    ExpectIntNE(wc_AesSivDecrypt(key_a1, 0,
                                 assoc_a1, sizeof(assoc_a1),
                                 NULL, 0, ct_a1, sizeof(ct_a1), siv, pt), 0);
    ExpectIntNE(wc_AesSivDecrypt(key_a1, sizeof(key_a1),
                                 assoc_a1, sizeof(assoc_a1),
                                 NULL, 0, ct_a1, sizeof(ct_a1), NULL, pt), 0);
    ExpectIntNE(wc_AesSivDecrypt(key_a1, sizeof(key_a1),
                                 assoc_a1, sizeof(assoc_a1),
                                 NULL, 0, ct_a1, sizeof(ct_a1), siv, NULL), 0);

    return EXPECT_RESULT();
} /* END test_wc_AesSivEncryptDecrypt */

#endif /* WOLFSSL_AES_SIV && WOLFSSL_AES_128 */

/*----------------------------------------------------------------------------*
 | CryptoCB AES SetKey Test
 *----------------------------------------------------------------------------*/

#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_AES_SETKEY) && \
    !defined(NO_AES) && defined(HAVE_AESGCM)

#include <wolfssl/wolfcrypt/cryptocb.h>

/* Test CryptoCB device IDs (must be unique across test_aes.c):
 *   7 = AES setkey + AES-GCM offload (see TEST_CRYPTOCB_AES_DEVID)
 *   9 = TLS 1.3 key-zeroing offload   (see TEST_TLS13_ZERO_DEVID) */
#define TEST_CRYPTOCB_AES_DEVID  7

/* Test state tracking */
static int cryptoCbAesSetKeyCalled = 0;
static int cryptoCbAesFreeCalled = 0;

/* Simulated SE key storage - in real SE this would be in secure hardware */
typedef struct {
    byte key[AES_256_KEY_SIZE];
    word32 keySz;
    int valid;
} MockSeKeySlot;

static MockSeKeySlot mockSeKey = {0};

/* Mock handle pointing to our key slot */
static void* cryptoCbAesMockHandle = (void*)&mockSeKey;

/* Test CryptoCB callback for AES key import operations
 * This emulates a Secure Element by:
 * - Storing the key on SetKey (simulating SE key import)
 * - Using stored key for encrypt/decrypt (simulating SE crypto)
 * - Clearing key on Free (simulating SE key deletion)
 */
static int test_CryptoCb_Aes_Cb(int devId, wc_CryptoInfo* info, void* ctx)
{
    (void)ctx;

    if (devId != TEST_CRYPTOCB_AES_DEVID)
        return CRYPTOCB_UNAVAILABLE;

    /* AES SetKey operation - simulate SE key import */
    if (info->algo_type == WC_ALGO_TYPE_CIPHER &&
        info->cipher.type == WC_CIPHER_AES &&
        info->cipher.aessetkey.aes != NULL) {

        Aes* aes = info->cipher.aessetkey.aes;
        const byte* key = info->cipher.aessetkey.key;
        word32 keySz = info->cipher.aessetkey.keySz;

        /* Validate key */
        if (key == NULL || keySz == 0 || keySz > AES_256_KEY_SIZE) {
            return BAD_FUNC_ARG;
        }

        /* "Import" key to simulated SE storage */
        XMEMCPY(mockSeKey.key, key, keySz);
        mockSeKey.keySz = keySz;
        mockSeKey.valid = 1;

        /* Store handle in aes->devCtx - this is what wolfSSL will use */
        aes->devCtx = cryptoCbAesMockHandle;


        cryptoCbAesSetKeyCalled++;

        return 0;
    }

    /* AES-GCM Encrypt - simulate SE encryption using stored key */
    if (info->algo_type == WC_ALGO_TYPE_CIPHER &&
        info->cipher.type == WC_CIPHER_AES_GCM &&
        info->cipher.enc) {

        Aes* aes = info->cipher.aesgcm_enc.aes;
        MockSeKeySlot* slot;
        Aes tempAes;
        int ret;

        /* Verify handle points to our key slot */
        if (aes == NULL || aes->devCtx != cryptoCbAesMockHandle) {
            return BAD_FUNC_ARG;
        }

        slot = (MockSeKeySlot*)aes->devCtx;
        if (!slot->valid) {
            return BAD_STATE_E;
        }

        /* Initialize a temporary Aes for software crypto (simulating SE internal operation) */
        XMEMSET(&tempAes, 0, sizeof(tempAes));
        ret = wc_AesInit(&tempAes, NULL, INVALID_DEVID);  /* No CryptoCB for internal use */
        if (ret != 0) return ret;

        ret = wc_AesGcmSetKey(&tempAes, slot->key, slot->keySz);
        if (ret != 0) {
            wc_AesFree(&tempAes);
            return ret;
        }

        /* Perform the actual encryption */
        ret = wc_AesGcmEncrypt(&tempAes,
            info->cipher.aesgcm_enc.out,
            info->cipher.aesgcm_enc.in,
            info->cipher.aesgcm_enc.sz,
            info->cipher.aesgcm_enc.iv,
            info->cipher.aesgcm_enc.ivSz,
            info->cipher.aesgcm_enc.authTag,
            info->cipher.aesgcm_enc.authTagSz,
            info->cipher.aesgcm_enc.authIn,
            info->cipher.aesgcm_enc.authInSz);

        wc_AesFree(&tempAes);

        return ret;
    }

    /* AES-GCM Decrypt - simulate SE decryption using stored key */
    if (info->algo_type == WC_ALGO_TYPE_CIPHER &&
        info->cipher.type == WC_CIPHER_AES_GCM &&
        !info->cipher.enc) {

        Aes* aes = info->cipher.aesgcm_dec.aes;
        MockSeKeySlot* slot;
        Aes tempAes;
        int ret;

        /* Verify handle points to our key slot */
        if (aes == NULL || aes->devCtx != cryptoCbAesMockHandle) {
            return BAD_FUNC_ARG;
        }

        slot = (MockSeKeySlot*)aes->devCtx;
        if (!slot->valid) {
            return BAD_STATE_E;
        }

        /* Initialize a temporary Aes for software crypto (simulating SE internal operation) */
        XMEMSET(&tempAes, 0, sizeof(tempAes));
        ret = wc_AesInit(&tempAes, NULL, INVALID_DEVID);
        if (ret != 0) return ret;

        ret = wc_AesGcmSetKey(&tempAes, slot->key, slot->keySz);
        if (ret != 0) {
            wc_AesFree(&tempAes);
            return ret;
        }

        /* Perform the actual decryption */
        ret = wc_AesGcmDecrypt(&tempAes,
            info->cipher.aesgcm_dec.out,
            info->cipher.aesgcm_dec.in,
            info->cipher.aesgcm_dec.sz,
            info->cipher.aesgcm_dec.iv,
            info->cipher.aesgcm_dec.ivSz,
            info->cipher.aesgcm_dec.authTag,
            info->cipher.aesgcm_dec.authTagSz,
            info->cipher.aesgcm_dec.authIn,
            info->cipher.aesgcm_dec.authInSz);

        wc_AesFree(&tempAes);

        return ret;
    }

#ifdef WOLF_CRYPTO_CB_FREE
    /* Free operation - simulate SE key deletion */
    if (info->algo_type == WC_ALGO_TYPE_FREE &&
        info->free.algo == WC_ALGO_TYPE_CIPHER &&
        info->free.type == WC_CIPHER_AES) {

        Aes* aes = (Aes*)info->free.obj;

        if (aes != NULL && aes->devCtx == cryptoCbAesMockHandle) {
            /* "Delete" key from simulated SE */
            ForceZero(&mockSeKey, sizeof(mockSeKey));
            cryptoCbAesFreeCalled++;
        }

        return 0;
    }
#endif

    return CRYPTOCB_UNAVAILABLE;
}

/*
 * Test: CryptoCB AES SetKey hook for key import / secure element support
 */
int test_wc_CryptoCb_AesSetKey(void)
{
    EXPECT_DECLS;
#ifdef WOLFSSL_SMALL_STACK
    Aes* aes = NULL;
    byte* key = NULL;
    byte* iv = NULL;
    byte* plain = NULL;
    byte* cipher = NULL;
    byte* decrypted = NULL;
    byte* authTag = NULL;
#else
    Aes aes[1];
    byte key[AES_128_KEY_SIZE];
    byte iv[GCM_NONCE_MID_SZ];
    byte plain[16];
    byte cipher[16];
    byte decrypted[16];
    byte authTag[AES_BLOCK_SIZE];
#endif
    int ret;

#ifdef WOLFSSL_SMALL_STACK
    aes = (Aes*)XMALLOC(sizeof(Aes), NULL, DYNAMIC_TYPE_TMP_BUFFER);
    key = (byte*)XMALLOC(AES_128_KEY_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    iv = (byte*)XMALLOC(GCM_NONCE_MID_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    plain = (byte*)XMALLOC(16, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    cipher = (byte*)XMALLOC(16, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    decrypted = (byte*)XMALLOC(16, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    authTag = (byte*)XMALLOC(AES_BLOCK_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);

    if (aes == NULL || key == NULL || iv == NULL || plain == NULL ||
        cipher == NULL || decrypted == NULL || authTag == NULL) {
        ret = MEMORY_E;
        goto out;
    }
#endif

    /* Initialize key, iv, plain arrays */
    {
        static const byte keyData[AES_128_KEY_SIZE] = {
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
            0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
        };
        static const byte plainData[16] = {
            0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77,
            0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x21, 0x00
        };
        XMEMCPY(key, keyData, AES_128_KEY_SIZE);
        XMEMSET(iv, 0, GCM_NONCE_MID_SZ);
        XMEMCPY(plain, plainData, 16);
    }

    XMEMSET(aes, 0, sizeof(Aes));
    XMEMSET(&mockSeKey, 0, sizeof(mockSeKey));

    /* Reset test state */
    cryptoCbAesSetKeyCalled = 0;
    cryptoCbAesFreeCalled = 0;

    /* Register test callback */
    ret = wc_CryptoCb_RegisterDevice(TEST_CRYPTOCB_AES_DEVID,
                                     test_CryptoCb_Aes_Cb, NULL);
    ExpectIntEQ(ret, 0);

    /* Initialize Aes with device ID */
    ret = wc_AesInit(aes, NULL, TEST_CRYPTOCB_AES_DEVID);
    ExpectIntEQ(ret, 0);
    ExpectIntEQ(aes->devId, TEST_CRYPTOCB_AES_DEVID);

    /* Set key - should trigger CryptoCB and "import" to mock SE */
    ret = wc_AesGcmSetKey(aes, key, sizeof(key));
    ExpectIntEQ(ret, 0);

    /* Verify callback was invoked */
    ExpectIntEQ(cryptoCbAesSetKeyCalled, 1);

    /* Verify handle stored in devCtx */
    ExpectPtrEq(aes->devCtx, cryptoCbAesMockHandle);

    /* Verify key was "imported" to mock SE */
    ExpectIntEQ(mockSeKey.valid, 1);
    ExpectIntEQ(mockSeKey.keySz, (int)sizeof(key));

    /* Verify keylen metadata stored in Aes struct */
    ExpectIntEQ(aes->keylen, (int)sizeof(key));

    /* After SetKey succeeds via CryptoCB, verify key NOT in devKey */
    {
        byte zeroKey[AES_128_KEY_SIZE] = {0};
        /* Key should NOT be copied to devKey - SE owns it */
        ExpectIntEQ(XMEMCMP(aes->devKey, zeroKey, sizeof(key)), 0);
    }

    /* Test encrypt - callback performs crypto using stored key */
    ret = wc_AesGcmEncrypt(aes, cipher, plain, sizeof(plain),
                           iv, sizeof(iv), authTag, sizeof(authTag),
                           NULL, 0);
    ExpectIntEQ(ret, 0);

    /* Test decrypt - callback performs crypto using stored key */
    ret = wc_AesGcmDecrypt(aes, decrypted, cipher, sizeof(cipher),
                           iv, sizeof(iv), authTag, sizeof(authTag),
                           NULL, 0);
    ExpectIntEQ(ret, 0);

    /* Verify round-trip */
    ExpectIntEQ(XMEMCMP(plain, decrypted, sizeof(plain)), 0);

#ifdef WOLF_CRYPTO_CB_FREE
    /* Free should trigger callback and "delete" key from mock SE */
    cryptoCbAesFreeCalled = 0;
    wc_AesFree(aes);

    /* Verify free callback invoked */
    ExpectIntEQ(cryptoCbAesFreeCalled, 1);

    /* Verify devCtx cleared */
    ExpectPtrEq(aes->devCtx, NULL);

    /* Verify key was "deleted" from mock SE */
    ExpectIntEQ(mockSeKey.valid, 0);
#else
    wc_AesFree(aes);
#endif

    /* Cleanup */
    wc_CryptoCb_UnRegisterDevice(TEST_CRYPTOCB_AES_DEVID);

    /* Test software path (no devId) still works */
    XMEMSET(aes, 0, sizeof(Aes));
    cryptoCbAesSetKeyCalled = 0;

    ret = wc_AesInit(aes, NULL, INVALID_DEVID);
    ExpectIntEQ(ret, 0);

    ret = wc_AesGcmSetKey(aes, key, sizeof(key));
    ExpectIntEQ(ret, 0);

    /* Callback should NOT have been invoked */
    ExpectIntEQ(cryptoCbAesSetKeyCalled, 0);

    /* devCtx should be NULL */
    ExpectPtrEq(aes->devCtx, NULL);

    wc_AesFree(aes);

#ifdef WOLFSSL_SMALL_STACK
out:
    XFREE(aes, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(iv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(plain, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(cipher, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(decrypted, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(authTag, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif

    return EXPECT_RESULT();
}

#endif /* WOLF_CRYPTO_CB && WOLF_CRYPTO_CB_AES_SETKEY && !NO_AES && HAVE_AESGCM */

/*----------------------------------------------------------------------------*
 | CryptoCB AES-GCM End-to-End Offload Test
 *----------------------------------------------------------------------------*/

#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_AES_SETKEY) && \
    !defined(NO_AES) && defined(HAVE_AESGCM)

#define TEST_CRYPTOCB_AESGCM_OFFLOAD_DEVID  8

/* Test state tracking for end-to-end offload test */
static int cryptoCbAesGcmSetKeyCalled = 0;
static int cryptoCbAesGcmEncryptCalled = 0;
static int cryptoCbAesGcmDecryptCalled = 0;
static int cryptoCbAesGcmFreeCalled = 0;

/* Mock SE key storage for offload test */
typedef struct {
    byte key[AES_256_KEY_SIZE];
    word32 keySz;
    int valid;
} MockSeKeySlotOffload;

static MockSeKeySlotOffload mockSeKeyOffload = {0};

/* Mock handle pointing to our key slot */
static void* cryptoCbAesGcmMockHandle = (void*)&mockSeKeyOffload;

/* Mock CryptoCB callback for end-to-end AES-GCM offload test
 * This emulates a Secure Element that:
 * - Stores the key on SetKey (simulating SE key import)
 * - Performs encryption/decryption using stored key (simulating SE crypto)
 * - Tracks all callback invocations to verify offload is working
 * - Uses software AES internally (simulating SE internal operation)
 */
static int test_CryptoCb_AesGcm_Offload_Cb(int devId, wc_CryptoInfo* info, void* ctx)
{
    (void)ctx;

    if (devId != TEST_CRYPTOCB_AESGCM_OFFLOAD_DEVID)
        return CRYPTOCB_UNAVAILABLE;

    /* AES SetKey operation - simulate SE key import */
    if (info->algo_type == WC_ALGO_TYPE_CIPHER &&
        info->cipher.type == WC_CIPHER_AES &&
        info->cipher.aessetkey.aes != NULL) {

        Aes* aes = info->cipher.aessetkey.aes;
        const byte* key = info->cipher.aessetkey.key;
        word32 keySz = info->cipher.aessetkey.keySz;

        /* Validate key */
        if (key == NULL || keySz == 0 || keySz > AES_256_KEY_SIZE) {
            return BAD_FUNC_ARG;
        }

        /* "Import" key to simulated SE storage */
        XMEMCPY(mockSeKeyOffload.key, key, keySz);
        mockSeKeyOffload.keySz = keySz;
        mockSeKeyOffload.valid = 1;

        /* Store handle in aes->devCtx - this is what wolfSSL will use */
        aes->devCtx = cryptoCbAesGcmMockHandle;


        cryptoCbAesGcmSetKeyCalled++;

        return 0;
    }

    /* AES-GCM Encrypt - simulate SE encryption using stored key */
    if (info->algo_type == WC_ALGO_TYPE_CIPHER &&
        info->cipher.type == WC_CIPHER_AES_GCM &&
        info->cipher.enc) {

        Aes* aes = info->cipher.aesgcm_enc.aes;
        MockSeKeySlotOffload* slot;
        Aes tempAes;
        int ret;

        /* Verify handle points to our key slot */
        if (aes == NULL || aes->devCtx != cryptoCbAesGcmMockHandle) {
            return BAD_FUNC_ARG;
        }

        slot = (MockSeKeySlotOffload*)aes->devCtx;
        if (!slot->valid) {
            return BAD_STATE_E;
        }

        /* Track that encrypt callback was invoked */
        cryptoCbAesGcmEncryptCalled++;

        /* Initialize a temporary Aes for software crypto (simulating SE internal operation) */
        XMEMSET(&tempAes, 0, sizeof(tempAes));
        ret = wc_AesInit(&tempAes, NULL, INVALID_DEVID);  /* No CryptoCB for internal use */
        if (ret != 0) return ret;

        ret = wc_AesGcmSetKey(&tempAes, slot->key, slot->keySz);
        if (ret != 0) {
            wc_AesFree(&tempAes);
            return ret;
        }

        /* Perform the actual encryption using software AES (simulating SE internal operation) */
        ret = wc_AesGcmEncrypt(&tempAes,
            info->cipher.aesgcm_enc.out,
            info->cipher.aesgcm_enc.in,
            info->cipher.aesgcm_enc.sz,
            info->cipher.aesgcm_enc.iv,
            info->cipher.aesgcm_enc.ivSz,
            info->cipher.aesgcm_enc.authTag,
            info->cipher.aesgcm_enc.authTagSz,
            info->cipher.aesgcm_enc.authIn,
            info->cipher.aesgcm_enc.authInSz);

        wc_AesFree(&tempAes);

        return ret;
    }

    /* AES-GCM Decrypt - simulate SE decryption using stored key */
    if (info->algo_type == WC_ALGO_TYPE_CIPHER &&
        info->cipher.type == WC_CIPHER_AES_GCM &&
        !info->cipher.enc) {

        Aes* aes = info->cipher.aesgcm_dec.aes;
        MockSeKeySlotOffload* slot;
        Aes tempAes;
        int ret;

        /* Verify handle points to our key slot */
        if (aes == NULL || aes->devCtx != cryptoCbAesGcmMockHandle) {
            return BAD_FUNC_ARG;
        }

        slot = (MockSeKeySlotOffload*)aes->devCtx;
        if (!slot->valid) {
            return BAD_STATE_E;
        }

        /* Track that decrypt callback was invoked */
        cryptoCbAesGcmDecryptCalled++;

        /* Initialize a temporary Aes for software crypto (simulating SE internal operation) */
        XMEMSET(&tempAes, 0, sizeof(tempAes));
        ret = wc_AesInit(&tempAes, NULL, INVALID_DEVID);
        if (ret != 0) return ret;

        ret = wc_AesGcmSetKey(&tempAes, slot->key, slot->keySz);
        if (ret != 0) {
            wc_AesFree(&tempAes);
            return ret;
        }

        /* Perform the actual decryption using software AES (simulating SE internal operation) */
        ret = wc_AesGcmDecrypt(&tempAes,
            info->cipher.aesgcm_dec.out,
            info->cipher.aesgcm_dec.in,
            info->cipher.aesgcm_dec.sz,
            info->cipher.aesgcm_dec.iv,
            info->cipher.aesgcm_dec.ivSz,
            info->cipher.aesgcm_dec.authTag,
            info->cipher.aesgcm_dec.authTagSz,
            info->cipher.aesgcm_dec.authIn,
            info->cipher.aesgcm_dec.authInSz);

        wc_AesFree(&tempAes);

        return ret;
    }

#ifdef WOLF_CRYPTO_CB_FREE
    /* Free operation - simulate SE key deletion */
    if (info->algo_type == WC_ALGO_TYPE_FREE &&
        info->free.algo == WC_ALGO_TYPE_CIPHER &&
        info->free.type == WC_CIPHER_AES) {

        Aes* aes = (Aes*)info->free.obj;

        if (aes != NULL && aes->devCtx == cryptoCbAesGcmMockHandle) {
            /* "Delete" key from simulated SE */
            ForceZero(&mockSeKeyOffload, sizeof(mockSeKeyOffload));
            cryptoCbAesGcmFreeCalled++;
        }

        return 0;
    }
#endif

    return CRYPTOCB_UNAVAILABLE;
}

/*
 * Test: End-to-End AES-GCM Offload via CryptoCB
 * This test verifies that:
 * - AES-GCM encryption/decryption operations are routed through CryptoCb
 * - Software AES is bypassed when offload is enabled
 * - Encrypted output and auth tag are correct
 * - Decryption via CryptoCb restores the original plaintext
 */
int test_wc_CryptoCb_AesGcm_EncryptDecrypt(void)
{
    EXPECT_DECLS;
#ifdef WOLFSSL_SMALL_STACK
    Aes* aes = NULL;
    byte* key = NULL;
    byte* iv = NULL;
    byte* aad = NULL;
    byte* plaintext = NULL;
    byte* ciphertext = NULL;
    byte* decrypted = NULL;
    byte* authTag = NULL;
#else
    Aes aes[1];
    byte key[AES_128_KEY_SIZE];
    byte iv[GCM_NONCE_MID_SZ];
    byte aad[16];
    byte plaintext[32];
    byte ciphertext[32];
    byte decrypted[32];
    byte authTag[AES_BLOCK_SIZE];
#endif
    int ret;
    int i;
    int hasNonZero = 0;

#ifdef WOLFSSL_SMALL_STACK
    aes = (Aes*)XMALLOC(sizeof(Aes), NULL, DYNAMIC_TYPE_TMP_BUFFER);
    key = (byte*)XMALLOC(AES_128_KEY_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    iv = (byte*)XMALLOC(GCM_NONCE_MID_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    aad = (byte*)XMALLOC(16, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    plaintext = (byte*)XMALLOC(32, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    ciphertext = (byte*)XMALLOC(32, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    decrypted = (byte*)XMALLOC(32, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    authTag = (byte*)XMALLOC(AES_BLOCK_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);

    if (aes == NULL || key == NULL || iv == NULL || aad == NULL ||
        plaintext == NULL || ciphertext == NULL || decrypted == NULL ||
        authTag == NULL) {
        ret = MEMORY_E;
        goto out;
    }
#endif

    /* Initialize key, iv, aad, plaintext arrays */
    {
        static const byte keyData[AES_128_KEY_SIZE] = {
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
            0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
        };
        static const byte ivData[GCM_NONCE_MID_SZ] = {
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
            0x08, 0x09, 0x0a, 0x0b
        };
        static const byte aadData[16] = {
            0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
            0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
        };
        static const byte plaintextData[32] = {
            0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77,
            0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x21, 0x00,
            0x54, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x73,
            0x73, 0x61, 0x67, 0x65, 0x20, 0x32, 0x21, 0x00
        };
        XMEMCPY(key, keyData, AES_128_KEY_SIZE);
        XMEMCPY(iv, ivData, GCM_NONCE_MID_SZ);
        XMEMCPY(aad, aadData, 16);
        XMEMCPY(plaintext, plaintextData, 32);
    }

    XMEMSET(aes, 0, sizeof(Aes));
    XMEMSET(&mockSeKeyOffload, 0, sizeof(mockSeKeyOffload));
    XMEMSET(ciphertext, 0, 32);
    XMEMSET(decrypted, 0, 32);
    XMEMSET(authTag, 0, AES_BLOCK_SIZE);

    /* Reset test state */
    cryptoCbAesGcmSetKeyCalled = 0;
    cryptoCbAesGcmEncryptCalled = 0;
    cryptoCbAesGcmDecryptCalled = 0;
    cryptoCbAesGcmFreeCalled = 0;

    /* Register test callback */
    ret = wc_CryptoCb_RegisterDevice(TEST_CRYPTOCB_AESGCM_OFFLOAD_DEVID,
                                     test_CryptoCb_AesGcm_Offload_Cb, NULL);
    ExpectIntEQ(ret, 0);

    /* Initialize Aes with device ID */
    ret = wc_AesInit(aes, NULL, TEST_CRYPTOCB_AESGCM_OFFLOAD_DEVID);
    ExpectIntEQ(ret, 0);
    ExpectIntEQ(aes->devId, TEST_CRYPTOCB_AESGCM_OFFLOAD_DEVID);

    /* Set key - should trigger CryptoCB and "import" to mock SE */
    ret = wc_AesGcmSetKey(aes, key, sizeof(key));
    ExpectIntEQ(ret, 0);

    /* Verify SetKey callback was invoked */
    ExpectIntEQ(cryptoCbAesGcmSetKeyCalled, 1);

    /* Verify handle stored in devCtx */
    ExpectPtrEq(aes->devCtx, cryptoCbAesGcmMockHandle);

    /* Verify key was "imported" to mock SE */
    ExpectIntEQ(mockSeKeyOffload.valid, 1);
    ExpectIntEQ(mockSeKeyOffload.keySz, (int)sizeof(key));

    /* Verify keylen metadata stored in Aes struct */
    ExpectIntEQ(aes->keylen, (int)sizeof(key));

    /* Encrypt via wolfCrypt API - should route through CryptoCb */
    ret = wc_AesGcmEncrypt(aes, ciphertext, plaintext, 32,
                           iv, sizeof(iv), authTag, sizeof(authTag),
                           aad, 16);
    ExpectIntEQ(ret, 0);

    /* Assert: Encrypt callback was invoked */
    ExpectIntEQ(cryptoCbAesGcmEncryptCalled, 1);

    /* Assert: Ciphertext is different from plaintext */
    ExpectIntNE(XMEMCMP(plaintext, ciphertext, 32), 0);

    /* Assert: Auth tag is non-zero */
    hasNonZero = 0;
    for (i = 0; i < (int)sizeof(authTag); i++) {
        if (authTag[i] != 0) {
            hasNonZero = 1;
            break;
        }
    }
    ExpectIntEQ(hasNonZero, 1);

    /* Decrypt via wolfCrypt API - should route through CryptoCb */
    ret = wc_AesGcmDecrypt(aes, decrypted, ciphertext, 32,
                           iv, sizeof(iv), authTag, sizeof(authTag),
                           aad, 16);
    ExpectIntEQ(ret, 0);

    /* Assert: Decrypt callback was invoked */
    ExpectIntEQ(cryptoCbAesGcmDecryptCalled, 1);

    /* Assert: Decrypted plaintext matches original */
    ExpectIntEQ(XMEMCMP(plaintext, decrypted, 32), 0);

#ifdef WOLF_CRYPTO_CB_FREE
    /* Free should trigger callback and "delete" key from mock SE */
    cryptoCbAesGcmFreeCalled = 0;
    wc_AesFree(aes);

    /* Verify free callback invoked */
    ExpectIntEQ(cryptoCbAesGcmFreeCalled, 1);

    /* Verify devCtx cleared */
    ExpectPtrEq(aes->devCtx, NULL);

    /* Verify key was "deleted" from mock SE */
    ExpectIntEQ(mockSeKeyOffload.valid, 0);
#else
    wc_AesFree(aes);
#endif

    /* Cleanup */
    wc_CryptoCb_UnRegisterDevice(TEST_CRYPTOCB_AESGCM_OFFLOAD_DEVID);

    /* Verify lifecycle: SetKey -> Encrypt -> Decrypt -> Free */
    ExpectIntEQ(cryptoCbAesGcmSetKeyCalled, 1);
    ExpectIntEQ(cryptoCbAesGcmEncryptCalled, 1);
    ExpectIntEQ(cryptoCbAesGcmDecryptCalled, 1);
#ifdef WOLF_CRYPTO_CB_FREE
    ExpectIntEQ(cryptoCbAesGcmFreeCalled, 1);
#endif

#ifdef WOLFSSL_SMALL_STACK
out:
    XFREE(aes, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(iv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(aad, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(plaintext, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(ciphertext, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(decrypted, NULL, DYNAMIC_TYPE_TMP_BUFFER);
    XFREE(authTag, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif

    return EXPECT_RESULT();
}

#endif /* WOLF_CRYPTO_CB && WOLF_CRYPTO_CB_AES_SETKEY && !NO_AES && HAVE_AESGCM */


/*----------------------------------------------------------------------------*
 | CryptoCB AES-GCM TLS 1.3 Key Zeroing Tests
 *----------------------------------------------------------------------------*/

#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_AES_SETKEY) && \
    !defined(NO_AES) && defined(HAVE_AESGCM) && \
    defined(WOLFSSL_TLS13) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
    !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)

#define TEST_TLS13_ZERO_DEVID  9
#define TEST_TLS13_ZERO_MAX_SLOTS  16

typedef struct {
    byte key[AES_256_KEY_SIZE];
    word32 keySz;
    int valid;
} Tls13ZeroKeySlot;

static Tls13ZeroKeySlot tls13ZeroSlots[TEST_TLS13_ZERO_MAX_SLOTS];
static word32 tls13ZeroSlotCount = 0;

/* Try to reclaim a slot previously invalidated by the FREE path
 * (valid == 0) before expanding the pool.  Without this, a long-running
 * handshake + multiple KeyUpdate cycles can exhaust TEST_TLS13_ZERO_MAX_SLOTS
 * even though most slots have been freed. */
static Tls13ZeroKeySlot* tls13Zero_AllocSlot(void)
{
    word32 i;
    for (i = 0; i < tls13ZeroSlotCount; i++) {
        if (!tls13ZeroSlots[i].valid)
            return &tls13ZeroSlots[i];
    }
    if (tls13ZeroSlotCount >= (word32)TEST_TLS13_ZERO_MAX_SLOTS)
        return NULL;
    return &tls13ZeroSlots[tls13ZeroSlotCount++];
}

static int test_Tls13Zero_CryptoCb(int devId, wc_CryptoInfo* info, void* ctx)
{
    (void)ctx;

    if (devId != TEST_TLS13_ZERO_DEVID)
        return CRYPTOCB_UNAVAILABLE;

    if (info->algo_type == WC_ALGO_TYPE_CIPHER &&
        info->cipher.type == WC_CIPHER_AES &&
        info->cipher.aessetkey.aes != NULL) {

        Aes* aes = info->cipher.aessetkey.aes;
        const byte* key = info->cipher.aessetkey.key;
        word32 keySz = info->cipher.aessetkey.keySz;
        Tls13ZeroKeySlot* slot;

        if (key == NULL || keySz == 0 || keySz > AES_256_KEY_SIZE)
            return BAD_FUNC_ARG;

        slot = tls13Zero_AllocSlot();
        if (slot == NULL)
            return MEMORY_E;

        XMEMCPY(slot->key, key, keySz);
        slot->keySz = keySz;
        slot->valid = 1;
        aes->devCtx = slot;
        return 0;
    }

    if (info->algo_type == WC_ALGO_TYPE_CIPHER &&
        info->cipher.type == WC_CIPHER_AES_GCM &&
        info->cipher.enc) {

        Aes* aes = info->cipher.aesgcm_enc.aes;
        Tls13ZeroKeySlot* slot;
        Aes tempAes;
        int ret;

        if (aes == NULL || aes->devCtx == NULL)
            return BAD_FUNC_ARG;

        slot = (Tls13ZeroKeySlot*)aes->devCtx;
        if (!slot->valid)
            return BAD_STATE_E;

        ret = wc_AesInit(&tempAes, NULL, INVALID_DEVID);
        if (ret != 0) return ret;
        ret = wc_AesGcmSetKey(&tempAes, slot->key, slot->keySz);
        if (ret != 0) { wc_AesFree(&tempAes); return ret; }
        ret = wc_AesGcmEncrypt(&tempAes,
            info->cipher.aesgcm_enc.out,
            info->cipher.aesgcm_enc.in,
            info->cipher.aesgcm_enc.sz,
            info->cipher.aesgcm_enc.iv,
            info->cipher.aesgcm_enc.ivSz,
            info->cipher.aesgcm_enc.authTag,
            info->cipher.aesgcm_enc.authTagSz,
            info->cipher.aesgcm_enc.authIn,
            info->cipher.aesgcm_enc.authInSz);
        wc_AesFree(&tempAes);
        return ret;
    }

    if (info->algo_type == WC_ALGO_TYPE_CIPHER &&
        info->cipher.type == WC_CIPHER_AES_GCM &&
        !info->cipher.enc) {

        Aes* aes = info->cipher.aesgcm_dec.aes;
        Tls13ZeroKeySlot* slot;
        Aes tempAes;
        int ret;

        if (aes == NULL || aes->devCtx == NULL)
            return BAD_FUNC_ARG;

        slot = (Tls13ZeroKeySlot*)aes->devCtx;
        if (!slot->valid)
            return BAD_STATE_E;

        ret = wc_AesInit(&tempAes, NULL, INVALID_DEVID);
        if (ret != 0) return ret;
        ret = wc_AesGcmSetKey(&tempAes, slot->key, slot->keySz);
        if (ret != 0) { wc_AesFree(&tempAes); return ret; }
        ret = wc_AesGcmDecrypt(&tempAes,
            info->cipher.aesgcm_dec.out,
            info->cipher.aesgcm_dec.in,
            info->cipher.aesgcm_dec.sz,
            info->cipher.aesgcm_dec.iv,
            info->cipher.aesgcm_dec.ivSz,
            info->cipher.aesgcm_dec.authTag,
            info->cipher.aesgcm_dec.authTagSz,
            info->cipher.aesgcm_dec.authIn,
            info->cipher.aesgcm_dec.authInSz);
        wc_AesFree(&tempAes);
        return ret;
    }

#ifdef WOLF_CRYPTO_CB_FREE
    if (info->algo_type == WC_ALGO_TYPE_FREE &&
        info->free.algo == WC_ALGO_TYPE_CIPHER &&
        info->free.type == WC_CIPHER_AES) {

        Aes* aes = (Aes*)info->free.obj;
        if (aes != NULL && aes->devCtx != NULL) {
            Tls13ZeroKeySlot* slot = (Tls13ZeroKeySlot*)aes->devCtx;
            ForceZero(slot, sizeof(*slot));
            aes->devCtx = NULL;
        }
        return 0;
    }
#endif

    return CRYPTOCB_UNAVAILABLE;
}

/* Test helper; not constant-time.  Fine for zero-fill assertions in unit
 * tests, NOT for comparing secrets. */
static int isBufferAllZero(const byte* buf, word32 sz)
{
    word32 i;
    for (i = 0; i < sz; i++) {
        if (buf[i] != 0)
            return 0;
    }
    return 1;
}

#endif /* WOLF_CRYPTO_CB && WOLF_CRYPTO_CB_AES_SETKEY && !NO_AES && HAVE_AESGCM
        * && WOLFSSL_TLS13 && HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES
        * && !NO_WOLFSSL_CLIENT && !NO_WOLFSSL_SERVER */

int test_wc_CryptoCb_Tls13_Key_Zero_After_Offload(void)
{
    EXPECT_DECLS;
#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_AES_SETKEY) && \
    !defined(NO_AES) && defined(HAVE_AESGCM) && \
    defined(WOLFSSL_TLS13) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
    !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
    WOLFSSL_CTX* ctx_c = NULL;
    WOLFSSL_CTX* ctx_s = NULL;
    WOLFSSL* ssl_c = NULL;
    WOLFSSL* ssl_s = NULL;
    struct test_memio_ctx test_ctx;
    byte msg[] = "hello";
    byte reply[sizeof(msg)];
    word32 keySz;
    word32 ivSz;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
    XMEMSET(tls13ZeroSlots, 0, sizeof(tls13ZeroSlots));
    tls13ZeroSlotCount = 0;

    ExpectIntEQ(wc_CryptoCb_RegisterDevice(TEST_TLS13_ZERO_DEVID,
                test_Tls13Zero_CryptoCb, NULL), 0);

    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
                wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);

    ExpectIntEQ(wolfSSL_CTX_SetDevId(ctx_c, TEST_TLS13_ZERO_DEVID),
                WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_CTX_SetDevId(ctx_s, TEST_TLS13_ZERO_DEVID),
                WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_SetDevId(ssl_c, TEST_TLS13_ZERO_DEVID),
                WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_SetDevId(ssl_s, TEST_TLS13_ZERO_DEVID),
                WOLFSSL_SUCCESS);

    /* Pin the ciphersuite to AES-GCM.  The zeroing under test is gated on
     * AES offload (devCtx set by our CryptoCB); negotiating ChaCha20 or
     * any non-AES suite leaves encrypt.aes / decrypt.aes unset and turns
     * the test into either a no-op (offload never runs) or a crash when
     * we later dereference ssl_c->encrypt.aes.  Offer both AES-GCM sizes
     * so the pin succeeds regardless of WOLFSSL_AES_128 / WOLFSSL_AES_256
     * build configuration. */
    ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c,
        "TLS13-AES128-GCM-SHA256:TLS13-AES256-GCM-SHA384"), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_set_cipher_list(ssl_s,
        "TLS13-AES128-GCM-SHA256:TLS13-AES256-GCM-SHA384"), WOLFSSL_SUCCESS);

    ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);

    if (ssl_c != NULL && ssl_s != NULL) {
        keySz = ssl_c->specs.key_size;
        ivSz  = ssl_c->specs.iv_size;
        ExpectTrue(keySz > 0);
        ExpectTrue(ivSz  > 0);

        ExpectTrue(isBufferAllZero(ssl_c->keys.client_write_key, keySz));
        ExpectTrue(isBufferAllZero(ssl_c->keys.server_write_key, keySz));
        ExpectTrue(isBufferAllZero(ssl_s->keys.client_write_key, keySz));
        ExpectTrue(isBufferAllZero(ssl_s->keys.server_write_key, keySz));

        /* The static IVs must be preserved: BuildTls13Nonce() reads
         * keys->aead_{enc,dec}_imp_IV on every AEAD record to build the
         * per-record nonce (RFC 8446 Section 5.3).  If a future change
         * starts zeroing these, both peers in this memio test would
         * silently agree on a degenerate all-zero IV and the handshake
         * would still pass, but the resulting wire format is
         * non-interoperable with any unpatched TLS 1.3 peer.  Assert
         * both the source buffers (client/server_write_IV) and the
         * AEAD copies BuildTls13Nonce() actually reads stay populated,
         * so a regression that zeroes either one is caught here. */
        ExpectTrue(!isBufferAllZero(ssl_c->keys.client_write_IV, ivSz));
        ExpectTrue(!isBufferAllZero(ssl_c->keys.server_write_IV, ivSz));
        ExpectTrue(!isBufferAllZero(ssl_s->keys.client_write_IV, ivSz));
        ExpectTrue(!isBufferAllZero(ssl_s->keys.server_write_IV, ivSz));

        ExpectTrue(!isBufferAllZero(ssl_c->keys.aead_enc_imp_IV, ivSz));
        ExpectTrue(!isBufferAllZero(ssl_c->keys.aead_dec_imp_IV, ivSz));
        ExpectTrue(!isBufferAllZero(ssl_s->keys.aead_enc_imp_IV, ivSz));
        ExpectTrue(!isBufferAllZero(ssl_s->keys.aead_dec_imp_IV, ivSz));

        /* Guard the Aes pointer dereferences: even though the Expect*
         * macros short-circuit after a prior failure via EXPECT_SUCCESS(),
         * a handshake that succeeded but negotiated a non-AES suite
         * would leave these NULL while _ret is still TEST_SUCCESS. */
        ExpectNotNull(ssl_c->encrypt.aes);
        ExpectNotNull(ssl_c->decrypt.aes);
        ExpectNotNull(ssl_s->encrypt.aes);
        ExpectNotNull(ssl_s->decrypt.aes);
        if (ssl_c->encrypt.aes && ssl_c->decrypt.aes &&
            ssl_s->encrypt.aes && ssl_s->decrypt.aes) {
            ExpectPtrNE(ssl_c->encrypt.aes->devCtx, NULL);
            ExpectPtrNE(ssl_c->decrypt.aes->devCtx, NULL);
            ExpectPtrNE(ssl_s->encrypt.aes->devCtx, NULL);
            ExpectPtrNE(ssl_s->decrypt.aes->devCtx, NULL);
        }

        ExpectIntEQ(wolfSSL_write(ssl_c, msg, sizeof(msg)),
                    (int)sizeof(msg));
        ExpectIntEQ(wolfSSL_read(ssl_s, reply, sizeof(reply)),
                    (int)sizeof(msg));
        ExpectIntEQ(XMEMCMP(msg, reply, sizeof(msg)), 0);

        ExpectIntEQ(wolfSSL_write(ssl_s, msg, sizeof(msg)),
                    (int)sizeof(msg));
        ExpectIntEQ(wolfSSL_read(ssl_c, reply, sizeof(reply)),
                    (int)sizeof(msg));
        ExpectIntEQ(XMEMCMP(msg, reply, sizeof(msg)), 0);

        /* Force a KeyUpdate so SetKeysSide runs again with a fresh
         * offload and we can re-check that the staging buffers remain
         * zeroed.  wolfSSL_update_keys is always available when
         * WOLFSSL_TLS13 is defined, which is part of the test gate. */
        ExpectIntEQ(wolfSSL_update_keys(ssl_c), WOLFSSL_SUCCESS);

        ExpectIntEQ(wolfSSL_write(ssl_c, msg, sizeof(msg)),
                    (int)sizeof(msg));
        ExpectIntEQ(wolfSSL_read(ssl_s, reply, sizeof(reply)),
                    (int)sizeof(msg));
        ExpectIntEQ(XMEMCMP(msg, reply, sizeof(msg)), 0);

        ExpectIntEQ(wolfSSL_write(ssl_s, msg, sizeof(msg)),
                    (int)sizeof(msg));
        ExpectIntEQ(wolfSSL_read(ssl_c, reply, sizeof(reply)),
                    (int)sizeof(msg));
        ExpectIntEQ(XMEMCMP(msg, reply, sizeof(msg)), 0);

        keySz = ssl_c->specs.key_size;
        ivSz  = ssl_c->specs.iv_size;
        ExpectTrue(isBufferAllZero(ssl_c->keys.client_write_key, keySz));
        ExpectTrue(isBufferAllZero(ssl_c->keys.server_write_key, keySz));
        ExpectTrue(isBufferAllZero(ssl_s->keys.client_write_key, keySz));
        ExpectTrue(isBufferAllZero(ssl_s->keys.server_write_key, keySz));

        /* Same invariant as the post-handshake block above: the static
         * IVs (both the source *_write_IV buffers and the AEAD copies
         * BuildTls13Nonce() actually reads) are required on every
         * record and must survive SetKeysSide after KeyUpdate. */
        ExpectTrue(!isBufferAllZero(ssl_c->keys.client_write_IV, ivSz));
        ExpectTrue(!isBufferAllZero(ssl_c->keys.server_write_IV, ivSz));
        ExpectTrue(!isBufferAllZero(ssl_s->keys.client_write_IV, ivSz));
        ExpectTrue(!isBufferAllZero(ssl_s->keys.server_write_IV, ivSz));

        ExpectTrue(!isBufferAllZero(ssl_c->keys.aead_enc_imp_IV, ivSz));
        ExpectTrue(!isBufferAllZero(ssl_c->keys.aead_dec_imp_IV, ivSz));
        ExpectTrue(!isBufferAllZero(ssl_s->keys.aead_enc_imp_IV, ivSz));
        ExpectTrue(!isBufferAllZero(ssl_s->keys.aead_dec_imp_IV, ivSz));
    }

    wolfSSL_free(ssl_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_CTX_free(ctx_s);
    wc_CryptoCb_UnRegisterDevice(TEST_TLS13_ZERO_DEVID);
#endif
    return EXPECT_RESULT();
}

int test_wc_CryptoCb_Tls13_Key_No_Zero_Without_Offload(void)
{
    EXPECT_DECLS;
#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_AES_SETKEY) && \
    !defined(NO_AES) && defined(HAVE_AESGCM) && \
    defined(WOLFSSL_TLS13) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
    !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
    WOLFSSL_CTX* ctx_c = NULL;
    WOLFSSL_CTX* ctx_s = NULL;
    WOLFSSL* ssl_c = NULL;
    WOLFSSL* ssl_s = NULL;
    struct test_memio_ctx test_ctx;
    word32 keySz;
    word32 ivSz;

    XMEMSET(&test_ctx, 0, sizeof(test_ctx));

    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
                wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);

    /* Pin the ciphersuite for the same reason as the offload test: so the
     * regression assertions below reference the same buffers the offload
     * test expects to see zeroed (or not zeroed, here).  See the companion
     * comment in test_wc_CryptoCb_Tls13_Key_Zero_After_Offload. */
    ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c,
        "TLS13-AES128-GCM-SHA256:TLS13-AES256-GCM-SHA384"), WOLFSSL_SUCCESS);
    ExpectIntEQ(wolfSSL_set_cipher_list(ssl_s,
        "TLS13-AES128-GCM-SHA256:TLS13-AES256-GCM-SHA384"), WOLFSSL_SUCCESS);

    ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);

    if (ssl_c != NULL && ssl_s != NULL) {
        keySz = ssl_c->specs.key_size;
        ivSz = ssl_c->specs.iv_size;
        ExpectTrue(keySz > 0);
        ExpectTrue(ivSz > 0);

        /* Check each buffer independently.  AND-combining these would
         * mask the case where one buffer was never populated, which
         * would produce a confusing "regression, keys were zeroed"
         * failure when the real issue is upstream. */
        ExpectTrue(!isBufferAllZero(ssl_c->keys.client_write_key, keySz));
        ExpectTrue(!isBufferAllZero(ssl_c->keys.server_write_key, keySz));
        ExpectTrue(!isBufferAllZero(ssl_s->keys.client_write_key, keySz));
        ExpectTrue(!isBufferAllZero(ssl_s->keys.server_write_key, keySz));

        ExpectTrue(!isBufferAllZero(ssl_c->keys.client_write_IV, ivSz));
        ExpectTrue(!isBufferAllZero(ssl_c->keys.server_write_IV, ivSz));
        ExpectTrue(!isBufferAllZero(ssl_s->keys.client_write_IV, ivSz));
        ExpectTrue(!isBufferAllZero(ssl_s->keys.server_write_IV, ivSz));
    }

    wolfSSL_free(ssl_c);
    wolfSSL_free(ssl_s);
    wolfSSL_CTX_free(ctx_c);
    wolfSSL_CTX_free(ctx_s);
#endif
    return EXPECT_RESULT();
}


/*******************************************************************************
 * Monte Carlo tests for AES modes
 ******************************************************************************/

#define MC_CIPHER_TEST_COUNT 100
#define MC_AES_MAX_DATA_SZ   1024

/* Monte Carlo test for AES-CBC: random key, IV, and plaintext each iteration */
int test_wc_AesCbc_MonteCarlo(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(HAVE_AES_DECRYPT)
    static const word32 keySizes[] = {
#ifdef WOLFSSL_AES_128
        16,
#endif
#ifdef WOLFSSL_AES_192
        24,
#endif
#ifdef WOLFSSL_AES_256
        32,
#endif
    };
    int numKeySizes = (int)(sizeof(keySizes) / sizeof(keySizes[0]));
    Aes enc, dec;
    WC_RNG rng;
    byte key[AES_256_KEY_SIZE];
    byte iv[WC_AES_BLOCK_SIZE];
    word32 plainLen = 0, keyLen;
    int i;
    WC_DECLARE_VAR(plain,     byte, MC_AES_MAX_DATA_SZ, NULL);
    WC_DECLARE_VAR(cipher,    byte, MC_AES_MAX_DATA_SZ, NULL);
    WC_DECLARE_VAR(decrypted, byte, MC_AES_MAX_DATA_SZ, NULL);

    WC_ALLOC_VAR(plain,     byte, MC_AES_MAX_DATA_SZ, NULL);
    WC_ALLOC_VAR(cipher,    byte, MC_AES_MAX_DATA_SZ, NULL);
    WC_ALLOC_VAR(decrypted, byte, MC_AES_MAX_DATA_SZ, NULL);
#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC
    ExpectNotNull(plain);
    ExpectNotNull(cipher);
    ExpectNotNull(decrypted);
#endif

    XMEMSET(&enc, 0, sizeof(enc));
    XMEMSET(&dec, 0, sizeof(dec));
    XMEMSET(&rng, 0, sizeof(rng));

    ExpectIntEQ(wc_AesInit(&enc, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesInit(&dec, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_InitRng(&rng), 0);

    for (i = 0; i < MC_CIPHER_TEST_COUNT && EXPECT_SUCCESS(); i++) {
        keyLen = keySizes[i % numKeySizes];
        ExpectIntEQ(wc_RNG_GenerateBlock(&rng, key, keyLen), 0);
        ExpectIntEQ(wc_RNG_GenerateBlock(&rng, iv, sizeof(iv)), 0);
        ExpectIntEQ(wc_RNG_GenerateBlock(&rng, (byte*)&plainLen,
            sizeof(plainLen)), 0);
        /* Length 1..1024, rounded up to AES block size */
        plainLen = (plainLen % MC_AES_MAX_DATA_SZ) + 1;
        plainLen = (plainLen + WC_AES_BLOCK_SIZE - 1) &
                   ~((word32)WC_AES_BLOCK_SIZE - 1);
        ExpectIntEQ(wc_RNG_GenerateBlock(&rng, plain, plainLen), 0);

        ExpectIntEQ(wc_AesSetKey(&enc, key, keyLen, iv, AES_ENCRYPTION), 0);
        ExpectIntEQ(wc_AesCbcEncrypt(&enc, cipher, plain, plainLen), 0);
        ExpectIntEQ(wc_AesSetKey(&dec, key, keyLen, iv, AES_DECRYPTION), 0);
        ExpectIntEQ(wc_AesCbcDecrypt(&dec, decrypted, cipher, plainLen), 0);
        ExpectBufEQ(decrypted, plain, plainLen);
    }

    wc_AesFree(&enc);
    wc_AesFree(&dec);
    wc_FreeRng(&rng);
    WC_FREE_VAR(plain,     NULL);
    WC_FREE_VAR(cipher,    NULL);
    WC_FREE_VAR(decrypted, NULL);
#endif
    return EXPECT_RESULT();
}

/* Monte Carlo test for AES-CTR: random key, IV, and plaintext each iteration */
int test_wc_AesCtr_MonteCarlo(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(WOLFSSL_AES_COUNTER)
    static const word32 keySizes[] = {
#ifdef WOLFSSL_AES_128
        16,
#endif
#ifdef WOLFSSL_AES_192
        24,
#endif
#ifdef WOLFSSL_AES_256
        32,
#endif
    };
    int numKeySizes = (int)(sizeof(keySizes) / sizeof(keySizes[0]));
    Aes enc, dec;
    WC_RNG rng;
    byte key[AES_256_KEY_SIZE];
    byte iv[WC_AES_BLOCK_SIZE];
    word32 plainLen = 0, keyLen;
    int i;
    WC_DECLARE_VAR(plain,     byte, MC_AES_MAX_DATA_SZ, NULL);
    WC_DECLARE_VAR(cipher,    byte, MC_AES_MAX_DATA_SZ, NULL);
    WC_DECLARE_VAR(decrypted, byte, MC_AES_MAX_DATA_SZ, NULL);

    WC_ALLOC_VAR(plain,     byte, MC_AES_MAX_DATA_SZ, NULL);
    WC_ALLOC_VAR(cipher,    byte, MC_AES_MAX_DATA_SZ, NULL);
    WC_ALLOC_VAR(decrypted, byte, MC_AES_MAX_DATA_SZ, NULL);
#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC
    ExpectNotNull(plain);
    ExpectNotNull(cipher);
    ExpectNotNull(decrypted);
#endif

    XMEMSET(&enc, 0, sizeof(enc));
    XMEMSET(&dec, 0, sizeof(dec));
    XMEMSET(&rng, 0, sizeof(rng));

    ExpectIntEQ(wc_AesInit(&enc, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesInit(&dec, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_InitRng(&rng), 0);

    for (i = 0; i < MC_CIPHER_TEST_COUNT && EXPECT_SUCCESS(); i++) {
        keyLen = keySizes[i % numKeySizes];
        ExpectIntEQ(wc_RNG_GenerateBlock(&rng, key, keyLen), 0);
        ExpectIntEQ(wc_RNG_GenerateBlock(&rng, iv, sizeof(iv)), 0);
        ExpectIntEQ(wc_RNG_GenerateBlock(&rng, (byte*)&plainLen,
            sizeof(plainLen)), 0);
        plainLen = (plainLen % MC_AES_MAX_DATA_SZ) + 1;
        ExpectIntEQ(wc_RNG_GenerateBlock(&rng, plain, plainLen), 0);

        /* CTR mode: decrypt is the same operation as encrypt */
        ExpectIntEQ(wc_AesSetKey(&enc, key, keyLen, iv, AES_ENCRYPTION), 0);
        ExpectIntEQ(wc_AesCtrEncrypt(&enc, cipher, plain, plainLen), 0);
        ExpectIntEQ(wc_AesSetKey(&dec, key, keyLen, iv, AES_ENCRYPTION), 0);
        ExpectIntEQ(wc_AesCtrEncrypt(&dec, decrypted, cipher, plainLen), 0);
        ExpectBufEQ(decrypted, plain, plainLen);
    }

    wc_AesFree(&enc);
    wc_AesFree(&dec);
    wc_FreeRng(&rng);
    WC_FREE_VAR(plain,     NULL);
    WC_FREE_VAR(cipher,    NULL);
    WC_FREE_VAR(decrypted, NULL);
#endif
    return EXPECT_RESULT();
}

/* Monte Carlo test for AES-GCM: random key, nonce, and plaintext each
 * iteration */
int test_wc_AesGcm_MonteCarlo(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(HAVE_AESGCM) && defined(HAVE_AES_DECRYPT) && \
    !defined(WOLFSSL_AFALG) && !defined(WOLFSSL_DEVCRYPTO)
    static const word32 keySizes[] = {
#ifdef WOLFSSL_AES_128
        16,
#endif
#ifdef WOLFSSL_AES_192
        24,
#endif
#ifdef WOLFSSL_AES_256
        32,
#endif
    };
    int numKeySizes = (int)(sizeof(keySizes) / sizeof(keySizes[0]));
    Aes aes;
    WC_RNG rng;
    byte key[AES_256_KEY_SIZE];
    byte nonce[GCM_NONCE_MID_SZ];
    byte tag[WC_AES_BLOCK_SIZE];
    word32 plainLen = 0, keyLen;
    int i;
    WC_DECLARE_VAR(plain,     byte, MC_AES_MAX_DATA_SZ, NULL);
    WC_DECLARE_VAR(cipher,    byte, MC_AES_MAX_DATA_SZ, NULL);
    WC_DECLARE_VAR(decrypted, byte, MC_AES_MAX_DATA_SZ, NULL);

    WC_ALLOC_VAR(plain,     byte, MC_AES_MAX_DATA_SZ, NULL);
    WC_ALLOC_VAR(cipher,    byte, MC_AES_MAX_DATA_SZ, NULL);
    WC_ALLOC_VAR(decrypted, byte, MC_AES_MAX_DATA_SZ, NULL);
#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC
    ExpectNotNull(plain);
    ExpectNotNull(cipher);
    ExpectNotNull(decrypted);
#endif

    XMEMSET(&aes, 0, sizeof(aes));
    XMEMSET(&rng, 0, sizeof(rng));

    ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_InitRng(&rng), 0);

    for (i = 0; i < MC_CIPHER_TEST_COUNT && EXPECT_SUCCESS(); i++) {
        keyLen = keySizes[i % numKeySizes];
        ExpectIntEQ(wc_RNG_GenerateBlock(&rng, key, keyLen), 0);
        ExpectIntEQ(wc_RNG_GenerateBlock(&rng, nonce, sizeof(nonce)), 0);
        ExpectIntEQ(wc_RNG_GenerateBlock(&rng, (byte*)&plainLen,
            sizeof(plainLen)), 0);
        plainLen = (plainLen % MC_AES_MAX_DATA_SZ) + 1;
        ExpectIntEQ(wc_RNG_GenerateBlock(&rng, plain, plainLen), 0);

        ExpectIntEQ(wc_AesGcmSetKey(&aes, key, keyLen), 0);
        ExpectIntEQ(wc_AesGcmEncrypt(&aes, cipher, plain, plainLen,
            nonce, sizeof(nonce), tag, sizeof(tag), NULL, 0), 0);
        ExpectIntEQ(wc_AesGcmDecrypt(&aes, decrypted, cipher, plainLen,
            nonce, sizeof(nonce), tag, sizeof(tag), NULL, 0), 0);
        ExpectBufEQ(decrypted, plain, plainLen);
    }

    wc_AesFree(&aes);
    wc_FreeRng(&rng);
    WC_FREE_VAR(plain,     NULL);
    WC_FREE_VAR(cipher,    NULL);
    WC_FREE_VAR(decrypted, NULL);
#endif /* !NO_AES && HAVE_AESGCM && HAVE_AES_DECRYPT && !WOLFSSL_AFALG && */
       /* !WOLFSSL_DEVCRYPTO                                              */

    return EXPECT_RESULT();
}

/* Monte Carlo test for AES-CCM: random key, nonce, and plaintext each
 * iteration */
int test_wc_AesCcm_MonteCarlo(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(HAVE_AESCCM) && defined(HAVE_AES_DECRYPT)
    static const word32 keySizes[] = {
#ifdef WOLFSSL_AES_128
        16,
#endif
#ifdef WOLFSSL_AES_192
        24,
#endif
#ifdef WOLFSSL_AES_256
        32,
#endif
    };
    int numKeySizes = (int)(sizeof(keySizes) / sizeof(keySizes[0]));
    Aes aes;
    WC_RNG rng;
    byte key[AES_256_KEY_SIZE];
    byte nonce[CCM_NONCE_MAX_SZ];
    byte tag[WC_AES_BLOCK_SIZE];
    word32 plainLen = 0, keyLen;
    int i;
    WC_DECLARE_VAR(plain,     byte, MC_AES_MAX_DATA_SZ, NULL);
    WC_DECLARE_VAR(cipher,    byte, MC_AES_MAX_DATA_SZ, NULL);
    WC_DECLARE_VAR(decrypted, byte, MC_AES_MAX_DATA_SZ, NULL);

    WC_ALLOC_VAR(plain,     byte, MC_AES_MAX_DATA_SZ, NULL);
    WC_ALLOC_VAR(cipher,    byte, MC_AES_MAX_DATA_SZ, NULL);
    WC_ALLOC_VAR(decrypted, byte, MC_AES_MAX_DATA_SZ, NULL);
#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC
    ExpectNotNull(plain);
    ExpectNotNull(cipher);
    ExpectNotNull(decrypted);
#endif

    XMEMSET(&aes, 0, sizeof(aes));
    XMEMSET(&rng, 0, sizeof(rng));

    ExpectIntEQ(wc_AesInit(&aes, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_InitRng(&rng), 0);

    for (i = 0; i < MC_CIPHER_TEST_COUNT && EXPECT_SUCCESS(); i++) {
        keyLen = keySizes[i % numKeySizes];
        ExpectIntEQ(wc_RNG_GenerateBlock(&rng, key, keyLen), 0);
        ExpectIntEQ(wc_RNG_GenerateBlock(&rng, nonce, sizeof(nonce)), 0);
        ExpectIntEQ(wc_RNG_GenerateBlock(&rng, (byte*)&plainLen,
            sizeof(plainLen)), 0);
        plainLen = (plainLen % MC_AES_MAX_DATA_SZ) + 1;
        ExpectIntEQ(wc_RNG_GenerateBlock(&rng, plain, plainLen), 0);

        ExpectIntEQ(wc_AesCcmSetKey(&aes, key, keyLen), 0);
        ExpectIntEQ(wc_AesCcmEncrypt(&aes, cipher, plain, plainLen,
            nonce, sizeof(nonce), tag, sizeof(tag), NULL, 0), 0);
        ExpectIntEQ(wc_AesCcmDecrypt(&aes, decrypted, cipher, plainLen,
            nonce, sizeof(nonce), tag, sizeof(tag), NULL, 0), 0);
        ExpectBufEQ(decrypted, plain, plainLen);
    }

    wc_AesFree(&aes);
    wc_FreeRng(&rng);
    WC_FREE_VAR(plain,     NULL);
    WC_FREE_VAR(cipher,    NULL);
    WC_FREE_VAR(decrypted, NULL);
#endif
    return EXPECT_RESULT();
}

/* Monte Carlo test for AES-CFB: random key, IV, and plaintext each
 * iteration */
int test_wc_AesCfb_MonteCarlo(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(WOLFSSL_AES_CFB) && defined(HAVE_AES_DECRYPT)
    static const word32 keySizes[] = {
#ifdef WOLFSSL_AES_128
        16,
#endif
#ifdef WOLFSSL_AES_192
        24,
#endif
#ifdef WOLFSSL_AES_256
        32,
#endif
    };
    int numKeySizes = (int)(sizeof(keySizes) / sizeof(keySizes[0]));
    Aes enc, dec;
    WC_RNG rng;
    byte key[AES_256_KEY_SIZE];
    byte iv[WC_AES_BLOCK_SIZE];
    word32 plainLen = 0, keyLen;
    int i;
    WC_DECLARE_VAR(plain,     byte, MC_AES_MAX_DATA_SZ, NULL);
    WC_DECLARE_VAR(cipher,    byte, MC_AES_MAX_DATA_SZ, NULL);
    WC_DECLARE_VAR(decrypted, byte, MC_AES_MAX_DATA_SZ, NULL);

    WC_ALLOC_VAR(plain,     byte, MC_AES_MAX_DATA_SZ, NULL);
    WC_ALLOC_VAR(cipher,    byte, MC_AES_MAX_DATA_SZ, NULL);
    WC_ALLOC_VAR(decrypted, byte, MC_AES_MAX_DATA_SZ, NULL);
#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC
    ExpectNotNull(plain);
    ExpectNotNull(cipher);
    ExpectNotNull(decrypted);
#endif

    XMEMSET(&enc, 0, sizeof(enc));
    XMEMSET(&dec, 0, sizeof(dec));
    XMEMSET(&rng, 0, sizeof(rng));

    ExpectIntEQ(wc_AesInit(&enc, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesInit(&dec, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_InitRng(&rng), 0);

    for (i = 0; i < MC_CIPHER_TEST_COUNT && EXPECT_SUCCESS(); i++) {
        keyLen = keySizes[i % numKeySizes];
        ExpectIntEQ(wc_RNG_GenerateBlock(&rng, key, keyLen), 0);
        ExpectIntEQ(wc_RNG_GenerateBlock(&rng, iv, sizeof(iv)), 0);
        ExpectIntEQ(wc_RNG_GenerateBlock(&rng, (byte*)&plainLen,
            sizeof(plainLen)), 0);
        plainLen = (plainLen % MC_AES_MAX_DATA_SZ) + 1;
        ExpectIntEQ(wc_RNG_GenerateBlock(&rng, plain, plainLen), 0);

        ExpectIntEQ(wc_AesSetKey(&enc, key, keyLen, NULL, AES_ENCRYPTION), 0);
        ExpectIntEQ(wc_AesSetIV(&enc, iv), 0);
        ExpectIntEQ(wc_AesCfbEncrypt(&enc, cipher, plain, plainLen), 0);
        ExpectIntEQ(wc_AesSetKey(&dec, key, keyLen, NULL, AES_ENCRYPTION), 0);
        ExpectIntEQ(wc_AesSetIV(&dec, iv), 0);
        ExpectIntEQ(wc_AesCfbDecrypt(&dec, decrypted, cipher, plainLen), 0);
        if (XMEMCMP(decrypted, plain, plainLen) != 0) {
            PRINT_DATA("Key", key, keyLen);
            PRINT_DATA("IV", iv, sizeof(iv));
            PRINT_DATA("Plain", plain, plainLen);
            PRINT_DATA("Decrypted", decrypted, plainLen);
        }
        ExpectBufEQ(decrypted, plain, plainLen);
    }

    wc_AesFree(&enc);
    wc_AesFree(&dec);
    wc_FreeRng(&rng);
    WC_FREE_VAR(plain,     NULL);
    WC_FREE_VAR(cipher,    NULL);
    WC_FREE_VAR(decrypted, NULL);
#endif
    return EXPECT_RESULT();
}

/* Monte Carlo test for AES-OFB: random key, IV, and plaintext each
 * iteration */
int test_wc_AesOfb_MonteCarlo(void)
{
    EXPECT_DECLS;
#if !defined(NO_AES) && defined(WOLFSSL_AES_OFB) && defined(HAVE_AES_DECRYPT)
    static const word32 keySizes[] = {
#ifdef WOLFSSL_AES_128
        16,
#endif
#ifdef WOLFSSL_AES_192
        24,
#endif
#ifdef WOLFSSL_AES_256
        32,
#endif
    };
    int numKeySizes = (int)(sizeof(keySizes) / sizeof(keySizes[0]));
    Aes enc, dec;
    WC_RNG rng;
    byte key[AES_256_KEY_SIZE];
    byte iv[WC_AES_BLOCK_SIZE];
    word32 plainLen = 0, keyLen;
    int i;
    WC_DECLARE_VAR(plain,     byte, MC_AES_MAX_DATA_SZ, NULL);
    WC_DECLARE_VAR(cipher,    byte, MC_AES_MAX_DATA_SZ, NULL);
    WC_DECLARE_VAR(decrypted, byte, MC_AES_MAX_DATA_SZ, NULL);

    WC_ALLOC_VAR(plain,     byte, MC_AES_MAX_DATA_SZ, NULL);
    WC_ALLOC_VAR(cipher,    byte, MC_AES_MAX_DATA_SZ, NULL);
    WC_ALLOC_VAR(decrypted, byte, MC_AES_MAX_DATA_SZ, NULL);
#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC
    ExpectNotNull(plain);
    ExpectNotNull(cipher);
    ExpectNotNull(decrypted);
#endif

    XMEMSET(&enc, 0, sizeof(enc));
    XMEMSET(&dec, 0, sizeof(dec));
    XMEMSET(&rng, 0, sizeof(rng));

    ExpectIntEQ(wc_AesInit(&enc, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_AesInit(&dec, NULL, INVALID_DEVID), 0);
    ExpectIntEQ(wc_InitRng(&rng), 0);

    for (i = 0; i < MC_CIPHER_TEST_COUNT && EXPECT_SUCCESS(); i++) {
        keyLen = keySizes[i % numKeySizes];
        ExpectIntEQ(wc_RNG_GenerateBlock(&rng, key, keyLen), 0);
        ExpectIntEQ(wc_RNG_GenerateBlock(&rng, iv, sizeof(iv)), 0);
        ExpectIntEQ(wc_RNG_GenerateBlock(&rng, (byte*)&plainLen,
            sizeof(plainLen)), 0);
        plainLen = (plainLen % MC_AES_MAX_DATA_SZ) + 1;
        ExpectIntEQ(wc_RNG_GenerateBlock(&rng, plain, plainLen), 0);

        ExpectIntEQ(wc_AesSetKey(&enc, key, keyLen, NULL, AES_ENCRYPTION), 0);
        ExpectIntEQ(wc_AesSetIV(&enc, iv), 0);
        ExpectIntEQ(wc_AesOfbEncrypt(&enc, cipher, plain, plainLen), 0);
        ExpectIntEQ(wc_AesSetKey(&dec, key, keyLen, NULL, AES_ENCRYPTION), 0);
        ExpectIntEQ(wc_AesSetIV(&dec, iv), 0);
        ExpectIntEQ(wc_AesOfbDecrypt(&dec, decrypted, cipher, plainLen), 0);
        if (XMEMCMP(decrypted, plain, plainLen) != 0) {
            PRINT_DATA("Key", key, keyLen);
            PRINT_DATA("IV", iv, sizeof(iv));
            PRINT_DATA("Plain", plain, plainLen);
            PRINT_DATA("Decrypted", decrypted, plainLen);
        }
        ExpectBufEQ(decrypted, plain, plainLen);
    }

    wc_AesFree(&enc);
    wc_AesFree(&dec);
    wc_FreeRng(&rng);
    WC_FREE_VAR(plain,     NULL);
    WC_FREE_VAR(cipher,    NULL);
    WC_FREE_VAR(decrypted, NULL);
#endif
    return EXPECT_RESULT();
}
