/**
 * \file
 * \brief Unity tests for the cryptoauthlib AES GCM functions.
 *
 * \copyright (c) 2015-2020 Microchip Technology Inc. and its subsidiaries.
 *
 * \page License
 *
 * Subject to your compliance with these terms, you may use Microchip software
 * and any derivatives exclusively with Microchip products. It is your
 * responsibility to comply with third party license terms applicable to your
 * use of third party software (including open source software) that may
 * accompany Microchip software.
 *
 * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
 * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED
 * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A
 * PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT,
 * SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE
 * OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF
 * MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE
 * FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL
 * LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED
 * THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR
 * THIS SOFTWARE.
 */
#include <stdlib.h>
#ifdef _WIN32
#include <time.h>
#endif
#include "atca_test.h"
#include "basic/atca_basic.h"
#include "basic/atca_basic_aes_gcm.h"
#include "host/atca_host.h"
#include "test/atca_tests.h"

#define GCM_TEST_VECTORS_DATA_SIZE_MAX      100
typedef struct
{
    const char* vector_name;
    uint8_t     key[32];
    size_t      iv_size;
    uint8_t     iv[GCM_TEST_VECTORS_DATA_SIZE_MAX];
    uint32_t    text_size;
    uint8_t     plaintext[GCM_TEST_VECTORS_DATA_SIZE_MAX];
    uint8_t     ciphertext[GCM_TEST_VECTORS_DATA_SIZE_MAX];
    uint32_t    aad_size;
    uint8_t     aad[GCM_TEST_VECTORS_DATA_SIZE_MAX];
    uint8_t     tag[AES_DATA_SIZE];
}aes_gcm_test_vectors;

// *INDENT-OFF* - Preserve formatting
const aes_gcm_test_vectors gcm_test_cases[] =
{
    //http://luca-giuzzi.unibs.it/corsi/Support/papers-cryptography/gcm-spec.pdf
    {
        "Test case 1",
        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
        12,
        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
        0,
        { 0 },
        { 0 },
        0,
        { 0 },
        { 0x58, 0xe2, 0xfc, 0xce, 0xfa, 0x7e, 0x30, 0x61, 0x36, 0x7f, 0x1d, 0x57, 0xa4, 0xe7, 0x45, 0x5a }
    },
    {
        "Test case 2",
        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
        12,
        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
        16,
        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
        { 0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92, 0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2, 0xfe, 0x78 },
        0,
        { 0 },
        { 0xab, 0x6e, 0x47, 0xd4, 0x2c, 0xec, 0x13, 0xbd, 0xf5, 0x3a, 0x67, 0xb2, 0x12, 0x57, 0xbd, 0xdf }
    },
    {
        "Test case 3",
        { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 },
        12,
        { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88 },
        64,
        { 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, 0x1a, 0xaf, 0xd2, 0x55 },
        { 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c,
          0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e,
          0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05,
          0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, 0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85 },
        0,
        { 0 },
        { 0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6, 0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6, 0xfa, 0xb4 }
    },
    {
        "Test case 4",
        { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 },
        12,
        { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88 },
        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 },
        { 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c,
          0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e,
          0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05,
          0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, 0x3d, 0x58, 0xe0, 0x91 },
        20,
        { 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
          0xab, 0xad, 0xda, 0xd2 },
        { 0x5b, 0xc9, 0x4f, 0xbc, 0x32, 0x21, 0xa5, 0xdb, 0x94, 0xfa, 0xe9, 0x5a, 0xe7, 0x12, 0x1a, 0x47 }
    },
    {
        "Test case 5",
        { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 },
        8,
        { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad },
        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 },
        { 0x61, 0x35, 0x3b, 0x4c, 0x28, 0x06, 0x93, 0x4a, 0x77, 0x7f, 0xf5, 0x1f, 0xa2, 0x2a, 0x47, 0x55,
          0x69, 0x9b, 0x2a, 0x71, 0x4f, 0xcd, 0xc6, 0xf8, 0x37, 0x66, 0xe5, 0xf9, 0x7b, 0x6c, 0x74, 0x23,
          0x73, 0x80, 0x69, 0x00, 0xe4, 0x9f, 0x24, 0xb2, 0x2b, 0x09, 0x75, 0x44, 0xd4, 0x89, 0x6b, 0x42,
          0x49, 0x89, 0xb5, 0xe1, 0xeb, 0xac, 0x0f, 0x07, 0xc2, 0x3f, 0x45, 0x98 },
        20,
        { 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
          0xab, 0xad, 0xda, 0xd2 },
        { 0x36, 0x12, 0xd2, 0xe7, 0x9e, 0x3b, 0x07, 0x85, 0x56, 0x1b, 0xe1, 0x4a, 0xac, 0xa2, 0xfc, 0xcb }
    },
    {
        "Test case 6",
        { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 },
        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 },
        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 },
        { 0x8c, 0xe2, 0x49, 0x98, 0x62, 0x56, 0x15, 0xb6, 0x03, 0xa0, 0x33, 0xac, 0xa1, 0x3f, 0xb8, 0x94,
          0xbe, 0x91, 0x12, 0xa5, 0xc3, 0xa2, 0x11, 0xa8, 0xba, 0x26, 0x2a, 0x3c, 0xca, 0x7e, 0x2c, 0xa7,
          0x01, 0xe4, 0xa9, 0xa4, 0xfb, 0xa4, 0x3c, 0x90, 0xcc, 0xdc, 0xb2, 0x81, 0xd4, 0x8c, 0x7c, 0x6f,
          0xd6, 0x28, 0x75, 0xd2, 0xac, 0xa4, 0x17, 0x03, 0x4c, 0x34, 0xae, 0xe5 },
        20,
        { 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
          0xab, 0xad, 0xda, 0xd2 },
        { 0x61, 0x9c, 0xc5, 0xae, 0xff, 0xfe, 0x0b, 0xfa, 0x46, 0x2a, 0xf4, 0x3c, 0x16, 0x99, 0xd0, 0x50 }
    },
    //http://www.ieee802.org/1/files/public/docs2011/bn-randall-test-vectors-0511-v1.pdf
    {
        "2.1.1 54-byte Packet",
        { 0xAD, 0x7A, 0x2B, 0xD0, 0x3E, 0xAC, 0x83, 0x5A, 0x6F, 0x62, 0x0F, 0xDC, 0xB5, 0x06, 0xB3, 0x45 },
        12,
        { 0x12, 0x15, 0x35, 0x24, 0xC0, 0x89, 0x5E, 0x81, 0xB2, 0xC2, 0x84, 0x65 },
        0,
        { 0 },
        { 0 },
        70,
        { 0xD6, 0x09, 0xB1, 0xF0, 0x56, 0x63, 0x7A, 0x0D, 0x46, 0xDF, 0x99, 0x8D, 0x88, 0xE5, 0x22, 0x2A,
          0xB2, 0xC2, 0x84, 0x65, 0x12, 0x15, 0x35, 0x24, 0xC0, 0x89, 0x5E, 0x81, 0x08, 0x00, 0x0F, 0x10,
          0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
          0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
          0x31, 0x32, 0x33, 0x34, 0x00, 0x01 },
        { 0xF0, 0x94, 0x78, 0xA9, 0xB0, 0x90, 0x07, 0xD0, 0x6F, 0x46, 0xE9, 0xB6, 0xA1, 0xDA, 0x25, 0xDD }
    },
    {
        "2.2.1 60-byte Packet",
        { 0xAD, 0x7A, 0x2B, 0xD0, 0x3E, 0xAC, 0x83, 0x5A, 0x6F, 0x62, 0x0F, 0xDC, 0xB5, 0x06, 0xB3, 0x45 },
        12,
        { 0x12, 0x15, 0x35, 0x24, 0xC0, 0x89, 0x5E, 0x81, 0xB2, 0xC2, 0x84, 0x65 },
        48,
        { 0x08, 0x00, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C,
          0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C,
          0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x00, 0x02 },
        { 0x70, 0x1A, 0xFA, 0x1C, 0xC0, 0x39, 0xC0, 0xD7, 0x65, 0x12, 0x8A, 0x66, 0x5D, 0xAB, 0x69, 0x24,
          0x38, 0x99, 0xBF, 0x73, 0x18, 0xCC, 0xDC, 0x81, 0xC9, 0x93, 0x1D, 0xA1, 0x7F, 0xBE, 0x8E, 0xDD,
          0x7D, 0x17, 0xCB, 0x8B, 0x4C, 0x26, 0xFC, 0x81, 0xE3, 0x28, 0x4F, 0x2B, 0x7F, 0xBA, 0x71, 0x3D },
        28,
        { 0xD6, 0x09, 0xB1, 0xF0, 0x56, 0x63, 0x7A, 0x0D, 0x46, 0xDF, 0x99, 0x8D, 0x88, 0xE5, 0x2E, 0x00,
          0xB2, 0xC2, 0x84, 0x65, 0x12, 0x15, 0x35, 0x24, 0xC0, 0x89, 0x5E, 0x81 },
        { 0x4F, 0x8D, 0x55, 0xE7, 0xD3, 0xF0, 0x6F, 0xD5, 0xA1, 0x3C, 0x0C, 0x29, 0xB9, 0xD5, 0xB8, 0x80 }
    },
    {
        "2.3.1 60-byte Packet",
        { 0x07, 0x1B, 0x11, 0x3B, 0x0C, 0xA7, 0x43, 0xFE, 0xCC, 0xCF, 0x3D, 0x05, 0x1F, 0x73, 0x73, 0x82 },
        12,
        { 0xF0, 0x76, 0x1E, 0x8D, 0xCD, 0x3D, 0x00, 0x01, 0x76, 0xD4, 0x57, 0xED },
        0,
        { 0 },
        { 0 },
        68,
        { 0xE2, 0x01, 0x06, 0xD7, 0xCD, 0x0D, 0xF0, 0x76, 0x1E, 0x8D, 0xCD, 0x3D, 0x88, 0xE5, 0x40, 0x00,
          0x76, 0xD4, 0x57, 0xED, 0x08, 0x00, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
          0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
          0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
          0x39, 0x3A, 0x00, 0x03 },
        { 0x0C, 0x01, 0x7B, 0xC7, 0x3B, 0x22, 0x7D, 0xFC, 0xC9, 0xBA, 0xFA, 0x1C, 0x41, 0xAC, 0xC3, 0x53 }
    },
    {
        "2.4.1 54-byte Packet",
        { 0x07, 0x1B, 0x11, 0x3B, 0x0C, 0xA7, 0x43, 0xFE, 0xCC, 0xCF, 0x3D, 0x05, 0x1F, 0x73, 0x73, 0x82 },
        12,
        { 0xF0, 0x76, 0x1E, 0x8D, 0xCD, 0x3D, 0x00, 0x01, 0x76, 0xD4, 0x57, 0xED },
        42,
        { 0x08, 0x00, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C,
          0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C,
          0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x00, 0x04 },
        { 0x13, 0xB4, 0xC7, 0x2B, 0x38, 0x9D, 0xC5, 0x01, 0x8E, 0x72, 0xA1, 0x71, 0xDD, 0x85, 0xA5, 0xD3,
          0x75, 0x22, 0x74, 0xD3, 0xA0, 0x19, 0xFB, 0xCA, 0xED, 0x09, 0xA4, 0x25, 0xCD, 0x9B, 0x2E, 0x1C,
          0x9B, 0x72, 0xEE, 0xE7, 0xC9, 0xDE, 0x7D, 0x52, 0xB3, 0xF3 },
        20,
        { 0xE2, 0x01, 0x06, 0xD7, 0xCD, 0x0D, 0xF0, 0x76, 0x1E, 0x8D, 0xCD, 0x3D, 0x88, 0xE5, 0x4C, 0x2A,
          0x76, 0xD4, 0x57, 0xED },
        { 0xD6, 0xA5, 0x28, 0x4F, 0x4A, 0x6D, 0x3F, 0xE2, 0x2A, 0x5D, 0x6C, 0x2B, 0x96, 0x04, 0x94, 0xC3 }
    },
    {
        "2.5.1 65-byte Packet",
        { 0x01, 0x3F, 0xE0, 0x0B, 0x5F, 0x11, 0xBE, 0x7F, 0x86, 0x6D, 0x0C, 0xBB, 0xC5, 0x5A, 0x7A, 0x90 },
        12,
        { 0x7C, 0xFD, 0xE9, 0xF9, 0xE3, 0x37, 0x24, 0xC6, 0x89, 0x32, 0xD6, 0x12 },
        0,
        { 0 },
        { 0 },
        81,
        { 0x84, 0xC5, 0xD5, 0x13, 0xD2, 0xAA, 0xF6, 0xE5, 0xBB, 0xD2, 0x72, 0x77, 0x88, 0xE5, 0x23, 0x00,
          0x89, 0x32, 0xD6, 0x12, 0x7C, 0xFD, 0xE9, 0xF9, 0xE3, 0x37, 0x24, 0xC6, 0x08, 0x00, 0x0F, 0x10,
          0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
          0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
          0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x00,
          0x05 },
        { 0x21, 0x78, 0x67, 0xE5, 0x0C, 0x2D, 0xAD, 0x74, 0xC2, 0x8C, 0x3B, 0x50, 0xAB, 0xDF, 0x69, 0x5A }
    },
    {
        "2.6.1 61-byte Packet",
        { 0x01, 0x3F, 0xE0, 0x0B, 0x5F, 0x11, 0xBE, 0x7F, 0x86, 0x6D, 0x0C, 0xBB, 0xC5, 0x5A, 0x7A, 0x90 },
        12,
        { 0x7C, 0xFD, 0xE9, 0xF9, 0xE3, 0x37, 0x24, 0xC6, 0x89, 0x32, 0xD6, 0x12 },
        49,
        { 0x08, 0x00, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C,
          0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C,
          0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x00,
          0x06 },
        { 0x3A, 0x4D, 0xE6, 0xFA, 0x32, 0x19, 0x10, 0x14, 0xDB, 0xB3, 0x03, 0xD9, 0x2E, 0xE3, 0xA9, 0xE8,
          0xA1, 0xB5, 0x99, 0xC1, 0x4D, 0x22, 0xFB, 0x08, 0x00, 0x96, 0xE1, 0x38, 0x11, 0x81, 0x6A, 0x3C,
          0x9C, 0x9B, 0xCF, 0x7C, 0x1B, 0x9B, 0x96, 0xDA, 0x80, 0x92, 0x04, 0xE2, 0x9D, 0x0E, 0x2A, 0x76,
          0x42 },
        28,
        { 0x84, 0xC5, 0xD5, 0x13, 0xD2, 0xAA, 0xF6, 0xE5, 0xBB, 0xD2, 0x72, 0x77, 0x88, 0xE5, 0x2F, 0x00,
          0x89, 0x32, 0xD6, 0x12, 0x7C, 0xFD, 0xE9, 0xF9, 0xE3, 0x37, 0x24, 0xC6 },
        { 0xBF, 0xD3, 0x10, 0xA4, 0x83, 0x7C, 0x81, 0x6C, 0xCF, 0xA5, 0xAC, 0x23, 0xAB, 0x00, 0x39, 0x88 }
    },
    {
        "2.7.1 79-byte Packet",
        { 0x88, 0xEE, 0x08, 0x7F, 0xD9, 0x5D, 0xA9, 0xFB, 0xF6, 0x72, 0x5A, 0xA9, 0xD7, 0x57, 0xB0, 0xCD },
        12,{ 0x7A, 0xE8, 0xE2, 0xCA, 0x4E, 0xC5, 0x00, 0x01, 0x2E, 0x58, 0x49, 0x5C },
        0,
        { 0 },
        { 0 },
        87,
        { 0x68, 0xF2, 0xE7, 0x76, 0x96, 0xCE, 0x7A, 0xE8, 0xE2, 0xCA, 0x4E, 0xC5, 0x88, 0xE5, 0x41, 0x00,
          0x2E, 0x58, 0x49, 0x5C, 0x08, 0x00, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
          0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
          0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
          0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
          0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x00, 0x07 },
        { 0x07, 0x92, 0x2B, 0x8E, 0xBC, 0xF1, 0x0B, 0xB2, 0x29, 0x75, 0x88, 0xCA, 0x4C, 0x61, 0x45, 0x23 }
    },
    {
        "2.8.1 75-byte Packet",
        { 0x88, 0xEE, 0x08, 0x7F, 0xD9, 0x5D, 0xA9, 0xFB, 0xF6, 0x72, 0x5A, 0xA9, 0xD7, 0x57, 0xB0, 0xCD },
        12,
        { 0x7A, 0xE8, 0xE2, 0xCA, 0x4E, 0xC5, 0x00, 0x01, 0x2E, 0x58, 0x49, 0x5C },
        63,
        { 0x08, 0x00, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C,
          0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C,
          0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C,
          0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x00, 0x08 },
        { 0xC3, 0x1F, 0x53, 0xD9, 0x9E, 0x56, 0x87, 0xF7, 0x36, 0x51, 0x19, 0xB8, 0x32, 0xD2, 0xAA, 0xE7,
          0x07, 0x41, 0xD5, 0x93, 0xF1, 0xF9, 0xE2, 0xAB, 0x34, 0x55, 0x77, 0x9B, 0x07, 0x8E, 0xB8, 0xFE,
          0xAC, 0xDF, 0xEC, 0x1F, 0x8E, 0x3E, 0x52, 0x77, 0xF8, 0x18, 0x0B, 0x43, 0x36, 0x1F, 0x65, 0x12,
          0xAD, 0xB1, 0x6D, 0x2E, 0x38, 0x54, 0x8A, 0x2C, 0x71, 0x9D, 0xBA, 0x72, 0x28, 0xD8, 0x40 },
        20,
        { 0x68, 0xF2, 0xE7, 0x76, 0x96, 0xCE, 0x7A, 0xE8, 0xE2, 0xCA, 0x4E, 0xC5, 0x88, 0xE5, 0x4D, 0x00,
          0x2E, 0x58, 0x49, 0x5C },
        { 0x88, 0xF8, 0x75, 0x7A, 0xDB, 0x8A, 0xA7, 0x88, 0xD8, 0xF6, 0x5A, 0xD6, 0x68, 0xBE, 0x70, 0xE7 }
    },
};
// *INDENT-ON*

typedef struct
{
    uint32_t text_size;
    uint8_t  plaintext[32];
    uint8_t  ciphertext[32];
    uint32_t aad_size;
    uint8_t  aad[32];
    uint8_t  tag[16];
} aes_gcm_partial_block_vectors;

// *INDENT-OFF* - Preserve formatting
const aes_gcm_partial_block_vectors test_vectors[] =
{
    {
        30,
        { 0x9f, 0xee, 0xbb, 0xdf, 0x16, 0x0f, 0x96, 0x52, 0x53, 0xd9, 0x99, 0x58, 0xcc, 0xb1, 0x76, 0xdf,
          0x9f, 0xee, 0xbb, 0xdf, 0x16, 0x0f, 0x96, 0x52, 0x53, 0xd9, 0x99, 0x58, 0xcc, 0xb1 },
        { 0xA6, 0x97, 0x10, 0x3A, 0x70, 0x29, 0x7A, 0xAA, 0xCD, 0x25, 0x9E, 0x1A, 0x85, 0x36, 0xA7, 0xDC,
          0x3E, 0x61, 0x7D, 0xA2, 0xA8, 0x66, 0x3F, 0xD2, 0xFC, 0x5D, 0x6A, 0x6C, 0x36, 0xEA },
        30,
        { 0x47, 0x6b, 0x48, 0x80, 0xf5, 0x93, 0x33, 0x14, 0xdc, 0xc2, 0x3d, 0xf5, 0xdc, 0xb0, 0x09, 0x66,
          0x47, 0x6b, 0x48, 0x80, 0xf5, 0x93, 0x33, 0x14, 0xdc, 0xc2, 0x3d, 0xf5, 0xdc, 0xb0 },
        { 0x72, 0xE3, 0x22, 0x8A, 0x06, 0xE5, 0x88, 0x14, 0x94, 0xC7, 0x08, 0xF3, 0xAC, 0x8B, 0xA9, 0xC5 }
    },
    {
        16,
        { 0x9f, 0xee, 0xbb, 0xdf, 0x16, 0x0f, 0x96, 0x52, 0x53, 0xd9, 0x99, 0x58, 0xcc, 0xb1, 0x76, 0xdf },
        { 0xA6, 0x97, 0x10, 0x3A, 0x70, 0x29, 0x7A, 0xAA, 0xCD, 0x25, 0x9E, 0x1A, 0x85, 0x36, 0xA7, 0xDC },
        16,
        { 0x47, 0x6b, 0x48, 0x80, 0xf5, 0x93, 0x33, 0x14, 0xdc, 0xc2, 0x3d, 0xf5, 0xdc, 0xb0, 0x09, 0x66 },
        { 0xE8, 0x8C, 0x95, 0x9A, 0xBC, 0x1E, 0x75, 0x93, 0xA0, 0x3E, 0xF0, 0x34, 0x84, 0x64, 0xF2, 0xD5 }
    },
    {
        32,
        { 0x9f, 0xee, 0xbb, 0xdf, 0x16, 0x0f, 0x96, 0x52, 0x53, 0xd9, 0x99, 0x58, 0xcc, 0xb1, 0x76, 0xdf,
          0x9f, 0xee, 0xbb, 0xdf, 0x16, 0x0f, 0x96, 0x52, 0x53, 0xd9, 0x99, 0x58, 0xcc, 0xb1, 0x76, 0xdf },
        { 0xA6, 0x97, 0x10, 0x3A, 0x70, 0x29, 0x7A, 0xAA, 0xCD, 0x25, 0x9E, 0x1A, 0x85, 0x36, 0xA7, 0xDC,
          0x3E, 0x61, 0x7D, 0xA2, 0xA8, 0x66, 0x3F, 0xD2, 0xFC, 0x5D, 0x6A, 0x6C, 0x36, 0xEA, 0x2C, 0xD8 },
        32,
        { 0x47, 0x6b, 0x48, 0x80, 0xf5, 0x93, 0x33, 0x14, 0xdc, 0xc2, 0x3d, 0xf5, 0xdc, 0xb0, 0x09, 0x66,
          0x47, 0x6b, 0x48, 0x80, 0xf5, 0x93, 0x33, 0x14, 0xdc, 0xc2, 0x3d, 0xf5, 0xdc, 0xb0, 0x09, 0x66 },
        { 0x3E, 0xCA, 0xD1, 0x08, 0xF6, 0x8D, 0xC4, 0x54, 0xE6, 0xA1, 0x17, 0x5B, 0x9D, 0x4E, 0x16, 0xB3 }
    },
    {
        24,
        { 0x9f, 0xee, 0xbb, 0xdf, 0x16, 0x0f, 0x96, 0x52, 0x53, 0xd9, 0x99, 0x58, 0xcc, 0xb1, 0x76, 0xdf,
          0x9f, 0xee, 0xbb, 0xdf, 0x16, 0x0f, 0x96, 0x52 },
        { 0xA6,0x97, 0x10, 0x3A, 0x70, 0x29, 0x7A, 0xAA, 0xCD, 0x25, 0x9E, 0x1A, 0x85, 0x36, 0xA7, 0xDC,
          0x3E, 0x61, 0x7D, 0xA2, 0xA8, 0x66, 0x3F, 0xD2 },
        24,
        { 0x47, 0x6b, 0x48, 0x80, 0xf5, 0x93, 0x33, 0x14, 0xdc, 0xc2, 0x3d, 0xf5, 0xdc, 0xb0, 0x09, 0x66,
          0x47, 0x6b, 0x48, 0x80, 0xf5, 0x93, 0x33, 0x14, },
        { 0x74, 0x99, 0x3B, 0x31, 0x06, 0xBA, 0x6B, 0xE5, 0x00, 0x8F, 0xD5, 0x3A, 0xA4, 0x91, 0xAA, 0xAF }
    },
};
// *INDENT-ON*

TEST(atca_cmd_basic_test, aes_gcm_encrypt_partial_blocks)
{
    ATCA_STATUS status;
    uint16_t key_id = ATCA_TEMPKEY_KEYID;
    uint8_t aes_key_block = 0;
    uint8_t ciphertext[32];
    uint8_t tag[AES_DATA_SIZE];
    atca_aes_gcm_ctx_t ctx;
    const aes_gcm_partial_block_vectors* current_vector;
    uint8_t key[] = { 0xb7, 0xcf, 0x6c, 0xf5, 0xe7, 0xf3, 0xca, 0x22, 0x3c, 0xa7, 0x3c, 0x81, 0x9d, 0xcd, 0x62, 0xfe };
    uint8_t iv[] = { 0xa4, 0x13, 0x60, 0x09, 0xc0, 0xa7, 0xfd, 0xac, 0xfe, 0x53, 0xf5, 0x07 };

    check_config_aes_enable();

    // Load AES keys into TempKey
    status = atcab_nonce_load(NONCE_MODE_TARGET_TEMPKEY, key, 32);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);

    current_vector = &test_vectors[0];
    //Initialize gcm ctx with IV
    status = atcab_aes_gcm_init(&ctx, key_id, aes_key_block, iv, sizeof(iv));
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    //Add aad to gcm
    status = atcab_aes_gcm_aad_update(&ctx, current_vector->aad, 15);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    status = atcab_aes_gcm_aad_update(&ctx, &current_vector->aad[15], 15);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    //Encrypt data
    status = atcab_aes_gcm_encrypt_update(&ctx, current_vector->plaintext, 15, ciphertext);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    status = atcab_aes_gcm_encrypt_update(&ctx, &current_vector->plaintext[15], 15, &ciphertext[15]);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    //Calculate authentication tag
    status = atcab_aes_gcm_encrypt_finish(&ctx, tag, sizeof(tag));
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    TEST_ASSERT_EQUAL_MEMORY(current_vector->ciphertext, ciphertext, current_vector->text_size);
    TEST_ASSERT_EQUAL_MEMORY(current_vector->tag, tag, sizeof(tag));

    current_vector = &test_vectors[1];
    //Initialize gcm ctx with IV
    status = atcab_aes_gcm_init(&ctx, key_id, aes_key_block, iv, sizeof(iv));
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    //Add aad to gcm
    status = atcab_aes_gcm_aad_update(&ctx, current_vector->aad, 15);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    status = atcab_aes_gcm_aad_update(&ctx, &current_vector->aad[15], 1);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    //Encrypt data
    status = atcab_aes_gcm_encrypt_update(&ctx, current_vector->plaintext, 15, ciphertext);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    status = atcab_aes_gcm_encrypt_update(&ctx, &current_vector->plaintext[15], 1, &ciphertext[15]);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    //Calculate authentication tag
    status = atcab_aes_gcm_encrypt_finish(&ctx, tag, sizeof(tag));
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    TEST_ASSERT_EQUAL_MEMORY(current_vector->ciphertext, ciphertext, current_vector->text_size);
    TEST_ASSERT_EQUAL_MEMORY(current_vector->tag, tag, sizeof(tag));

    current_vector = &test_vectors[2];
    //Initialize gcm ctx with IV
    status = atcab_aes_gcm_init(&ctx, key_id, aes_key_block, iv, sizeof(iv));
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    //Add aad to gcm
    status = atcab_aes_gcm_aad_update(&ctx, current_vector->aad, 16);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    status = atcab_aes_gcm_aad_update(&ctx, &current_vector->aad[16], 16);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    //Encrypt data
    status = atcab_aes_gcm_encrypt_update(&ctx, current_vector->plaintext, 16, ciphertext);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    status = atcab_aes_gcm_encrypt_update(&ctx, &current_vector->plaintext[16], 16, &ciphertext[16]);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    //Calculate authentication tag
    status = atcab_aes_gcm_encrypt_finish(&ctx, tag, sizeof(tag));
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    TEST_ASSERT_EQUAL_MEMORY(current_vector->ciphertext, ciphertext, current_vector->text_size);
    TEST_ASSERT_EQUAL_MEMORY(current_vector->tag, tag, sizeof(tag));

    current_vector = &test_vectors[3];
    //Initialize gcm ctx with IV
    status = atcab_aes_gcm_init(&ctx, key_id, aes_key_block, iv, sizeof(iv));
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    //Add aad to gcm
    status = atcab_aes_gcm_aad_update(&ctx, current_vector->aad, 16);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    status = atcab_aes_gcm_aad_update(&ctx, &current_vector->aad[16], 8);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    //Encrypt data
    status = atcab_aes_gcm_encrypt_update(&ctx, current_vector->plaintext, 16, ciphertext);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    status = atcab_aes_gcm_encrypt_update(&ctx, &current_vector->plaintext[16], 8, &ciphertext[16]);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    //Calculate authentication tag
    status = atcab_aes_gcm_encrypt_finish(&ctx, tag, sizeof(tag));
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    TEST_ASSERT_EQUAL_MEMORY(current_vector->ciphertext, ciphertext, current_vector->text_size);
    TEST_ASSERT_EQUAL_MEMORY(current_vector->tag, tag, sizeof(tag));
}

TEST(atca_cmd_basic_test, aes_gcm_decrypt_partial_blocks)
{
    ATCA_STATUS status;
    uint16_t key_id = ATCA_TEMPKEY_KEYID;
    uint8_t aes_key_block = 0;
    uint8_t plaintext[32];
    bool is_verified;
    atca_aes_gcm_ctx_t ctx;
    const aes_gcm_partial_block_vectors* current_vector;
    uint8_t key[] = { 0xb7, 0xcf, 0x6c, 0xf5, 0xe7, 0xf3, 0xca, 0x22, 0x3c, 0xa7, 0x3c, 0x81, 0x9d, 0xcd, 0x62, 0xfe };
    uint8_t iv[] = { 0xa4, 0x13, 0x60, 0x09, 0xc0, 0xa7, 0xfd, 0xac, 0xfe, 0x53, 0xf5, 0x07 };

    check_config_aes_enable();

    // Load AES keys into TempKey
    status = atcab_nonce_load(NONCE_MODE_TARGET_TEMPKEY, key, 32);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);

    current_vector = &test_vectors[0];
    //Initialize gcm ctx with IV
    status = atcab_aes_gcm_init(&ctx, key_id, aes_key_block, iv, sizeof(iv));
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    //Add aad to gcm
    status = atcab_aes_gcm_aad_update(&ctx, current_vector->aad, 15);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    status = atcab_aes_gcm_aad_update(&ctx, &current_vector->aad[15], 15);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    //Encrypt data
    status = atcab_aes_gcm_decrypt_update(&ctx, current_vector->ciphertext, 15, plaintext);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    status = atcab_aes_gcm_decrypt_update(&ctx, &current_vector->ciphertext[15], 15, &plaintext[15]);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    //Calculate authentication tag
    status = atcab_aes_gcm_decrypt_finish(&ctx, current_vector->tag, sizeof(current_vector->tag), &is_verified);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    TEST_ASSERT_EQUAL_MEMORY(current_vector->plaintext, plaintext, current_vector->text_size);
    TEST_ASSERT(is_verified);

    current_vector = &test_vectors[1];
    //Initialize gcm ctx with IV
    status = atcab_aes_gcm_init(&ctx, key_id, aes_key_block, iv, sizeof(iv));
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    //Add aad to gcm
    status = atcab_aes_gcm_aad_update(&ctx, current_vector->aad, 15);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    status = atcab_aes_gcm_aad_update(&ctx, &current_vector->aad[15], 1);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    //Encrypt data
    status = atcab_aes_gcm_decrypt_update(&ctx, current_vector->ciphertext, 15, plaintext);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    status = atcab_aes_gcm_decrypt_update(&ctx, &current_vector->ciphertext[15], 1, &plaintext[15]);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    //Calculate authentication tag
    status = atcab_aes_gcm_decrypt_finish(&ctx, current_vector->tag, sizeof(current_vector->tag), &is_verified);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    TEST_ASSERT_EQUAL_MEMORY(current_vector->plaintext, plaintext, current_vector->text_size);
    TEST_ASSERT(is_verified);

    current_vector = &test_vectors[2];
    //Initialize gcm ctx with IV
    status = atcab_aes_gcm_init(&ctx, key_id, aes_key_block, iv, sizeof(iv));
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    //Add aad to gcm
    status = atcab_aes_gcm_aad_update(&ctx, current_vector->aad, 16);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    status = atcab_aes_gcm_aad_update(&ctx, &current_vector->aad[16], 16);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    //Encrypt data
    status = atcab_aes_gcm_decrypt_update(&ctx, current_vector->ciphertext, 16, plaintext);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    status = atcab_aes_gcm_decrypt_update(&ctx, &current_vector->ciphertext[16], 16, &plaintext[16]);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    //Calculate authentication tag
    status = atcab_aes_gcm_decrypt_finish(&ctx, current_vector->tag, sizeof(current_vector->tag), &is_verified);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    TEST_ASSERT_EQUAL_MEMORY(current_vector->plaintext, plaintext, current_vector->text_size);
    TEST_ASSERT(is_verified);

    current_vector = &test_vectors[3];
    //Initialize gcm ctx with IV
    status = atcab_aes_gcm_init(&ctx, key_id, aes_key_block, iv, sizeof(iv));
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    //Add aad to gcm
    status = atcab_aes_gcm_aad_update(&ctx, current_vector->aad, 16);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    status = atcab_aes_gcm_aad_update(&ctx, &current_vector->aad[16], 8);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    //Encrypt data
    status = atcab_aes_gcm_decrypt_update(&ctx, current_vector->ciphertext, 16, plaintext);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    status = atcab_aes_gcm_decrypt_update(&ctx, &current_vector->ciphertext[16], 8, &plaintext[16]);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    //Calculate authentication tag
    status = atcab_aes_gcm_decrypt_finish(&ctx, current_vector->tag, sizeof(current_vector->tag), &is_verified);
    TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
    TEST_ASSERT_EQUAL_MEMORY(current_vector->plaintext, plaintext, current_vector->text_size);
    TEST_ASSERT(is_verified);
}

TEST(atca_cmd_basic_test, aes_gcm_nist_vectors)
{
    ATCA_STATUS status;
    uint8_t test_index;
    uint16_t key_id = ATCA_TEMPKEY_KEYID;
    uint8_t aes_key_block = 0;
    uint8_t ciphertext[GCM_TEST_VECTORS_DATA_SIZE_MAX];
    uint8_t plaintext[GCM_TEST_VECTORS_DATA_SIZE_MAX];
    uint8_t tag[AES_DATA_SIZE];
    bool is_verified;
    atca_aes_gcm_ctx_t ctx;

    check_config_aes_enable();

    for (test_index = 0; test_index < (sizeof(gcm_test_cases) / sizeof(aes_gcm_test_vectors)); test_index++)
    {
        // Load AES keys into TempKey
        status = atcab_nonce_load(NONCE_MODE_TARGET_TEMPKEY, gcm_test_cases[test_index].key, 32);
        TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);

        //////////////////////////////////////   Encryption /////////////////////////////////////////
        //Initialize gcm ctx with IV
        status = atcab_aes_gcm_init(&ctx, key_id, aes_key_block, gcm_test_cases[test_index].iv, gcm_test_cases[test_index].iv_size);
        TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);

        //Add aad to gcm
        status = atcab_aes_gcm_aad_update(&ctx, gcm_test_cases[test_index].aad, gcm_test_cases[test_index].aad_size);
        TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);

        //Encrypt data
        status = atcab_aes_gcm_encrypt_update(&ctx, gcm_test_cases[test_index].plaintext, gcm_test_cases[test_index].text_size, ciphertext);
        TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);

        //Verify ciphertext with expected data
        if (gcm_test_cases[test_index].text_size > 0)
        {
            TEST_ASSERT_EQUAL_MEMORY(gcm_test_cases[test_index].ciphertext, ciphertext, gcm_test_cases[test_index].text_size);
        }

        //Calculate authentication tag
        status = atcab_aes_gcm_encrypt_finish(&ctx, tag, sizeof(tag));
        TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);

        //Verify calculated tag
        TEST_ASSERT_EQUAL_MEMORY(gcm_test_cases[test_index].tag, tag, sizeof(tag));

        // Repeat, but skip unused calls
        if (gcm_test_cases[test_index].aad_size == 0 || gcm_test_cases[test_index].text_size == 0)
        {
            //Initialize gcm ctx with IV
            status = atcab_aes_gcm_init(&ctx, key_id, aes_key_block, gcm_test_cases[test_index].iv, gcm_test_cases[test_index].iv_size);
            TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);

            //Add aad to gcm
            if (gcm_test_cases[test_index].aad_size > 0)
            {
                status = atcab_aes_gcm_aad_update(&ctx, gcm_test_cases[test_index].aad, gcm_test_cases[test_index].aad_size);
                TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
            }

            //Encrypt data
            if (gcm_test_cases[test_index].text_size > 0)
            {
                status = atcab_aes_gcm_encrypt_update(&ctx, gcm_test_cases[test_index].plaintext, gcm_test_cases[test_index].text_size, ciphertext);
                TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
                TEST_ASSERT_EQUAL_MEMORY(gcm_test_cases[test_index].ciphertext, ciphertext, gcm_test_cases[test_index].text_size);
            }

            //Calculate authentication tag
            status = atcab_aes_gcm_encrypt_finish(&ctx, tag, sizeof(tag));
            TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);

            //Verify calculated tag
            TEST_ASSERT_EQUAL_MEMORY(gcm_test_cases[test_index].tag, tag, sizeof(tag));
        }


        //////////////////////////////////////   Decryption /////////////////////////////////////////
        //Initialize gcm ctx with IV
        status = atcab_aes_gcm_init(&ctx, key_id, aes_key_block, gcm_test_cases[test_index].iv, gcm_test_cases[test_index].iv_size);
        TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);

        //Add aad to gcm
        status = atcab_aes_gcm_aad_update(&ctx, gcm_test_cases[test_index].aad, gcm_test_cases[test_index].aad_size);
        TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);

        //Add ciphertext to gcm
        status = atcab_aes_gcm_decrypt_update(&ctx, gcm_test_cases[test_index].ciphertext, gcm_test_cases[test_index].text_size, plaintext);
        TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);

        //Verify plaintext with expected data
        if (gcm_test_cases[test_index].text_size > 0)
        {
            TEST_ASSERT_EQUAL_MEMORY(plaintext, gcm_test_cases[test_index].plaintext, gcm_test_cases[test_index].text_size);
        }

        status = atcab_aes_gcm_decrypt_finish(&ctx, gcm_test_cases[test_index].tag, sizeof(tag), &is_verified);
        TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
        TEST_ASSERT(is_verified);

        // Repeat, but skip unused calls
        if (gcm_test_cases[test_index].aad_size == 0 || gcm_test_cases[test_index].text_size == 0)
        {
            //Initialize gcm ctx with IV
            status = atcab_aes_gcm_init(&ctx, key_id, aes_key_block, gcm_test_cases[test_index].iv, gcm_test_cases[test_index].iv_size);
            TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);

            //Add aad to gcm
            if (gcm_test_cases[test_index].aad_size > 0)
            {
                status = atcab_aes_gcm_aad_update(&ctx, gcm_test_cases[test_index].aad, gcm_test_cases[test_index].aad_size);
                TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
            }

            //Add ciphertext to gcm
            if (gcm_test_cases[test_index].text_size > 0)
            {
                status = atcab_aes_gcm_decrypt_update(&ctx, gcm_test_cases[test_index].ciphertext, gcm_test_cases[test_index].text_size, plaintext);
                TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);

                //Verify plaintext with expected data
                TEST_ASSERT_EQUAL_MEMORY(plaintext, gcm_test_cases[test_index].plaintext, gcm_test_cases[test_index].text_size);
            }

            status = atcab_aes_gcm_decrypt_finish(&ctx, gcm_test_cases[test_index].tag, sizeof(tag), &is_verified);
            TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);
            TEST_ASSERT(is_verified);
        }
    }
}

TEST(atca_cmd_basic_test, aes_gcm_encrypt_cavp_vectors)
{
#ifndef _WIN32
    TEST_IGNORE_MESSAGE("Test only available under windows.");
#else
    ATCA_STATUS status;
    FILE* req_file = NULL;
    FILE* rsp_file = NULL;
    uint8_t line[255];
    char *str, *name_value;
    uint8_t key[128], iv[128], pt[128], ct[128], aad[128];
    size_t key_size, iv_size;
    uint32_t text_size, aad_size;
    uint16_t key_id = ATCA_TEMPKEY_KEYID;
    uint8_t aes_key_block = 0;
    uint8_t cal_tag[AES_DATA_SIZE];
    size_t i;
    uint16_t test_count = 0;
    atca_aes_gcm_ctx_t ctx;

    check_config_aes_enable();

    req_file = fopen("cryptoauthlib/test/aes_gcm_cavp_vectors/gcmEncryptExtIV128.req", "r");
    TEST_ASSERT_NOT_NULL_MESSAGE(req_file, "Failed to open .req file");

    rsp_file = fopen("cryptoauthlib/test/aes_gcm_cavp_vectors/gcmEncryptExtIV128.rsp", "w");
    TEST_ASSERT_NOT_NULL_MESSAGE(rsp_file, "Failed to open .rsp file");

    time_t current_time;
    current_time = time(NULL);
    fprintf(rsp_file, "# Executed Vectors on %s", ctime(&current_time));

    do
    {
        if (NULL == (str = fgets(line, sizeof(line), req_file)))
        {
            continue;
        }

        fputs(str, rsp_file);
        if (!memcmp(str, "Key = ", strlen("Key = ")))
        {
            name_value = &line[strlen("Key = ")];
            key_size = strlen(name_value) / 2;
            hex_to_data(name_value, key, key_size);
        }
        else if (!memcmp(str, "IV = ", strlen("IV = ")))
        {
            name_value = &line[strlen("IV = ")];
            iv_size = strlen(name_value) / 2;
            hex_to_data(name_value, iv, iv_size);
        }
        else if (!memcmp(str, "PT = ", strlen("PT = ")))
        {
            name_value = &line[strlen("PT = ")];
            text_size = (uint32_t)strlen(name_value) / 2;
            hex_to_data(name_value, pt, text_size);
        }
        else if (!memcmp(str, "AAD = ", strlen("AAD = ")))
        {
            name_value = &line[strlen("AAD = ")];
            aad_size = (uint32_t)strlen(name_value) / 2;
            hex_to_data(name_value, aad, aad_size);

            //Process read vector
            printf("%04d\r", test_count++);
            // Load AES keys into TempKey
            status = atcab_nonce_load(NONCE_MODE_TARGET_TEMPKEY, key, 32);
            TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);

            //Initialize gcm ctx with IV
            status = atcab_aes_gcm_init(&ctx, key_id, aes_key_block, iv, iv_size);
            TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);

            //Add aad to gcm
            status = atcab_aes_gcm_aad_update(&ctx, aad, aad_size);
            TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);

            //Add plaintext to gcm
            status = atcab_aes_gcm_encrypt_update(&ctx, pt, text_size, ct);
            TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);

            //Finish encrypt and get tag
            status = atcab_aes_gcm_encrypt_finish(&ctx, cal_tag, sizeof(cal_tag));
            TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);

            fputs("CT = ", rsp_file);
            for (i = 0; i < text_size; i++)
            {
                fprintf(rsp_file, "%02x", ct[i]);
            }
            fputs("\n", rsp_file);

            fputs("Tag = ", rsp_file);
            for (i = 0; i < AES_DATA_SIZE; i++)
            {
                fprintf(rsp_file, "%02x", cal_tag[i]);
            }
            fputs("\n", rsp_file);
        }


    }
    while (!feof(req_file));

    fclose(req_file);
    fclose(rsp_file);
    printf("\n");
#endif
}

TEST(atca_cmd_basic_test, aes_gcm_decrypt_cavp_vectors)
{
#ifndef _WIN32
    TEST_IGNORE_MESSAGE("Test only available under windows.");
#else
    ATCA_STATUS status;
    FILE* req_file = NULL;
    FILE* rsp_file = NULL;
    uint8_t line[255];
    char *str, *name_value;
    uint8_t key[128], iv[128], pt[128], ct[128], aad[128], tag[128];
    size_t key_size, iv_size, tag_size;
    uint32_t text_size, aad_size;
    uint16_t key_id = ATCA_TEMPKEY_KEYID;
    uint8_t aes_key_block = 0;
    size_t i;
    bool is_verified;
    uint16_t test_count = 0;
    atca_aes_gcm_ctx_t ctx;

    check_config_aes_enable();

    req_file = fopen("cryptoauthlib/test/aes_gcm_cavp_vectors/gcmDecrypt128.req", "r");
    TEST_ASSERT_NOT_NULL_MESSAGE(req_file, "Failed to open .req file");

    rsp_file = fopen("cryptoauthlib/test/aes_gcm_cavp_vectors/gcmDecrypt128.rsp", "w");
    TEST_ASSERT_NOT_NULL_MESSAGE(rsp_file, "Failed to open .rsp file");

    time_t current_time;
    current_time = time(NULL);
    fprintf(rsp_file, "# Executed Vectors on %s", ctime(&current_time));

    do
    {
        if (NULL == (str = fgets(line, sizeof(line), req_file)))
        {
            continue;
        }

        fputs(str, rsp_file);
        if (!memcmp(str, "Key = ", strlen("Key = ")))
        {
            name_value = &line[strlen("Key = ")];
            key_size = strlen(name_value) / 2;
            hex_to_data(name_value, key, key_size);
        }
        else if (!memcmp(str, "IV = ", strlen("IV = ")))
        {
            name_value = &line[strlen("IV = ")];
            iv_size = strlen(name_value) / 2;
            hex_to_data(name_value, iv, iv_size);
        }
        else if (!memcmp(str, "CT = ", strlen("CT = ")))
        {
            name_value = &line[strlen("CT = ")];
            text_size = (uint32_t)strlen(name_value) / 2;
            hex_to_data(name_value, ct, text_size);
        }
        else if (!memcmp(str, "AAD = ", strlen("AAD = ")))
        {
            name_value = &line[strlen("AAD = ")];
            aad_size = (uint32_t)strlen(name_value) / 2;
            hex_to_data(name_value, aad, aad_size);
        }
        else if (!memcmp(str, "Tag = ", strlen("Tag = ")))
        {
            name_value = &line[strlen("Tag = ")];
            tag_size = strlen(name_value) / 2;
            hex_to_data(name_value, tag, tag_size);

            //Process read vector
            printf("%04d\r", test_count++);
            // Load AES keys into TempKey
            status = atcab_nonce_load(NONCE_MODE_TARGET_TEMPKEY, key, 32);
            TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);

            //Initialize gcm ctx with IV
            status = atcab_aes_gcm_init(&ctx, key_id, aes_key_block, iv, iv_size);
            TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);

            //Add aad to gcm
            status = atcab_aes_gcm_aad_update(&ctx, aad, aad_size);
            TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);

            //Add cipher to gcm
            status = atcab_aes_gcm_decrypt_update(&ctx, ct, text_size, pt);
            TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);

            //Complete GCM decrypt and validate tag
            status = atcab_aes_gcm_decrypt_finish(&ctx, tag, tag_size, &is_verified);
            TEST_ASSERT_EQUAL(ATCA_SUCCESS, status);

            if (!is_verified)
            {
                fputs("FAIL\n", rsp_file);
            }
            else
            {
                fputs("PT = ", rsp_file);
                for (i = 0; i < text_size; i++)
                {
                    fprintf(rsp_file, "%02x", pt[i]);
                }
                fputs("\n", rsp_file);
            }
        }
    }
    while (!feof(req_file));

    fclose(req_file);
    fclose(rsp_file);
    printf("\n");
#endif
}

// *INDENT-OFF* - Preserve formatting
t_test_case_info aes_gcm_basic_test_info[] =
{
    { REGISTER_TEST_CASE(atca_cmd_basic_test, aes_gcm_nist_vectors),             DEVICE_MASK(ATECC608A) },
    { REGISTER_TEST_CASE(atca_cmd_basic_test, aes_gcm_encrypt_partial_blocks),   DEVICE_MASK(ATECC608A) },
    { REGISTER_TEST_CASE(atca_cmd_basic_test, aes_gcm_decrypt_partial_blocks),   DEVICE_MASK(ATECC608A) },
    { REGISTER_TEST_CASE(atca_cmd_basic_test, aes_gcm_encrypt_cavp_vectors),     DEVICE_MASK(ATECC608A) },
    { REGISTER_TEST_CASE(atca_cmd_basic_test, aes_gcm_decrypt_cavp_vectors),     DEVICE_MASK(ATECC608A) },
    { (fp_test_case)NULL,                     (uint8_t)0 },             /* Array Termination element*/
};

// *INDENT-ON*
