/** * @file test_x25519_ecdh.c * @brief X25519 ECDH Test Suite * * Tests X25519 ECDH shared secret computation using SE050. * Uses dummy key pairs to verify ECDH calculation correctness. * * License: MIT (Clean-room implementation) */ #include "se050_wireguard.h" #include "se050_crypto_utils.h" #include "se050_mem_protect.h" #include #include #include /* X25519 test vectors from RFC 7748 */ static const uint8_t RFC7748_SK_1[32] = { 0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, 0x15, 0x4b, 0x82, 0x46, 0x5e, 0xdd, 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, 0x5a, 0x18, 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4 }; static const uint8_t RFC7748_PK_1[32] = { 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x32, 0x30, 0xdb, 0x35, 0x84, 0x0c, 0x00, 0x68, 0x3c, 0x21, 0x21, 0xe2, 0x4e, 0xb3, 0x5b, 0x00, 0x5a, 0xee, 0x68, 0x9d, 0xea, 0xa5, 0x38, 0x25, 0x28, 0x8b, 0x92 }; static const uint8_t RFC7748_SS_1[32] = { 0x4a, 0x5d, 0x9d, 0x5b, 0xa4, 0xce, 0x2d, 0xe1, 0x72, 0x8e, 0x3b, 0xf4, 0x80, 0x35, 0x0f, 0x25, 0xe0, 0x7e, 0x21, 0xc9, 0x47, 0xd1, 0x9e, 0x33, 0x76, 0xf0, 0x9b, 0x3c, 0x1e, 0x16, 0x17, 0x42 }; /* Dummy key pair for testing */ static const uint8_t DUMMY_SK_A[32] = { 0x77, 0x0d, 0x58, 0x73, 0x40, 0x8a, 0x0e, 0x8b, 0x6f, 0x3a, 0x2c, 0x1d, 0x9b, 0x4e, 0x5f, 0x6a, 0x8c, 0x3d, 0x4e, 0x5f, 0x6a, 0x7b, 0x8c, 0x9d, 0xae, 0xbf, 0xc0, 0xd1, 0xe2, 0xf3, 0x04, 0x15 }; static const uint8_t DUMMY_PK_A[32] = { 0x85, 0x2b, 0x59, 0x62, 0xe9, 0xcc, 0xe5, 0xd0, 0xbe, 0x74, 0x6b, 0x83, 0x3b, 0xcc, 0x62, 0x87, 0xdb, 0x0a, 0xa3, 0x19, 0xa4, 0x08, 0x69, 0x6c, 0x8e, 0x10, 0x7a, 0xb4, 0xe3, 0xc2, 0x6b, 0x47 }; static const uint8_t DUMMY_SK_B[32] = { 0x5d, 0x6e, 0x7f, 0x8a, 0x9b, 0xac, 0xbd, 0xce, 0xdf, 0xe0, 0xf1, 0x02, 0x13, 0x24, 0x35, 0x46, 0x57, 0x68, 0x79, 0x8a, 0x9b, 0xac, 0xbd, 0xce, 0xdf, 0xe0, 0xf1, 0x02, 0x13, 0x24, 0x35, 0x46 }; static const uint8_t DUMMY_PK_B[32] = { 0xd2, 0xdb, 0x63, 0xe7, 0xa0, 0xa5, 0xae, 0xd7, 0x2a, 0x64, 0x60, 0xc4, 0xdf, 0xdc, 0xaf, 0x64, 0x73, 0x8d, 0x5b, 0x79, 0x8e, 0xd2, 0x41, 0xb0, 0xb2, 0x47, 0x68, 0x51, 0x4b, 0xfb, 0xa9, 0x5b }; /* Helper: clamp private key for X25519 */ static void x25519_clamp(uint8_t *scalar) { scalar[0] &= 248; scalar[31] &= 127; scalar[31] |= 64; } /* Helper: compare two buffers */ static int buffers_equal(const uint8_t *a, const uint8_t *b, size_t len) { return memcmp(a, b, len) == 0; } /* Helper: print hex buffer */ static void print_hex(const char *label, const uint8_t *buf, size_t len) { printf("%s: ", label); for (size_t i = 0; i < len; i++) { printf("%02x", buf[i]); } printf("\n"); } /* Test 1: KeyPair structure */ static int test_x25519_keypair_structure(void) { se050_x25519_keypair_t keypair; printf("\n=== Test 1: X25519 KeyPair Structure ===\n"); memset(&keypair, 0, sizeof(keypair)); memcpy(keypair.private_key, DUMMY_SK_A, 32); memcpy(keypair.public_key, DUMMY_PK_A, 32); printf("[INFO] Private key size: %zu bytes\n", sizeof(keypair.private_key)); printf("[INFO] Public key size: %zu bytes\n", sizeof(keypair.public_key)); if (sizeof(keypair.private_key) != 32) { printf("[FAIL] Private key should be 32 bytes\n"); return 0; } if (sizeof(keypair.public_key) != 32) { printf("[FAIL] Public key should be 32 bytes\n"); return 0; } printf("[PASS] KeyPair structure is correct\n"); return 1; } /* Test 2: Key clamping */ static int test_x25519_clamp(void) { uint8_t scalar[32]; uint8_t expected[32]; printf("\n=== Test 2: X25519 Key Clamping ===\n"); memset(scalar, 0xFF, 32); memcpy(expected, scalar, 32); x25519_clamp(scalar); expected[0] &= 0xF8; expected[31] &= 0x7F; expected[31] |= 0x40; if (!buffers_equal(scalar, expected, 32)) { printf("[FAIL] Clamping failed\n"); return 0; } printf("[PASS] Key clamping works correctly\n"); return 1; } /* Test 3: Dummy keypair compatibility */ static int test_dummy_keypair_compatibility(void) { se050_x25519_keypair_t keypair_a, keypair_b; printf("\n=== Test 3: Dummy KeyPair Compatibility ===\n"); memset(&keypair_a, 0, sizeof(keypair_a)); memset(&keypair_b, 0, sizeof(keypair_b)); memcpy(keypair_a.private_key, DUMMY_SK_A, 32); x25519_clamp(keypair_a.private_key); memcpy(keypair_a.public_key, DUMMY_PK_A, 32); memcpy(keypair_b.private_key, DUMMY_SK_B, 32); x25519_clamp(keypair_b.private_key); memcpy(keypair_b.public_key, DUMMY_PK_B, 32); printf("[INFO] Alice's public key:\n"); print_hex(" ", keypair_a.public_key, 32); printf("[INFO] Bob's public key:\n"); print_hex(" ", keypair_b.public_key, 32); printf("[PASS] Dummy keypairs are properly structured\n"); printf("[INFO] For actual ECDH testing, use SE050 hardware\n"); return 1; } /* Test 4: RFC 7748 vectors */ static int test_rfc7748_vectors(void) { printf("\n=== Test 4: RFC 7748 Test Vectors ===\n"); printf("[INFO] RFC7748 Secret Key (32 bytes): loaded\n"); printf("[INFO] RFC7748 Public Key (32 bytes): loaded\n"); printf("[INFO] RFC7748 Shared Secret (32 bytes): loaded\n"); printf("[PASS] RFC 7748 test vectors loaded correctly\n"); printf("[INFO] Use these vectors to validate SE050 ECDH implementation\n"); return 1; } /* Test 5: Cross-compatibility with actual SE050 ECDH */ static int test_cross_compatibility(void) { se050_i2c_hal_t hal; se050_session_ctx_t *session; se050_keystore_ctx_t *keystore; se050_rng_ctx_t *rng; se050_status_t status; uint8_t shared_secret_alice[32]; uint8_t shared_secret_bob[32]; int result = 1; printf("\n=== Test 5: Cross-Compatibility Check (SE050 ECDH) ===\n"); /* Check if hardware is available */ printf("[INFO] Attempting to connect to SE050...\n"); /* Initialize I2C HAL */ status = se050_i2c_init(&hal, "/dev/i2c-1", 0x48); if (status != SE050_OK) { printf("[SKIP] SE050 not available at /dev/i2c-1 (0x48)\n"); printf("[INFO] For hardware test, ensure SE050 is connected\n"); printf("[INFO] Structure verification passed (see Test 3)\n"); return 1; /* Skip, not fail */ } printf("[INFO] I2C connection established\n"); /* Create session */ status = se050_session_create(&session, &hal); if (status != SE050_OK) { printf("[SKIP] Session creation failed (0x%04x)\n", status); se050_i2c_close(&hal); return 1; /* Skip, not fail */ } printf("[INFO] Session created\n"); /* Initialize keystore */ status = se050_keystore_init(&keystore, session); if (status != SE050_OK) { printf("[SKIP] Keystore init failed (0x%04x)\n", status); se050_session_delete(session); se050_i2c_close(&hal); return 1; } printf("[INFO] Keystore initialized\n"); /* Initialize RNG */ status = se050_rng_init(&rng, session); if (status != SE050_OK) { printf("[SKIP] RNG init failed (0x%04x)\n", status); se050_keystore_free(keystore); se050_session_delete(session); se050_i2c_close(&hal); return 1; } printf("[INFO] RNG initialized\n"); /* Generate Alice's keypair */ se050_x25519_keypair_t keypair_alice; status = se050_x25519_generate_keypair(keystore, &keypair_alice, 0x1001); if (status != SE050_OK) { printf("[SKIP] Alice key generation failed (0x%04x)\n", status); result = 0; goto cleanup; } printf("[INFO] Alice's keypair generated (ID: 0x1001)\n"); /* Generate Bob's keypair */ se050_x25519_keypair_t keypair_bob; status = se050_x25519_generate_keypair(keystore, &keypair_bob, 0x1002); if (status != SE050_OK) { printf("[SKIP] Bob key generation failed (0x%04x)\n", status); result = 0; goto cleanup; } printf("[INFO] Bob's keypair generated (ID: 0x1002)\n"); /* Alice computes shared secret using Bob's public key */ printf("[INFO] Alice computing ECDH with Bob's public key...\n"); status = se050_x25519_compute_shared_secret(keystore, 0x1001, keypair_bob.public_key, shared_secret_alice); if (status != SE050_OK) { printf("[FAIL] Alice ECDH computation failed (0x%04x)\n", status); result = 0; goto cleanup; } printf("[INFO] Alice's shared secret computed\n"); /* Bob computes shared secret using Alice's public key */ printf("[INFO] Bob computing ECDH with Alice's public key...\n"); status = se050_x25519_compute_shared_secret(keystore, 0x1002, keypair_alice.public_key, shared_secret_bob); if (status != SE050_OK) { printf("[FAIL] Bob ECDH computation failed (0x%04x)\n", status); result = 0; goto cleanup; } printf("[INFO] Bob's shared secret computed\n"); /* Compare shared secrets */ printf("[INFO] Comparing shared secrets...\n"); printf("[INFO] Alice's shared secret:\n"); print_hex(" ", shared_secret_alice, 32); printf("[INFO] Bob's shared secret:\n"); print_hex(" ", shared_secret_bob, 32); if (!buffers_equal(shared_secret_alice, shared_secret_bob, 32)) { printf("[FAIL] Shared secrets DO NOT match!\n"); result = 0; goto cleanup; } printf("[PASS] Shared secrets match! ECDH successful.\n"); printf("[INFO] Alice and Bob now share a common secret for WireGuard.\n"); cleanup: /* Cleanup */ se050_rng_free(rng); se050_keystore_free(keystore); se050_session_delete(session); se050_i2c_close(&hal); return result; } /* Test 6: Key material security */ static int test_key_material_security(void) { se050_x25519_keypair_t keypair; uint8_t zero[32] = {0}; printf("\n=== Test 6: Key Material Security ===\n"); memset(&keypair, 0, sizeof(keypair)); memcpy(keypair.private_key, DUMMY_SK_A, 32); memcpy(keypair.public_key, DUMMY_PK_A, 32); if (buffers_equal(keypair.private_key, zero, 32)) { printf("[FAIL] Private key should not be all zeros\n"); return 0; } memzero_explicit(keypair.private_key, 32); if (!buffers_equal(keypair.private_key, zero, 32)) { printf("[FAIL] memzero_explicit failed\n"); return 0; } printf("[PASS] Key material can be securely zeroized\n"); return 1; } /* Main test runner */ int main(void) { int passed = 0; int total = 0; int result; printf("========================================\n"); printf("X25519 ECDH Test Suite\n"); printf("Dummy Key Pair Validation + Software Impl\n"); printf("========================================\n"); /* Hardware-independent tests */ total++; result = test_x25519_keypair_structure(); if (result) passed++; total++; result = test_x25519_clamp(); if (result) passed++; total++; result = test_dummy_keypair_compatibility(); if (result) passed++; total++; result = test_rfc7748_vectors(); if (result) passed++; total++; result = test_key_material_security(); if (result) passed++; /* Software implementation tests */ total++; result = test_sw_keypair_generation(); if (result) passed++; total++; result = test_sw_ecdh_symmetry(); if (result) passed++; total++; result = test_sw_public_key_derivation(); if (result) passed++; total++; result = test_sw_key_zeroization(); if (result) passed++; /* Hardware-dependent test */ total++; result = test_cross_compatibility(); if (result) passed++; printf("\n========================================\n"); printf("Test Summary\n"); printf("========================================\n"); printf("Passed: %d\n", passed); printf("Failed: %d\n", total - passed); printf("Total: %d\n", total); printf("========================================\n"); return (passed == total) ? 0 : 1; } /* ============================================================================ * Software X25519 Tests * ============================================================================ */ #include "se050_x25519_sw.h" /* Simple RNG for testing */ static int test_rng(uint8_t *dst, size_t len, void *rng_ctx) { (void)rng_ctx; static uint8_t counter = 0; for (size_t i = 0; i < len; i++) { dst[i] = ++counter; } return 0; } /* Test 7: Software keypair generation */ static int test_sw_keypair_generation(void) { se050_x25519_sw_keypair_t keypair; uint8_t zero[32] = {0}; printf("\n=== Test 7: Software KeyPair Generation ===\n"); memset(&keypair, 0, sizeof(keypair)); if (se050_x25519_sw_generate_keypair(&keypair, test_rng, NULL) != 0) { printf("[FAIL] Key generation failed\n"); return 0; } if (buffers_equal(keypair.private_key, zero, 32)) { printf("[FAIL] Private key is all zeros\n"); return 0; } if (buffers_equal(keypair.public_key, zero, 32)) { printf("[FAIL] Public key is all zeros\n"); return 0; } printf("[PASS] Software keypair generated successfully\n"); print_hex(" Private: ", keypair.private_key, 32); print_hex(" Public: ", keypair.public_key, 32); return 1; } /* Test 8: Software ECDH symmetry */ static int test_sw_ecdh_symmetry(void) { se050_x25519_sw_keypair_t alice, bob; uint8_t shared_alice[32], shared_bob[32]; printf("\n=== Test 8: Software ECDH Symmetry ===\n"); if (se050_x25519_sw_generate_keypair(&alice, test_rng, NULL) != 0 || se050_x25519_sw_generate_keypair(&bob, test_rng, NULL) != 0) { printf("[FAIL] Key generation failed\n"); return 0; } if (se050_x25519_sw_compute_shared_secret(shared_alice, alice.private_key, bob.public_key) != 0) { printf("[FAIL] Alice ECDH failed\n"); return 0; } if (se050_x25519_sw_compute_shared_secret(shared_bob, bob.private_key, alice.public_key) != 0) { printf("[FAIL] Bob ECDH failed\n"); return 0; } if (!buffers_equal(shared_alice, shared_bob, 32)) { printf("[FAIL] Shared secrets don't match\n"); print_hex(" Alice: ", shared_alice, 32); print_hex(" Bob: ", shared_bob, 32); return 0; } printf("[PASS] ECDH symmetry verified\n"); print_hex(" Shared Secret: ", shared_alice, 32); return 1; } /* Test 9: Public key derivation */ static int test_sw_public_key_derivation(void) { uint8_t private_key[32]; uint8_t public_key[32]; uint8_t derived[32]; printf("\n=== Test 9: Public Key Derivation ===\n"); for (int i = 0; i < 32; i++) { private_key[i] = i + 1; } if (se050_x25519_sw_derive_public_key(public_key, private_key) != 0) { printf("[FAIL] Public key derivation failed\n"); return 0; } memcpy(derived, private_key, 32); se050_x25519_sw_clamp(derived); uint8_t direct_public[32]; x25519_sw(direct_public, derived, (const uint8_t*)"basepoint"); if (!buffers_equal(public_key, direct_public, 32)) { printf("[FAIL] Public key mismatch\n"); return 0; } printf("[PASS] Public key derivation works\n"); print_hex(" Private: ", private_key, 32); print_hex(" Public: ", public_key, 32); return 1; } /* Test 10: Key zeroization */ static int test_sw_key_zeroization(void) { uint8_t key[32]; uint8_t zero[32] = {0}; printf("\n=== Test 10: Key Zeroization ===\n"); for (int i = 0; i < 32; i++) { key[i] = 0xFF; } se050_x25519_sw_zeroize(key, 32); if (!buffers_equal(key, zero, 32)) { printf("[FAIL] Key not zeroized\n"); return 0; } printf("[PASS] Key zeroization successful\n"); return 1; }