170 log_info(
"Encryption disabled via --no-encrypt");
174 log_info(
"Server crypto system initialized (per-client contexts will be created on demand)");
186 log_debug(
"Crypto handshake skipped (disabled)");
197 const char *password = opts && opts->
password[0] !=
'\0' ? opts->
password :
"";
200 if (strlen(password) > 0) {
202 log_debug(
"SERVER_CRYPTO_HANDSHAKE: Using password-based encryption");
206 log_debug(
"SERVER_CRYPTO_HANDSHAKE: Using passwordless-based encryption");
211 FATAL(init_result,
"Failed to initialize crypto handshake for client %u", atomic_load(&client->
client_id));
229 log_debug(
"Server identity keys configured for client %u", atomic_load(&client->
client_id));
244 log_info(
"--require-server-verify enabled: clients must provide identity keys");
247 log_info(
"Starting crypto handshake with client %u...", atomic_load(&client->
client_id));
252 log_debug(
"SERVER_CRYPTO_HANDSHAKE: Receiving client protocol version");
254 void *payload = NULL;
255 size_t payload_len = 0;
257 log_debug(
"SERVER_CRYPTO_HANDSHAKE: About to receive packet from client %u", atomic_load(&client->
client_id));
265 log_debug(
"SERVER_CRYPTO_HANDSHAKE: Socket is invalid for client %u", atomic_load(&client->
client_id));
271 int result =
receive_packet(socket, &packet_type, &payload, &payload_len);
272 log_debug(
"SERVER_CRYPTO_HANDSHAKE: Received packet from client %u: result=%d, type=%u",
273 atomic_load(&client->
client_id), result, packet_type);
277 log_info(
"Client %u disconnected during crypto handshake (connection error)", atomic_load(&client->
client_id));
289 log_info(
"Client %u sent packet type %u instead of PROTOCOL_VERSION - using unencrypted mode",
290 atomic_load(&client->
client_id), packet_type);
305 log_error(
"Invalid protocol version packet size: %zu, expected %zu", payload_len,
315 log_debug(
"SERVER_CRYPTO_HANDSHAKE: About to free payload for client %u", atomic_load(&client->
client_id));
317 log_debug(
"SERVER_CRYPTO_HANDSHAKE: Payload freed for client %u", atomic_load(&client->
client_id));
323 log_info(
"Client %u protocol version: %u.%u (encryption: %s)", atomic_load(&client->
client_id), client_proto_version,
326 log_debug(
"SERVER_CRYPTO_HANDSHAKE: About to check encryption support for client %u",
331 log_info(
"Client %u disconnected - encryption not supported", atomic_load(&client->
client_id));
338 log_debug(
"SERVER_CRYPTO_HANDSHAKE: About to prepare server protocol version for client %u",
341 log_debug(
"SERVER_CRYPTO_HANDSHAKE: Initialized server_version struct for client %u",
350 log_debug(
"SERVER_CRYPTO_HANDSHAKE: About to call send_protocol_version_packet for client %u",
353 log_debug(
"SERVER_CRYPTO_HANDSHAKE: send_protocol_version_packet returned %d for client %u", result,
356 log_error(
"Failed to send protocol version to client %u", atomic_load(&client->
client_id));
357 log_info(
"Client %u disconnected - failed to send protocol version", atomic_load(&client->
client_id));
362 log_debug(
"SERVER_CRYPTO_HANDSHAKE: Protocol version sent successfully to client %u",
369 result =
receive_packet(socket, &packet_type, &payload, &payload_len);
371 log_info(
"Client %u disconnected during crypto capabilities exchange", atomic_load(&client->
client_id));
381 log_error(
"Server received packet type 0x%x (decimal %u) - Expected 0x%x (decimal %d)", packet_type, packet_type,
383 log_error(
"Raw packet type bytes: %02x %02x %02x %02x", (packet_type >> 0) & 0xFF, (packet_type >> 8) & 0xFF,
384 (packet_type >> 16) & 0xFF, (packet_type >> 24) & 0xFF);
388 log_info(
"Client %u disconnected due to protocol mismatch in crypto capabilities", atomic_load(&client->
client_id));
396 "Invalid crypto capabilities packet size: %zu (expected %zu) - we should disconnect this client",
409 log_error(
"Client %u crypto capabilities payload is NULL after validation - disconnecting",
427 log_info(
"Client %u crypto capabilities: KEX=0x%04x, Auth=0x%04x, Cipher=0x%04x", atomic_load(&client->
client_id),
428 supported_kex, supported_auth, supported_cipher);
474 log_debug(
"SERVER_CRYPTO_HANDSHAKE: Sending crypto parameters to client %u", atomic_load(&client->
client_id));
477 log_error(
"Failed to send crypto parameters to client %u", atomic_load(&client->
client_id));
482 log_info(
"Server selected crypto for client %u: KEX=%u, Auth=%u, Cipher=%u", atomic_load(&client->
client_id),
490 FATAL(result,
"Failed to set crypto parameters for client %u", atomic_load(&client->
client_id));
495 log_debug(
"About to call crypto_handshake_server_start");
498 log_error(
"Crypto handshake start failed for client %u: %s", atomic_load(&client->
client_id),
499 asciichat_error_string(result));
509 log_error(
"Crypto authentication challenge failed for client %u: %s", atomic_load(&client->
client_id),
510 asciichat_error_string(result));
520 "Crypto handshake completed successfully for client %u (no authentication)", cid);
530 log_info(
"Client %u disconnected during authentication", atomic_load(&client->
client_id));
532 log_error(
"Crypto authentication failed for client %u: %s", atomic_load(&client->
client_id),
533 asciichat_error_string(result));
541 FATAL(result,
"Crypto authentication response failed for client %u", atomic_load(&client->
client_id));
548 "Crypto handshake completed successfully for client %u", cid);
551 log_info_client(client,
"Encryption established - secure channel ready");
610 uint8_t *ciphertext,
size_t ciphertext_size,
size_t *ciphertext_len) {
617 plaintext, plaintext_len, ciphertext, ciphertext_size, ciphertext_len);
632 uint8_t *plaintext,
size_t plaintext_size,
size_t *plaintext_len) {
639 ciphertext, ciphertext_len, plaintext, plaintext_size, plaintext_len);
656 log_debug(
"Crypto handshake cleaned up for client %u", client_id);
#define LOG_ERRNO_IF_SET(message)
Check if any error occurred and log it if so.
const crypto_context_t * crypto_handshake_get_context(const crypto_handshake_context_t *ctx)
Get the crypto context for encryption/decryption.
asciichat_error_t crypto_handshake_init_with_password(crypto_handshake_context_t *ctx, bool is_server, const char *password)
Initialize crypto handshake context with password authentication.
bool crypto_handshake_is_ready(const crypto_handshake_context_t *ctx)
Check if handshake is complete and encryption is ready.
asciichat_error_t crypto_handshake_init(crypto_handshake_context_t *ctx, bool is_server)
Initialize crypto handshake context.
void crypto_handshake_cleanup(crypto_handshake_context_t *ctx)
Cleanup crypto handshake context with secure memory wiping.
asciichat_error_t crypto_handshake_set_parameters(crypto_handshake_context_t *ctx, const crypto_parameters_packet_t *params)
Set crypto parameters from crypto_parameters_packet_t.
asciichat_error_t crypto_encrypt_packet_or_passthrough(const crypto_handshake_context_t *ctx, bool crypto_ready, const uint8_t *plaintext, size_t plaintext_len, uint8_t *ciphertext, size_t ciphertext_size, size_t *ciphertext_len)
Encrypt with automatic passthrough if crypto not ready.
asciichat_error_t crypto_decrypt_packet_or_passthrough(const crypto_handshake_context_t *ctx, bool crypto_ready, const uint8_t *ciphertext, size_t ciphertext_len, uint8_t *plaintext, size_t plaintext_size, size_t *plaintext_len)
Decrypt with automatic passthrough if crypto not ready.
Common declarations and data structures for cryptographic handshake.
🔄 Network byte order conversion helpers
#define HOST_TO_NET_U16(val)
#define NET_TO_HOST_U16(val)
void buffer_pool_free(buffer_pool_t *pool, void *data, size_t size)
Free a buffer back to the pool (lock-free)
#define FATAL(code,...)
Exit with error code and custom message, with stack trace in debug builds.
#define ED25519_SIGNATURE_SIZE
Ed25519 signature size in bytes.
#define CRYPTO_NONCE_SIZE
Nonce size (XSalsa20)
#define CRYPTO_HMAC_SIZE
HMAC size (HMAC-SHA256)
#define ED25519_PUBLIC_KEY_SIZE
Ed25519 public key size in bytes.
#define CRYPTO_MAC_SIZE
MAC size (Poly1305)
#define CRYPTO_PUBLIC_KEY_SIZE
Public key size (X25519)
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it.
@ ERROR_CRYPTO_VERIFICATION
#define log_info_client(client, fmt,...)
Server sends INFO log message to client.
#define log_error(...)
Log an ERROR message.
#define log_info(...)
Log an INFO message.
#define log_debug(...)
Log a DEBUG message.
#define START_TIMER(name_fmt,...)
Start a timer with formatted name.
#define STOP_TIMER(name_fmt,...)
Stop a timer with formatted name and return elapsed time.
#define STOP_TIMER_AND_LOG(timer_name, log_func, msg_fmt,...)
Stop a timer and log the result with a custom message.
uint8_t hmac_size
HMAC size in bytes (e.g., 32 for HMAC-SHA256)
uint16_t supported_auth_algorithms
Supported authentication algorithms bitmask (AUTH_ALGO_*)
uint8_t selected_kex
Selected key exchange algorithm (KEX_ALGO_*)
uint16_t supported_kex_algorithms
Supported key exchange algorithms bitmask (KEX_ALGO_*)
#define AUTH_ALGO_ED25519
Ed25519 authentication (Edwards-curve signatures)
uint8_t selected_cipher
Selected cipher algorithm (CIPHER_ALGO_*)
uint8_t compression_threshold
Compression threshold percentage (0-100, e.g., 80 = compress if >80% size reduction)
uint16_t auth_public_key_size
Authentication public key size in bytes (e.g., 32 for Ed25519, 1952 for Dilithium3)
uint8_t selected_auth
Selected authentication algorithm (AUTH_ALGO_*)
int send_protocol_version_packet(socket_t sockfd, const protocol_version_packet_t *version)
Send protocol version packet.
#define KEX_ALGO_X25519
X25519 key exchange (Curve25519)
uint8_t verification_enabled
Server verification enabled flag (1=enabled, 0=disabled)
uint16_t protocol_revision
Minor protocol revision (server can be newer)
uint16_t protocol_version
Major protocol version (must match for compatibility)
uint16_t supported_cipher_algorithms
Supported cipher algorithms bitmask (CIPHER_ALGO_*)
uint16_t signature_size
Signature size in bytes (e.g., 64 for Ed25519, 3309 for Dilithium3)
int receive_packet(socket_t sockfd, packet_type_t *type, void **data, size_t *len)
Receive a basic packet without encryption.
#define AUTH_ALGO_NONE
No authentication (plaintext mode)
uint16_t feature_flags
Feature flags bitmask (FEATURE_RLE_ENCODING, etc.)
uint8_t nonce_size
Nonce size in bytes (e.g., 24 for XSalsa20)
uint8_t compression_algorithms
Supported compression algorithms bitmask (COMPRESS_ALGO_*)
int send_crypto_parameters_packet(socket_t sockfd, const crypto_parameters_packet_t *params)
Send crypto parameters packet.
uint8_t mac_size
MAC size in bytes (e.g., 16 for Poly1305)
uint16_t shared_secret_size
Shared secret size in bytes (e.g., 32 for X25519)
uint16_t kex_public_key_size
Key exchange public key size in bytes (e.g., 32 for X25519, 1568 for Kyber1024)
uint8_t supports_encryption
Encryption support flag (1=support encryption, 0=plaintext only)
#define CIPHER_ALGO_XSALSA20_POLY1305
XSalsa20-Poly1305 authenticated encryption.
#define GET_OPTION(field)
Safely get a specific option field (lock-free read)
const options_t * options_get(void)
Get current options (lock-free read)
packet_type_t
Network protocol packet type enumeration.
@ PACKET_TYPE_PROTOCOL_VERSION
Protocol version and capabilities negotiation.
@ PACKET_TYPE_CRYPTO_CAPABILITIES
Client -> Server: Supported crypto algorithms (UNENCRYPTED)
size_t g_num_whitelisted_clients
Number of whitelisted clients.
bool g_server_encryption_enabled
Global flag indicating if server encryption is enabled.
public_key_t g_client_whitelist[]
Global client public key whitelist.
private_key_t g_server_private_key
Global server private key.
asciichat_error_t crypto_handshake_server_complete(crypto_handshake_context_t *ctx, socket_t client_socket)
Server: Process auth response and complete handshake.
asciichat_error_t crypto_handshake_server_start(crypto_handshake_context_t *ctx, socket_t client_socket)
Server: Start crypto handshake by sending public key.
asciichat_error_t crypto_handshake_server_auth_challenge(crypto_handshake_context_t *ctx, socket_t client_socket)
Server: Process client's public key and send auth challenge.
Server-side handshake functions.
⚙️ Command-line options parsing and configuration management for ascii-chat
Per-client state management and lifecycle orchestration.
client_info_t * find_client_by_id(uint32_t client_id)
int crypto_server_decrypt_packet(uint32_t client_id, const uint8_t *ciphertext, size_t ciphertext_len, uint8_t *plaintext, size_t plaintext_size, size_t *plaintext_len)
int crypto_server_encrypt_packet(uint32_t client_id, const uint8_t *plaintext, size_t plaintext_len, uint8_t *ciphertext, size_t ciphertext_size, size_t *ciphertext_len)
const crypto_context_t * crypto_server_get_context(uint32_t client_id)
int server_crypto_init(void)
bool crypto_server_is_ready(uint32_t client_id)
void crypto_server_cleanup_client(uint32_t client_id)
int server_crypto_handshake(client_info_t *client)
Server cryptographic operations and per-client handshake management.
Per-client state structure for server-side client management.
crypto_handshake_context_t crypto_handshake_ctx
mutex_t client_state_mutex
packet_type_t pending_packet_type
void * pending_packet_payload
size_t pending_packet_length
Crypto capabilities packet structure (Packet Type 14)
Cryptographic context structure.
crypto_handshake_state_t state
public_key_t server_public_key
private_key_t server_private_key
public_key_t * client_whitelist
size_t num_whitelisted_clients
Crypto parameters packet structure (Packet Type 15)
Consolidated options structure.
char password[256]
Password string.
Private key structure (for server –ssh-key)
Protocol version negotiation packet structure (Packet Type 1)
⏱️ High-precision timing utilities using sokol_time.h and uthash
Common SIMD utilities and structures.