diff options
Diffstat (limited to 'src/lib/tests/crypt_test.c')
| -rw-r--r-- | src/lib/tests/crypt_test.c | 430 |
1 files changed, 263 insertions, 167 deletions
diff --git a/src/lib/tests/crypt_test.c b/src/lib/tests/crypt_test.c index 028c4eb5..2d752238 100644 --- a/src/lib/tests/crypt_test.c +++ b/src/lib/tests/crypt_test.c @@ -30,6 +30,7 @@ #include <stdio.h> #define TEST_PACKET_SIZE 1500 +#define TEST_N_PACKETS 1000 extern const uint16_t crypt_supported_nids[]; extern const uint16_t md_supported_nids[]; @@ -39,9 +40,10 @@ static int test_crypt_create_destroy(void) struct crypt_ctx * ctx; uint8_t key[SYMMKEYSZ]; struct crypt_sk sk = { - .nid = NID_aes_256_gcm, - .key = key, - .rot_bit = KEY_ROTATION_BIT + .nid = NID_aes_256_gcm, + .key = key, + .epoch = 0, + .role = CRYPT_ROLE_INIT }; TEST_START(); @@ -67,18 +69,27 @@ static int test_crypt_create_destroy(void) static int test_crypt_encrypt_decrypt(int nid) { uint8_t pkt[TEST_PACKET_SIZE]; - struct crypt_ctx * ctx; + struct crypt_ctx * tx; + struct crypt_ctx * rx; uint8_t key[SYMMKEYSZ]; - struct crypt_sk sk = { - .nid = NID_aes_256_gcm, - .key = key, - .rot_bit = KEY_ROTATION_BIT + struct crypt_sk sk_tx = { + .key = key, + .epoch = 0, + .role = CRYPT_ROLE_INIT + }; + struct crypt_sk sk_rx = { + .key = key, + .epoch = 0, + .role = CRYPT_ROLE_RESP }; buffer_t in; buffer_t out; buffer_t out2; const char * cipher; + sk_tx.nid = nid; + sk_rx.nid = nid; + cipher = crypt_nid_to_str(nid); TEST_START("(%s)", cipher); @@ -92,53 +103,63 @@ static int test_crypt_encrypt_decrypt(int nid) goto fail_init; } - ctx = crypt_create_ctx(&sk); - if (ctx == NULL) { - printf("Failed to initialize cryptography.\n"); + tx = crypt_create_ctx(&sk_tx); + if (tx == NULL) { + printf("Failed to initialize TX cryptography.\n"); goto fail_init; } + rx = crypt_create_ctx(&sk_rx); + if (rx == NULL) { + printf("Failed to initialize RX cryptography.\n"); + goto fail_tx; + } + in.len = sizeof(pkt); in.data = pkt; - if (crypt_encrypt(ctx, in, &out) < 0) { + if (crypt_encrypt(tx, in, &out) < 0) { printf("Encryption failed.\n"); goto fail_encrypt; } if (out.len < in.len) { printf("Encryption returned too little data.\n"); - goto fail_encrypt; + goto fail_chk; } - if (crypt_decrypt(ctx, out, &out2) < 0) { + if (crypt_decrypt(rx, out, &out2) < 0) { printf("Decryption failed.\n"); goto fail_decrypt; } if (out2.len != in.len) { printf("Decrypted data length does not match original.\n"); - goto fail_chk; + goto fail_chk2; } if (memcmp(in.data, out2.data, in.len) != 0) { printf("Decrypted data does not match original.\n"); - goto fail_chk; + goto fail_chk2; } - crypt_destroy_ctx(ctx); freebuf(out2); freebuf(out); + crypt_destroy_ctx(rx); + crypt_destroy_ctx(tx); TEST_SUCCESS("(%s)", cipher); return TEST_RC_SUCCESS; - fail_chk: + fail_chk2: freebuf(out2); fail_decrypt: + fail_chk: freebuf(out); fail_encrypt: - crypt_destroy_ctx(ctx); + crypt_destroy_ctx(rx); + fail_tx: + crypt_destroy_ctx(tx); fail_init: TEST_FAIL("(%s)", cipher); return TEST_RC_FAIL; @@ -155,6 +176,214 @@ static int test_encrypt_decrypt_all(void) return ret; } +static int test_crypt_multi_packet(int nid) +{ + uint8_t pkt[TEST_PACKET_SIZE]; + struct crypt_ctx * tx; + struct crypt_ctx * rx; + uint8_t key[SYMMKEYSZ]; + struct crypt_sk sk_tx = { + .key = key, + .epoch = 0, + .role = CRYPT_ROLE_INIT + }; + struct crypt_sk sk_rx = { + .key = key, + .epoch = 0, + .role = CRYPT_ROLE_RESP + }; + buffer_t in; + buffer_t enc; + buffer_t dec; + const char * cipher; + int i; + + sk_tx.nid = nid; + sk_rx.nid = nid; + + cipher = crypt_nid_to_str(nid); + TEST_START("(%s)", cipher); + + if (random_buffer(key, sizeof(key)) < 0) { + printf("Failed to generate random key.\n"); + goto fail_init; + } + + if (random_buffer(pkt, sizeof(pkt)) < 0) { + printf("Failed to generate random data.\n"); + goto fail_init; + } + + tx = crypt_create_ctx(&sk_tx); + if (tx == NULL) { + printf("Failed to create TX context.\n"); + goto fail_init; + } + + rx = crypt_create_ctx(&sk_rx); + if (rx == NULL) { + printf("Failed to create RX context.\n"); + goto fail_tx; + } + + in.len = sizeof(pkt); + in.data = pkt; + + for (i = 0; i < TEST_N_PACKETS; i++) { + if (crypt_encrypt(tx, in, &enc) < 0) { + printf("Encryption failed at packet %d.\n", i); + goto fail_rx; + } + + if (crypt_decrypt(rx, enc, &dec) < 0) { + printf("Decryption failed at packet %d.\n", i); + freebuf(enc); + goto fail_rx; + } + + if (dec.len != in.len || + memcmp(in.data, dec.data, in.len) != 0) { + printf("Data mismatch at packet %d.\n", i); + freebuf(dec); + freebuf(enc); + goto fail_rx; + } + + freebuf(dec); + freebuf(enc); + } + + crypt_destroy_ctx(rx); + crypt_destroy_ctx(tx); + + TEST_SUCCESS("(%s)", cipher); + + return TEST_RC_SUCCESS; + fail_rx: + crypt_destroy_ctx(rx); + fail_tx: + crypt_destroy_ctx(tx); + fail_init: + TEST_FAIL("(%s)", cipher); + return TEST_RC_FAIL; +} + +static int test_multi_packet_all(void) +{ + int ret = 0; + int i; + + for (i = 0; crypt_supported_nids[i] != NID_undef; i++) + ret |= test_crypt_multi_packet(crypt_supported_nids[i]); + + return ret; +} + +static int test_crypt_aad_tamper(int nid) +{ + uint8_t pkt[TEST_PACKET_SIZE]; + struct crypt_ctx * tx; + struct crypt_ctx * rx; + uint8_t key[SYMMKEYSZ]; + struct crypt_sk sk_tx = { + .key = key, + .epoch = 0, + .role = CRYPT_ROLE_INIT + }; + struct crypt_sk sk_rx = { + .key = key, + .epoch = 0, + .role = CRYPT_ROLE_RESP + }; + buffer_t in; + buffer_t enc; + buffer_t dec; + const char * cipher; + + sk_tx.nid = nid; + sk_rx.nid = nid; + + cipher = crypt_nid_to_str(nid); + TEST_START("(%s)", cipher); + + if (random_buffer(key, sizeof(key)) < 0) { + printf("Failed to generate random key.\n"); + goto fail_init; + } + + if (random_buffer(pkt, sizeof(pkt)) < 0) { + printf("Failed to generate random data.\n"); + goto fail_init; + } + + tx = crypt_create_ctx(&sk_tx); + if (tx == NULL) { + printf("Failed to create TX context.\n"); + goto fail_init; + } + + rx = crypt_create_ctx(&sk_rx); + if (rx == NULL) { + printf("Failed to create RX context.\n"); + goto fail_tx; + } + + /* Only AEAD ciphers bind the selector as AAD. */ + if (crypt_get_tagsz(tx) == 0) { + crypt_destroy_ctx(rx); + crypt_destroy_ctx(tx); + + TEST_SUCCESS("(%s)", cipher); + + return TEST_RC_SUCCESS; + } + + in.len = sizeof(pkt); + in.data = pkt; + + if (crypt_encrypt(tx, in, &enc) < 0) { + printf("Encryption failed.\n"); + goto fail_rx; + } + + /* Flip a seq byte: epoch/node stay valid so the AEAD tag rejects. */ + enc.data[5] ^= 0x01; + + if (crypt_decrypt(rx, enc, &dec) == 0) { + printf("Decryption accepted a tampered selector.\n"); + freebuf(dec); + freebuf(enc); + goto fail_rx; + } + + freebuf(enc); + + crypt_destroy_ctx(rx); + crypt_destroy_ctx(tx); + + TEST_SUCCESS("(%s)", cipher); + + return TEST_RC_SUCCESS; + fail_rx: + crypt_destroy_ctx(rx); + fail_tx: + crypt_destroy_ctx(tx); + fail_init: + TEST_FAIL("(%s)", cipher); + return TEST_RC_FAIL; +} + +static int test_aad_tamper_all(void) +{ + int ret = 0; + int i; + + for (i = 0; crypt_supported_nids[i] != NID_undef; i++) + ret |= test_crypt_aad_tamper(crypt_supported_nids[i]); + + return ret; +} + #ifdef HAVE_OPENSSL #include <openssl/evp.h> #include <openssl/obj_mac.h> @@ -256,109 +485,17 @@ static int test_md_nid_values(void) } #endif -static int test_key_rotation(void) +static int test_crypt_headsz(void) { - uint8_t pkt[TEST_PACKET_SIZE]; - struct crypt_ctx * tx_ctx; - struct crypt_ctx * rx_ctx; - uint8_t key[SYMMKEYSZ]; - struct crypt_sk sk = { - .nid = NID_aes_256_gcm, - .key = key, - .rot_bit = 7 - }; - buffer_t in; - buffer_t enc; - buffer_t dec; - uint32_t i; - uint32_t threshold; - - TEST_START(); - - if (random_buffer(key, sizeof(key)) < 0) { - printf("Failed to generate random key.\n"); - goto fail; - } - - if (random_buffer(pkt, sizeof(pkt)) < 0) { - printf("Failed to generate random data.\n"); - goto fail; - } - - tx_ctx = crypt_create_ctx(&sk); - if (tx_ctx == NULL) { - printf("Failed to create TX context.\n"); - goto fail; - } - - rx_ctx = crypt_create_ctx(&sk); - if (rx_ctx == NULL) { - printf("Failed to create RX context.\n"); - goto fail_tx; - } - - in.len = sizeof(pkt); - in.data = pkt; - - threshold = (1U << sk.rot_bit); - - /* Encrypt and decrypt across multiple rotations */ - for (i = 0; i < threshold * 3; i++) { - if (crypt_encrypt(tx_ctx, in, &enc) < 0) { - printf("Encryption failed at packet %u.\n", i); - goto fail_rx; - } - - if (crypt_decrypt(rx_ctx, enc, &dec) < 0) { - printf("Decryption failed at packet %u.\n", i); - freebuf(enc); - goto fail_rx; - } - - if (dec.len != in.len || - memcmp(in.data, dec.data, in.len) != 0) { - printf("Data mismatch at packet %u.\n", i); - freebuf(dec); - freebuf(enc); - goto fail_rx; - } - - freebuf(dec); - freebuf(enc); - } - - crypt_destroy_ctx(rx_ctx); - crypt_destroy_ctx(tx_ctx); - - TEST_SUCCESS(); - - return TEST_RC_SUCCESS; - fail_rx: - crypt_destroy_ctx(rx_ctx); - fail_tx: - crypt_destroy_ctx(tx_ctx); - fail: - TEST_FAIL(); - return TEST_RC_FAIL; -} - -static int test_key_phase_bit(void) -{ - uint8_t pkt[TEST_PACKET_SIZE]; struct crypt_ctx * ctx; uint8_t key[SYMMKEYSZ]; struct crypt_sk sk = { - .nid = NID_aes_256_gcm, - .key = key, - .rot_bit = 7 + .nid = NID_aes_256_gcm, + .key = key, + .epoch = 0, + .role = CRYPT_ROLE_INIT }; - buffer_t in; - buffer_t out; - uint32_t count; - uint32_t threshold; - uint8_t phase_before; - uint8_t phase_after; - int ivsz; + int headsz; TEST_START(); @@ -367,58 +504,15 @@ static int test_key_phase_bit(void) goto fail; } - if (random_buffer(pkt, sizeof(pkt)) < 0) { - printf("Failed to generate random data.\n"); - goto fail; - } - ctx = crypt_create_ctx(&sk); if (ctx == NULL) { printf("Failed to initialize cryptography.\n"); goto fail; } - ivsz = crypt_get_ivsz(ctx); - if (ivsz <= 0) { - printf("Invalid IV size.\n"); - goto fail_ctx; - } - - in.len = sizeof(pkt); - in.data = pkt; - - /* Encrypt packets up to just before rotation threshold */ - threshold = (1U << sk.rot_bit); - - /* Encrypt threshold - 1 packets (indices 0 to threshold-2) */ - for (count = 0; count < threshold - 1; count++) { - if (crypt_encrypt(ctx, in, &out) < 0) { - printf("Encryption failed at count %u.\n", count); - goto fail_ctx; - } - freebuf(out); - } - - /* Packet at index threshold-1: phase should still be initial */ - if (crypt_encrypt(ctx, in, &out) < 0) { - printf("Encryption failed before rotation.\n"); - goto fail_ctx; - } - phase_before = (out.data[0] & 0x80) ? 1 : 0; - freebuf(out); - - /* Packet at index threshold: phase should have toggled */ - if (crypt_encrypt(ctx, in, &out) < 0) { - printf("Encryption failed at rotation threshold.\n"); - goto fail_ctx; - } - phase_after = (out.data[0] & 0x80) ? 1 : 0; - freebuf(out); - - /* Phase bit should have toggled */ - if (phase_before == phase_after) { - printf("Phase bit did not toggle: before=%u, after=%u.\n", - phase_before, phase_after); + headsz = crypt_get_headsz(ctx); + if (headsz != 6) { + printf("Unexpected header size: %d (expected 6).\n", headsz); goto fail_ctx; } @@ -447,11 +541,13 @@ int crypt_test(int argc, #ifdef HAVE_OPENSSL ret |= test_cipher_nid_values(); ret |= test_md_nid_values(); - ret |= test_key_rotation(); - ret |= test_key_phase_bit(); + ret |= test_multi_packet_all(); + ret |= test_aad_tamper_all(); + ret |= test_crypt_headsz(); #else - (void) test_key_rotation; - (void) test_key_phase_bit; + (void) test_multi_packet_all; + (void) test_aad_tamper_all; + (void) test_crypt_headsz; return TEST_RC_SKIP; #endif |
