summaryrefslogtreecommitdiff
path: root/src/lib/tests/crypt_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/tests/crypt_test.c')
-rw-r--r--src/lib/tests/crypt_test.c385
1 files changed, 293 insertions, 92 deletions
diff --git a/src/lib/tests/crypt_test.c b/src/lib/tests/crypt_test.c
index e7a09e8f..028c4eb5 100644
--- a/src/lib/tests/crypt_test.c
+++ b/src/lib/tests/crypt_test.c
@@ -1,5 +1,5 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2024
+ * Ouroboros - Copyright (C) 2016 - 2026
*
* Test of the cryptography functions
*
@@ -22,20 +22,33 @@
#include "config.h"
-#include <ouroboros/test.h>
-#include <ouroboros/crypt.h>
+#include <test/test.h>
#include <ouroboros/random.h>
+#include <ouroboros/crypt.h>
#include <ouroboros/utils.h>
+#include <stdio.h>
+
#define TEST_PACKET_SIZE 1500
+extern const uint16_t crypt_supported_nids[];
+extern const uint16_t md_supported_nids[];
+
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
+ };
TEST_START();
- ctx = crypt_create_ctx(NULL);
+ memset(key, 0, sizeof(key));
+
+ ctx = crypt_create_ctx(&sk);
if (ctx == NULL) {
printf("Failed to initialize cryptography.\n");
goto fail;
@@ -51,44 +64,155 @@ static int test_crypt_create_destroy(void)
return TEST_RC_FAIL;
}
-static int test_crypt_create_destroy_with_key(void)
+static int test_crypt_encrypt_decrypt(int nid)
{
+ 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 = KEY_ROTATION_BIT
+ };
+ buffer_t in;
+ buffer_t out;
+ buffer_t out2;
+ const char * cipher;
- TEST_START();
+ cipher = crypt_nid_to_str(nid);
+ TEST_START("(%s)", cipher);
- memset(key, 0, sizeof(key));
+ 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;
+ }
- ctx = crypt_create_ctx(key);
+ ctx = crypt_create_ctx(&sk);
if (ctx == NULL) {
printf("Failed to initialize cryptography.\n");
- goto fail;
+ goto fail_init;
+ }
+
+ in.len = sizeof(pkt);
+ in.data = pkt;
+
+ if (crypt_encrypt(ctx, 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;
+ }
+
+ if (crypt_decrypt(ctx, 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;
+ }
+
+ if (memcmp(in.data, out2.data, in.len) != 0) {
+ printf("Decrypted data does not match original.\n");
+ goto fail_chk;
}
crypt_destroy_ctx(ctx);
+ freebuf(out2);
+ freebuf(out);
- TEST_SUCCESS();
+ TEST_SUCCESS("(%s)", cipher);
return TEST_RC_SUCCESS;
- fail:
- TEST_FAIL();
+ fail_chk:
+ freebuf(out2);
+ fail_decrypt:
+ freebuf(out);
+ fail_encrypt:
+ crypt_destroy_ctx(ctx);
+ fail_init:
+ TEST_FAIL("(%s)", cipher);
return TEST_RC_FAIL;
}
-static int test_crypt_dh_pkp_create_destroy(void)
+static int test_encrypt_decrypt_all(void)
+{
+ int ret = 0;
+ int i;
+
+ for (i = 0; crypt_supported_nids[i] != NID_undef; i++)
+ ret |= test_crypt_encrypt_decrypt(crypt_supported_nids[i]);
+
+ return ret;
+}
+
+#ifdef HAVE_OPENSSL
+#include <openssl/evp.h>
+#include <openssl/obj_mac.h>
+
+static int test_cipher_nid_values(void)
{
- void * pkp;
- uint8_t buf[MSGBUFSZ];
+ int i;
TEST_START();
- if (crypt_dh_pkp_create(&pkp, buf) < 0) {
- printf("Failed to create DH PKP.");
+ /* Loop over all supported ciphers and verify NIDs match OpenSSL's */
+ for (i = 0; crypt_supported_nids[i] != NID_undef; i++) {
+ uint16_t our_nid = crypt_supported_nids[i];
+ const char * str = crypt_nid_to_str(our_nid);
+ const EVP_CIPHER * cipher;
+ int openssl_nid;
+
+ if (str == NULL) {
+ printf("crypt_nid_to_str failed for NID %u\n", our_nid);
+ goto fail;
+ }
+
+ cipher = EVP_get_cipherbyname(str);
+ if (cipher == NULL) {
+ printf("OpenSSL doesn't recognize cipher '%s'\n", str);
+ goto fail;
+ }
+
+ openssl_nid = EVP_CIPHER_nid(cipher);
+
+ if (our_nid != openssl_nid) {
+ printf("NID mismatch for '%s': ours=%u, OpenSSL=%d\n",
+ str, our_nid, openssl_nid);
+ goto fail;
+ }
+
+ /* Test reverse conversion */
+ if (crypt_str_to_nid(str) != our_nid) {
+ printf("crypt_str_to_nid failed for '%s'\n", str);
+ goto fail;
+ }
+ }
+
+ /* Test error cases */
+ if (crypt_str_to_nid("invalid") != NID_undef) {
+ printf("crypt_str_to_nid: no NID_undef for invalid.\n");
goto fail;
}
- crypt_dh_pkp_destroy(pkp);
+ if (crypt_nid_to_str(9999) != NULL) {
+ printf("crypt_nid_to_str should return NULL for invalid NID\n");
+ goto fail;
+ }
+
+ if (crypt_str_to_nid(NULL) != NID_undef) {
+ printf("crypt_str_to_nid should return NID_undef for NULL\n");
+ goto fail;
+ }
TEST_SUCCESS();
@@ -98,137 +222,214 @@ static int test_crypt_dh_pkp_create_destroy(void)
return TEST_RC_FAIL;
}
-static int test_crypt_dh_derive(void)
+static int test_md_nid_values(void)
{
- void * pkp1;
- void * pkp2;
- buffer_t pk1;
- buffer_t pk2;
- ssize_t len;
- uint8_t buf1[MSGBUFSZ];
- uint8_t buf2[MSGBUFSZ];
- uint8_t s1[SYMMKEYSZ];
- uint8_t s2[SYMMKEYSZ];
+ int i;
TEST_START();
- len = crypt_dh_pkp_create(&pkp1, buf1);
- if (len < 0) {
- printf("Failed to create first key pair.");
- goto fail_pkp1;
+ for (i = 0; md_supported_nids[i] != NID_undef; i++) {
+ uint16_t our_nid = md_supported_nids[i];
+ const EVP_MD * md;
+ int openssl_nid;
+
+ md = EVP_get_digestbynid(our_nid);
+ if (md == NULL) {
+ printf("OpenSSL doesn't recognize NID %u\n", our_nid);
+ goto fail;
+ }
+
+ openssl_nid = EVP_MD_nid(md);
+ if (our_nid != openssl_nid) {
+ printf("NID mismatch: ours=%u, OpenSSL=%d\n",
+ our_nid, openssl_nid);
+ goto fail;
+ }
}
- pk1.len = (size_t) len;
- pk1.data = buf1;
+ TEST_SUCCESS();
- len = crypt_dh_pkp_create(&pkp2, buf2);
- if (len < 0) {
- printf("Failed to create second key pair.");
- goto fail_pkp2;
- }
+ return TEST_RC_SUCCESS;
+ fail:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+#endif
+
+static int test_key_rotation(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;
- pk2.len = (size_t) len;
- pk2.data = buf2;
+ TEST_START();
- if (crypt_dh_derive(pkp1, pk2, s1) < 0) {
- printf("Failed to derive first key.");
+ if (random_buffer(key, sizeof(key)) < 0) {
+ printf("Failed to generate random key.\n");
goto fail;
}
- if (crypt_dh_derive(pkp2, pk1, s2) < 0) {
- printf("Failed to derive second key.");
+ if (random_buffer(pkt, sizeof(pkt)) < 0) {
+ printf("Failed to generate random data.\n");
goto fail;
}
- if (memcmp(s1, s2, SYMMKEYSZ) != 0) {
- printf("Derived keys do not match.");
+ tx_ctx = crypt_create_ctx(&sk);
+ if (tx_ctx == NULL) {
+ printf("Failed to create TX context.\n");
goto fail;
}
- crypt_dh_pkp_destroy(pkp2);
- crypt_dh_pkp_destroy(pkp1);
+ 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:
- crypt_dh_pkp_destroy(pkp2);
- fail_pkp2:
- crypt_dh_pkp_destroy(pkp1);
- fail_pkp1:
TEST_FAIL();
return TEST_RC_FAIL;
}
-int test_crypt_encrypt_decrypt(void)
+static int test_key_phase_bit(void)
{
uint8_t pkt[TEST_PACKET_SIZE];
- uint8_t key[SYMMKEYSZ];
struct crypt_ctx * ctx;
+ uint8_t key[SYMMKEYSZ];
+ struct crypt_sk sk = {
+ .nid = NID_aes_256_gcm,
+ .key = key,
+ .rot_bit = 7
+ };
buffer_t in;
buffer_t out;
- buffer_t out2;
+ uint32_t count;
+ uint32_t threshold;
+ uint8_t phase_before;
+ uint8_t phase_after;
+ int ivsz;
TEST_START();
if (random_buffer(key, sizeof(key)) < 0) {
printf("Failed to generate random key.\n");
- goto fail_init;
+ goto fail;
}
if (random_buffer(pkt, sizeof(pkt)) < 0) {
printf("Failed to generate random data.\n");
- goto fail_init;
+ goto fail;
}
- ctx = crypt_create_ctx(key);
+ ctx = crypt_create_ctx(&sk);
if (ctx == NULL) {
printf("Failed to initialize cryptography.\n");
- goto fail_init;
+ 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;
- if (crypt_encrypt(ctx, in, &out) < 0) {
- printf("Encryption failed.\n");
- goto fail_encrypt;
- }
+ /* Encrypt packets up to just before rotation threshold */
+ threshold = (1U << sk.rot_bit);
- if (out.len < in.len) {
- printf("Encryption returned too little data.\n");
- goto fail_encrypt;
+ /* 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);
}
- if (crypt_decrypt(ctx, out, &out2) < 0) {
- printf("Decryption failed.\n");
- goto fail_decrypt;
+ /* 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);
- if (out2.len != in.len) {
- printf("Decrypted data length does not match original.\n");
- goto fail_chk;
+ /* 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);
- if (memcmp(in.data, out2.data, in.len) != 0) {
- printf("Decrypted data does not match original.\n");
- goto fail_chk;
+ /* 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);
+ goto fail_ctx;
}
crypt_destroy_ctx(ctx);
- freebuf(out2);
- freebuf(out);
TEST_SUCCESS();
return TEST_RC_SUCCESS;
- fail_chk:
- freebuf(out2);
- fail_decrypt:
- freebuf(out);
- fail_encrypt:
+ fail_ctx:
crypt_destroy_ctx(ctx);
- fail_init:
+ fail:
TEST_FAIL();
return TEST_RC_FAIL;
}
@@ -242,17 +443,17 @@ int crypt_test(int argc,
(void) argv;
ret |= test_crypt_create_destroy();
- ret |= test_crypt_create_destroy_with_key();
+ ret |= test_encrypt_decrypt_all();
#ifdef HAVE_OPENSSL
- ret |= test_crypt_dh_pkp_create_destroy();
- ret |= test_crypt_dh_derive();
- ret |= test_crypt_encrypt_decrypt();
+ ret |= test_cipher_nid_values();
+ ret |= test_md_nid_values();
+ ret |= test_key_rotation();
+ ret |= test_key_phase_bit();
#else
- (void) test_crypt_dh_pkp_create_destroy;
- (void) test_crypt_dh_derive;
- (void) test_crypt_encrypt_decrypt;
+ (void) test_key_rotation;
+ (void) test_key_phase_bit;
- ret = TEST_RC_SKIP;
+ return TEST_RC_SKIP;
#endif
return ret;
}