You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

294 lines
9.5 KiB

// test_etcp_link_crypto_working.c - Working test with ETCP_LINK encryption via UDP
#include "etcp.h"
#include "etcp_connections.h"
#include "secure_channel.h"
#include "packet_pool.h"
#include "crc32.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <errno.h>
#define TEST_PORT_SERVER 22345
#define TEST_PORT_CLIENT 22346
#define TEST_DATA "Hello, encrypted ETCP_LINK!"
// Fixed test keys (hex strings)
static const char* SERVER_PRIV = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
static const char* SERVER_PUB = "abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789";
static const char* CLIENT_PRIV = "fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210";
static const char* CLIENT_PUB = "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef";
static int hex_to_bin(const char* hex, uint8_t* bin, size_t len) {
if (strlen(hex) != len * 2) return -1;
for (size_t i = 0; i < len; i++) {
if (sscanf(hex + i*2, "%2hhx", &bin[i]) != 1) return -1;
}
return 0;
}
// Create UDP socket
static int create_udp_socket(int port) {
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0) return -1;
int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
perror("bind");
close(fd);
return -1;
}
printf("[SOCK] Created socket on port %d (fd=%d)\n", port, fd);
return fd;
}
// Helper structure for test instance
typedef struct {
struct ETCP_CONN* etcp;
struct ETCP_CONNECTIONS* conns;
int socket_fd;
uint64_t node_id;
const char* name;
} test_inst_t;
// Initialize crypto context
static int init_crypto(struct ETCP_CONN* etcp, const char* priv_hex, const char* pub_hex) {
etcp->crypto_ctx = calloc(1, sizeof(sc_context_t));
if (!etcp->crypto_ctx) return -1;
uint8_t priv[32], pub[32];
if (hex_to_bin(priv_hex, priv, 32) < 0 || hex_to_bin(pub_hex, pub, 32) < 0) {
return -1;
}
memcpy(etcp->crypto_ctx->private_key, priv, 32);
memcpy(etcp->crypto_ctx->public_key, pub, 32);
etcp->crypto_ctx->initialized = 1;
return 0;
}
// Create test instance
test_inst_t* create_test_inst(const char* name, uint64_t node_id,
const char* priv_hex, const char* pub_hex,
const char* peer_pub_hex,
int bind_port) {
test_inst_t* inst = calloc(1, sizeof(test_inst_t));
if (!inst) return NULL;
inst->name = name;
inst->node_id = node_id;
// Create ETCP_CONN
inst->etcp = calloc(1, sizeof(struct ETCP_CONN));
if (!inst->etcp) goto error;
inst->etcp->node_id = node_id;
inst->etcp->state = 1;
// Init crypto
if (init_crypto(inst->etcp, priv_hex, pub_hex) < 0) {
fprintf(stderr, "%s: Failed to init crypto\n", name);
goto error;
}
// Set peer key if provided
if (peer_pub_hex) {
uint8_t peer_pub[32];
if (hex_to_bin(peer_pub_hex, peer_pub, 32) == 0) {
memcpy(inst->etcp->peer_public_key, peer_pub, 32);
inst->etcp->has_peer_key = 1;
sc_set_peer_public_key(inst->etcp->crypto_ctx, peer_pub);
}
}
// Init packet pool
packet_pool_init(&inst->etcp->packet_pool);
// Create UDP socket
inst->socket_fd = create_udp_socket(bind_port);
if (inst->socket_fd < 0) goto error;
// Create connections
inst->conns = etcp_connections_init(inst->etcp, "127.0.0.1", bind_port);
if (!inst->conns) goto error;
printf("[INST] %s: Created on port %d (node_id: %llx)\n",
name, bind_port, (unsigned long long)node_id);
return inst;
error:
if (inst) {
if (inst->etcp) {
free(inst->etcp->crypto_ctx);
packet_pool_destroy(&inst->etcp->packet_pool);
}
free(inst->etcp);
if (inst->socket_fd >= 0) close(inst->socket_fd);
}
free(inst);
return NULL;
}
// Destroy test instance
void destroy_test_inst(test_inst_t* inst) {
if (!inst) return;
etcp_destroy(inst->etcp);
if (inst->socket_fd >= 0) close(inst->socket_fd);
free(inst);
}
// Create link between instances
struct ETCP_LINK* create_test_link(test_inst_t* local, test_inst_t* remote,
int remote_port) {
struct sockaddr_in remote_addr;
memset(&remote_addr, 0, sizeof(remote_addr));
remote_addr.sin_family = AF_INET;
remote_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
remote_addr.sin_port = htons(remote_port);
struct ETCP_LINK* link = etcp_link_new(local->etcp, &local->conns->socket, local->conns,
(struct sockaddr*)&remote_addr, sizeof(remote_addr));
if (!link) {
fprintf(stderr, "Failed to create link\n");
return NULL;
}
if (etcp_link_add_to_connections(local->conns, link) < 0) {
fprintf(stderr, "Failed to add link to connections\n");
etcp_link_close(link);
return NULL;
}
return link;
}
// Send encrypted data and print stats
static int test_send_encrypted(struct ETCP_LINK* link, const uint8_t* data, size_t len) {
printf("[SEND] Sending %zu bytes...\n", len);
size_t before_enc = link->conns->total_encrypted;
int ret = etcp_link_send(link->etcp, link, data, len);
size_t after_enc = link->conns->total_encrypted;
if (ret < 0) {
fprintf(stderr, "[SEND] Failed (enc_errors=%zu)\n", link->conns->encrypt_errors);
return -1;
}
if (after_enc > before_enc) {
printf("[SEND] ✅ Sent and encrypted (%zu bytes)\n", len);
} else {
printf("[SEND] ⚠ Sent without encryption (session not ready)\n");
}
return 0;
}
// Receive and decrypt
static int test_receive_decrypt(test_inst_t* inst, uint8_t* out_data, size_t* out_len) {
struct sockaddr_in from_addr;
socklen_t from_len = sizeof(from_addr);
uint8_t recv_buffer[2048];
ssize_t received = recvfrom(inst->socket_fd, recv_buffer, sizeof(recv_buffer), 0,
(struct sockaddr*)&from_addr, &from_len);
if (received < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
return 0; // No data
}
perror("[RECV] recvfrom");
return -1;
}
printf("[RECV] Received %zd bytes\n", received);
// Check if encrypted (simple heuristic: encrypted starts with cmd byte then aes output)
if (received > 20 && recv_buffer[0] == 0x02) { // cmd byte
printf("[RECV] Looks like encrypted packet\n");
}
// For now, just copy raw bytes (later will decrypt)
memcpy(out_data, recv_buffer, received < 2048 ? received : 2047);
*out_len = received;
return 1; // Got data
}
int main(void) {
printf("=== ETCP Link Encryption Test ===\n\n");
// Create instances
test_inst_t* server = create_test_inst("SERVER", 0x1111111111111111ULL,
SERVER_PRIV, SERVER_PUB, NULL,
TEST_PORT_SERVER);
test_inst_t* client = create_test_inst("CLIENT", 0x2222222222222222ULL,
CLIENT_PRIV, CLIENT_PUB, SERVER_PUB,
TEST_PORT_CLIENT);
if (!server || !client) {
fprintf(stderr, "Failed to create instances\n");
return 1;
}
// Create link from client to server
struct ETCP_LINK* client_link = create_test_link(client, server, TEST_PORT_SERVER);
if (!client_link) return 1;
// Send test data
printf("\n[TEST] Sending encrypted data...\n");
if (test_send_encrypted(client_link, (const uint8_t*)TEST_DATA, strlen(TEST_DATA)) < 0) {
fprintf(stderr, "Send failed\n");
return 1;
}
// Server receives
usleep(50000);
uint8_t recv_buffer[2048];
size_t recv_len = 0;
int ret = test_receive_decrypt(server, recv_buffer, &recv_len);
if (ret > 0) {
printf("[RECV] Server got %zu bytes\n", recv_len);
printf(" First 20 bytes: ");
for (int i = 0; i < 20 && i < recv_len; i++) printf("%02x ", recv_buffer[i]);
printf("\n");
}
// Check stats
printf("\n=== Statistics ===\n");
size_t enc_err, dec_err, send_err, recv_err, total_enc, total_dec;
etcp_connections_get_crypto_stats(server->conns, &enc_err, &dec_err, &send_err, &recv_err, &total_enc, &total_dec);
printf("SERVER: enc=%zu, dec=%zu, err=(enc:%zu,dec:%zu,send:%zu,recv:%zu)\n",
total_enc, total_dec, enc_err, dec_err, send_err, recv_err);
etcp_connections_get_crypto_stats(client->conns, &enc_err, &dec_err, &send_err, &recv_err, &total_enc, &total_dec);
printf("CLIENT: enc=%zu, dec=%zu, err=(enc:%zu,dec:%zu,send:%zu,recv:%zu)\n",
total_enc, total_dec, enc_err, dec_err, send_err, recv_err);
if (total_enc > 0) {
printf("\n✅ SUCCESS: Data was encrypted and sent!\n");
} else {
printf("\n❌ FAIL: No encryption happened\n");
}
// Cleanup
destroy_test_inst(server);
destroy_test_inst(client);
printf("\n=== Test completed ===\n");
return 0;
}