Line data Source code
1 : /**
2 : * @file test_ige_aes.c
3 : * @brief Unit tests for AES-256-IGE (using mock crypto).
4 : *
5 : * Verifies IGE block chaining logic and call counts with mock crypto.
6 : * Real-crypto functional tests (known-answer, IV propagation) belong in
7 : * a separate functional test binary linked with production crypto.c.
8 : *
9 : * Known mock limitations (functional tests needed):
10 : * - Mock encrypt_block is identity → identical plaintext blocks may produce
11 : * identical ciphertext (IV XOR cancellation when iv_c == iv_p).
12 : * - Cannot verify that ciphertext actually differs from plaintext with
13 : * uniform IVs (XOR symmetry with identity encrypt).
14 : * - Round-trip works because encrypt/decrypt are symmetric under identity.
15 : */
16 :
17 : #include "test_helpers.h"
18 : #include "ige_aes.h"
19 : #include "mock_crypto.h"
20 : #include "crypto.h"
21 :
22 : #include <stdlib.h>
23 : #include <string.h>
24 :
25 1 : void test_ige_encrypt_1block(void) {
26 1 : mock_crypto_reset();
27 1 : uint8_t key[32] = {0}, iv[32] = {0};
28 1 : uint8_t plain[16] = {1}, cipher[16];
29 :
30 1 : aes_ige_encrypt(plain, 16, key, iv, cipher);
31 1 : ASSERT(mock_crypto_encrypt_block_call_count() == 1,
32 : "1 block → 1 encrypt_block call");
33 : }
34 :
35 1 : void test_ige_encrypt_3blocks(void) {
36 1 : mock_crypto_reset();
37 1 : uint8_t key[32] = {0}, iv[32] = {0};
38 1 : uint8_t plain[48] = {0}, cipher[48];
39 :
40 1 : aes_ige_encrypt(plain, 48, key, iv, cipher);
41 1 : ASSERT(mock_crypto_encrypt_block_call_count() == 3,
42 : "3 blocks → 3 encrypt_block calls");
43 : }
44 :
45 1 : void test_ige_decrypt_2blocks(void) {
46 1 : mock_crypto_reset();
47 1 : uint8_t key[32] = {0}, iv[32] = {0};
48 1 : uint8_t cipher[32] = {0}, plain[32];
49 :
50 1 : aes_ige_decrypt(cipher, 32, key, iv, plain);
51 1 : ASSERT(mock_crypto_decrypt_block_call_count() == 2,
52 : "2 blocks → 2 decrypt_block calls");
53 : }
54 :
55 1 : void test_ige_set_encrypt_key(void) {
56 1 : mock_crypto_reset();
57 1 : uint8_t key[32] = {0}, iv[32] = {0};
58 1 : uint8_t plain[16] = {0}, cipher[16];
59 :
60 1 : aes_ige_encrypt(plain, 16, key, iv, cipher);
61 1 : ASSERT(mock_crypto_set_encrypt_key_call_count() == 1,
62 : "set_encrypt_key should be called once");
63 : }
64 :
65 1 : void test_ige_roundtrip_1block(void) {
66 : /* With identity mock, IGE is XOR-symmetric → round-trip works */
67 : uint8_t key[32], iv[32], plain[16], cipher[16], dec[16];
68 1 : memset(key, 0x42, 32);
69 1 : memset(iv, 0x55, 32);
70 17 : for (int i = 0; i < 16; i++) plain[i] = (uint8_t)i;
71 :
72 1 : aes_ige_encrypt(plain, 16, key, iv, cipher);
73 1 : aes_ige_decrypt(cipher, 16, key, iv, dec);
74 1 : ASSERT(memcmp(plain, dec, 16) == 0, "round-trip 1 block");
75 : }
76 :
77 1 : void test_ige_roundtrip_4blocks(void) {
78 : uint8_t key[32], iv[32], plain[64], cipher[64], dec[64];
79 1 : memset(key, 0xAB, 32);
80 1 : memset(iv, 0xCD, 32);
81 65 : for (int i = 0; i < 64; i++) plain[i] = (uint8_t)(i * 7);
82 :
83 1 : aes_ige_encrypt(plain, 64, key, iv, cipher);
84 1 : aes_ige_decrypt(cipher, 64, key, iv, dec);
85 1 : ASSERT(memcmp(plain, dec, 64) == 0, "round-trip 4 blocks");
86 : }
87 :
88 1 : void test_ige_null_safe(void) {
89 1 : uint8_t buf[16] = {0};
90 1 : aes_ige_encrypt(NULL, 16, buf, buf, buf);
91 1 : aes_ige_encrypt(buf, 0, buf, buf, buf);
92 1 : aes_ige_decrypt(NULL, 16, buf, buf, buf);
93 1 : aes_ige_decrypt(buf, 0, buf, buf, buf);
94 1 : ASSERT(1, "null/zero inputs should not crash");
95 : }
96 :
97 1 : void test_ige_unaligned_len(void) {
98 : /* QA-10: len must be a multiple of 16; otherwise the function must
99 : * return without reading past the buffer. Using tight 15/17/31 byte
100 : * buffers ensures ASAN would trip if we iterated past end. */
101 1 : mock_crypto_reset();
102 1 : uint8_t key[32] = {0}, iv[32] = {0};
103 1 : uint8_t plain15[15] = {0}, cipher15[15] = {0};
104 1 : uint8_t plain17[17] = {0}, cipher17[17] = {0};
105 1 : uint8_t plain31[31] = {0}, cipher31[31] = {0};
106 :
107 1 : aes_ige_encrypt(plain15, 15, key, iv, cipher15);
108 1 : aes_ige_encrypt(plain17, 17, key, iv, cipher17);
109 1 : aes_ige_encrypt(plain31, 31, key, iv, cipher31);
110 1 : aes_ige_decrypt(cipher15, 15, key, iv, plain15);
111 1 : aes_ige_decrypt(cipher17, 17, key, iv, plain17);
112 1 : aes_ige_decrypt(cipher31, 31, key, iv, plain31);
113 :
114 1 : ASSERT(mock_crypto_encrypt_block_call_count() == 0,
115 : "unaligned len → no encrypt_block calls");
116 1 : ASSERT(mock_crypto_decrypt_block_call_count() == 0,
117 : "unaligned len → no decrypt_block calls");
118 : }
119 :
120 1 : void test_ige(void) {
121 1 : RUN_TEST(test_ige_encrypt_1block);
122 1 : RUN_TEST(test_ige_encrypt_3blocks);
123 1 : RUN_TEST(test_ige_decrypt_2blocks);
124 1 : RUN_TEST(test_ige_set_encrypt_key);
125 1 : RUN_TEST(test_ige_roundtrip_1block);
126 1 : RUN_TEST(test_ige_roundtrip_4blocks);
127 1 : RUN_TEST(test_ige_null_safe);
128 1 : RUN_TEST(test_ige_unaligned_len);
129 1 : }
|