From b08ac23f825474070b67c96a71389cef227ab61a Mon Sep 17 00:00:00 2001 From: Neelima P S Date: Fri, 22 May 2026 15:12:47 +0000 Subject: [PATCH] added ossl350_test_utils.c in ATPTestRelated directory (#39) Co-authored-by: neelimap Reviewed-on: http://13.234.246.121:3000/Neominds/ossl35vx69/pulls/39 Co-authored-by: Neelima P S Co-committed-by: Neelima P S --- TestPrograms/ossl350_test_utils.c | 848 ++++++++++++++++++++++++++++++ 1 file changed, 848 insertions(+) create mode 100644 TestPrograms/ossl350_test_utils.c diff --git a/TestPrograms/ossl350_test_utils.c b/TestPrograms/ossl350_test_utils.c new file mode 100644 index 00000000..111b5f28 --- /dev/null +++ b/TestPrograms/ossl350_test_utils.c @@ -0,0 +1,848 @@ +/** + * TEST PROGRAM: AES-GCM Authenticated Encryption/Decryption Test + * Environment: VxWorks 6.9, OpenSSL 3.5.0, 32-bit ARM + * + * Features: Positive tests + Negative tests for integrity validation + * - Modified ciphertext detection + * - Modified AAD detection + * - Modified tag detection + * - Wrong IV detection + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* ========== TEST DATA ========== */ +/* Fixed key (16 bytes / 128 bits) for reproducibility */ +static const unsigned char test_key[] = { + 0x0A, 0x1B, 0x2C, 0x3D, 0x4E, 0x5F, 0x6A, 0x7B, + 0x8C, 0x9D, 0x0E, 0x1F, 0x2A, 0x3B, 0x4C, 0x5D +}; + +/* Fixed IV (12 bytes / 96 bits) - GCM recommended length */ +static const unsigned char test_iv[] = { + 0x1A, 0x2B, 0x3C, 0x4D, 0x5E, 0x6F, 0x7A, 0x8B, + 0x9C, 0x0D, 0x1E, 0x2F /* Added 0x2F for 12 bytes total */ +}; + +/* Associated Data (AAD) - authenticated but not encrypted */ +static const char* test_aad = "AAD-TEST-DATA-FOR-VXWORKS"; + +/* Plaintext test vectors */ +static const char* test_plaintexts[] = { + "AES-GCM-Authenticated-Encryption-Test", /* 32 bytes */ + "GCM-INTEGRITY-TEST-PATTERN-GCM-INTEGRITY-TEST-PATTERN-", /* 50+ bytes */ + "", /* 0 bytes (empty) */ + "X" /* 1 byte */ +}; + +static const int test_plaintext_lengths[] = {32, 50, 0, 1}; + +/* ========== UTILITY FUNCTIONS ========== */ +void print_hex(const char* label, const unsigned char* data, int len) { + printf("%s (%d bytes): ", label, len); + int i; + for (i = 0; i < len && i < 48; i++) { + printf("%02X", data[i]); + } + if (len > 48) printf("..."); + printf("\n"); +} + +void print_hex_full(const char* label, const unsigned char* data, int len) { + printf("%s (%d bytes):\n", label, len); + int i; + for (i = 0; i < len; i++) { + printf("%02X", data[i]); + if ((i + 1) % 4 == 0 && i + 1 < len) { + printf(" "); + } + if ((i + 1) % 16 == 0 && i + 1 < len) { + printf("\n"); + } + } + printf("\n"); +} + +void print_string(const char* label, const char* data, int len) { + printf("%s (%d bytes): ", label, len); + int i; + for (i = 0; i < len && i < 48; i++) { + if (data[i] >= 32 && data[i] <= 126) + printf("%c", data[i]); + else + printf("."); + } + if (len > 48) printf("..."); + printf("\n"); +} + +void print_string_full(const char* label, const char* data, int len) { + printf("%s (%d bytes):\n", label, len); + printf(" String: \""); + int i; + for (i = 0; i < len; i++) { + if (data[i] >= 32 && data[i] <= 126) + printf("%c", data[i]); + else if (data[i] == '\0') + printf("\\0"); + else + printf("\\x%02X", (unsigned char)data[i]); + } + printf("\"\n"); +} + +int compare_buffers(const unsigned char* buf1, const unsigned char* buf2, int len) { + return memcmp(buf1, buf2, len) == 0; +} + +void flip_bit(unsigned char* buffer, int position) { + int byte_pos = position / 8; + int bit_pos = position % 8; + buffer[byte_pos] ^= (1 << bit_pos); +} + +void print_openssl_errors(void) { + unsigned long err; + char err_buf[256]; + while ((err = ERR_get_error()) != 0) { + ERR_error_string_n(err, err_buf, sizeof(err_buf)); + printf("OpenSSL error: %s\n", err_buf); + } +} + +/* ========== FILE COMPARISON FUNCTION ========== */ +/** + * Compare two files byte by byte to check if they are identical + * Returns: 1 if files are identical, 0 otherwise + */ +int filesMatch(const char* f1, const char* f2) +{ + int fd1, fd2, match = 1; + char c1, c2; + + fd1 = open(f1, O_RDONLY, 0); + fd2 = open(f2, O_RDONLY, 0); + + if (fd1 == -1 || fd2 == -1) + { + if (fd1 != -1) close(fd1); + if (fd2 != -1) close(fd2); + printf("ERROR: Cannot open one or both files\n"); + return 0; + } + + /* Compare byte by byte */ + while (read(fd1, &c1, 1) == 1 && read(fd2, &c2, 1) == 1) + { + if (c1 != c2) + { + match = 0; + break; + } + } + + /* If still matching, check if both files reached EOF */ + if (match == 1) + { + int remaining1 = read(fd1, &c1, 1); + int remaining2 = read(fd2, &c2, 1); + + if (remaining1 != 0 || remaining2 != 0) + match = 0; + } + + close(fd1); + close(fd2); + + printf(match ? "Files are IDENTICAL\n" : "Files are NOT IDENTICAL\n"); + return match; +} + +/* ========== CORE AES-GCM FUNCTIONS ========== */ +/** + * Encrypt plaintext using AES-128-GCM + * Returns: ciphertext length (>=0), -1 on error + * Also outputs authentication tag + */ +int aes_gcm_encrypt(const unsigned char* plaintext, int plaintext_len, + const unsigned char* key, const unsigned char* iv, int iv_len, + const unsigned char* aad, int aad_len, + unsigned char** ciphertext, unsigned char** tag, int tag_len) { + EVP_CIPHER_CTX* ctx; + int len; + int ciphertext_len; + + /* For empty plaintext, allocate at least 1 byte to avoid NULL issues */ + int alloc_len = (plaintext_len > 0) ? plaintext_len : 1; + *ciphertext = (unsigned char*)malloc(alloc_len + 16); + *tag = (unsigned char*)malloc(tag_len); + if (*ciphertext == NULL || *tag == NULL) { + if (*ciphertext) free(*ciphertext); + if (*tag) free(*tag); + return -1; + } + + ctx = EVP_CIPHER_CTX_new(); + if (!ctx) { + free(*ciphertext); + free(*tag); + return -1; + } + + /* Initialize encryption */ + if (EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL) != 1) { + print_openssl_errors(); + EVP_CIPHER_CTX_free(ctx); + free(*ciphertext); + free(*tag); + return -1; + } + + /* Set IV length */ + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL) != 1) { + print_openssl_errors(); + EVP_CIPHER_CTX_free(ctx); + free(*ciphertext); + free(*tag); + return -1; + } + + /* Initialize key and IV */ + if (EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv) != 1) { + print_openssl_errors(); + EVP_CIPHER_CTX_free(ctx); + free(*ciphertext); + free(*tag); + return -1; + } + + /* Add AAD (authenticated but not encrypted) */ + if (aad && aad_len > 0) { + if (EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len) != 1) { + print_openssl_errors(); + EVP_CIPHER_CTX_free(ctx); + free(*ciphertext); + free(*tag); + return -1; + } + } + + /* Encrypt plaintext */ + if (plaintext_len > 0) { + if (EVP_EncryptUpdate(ctx, *ciphertext, &len, plaintext, plaintext_len) != 1) { + print_openssl_errors(); + EVP_CIPHER_CTX_free(ctx); + free(*ciphertext); + free(*tag); + return -1; + } + ciphertext_len = len; + } else { + ciphertext_len = 0; + } + + /* Finalize encryption */ + if (EVP_EncryptFinal_ex(ctx, *ciphertext + ciphertext_len, &len) != 1) { + print_openssl_errors(); + EVP_CIPHER_CTX_free(ctx); + free(*ciphertext); + free(*tag); + return -1; + } + ciphertext_len += len; + + /* Get authentication tag */ + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, tag_len, *tag) != 1) { + print_openssl_errors(); + EVP_CIPHER_CTX_free(ctx); + free(*ciphertext); + free(*tag); + return -1; + } + + EVP_CIPHER_CTX_free(ctx); + return ciphertext_len; +} + +/** + * Decrypt ciphertext using AES-128-GCM + * Returns: plaintext length (>=0), -1 on error (including tag mismatch) + */ +int aes_gcm_decrypt(const unsigned char* ciphertext, int ciphertext_len, + const unsigned char* key, const unsigned char* iv, int iv_len, + const unsigned char* aad, int aad_len, + const unsigned char* tag, int tag_len, + unsigned char** plaintext) { + EVP_CIPHER_CTX* ctx; + int len; + int plaintext_len; + int ret; + + /* For empty ciphertext, allocate at least 1 byte */ + int alloc_len = (ciphertext_len > 0) ? ciphertext_len : 1; + *plaintext = (unsigned char*)malloc(alloc_len); + if (*plaintext == NULL) return -1; + + ctx = EVP_CIPHER_CTX_new(); + if (!ctx) { + free(*plaintext); + return -1; + } + + /* Initialize decryption */ + if (EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL) != 1) { + print_openssl_errors(); + EVP_CIPHER_CTX_free(ctx); + free(*plaintext); + return -1; + } + + /* Set IV length */ + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL) != 1) { + print_openssl_errors(); + EVP_CIPHER_CTX_free(ctx); + free(*plaintext); + return -1; + } + + /* Initialize key and IV */ + if (EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv) != 1) { + print_openssl_errors(); + EVP_CIPHER_CTX_free(ctx); + free(*plaintext); + return -1; + } + + /* Add AAD */ + if (aad && aad_len > 0) { + if (EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len) != 1) { + print_openssl_errors(); + EVP_CIPHER_CTX_free(ctx); + free(*plaintext); + return -1; + } + } + + /* Decrypt ciphertext */ + if (ciphertext_len > 0) { + if (EVP_DecryptUpdate(ctx, *plaintext, &len, ciphertext, ciphertext_len) != 1) { + print_openssl_errors(); + EVP_CIPHER_CTX_free(ctx); + free(*plaintext); + return -1; + } + plaintext_len = len; + } else { + plaintext_len = 0; + } + + /* Set expected tag */ + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, tag_len, (void*)tag) != 1) { + print_openssl_errors(); + EVP_CIPHER_CTX_free(ctx); + free(*plaintext); + return -1; + } + + /* Finalize decryption - tag verification happens here */ + ret = EVP_DecryptFinal_ex(ctx, *plaintext + plaintext_len, &len); + + EVP_CIPHER_CTX_free(ctx); + + if (ret != 1) { + /* Tag mismatch or other error */ + free(*plaintext); + *plaintext = NULL; + return -1; + } + + plaintext_len += len; + return plaintext_len; +} + +/* ========== POSITIVE TEST (Normal Operation) ========== */ +int run_positive_test(const char* test_name, const unsigned char* plaintext, int plaintext_len, + const unsigned char* key, const unsigned char* iv, int iv_len, + const char* aad, int aad_len) { + unsigned char* ciphertext = NULL; + unsigned char* decrypted = NULL; + unsigned char* tag = NULL; + int ciphertext_len; + int decrypted_len; + int tag_len = 16; /* 128-bit tag */ + int pass = 1; + int is_empty = (plaintext_len == 0); + + printf("\n========================================\n"); + printf("POSITIVE TEST: %s\n", test_name); + printf("Plaintext length: %d bytes\n", plaintext_len); + if (plaintext_len > 0 && plaintext_len <= 64) { + print_string_full("Original Plaintext", (const char*)plaintext, plaintext_len); + print_hex_full("Original Plaintext (Hex)", plaintext, plaintext_len); + } else if (is_empty) { + printf("Plaintext: (empty)\n"); + } + printf("AAD: %s\n", aad); + + /* STEP 1: Encrypt */ + printf("\n[STEP 1] AES-GCM Encrypting...\n"); + ciphertext_len = aes_gcm_encrypt(plaintext, plaintext_len, key, iv, iv_len, + (const unsigned char*)aad, aad_len, + &ciphertext, &tag, tag_len); + + if (ciphertext_len < 0) { + printf("FAIL: Encryption failed (ciphertext_len=%d)\n", ciphertext_len); + pass = 0; + goto cleanup; + } + + if (is_empty && ciphertext_len == 0) { + printf("PASS: Empty plaintext encryption successful (ciphertext empty, tag generated)\n"); + } else { + printf("PASS: Encryption successful\n"); + } + printf(" Ciphertext length: %d bytes\n", ciphertext_len); + printf(" Tag length: %d bytes\n", tag_len); + print_hex_full("Generated Tag", tag, tag_len); + + /* Print FULL ciphertext */ + if (ciphertext_len > 0) { + print_hex_full("Ciphertext (Encrypted Output)", ciphertext, ciphertext_len); + } else { + printf("Ciphertext: (empty)\n"); + } + + /* STEP 2: Verify ciphertext != plaintext */ + printf("\n[STEP 2] Verifying ciphertext != plaintext...\n"); + if (is_empty) { + printf("PASS: Both plaintext and ciphertext are empty (trivially not identical)\n"); + } else if (plaintext_len == ciphertext_len && compare_buffers(plaintext, ciphertext, plaintext_len)) { + printf("FAIL: Ciphertext is identical to plaintext\n"); + pass = 0; + goto cleanup; + } else { + printf("PASS: Ciphertext is different from plaintext\n"); + } + + /* STEP 3: Decrypt with valid inputs */ + printf("\n[STEP 3] AES-GCM Decrypting with valid tag...\n"); + decrypted_len = aes_gcm_decrypt(ciphertext, ciphertext_len, key, iv, iv_len, + (const unsigned char*)aad, aad_len, + tag, tag_len, &decrypted); + + if (decrypted_len < 0) { + printf("FAIL: Decryption failed (decrypted_len=%d) - Tag mismatch?\n", decrypted_len); + pass = 0; + goto cleanup; + } + + if (is_empty && decrypted_len == 0) { + printf("PASS: Empty plaintext decryption successful\n"); + } else { + printf("PASS: Decryption successful\n"); + } + printf(" Decrypted length: %d bytes\n", decrypted_len); + + /* Print FULL decrypted plaintext */ + if (decrypted_len > 0) { + print_string_full("Decrypted Plaintext (Recovered)", (const char*)decrypted, decrypted_len); + print_hex_full("Decrypted Plaintext (Hex)", decrypted, decrypted_len); + } else { + printf("Decrypted plaintext: (empty)\n"); + } + + /* STEP 4: Verify decrypted != ciphertext */ + printf("\n[STEP 4] Verifying decrypted text != ciphertext...\n"); + if (is_empty) { + printf("PASS: Both are empty (trivially not identical)\n"); + } else if (decrypted_len == ciphertext_len && compare_buffers(decrypted, ciphertext, decrypted_len)) { + printf("FAIL: Decrypted text is identical to ciphertext\n"); + pass = 0; + goto cleanup; + } else { + printf("PASS: Decrypted text is different from ciphertext\n"); + } + + /* STEP 5: Verify decrypted == original plaintext */ + printf("\n[STEP 5] Verifying decrypted text matches original plaintext...\n"); + if (decrypted_len != plaintext_len) { + printf("FAIL: Length mismatch (plaintext=%d, decrypted=%d)\n", + plaintext_len, decrypted_len); + pass = 0; + goto cleanup; + } + if (plaintext_len > 0 && !compare_buffers(plaintext, decrypted, plaintext_len)) { + printf("FAIL: Decrypted text does NOT match original plaintext\n"); + pass = 0; + goto cleanup; + } + printf("PASS: Decrypted text matches original plaintext exactly\n"); + + printf("\n*** POSITIVE TEST RESULT: %s ***\n", pass ? "PASS" : "FAIL"); + +cleanup: + if (ciphertext) free(ciphertext); + if (decrypted) free(decrypted); + if (tag) free(tag); + return pass; +} + +/* ========== NEGATIVE TESTS (Integrity Protection) ========== */ + +/* Negative Test 1: Modified Ciphertext */ +int run_negative_test_modified_ciphertext(const unsigned char* plaintext, int plaintext_len, + const unsigned char* key, const unsigned char* iv, int iv_len, + const char* aad, int aad_len) { + unsigned char* ciphertext = NULL; + unsigned char* decrypted = NULL; + unsigned char* tag = NULL; + int ciphertext_len; + int decrypted_len; + int tag_len = 16; + int pass = 1; + + printf("\n========================================\n"); + printf("NEGATIVE TEST N1: Modified Ciphertext\n"); + printf("Expected: Decryption should FAIL due to tag mismatch\n"); + + /* First, encrypt normally */ + ciphertext_len = aes_gcm_encrypt(plaintext, plaintext_len, key, iv, iv_len, + (const unsigned char*)aad, aad_len, + &ciphertext, &tag, tag_len); + if (ciphertext_len < 0) { + printf("FAIL: Setup encryption failed\n"); + return 0; + } + + /* Only modify if ciphertext has content */ + if (ciphertext_len > 0) { + printf("\nOriginal ciphertext (first 16 bytes): "); + int i; + for (i = 0; i < 16 && i < ciphertext_len; i++) { + printf("%02X", ciphertext[i]); + } + printf("\n"); + printf("Modifying ciphertext: flipping bit 0 of byte 0\n"); + flip_bit(ciphertext, 0); + printf("Modified ciphertext (first 16 bytes): "); + for (i = 0; i < 16 && i < ciphertext_len; i++) { + printf("%02X", ciphertext[i]); + } + printf("\n"); + } else { + printf("Ciphertext is empty, skipping modification (test not applicable)\n"); + printf("PASS: Empty ciphertext cannot be modified - test skipped\n"); + if (ciphertext) free(ciphertext); + if (tag) free(tag); + return 1; + } + + /* Try to decrypt with modified ciphertext */ + decrypted_len = aes_gcm_decrypt(ciphertext, ciphertext_len, key, iv, iv_len, + (const unsigned char*)aad, aad_len, + tag, tag_len, &decrypted); + + if (decrypted_len == -1) { + printf("\nPASS: Decryption correctly FAILED (tag mismatch detected)\n"); + } else { + printf("\nFAIL: Decryption SUCCEEDED when it should have failed!\n"); + if (decrypted_len >= 0) { + printf(" Decrypted %d bytes of invalid data!\n", decrypted_len); + } + pass = 0; + } + + if (ciphertext) free(ciphertext); + if (decrypted) free(decrypted); + if (tag) free(tag); + + printf("*** NEGATIVE TEST RESULT: %s ***\n", pass ? "PASS" : "FAIL"); + return pass; +} + +/* Negative Test 2: Modified AAD */ +int run_negative_test_modified_aad(const unsigned char* plaintext, int plaintext_len, + const unsigned char* key, const unsigned char* iv, int iv_len, + const char* aad, int aad_len) { + unsigned char* ciphertext = NULL; + unsigned char* decrypted = NULL; + unsigned char* tag = NULL; + int ciphertext_len; + int decrypted_len; + int tag_len = 16; + int pass = 1; + char modified_aad[256]; + + printf("\n========================================\n"); + printf("NEGATIVE TEST N2: Modified AAD\n"); + printf("Expected: Decryption should FAIL due to tag mismatch\n"); + + /* First, encrypt normally with original AAD */ + ciphertext_len = aes_gcm_encrypt(plaintext, plaintext_len, key, iv, iv_len, + (const unsigned char*)aad, aad_len, + &ciphertext, &tag, tag_len); + if (ciphertext_len < 0) { + printf("FAIL: Setup encryption failed\n"); + return 0; + } + + /* Modify AAD - change one character */ + strcpy(modified_aad, aad); + modified_aad[0] = (modified_aad[0] == 'A') ? 'B' : 'A'; + printf("\nOriginal AAD: %s\n", aad); + printf("Modified AAD: %s\n", modified_aad); + + /* Try to decrypt with modified AAD */ + decrypted_len = aes_gcm_decrypt(ciphertext, ciphertext_len, key, iv, iv_len, + (const unsigned char*)modified_aad, strlen(modified_aad), + tag, tag_len, &decrypted); + + if (decrypted_len == -1) { + printf("\nPASS: Decryption correctly FAILED (AAD mismatch detected)\n"); + } else { + printf("\nFAIL: Decryption SUCCEEDED with modified AAD!\n"); + pass = 0; + } + + if (ciphertext) free(ciphertext); + if (decrypted) free(decrypted); + if (tag) free(tag); + + printf("*** NEGATIVE TEST RESULT: %s ***\n", pass ? "PASS" : "FAIL"); + return pass; +} + +/* Negative Test 3: Modified Tag */ +int run_negative_test_modified_tag(const unsigned char* plaintext, int plaintext_len, + const unsigned char* key, const unsigned char* iv, int iv_len, + const char* aad, int aad_len) { + unsigned char* ciphertext = NULL; + unsigned char* decrypted = NULL; + unsigned char* tag = NULL; + int ciphertext_len; + int decrypted_len; + int tag_len = 16; + int pass = 1; + unsigned char original_tag[16]; + + printf("\n========================================\n"); + printf("NEGATIVE TEST N3: Modified Authentication Tag\n"); + printf("Expected: Decryption should FAIL due to tag mismatch\n"); + + /* First, encrypt normally */ + ciphertext_len = aes_gcm_encrypt(plaintext, plaintext_len, key, iv, iv_len, + (const unsigned char*)aad, aad_len, + &ciphertext, &tag, tag_len); + if (ciphertext_len < 0) { + printf("FAIL: Setup encryption failed\n"); + return 0; + } + + /* Save original tag for display */ + memcpy(original_tag, tag, tag_len); + + printf("\nOriginal tag: "); + int i; + for (i = 0; i < tag_len; i++) { + printf("%02X", original_tag[i]); + } + printf("\n"); + + /* Modify tag - flip first bit */ + printf("Modifying tag: flipping bit 0 of byte 0\n"); + flip_bit(tag, 0); + printf("Modified tag: "); + for (i = 0; i < tag_len; i++) { + printf("%02X", tag[i]); + } + printf("\n"); + + /* Try to decrypt with modified tag */ + decrypted_len = aes_gcm_decrypt(ciphertext, ciphertext_len, key, iv, iv_len, + (const unsigned char*)aad, aad_len, + tag, tag_len, &decrypted); + + if (decrypted_len == -1) { + printf("\nPASS: Decryption correctly FAILED (modified tag detected)\n"); + } else { + printf("\nFAIL: Decryption SUCCEEDED with modified tag!\n"); + pass = 0; + } + + if (ciphertext) free(ciphertext); + if (decrypted) free(decrypted); + if (tag) free(tag); + + printf("*** NEGATIVE TEST RESULT: %s ***\n", pass ? "PASS" : "FAIL"); + return pass; +} + +/* Negative Test 4: Wrong IV */ +int run_negative_test_wrong_iv(const unsigned char* plaintext, int plaintext_len, + const unsigned char* key, const unsigned char* iv, int iv_len, + const char* aad, int aad_len) { + unsigned char* ciphertext = NULL; + unsigned char* decrypted = NULL; + unsigned char* tag = NULL; + unsigned char wrong_iv[12]; + int ciphertext_len; + int decrypted_len; + int tag_len = 16; + int pass = 1; + + printf("\n========================================\n"); + printf("NEGATIVE TEST N4: Wrong IV\n"); + printf("Expected: Decryption should FAIL due to tag mismatch\n"); + + /* First, encrypt normally */ + ciphertext_len = aes_gcm_encrypt(plaintext, plaintext_len, key, iv, iv_len, + (const unsigned char*)aad, aad_len, + &ciphertext, &tag, tag_len); + if (ciphertext_len < 0) { + printf("FAIL: Setup encryption failed\n"); + return 0; + } + + /* Create wrong IV (different from original) */ + memset(wrong_iv, 0xFF, sizeof(wrong_iv)); + printf("\nOriginal IV: "); + int i; + for (i = 0; i < iv_len; i++) { + printf("%02X", iv[i]); + } + printf("\n"); + printf("Wrong IV: "); + for (i = 0; i < iv_len; i++) { + printf("%02X", wrong_iv[i]); + } + printf("\n"); + + /* Try to decrypt with wrong IV */ + decrypted_len = aes_gcm_decrypt(ciphertext, ciphertext_len, key, wrong_iv, iv_len, + (const unsigned char*)aad, aad_len, + tag, tag_len, &decrypted); + + if (decrypted_len == -1) { + printf("\nPASS: Decryption correctly FAILED (wrong IV detected)\n"); + } else { + printf("\nFAIL: Decryption SUCCEEDED with wrong IV!\n"); + pass = 0; + } + + if (ciphertext) free(ciphertext); + if (decrypted) free(decrypted); + if (tag) free(tag); + + printf("*** NEGATIVE TEST RESULT: %s ***\n", pass ? "PASS" : "FAIL"); + return pass; +} + + +/* ========== MAIN TEST ENTRY POINT ========== */ +int test_aes_gcm(void) { + int positive_passed = 0; + int positive_total = 4; + int negative_passed = 0; + int negative_total = 4; + int i; + + printf("\n"); + printf("=================================================\n"); + printf(" AES-GCM Authenticated Encryption Test Suite\n"); + printf(" Environment: VxWorks 6.9 + OpenSSL 3.5.0\n"); + printf(" Algorithm: AES-128-GCM | IV: 96 bits | Tag: 128 bits\n"); + printf("=================================================\n"); + printf("\n"); + printf("+-------------------------------------------------+\n"); + printf("| POSITIVE TESTS (Normal Operation) |\n"); + printf("+-------------------------------------------------+\n"); + + /* Initialize OpenSSL */ + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + + /* Run positive tests */ + for (i = 0; i < positive_total; i++) { + if (run_positive_test(test_plaintexts[i], + (const unsigned char*)test_plaintexts[i], + test_plaintext_lengths[i], + test_key, test_iv, sizeof(test_iv), + test_aad, strlen(test_aad))) { + positive_passed++; + } + } + + /* Use first plaintext for negative tests (32 bytes) */ + const unsigned char* neg_plaintext = (const unsigned char*)test_plaintexts[0]; + int neg_plaintext_len = test_plaintext_lengths[0]; + + printf("\n"); + printf("+-------------------------------------------------+\n"); + printf("| NEGATIVE TESTS (Integrity Protection) |\n"); + printf("+-------------------------------------------------+\n"); + + /* Run negative tests */ + if (run_negative_test_modified_ciphertext(neg_plaintext, neg_plaintext_len, + test_key, test_iv, sizeof(test_iv), + test_aad, strlen(test_aad))) { + negative_passed++; + } + + if (run_negative_test_modified_aad(neg_plaintext, neg_plaintext_len, + test_key, test_iv, sizeof(test_iv), + test_aad, strlen(test_aad))) { + negative_passed++; + } + + if (run_negative_test_modified_tag(neg_plaintext, neg_plaintext_len, + test_key, test_iv, sizeof(test_iv), + test_aad, strlen(test_aad))) { + negative_passed++; + } + + if (run_negative_test_wrong_iv(neg_plaintext, neg_plaintext_len, + test_key, test_iv, sizeof(test_iv), + test_aad, strlen(test_aad))) { + negative_passed++; + } + + /* Summary */ + printf("\n"); + printf("=================================================\n"); + printf(" TEST SUMMARY\n"); + printf("=================================================\n"); + printf(" Positive Tests: %d passed, %d failed\n", positive_passed, positive_total - positive_passed); + printf(" Negative Tests: %d passed, %d failed\n", negative_passed, negative_total - negative_passed); + printf("=================================================\n"); + + if (positive_passed == positive_total && negative_passed == negative_total) { + printf("\n*** ALL TESTS PASSED ***\n"); + printf(" - All positive tests passed (including empty plaintext)\n"); + printf(" - All negative tests correctly detected integrity violations\n"); + return 0; + } else { + printf("\n*** SOME TESTS FAILED ***\n"); + if (positive_passed != positive_total) { + printf(" - Positive test failure(s)\n"); + } + if (negative_passed != negative_total) { + printf(" - Negative test failure(s) - integrity protection may be broken\n"); + } + return 1; + } +} + +/* ========== VXWORKS SPAWN ENTRY ========== */ +void test_aes_gcm_entry(void) { + printf("\n[VxWorks] Starting AES-GCM test program...\n"); + test_aes_gcm(); + printf("\n[VxWorks] Test program completed.\n"); +} \ No newline at end of file