added ossl350_test_utils.c in ATPTestRelated directory (#39)
Co-authored-by: neelimap <neelimaps@neominds.in> Reviewed-on: http://13.234.246.121:3000/Neominds/ossl35vx69/pulls/39 Co-authored-by: Neelima P S <neelima.ps@neominds.in> Co-committed-by: Neelima P S <neelima.ps@neominds.in>
This commit is contained in:
committed by
neelimap
co-authored by
neelimap
parent
7d6aa91741
commit
b08ac23f82
@@ -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 <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <openssl/err.h>
|
||||||
|
#include <openssl/rand.h>
|
||||||
|
|
||||||
|
/* ========== 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");
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user