ascii-chat 0.6.0
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
Cryptographic Operations

🔐 Client-side cryptographic handshake and key management More...

Files

file  crypto.c
 🔐 Client cryptography: handshake integration, X25519 key exchange, and per-session encryption
 
file  crypto.h
 ascii-chat Client Cryptography Handler Interface
 

Functions

int client_crypto_init (void)
 Initialize client crypto handshake.
 
int client_crypto_handshake (socket_t socket)
 Perform crypto handshake with server.
 
bool crypto_client_is_ready (void)
 Check if crypto handshake is ready.
 
const crypto_context_tcrypto_client_get_context (void)
 Get crypto context for encryption/decryption.
 
int crypto_client_encrypt_packet (const uint8_t *plaintext, size_t plaintext_len, uint8_t *ciphertext, size_t ciphertext_size, size_t *ciphertext_len)
 Encrypt a packet for transmission.
 
int crypto_client_decrypt_packet (const uint8_t *ciphertext, size_t ciphertext_len, uint8_t *plaintext, size_t plaintext_size, size_t *plaintext_len)
 Decrypt a received packet.
 
void crypto_client_cleanup (void)
 Cleanup crypto client resources.
 
bool crypto_client_should_rekey (void)
 Check if session rekeying should be triggered.
 
int crypto_client_initiate_rekey (void)
 Initiate session rekeying (client-initiated)
 
int crypto_client_process_rekey_request (const uint8_t *packet, size_t packet_len)
 Process received REKEY_REQUEST packet from server.
 
int crypto_client_send_rekey_response (void)
 Send REKEY_RESPONSE packet to server.
 
int crypto_client_process_rekey_response (const uint8_t *packet, size_t packet_len)
 Process received REKEY_RESPONSE packet from server.
 
int crypto_client_send_rekey_complete (void)
 Send REKEY_COMPLETE packet to server and commit to new key.
 

Detailed Description

🔐 Client-side cryptographic handshake and key management

Cryptographic Operations

Overview

The client crypto subsystem coordinates the cryptographic handshake with the server, loads client and server keys, verifies host identity, and manages the encryption context for secure communication.

Implementation: src/client/crypto.c, src/client/crypto.h

Handshake Process

{
// Perform client-side handshake
crypto_handshake_result_t result =
perform_crypto_handshake_client(socket, &handshake_ctx,
opt_server_key, server_ip, opt_client_key);
switch (result) {
case HANDSHAKE_SUCCESS:
log_info("Secure connection established");
g_crypto_ctx = handshake_ctx.crypto_ctx;
g_crypto_ready = true;
return 0;
case HANDSHAKE_WARNING_NO_CLIENT_AUTH:
log_warn("Server not verifying client identity");
g_crypto_ctx = handshake_ctx.crypto_ctx;
g_crypto_ready = true;
case HANDSHAKE_ERROR_AUTH_FAILED:
log_error("Client authentication failed - wrong client key?");
return CONNECTION_ERROR_AUTH_FAILED; // No retry
case HANDSHAKE_ERROR_HOST_KEY_FAILED:
log_error("Server host key verification failed");
default:
log_error("Handshake failed");
return CONNECTION_ERROR_GENERIC; // Allow retry
}
}
crypto_handshake_context_t g_crypto_ctx
Per-connection crypto handshake context.
int client_crypto_handshake(socket_t socket)
Perform crypto handshake with server.
#define log_warn(...)
Log a WARN message.
#define log_error(...)
Log an ERROR message.
#define log_info(...)
Log an INFO message.
int socket_t
Socket handle type (POSIX: int)
Definition socket.h:50
ASCIICHAT_API char opt_server_key[OPTIONS_BUFF_SIZE]
@ CONNECTION_ERROR_GENERIC
Generic error (retry allowed)
@ CONNECTION_ERROR_HOST_KEY_FAILED
Host key verification failed (no retry)
@ CONNECTION_ERROR_AUTH_FAILED
Authentication failure (no retry)
@ CONNECTION_WARNING_NO_CLIENT_AUTH
Server not using client verification (warning)
Cryptographic handshake context structure.

Key Management

Client Keys (--client-key):

  • Ed25519 SSH private keys for client authentication
  • Loaded from filesystem or SSH agent
  • Password support via $ASCII_CHAT_KEY_PASSWORD

Server Keys (--server-key):

  • Ed25519 SSH public keys for server verification
  • Can be loaded from:
    • Filesystem path (~/.ssh/server_id_ed25519.pub)
    • GitHub URL (github:username)
    • GitLab URL (gitlab:username)
  • Verified against known_hosts file
Note
Native Decryption: Encrypted SSH keys are decrypted natively using bcrypt_pbkdf (from libsodium-bcrypt-pbkdf) + BearSSL AES-256-CTR. No external tools required. Alternatively, use $SSH_AUTH_SOCK (ssh-agent) for password-free authentication.

Known Hosts Verification

TOFU (Trust On First Use):

  • First connection: Record server public key by IP
  • Subsequent connections: Verify key matches recorded value
  • Key mismatch: Connection rejected (possible MITM attack)

Known hosts file: ~/.ascii-chat/known_hosts

See also
src/client/crypto.c
src/client/crypto.h
lib/crypto/handshake.h
lib/crypto/keys/keys.h
Client Overview

Function Documentation

◆ client_crypto_handshake()

int client_crypto_handshake ( socket_t  socket)

#include <crypto.c>

Perform crypto handshake with server.

Perform crypto handshake with server

Parameters
socketConnected socket to server
Returns
0 on success, -1 on failure

Executes the complete cryptographic handshake protocol with the server, including protocol negotiation, key exchange, and authentication.

Parameters
socketConnected socket to server
Returns
0 on success, -1 on failure

Definition at line 399 of file src/client/crypto.c.

399 {
400 // If client has --no-encrypt, skip handshake entirely
401 if (GET_OPTION(no_encrypt)) {
402 log_debug("Client has --no-encrypt, skipping crypto handshake");
403 return 0;
404 }
405
406 // If we reach here, crypto must be initialized for encryption
407 if (!g_crypto_initialized) {
408 log_error("Crypto not initialized but server requires encryption");
409 log_error("Server requires encrypted connection but client has no encryption configured");
410 log_error("Use --key to specify a client key or --password for password authentication");
411 return CONNECTION_ERROR_AUTH_FAILED; // No retry - configuration error
412 }
413
414 log_info("Starting crypto handshake with server...");
415
416 START_TIMER("client_crypto_handshake");
417
418 // Step 0a: Send protocol version to server
419 protocol_version_packet_t client_version = {0};
420 client_version.protocol_version = HOST_TO_NET_U16(1); // Protocol version 1
421 client_version.protocol_revision = HOST_TO_NET_U16(0); // Revision 0
422 client_version.supports_encryption = 1; // We support encryption
423 client_version.compression_algorithms = 0; // No compression for now
424 client_version.compression_threshold = 0;
425 client_version.feature_flags = 0;
426
427 int result = send_protocol_version_packet(socket, &client_version);
428 if (result != 0) {
429 log_error("Failed to send protocol version to server");
430 STOP_TIMER("client_crypto_handshake");
431 return -1;
432 }
433 log_debug("CLIENT_CRYPTO_HANDSHAKE: Protocol version sent successfully");
434
435 // Step 0b: Receive server's protocol version
436 packet_type_t packet_type;
437 void *payload = NULL;
438 size_t payload_len = 0;
439
440 result = receive_packet(socket, &packet_type, &payload, &payload_len);
441 if (result != ASCIICHAT_OK || packet_type != PACKET_TYPE_PROTOCOL_VERSION) {
442 log_error("Failed to receive server protocol version (got type %u)", packet_type);
443 log_error("Packet type 0x%x (decimal %u) - Expected 0x%x (decimal %d)", packet_type, packet_type,
445 log_error("This suggests a protocol mismatch or packet corruption");
446 log_error("Raw packet type bytes: %02x %02x %02x %02x", (packet_type >> 0) & 0xFF, (packet_type >> 8) & 0xFF,
447 (packet_type >> 16) & 0xFF, (packet_type >> 24) & 0xFF);
448 if (payload) {
449 buffer_pool_free(NULL, payload, payload_len);
450 }
451 STOP_TIMER("client_crypto_handshake");
452 return -1;
453 }
454
455 if (payload_len != sizeof(protocol_version_packet_t)) {
456 log_error("Invalid protocol version packet size: %zu, expected %zu", payload_len,
458 buffer_pool_free(NULL, payload, payload_len);
459 STOP_TIMER("client_crypto_handshake");
460 return -1;
461 }
462
463 protocol_version_packet_t server_version;
464 memcpy(&server_version, payload, sizeof(protocol_version_packet_t));
465 buffer_pool_free(NULL, payload, payload_len);
466
467 // Convert from network byte order
468 uint16_t server_proto_version = NET_TO_HOST_U16(server_version.protocol_version);
469 uint16_t server_proto_revision = NET_TO_HOST_U16(server_version.protocol_revision);
470
471 log_info("Server protocol version: %u.%u (encryption: %s)", server_proto_version, server_proto_revision,
472 server_version.supports_encryption ? "yes" : "no");
473
474 if (!server_version.supports_encryption) {
475 log_error("Server does not support encryption");
476 STOP_TIMER("client_crypto_handshake");
478 }
479
480 // Step 0c: Send crypto capabilities to server
481 log_debug("CLIENT_CRYPTO_HANDSHAKE: Sending crypto capabilities");
482 crypto_capabilities_packet_t client_caps = {0};
486 client_caps.requires_verification = 0; // Client doesn't require server verification (uses known_hosts)
487 client_caps.preferred_kex = KEX_ALGO_X25519;
488 client_caps.preferred_auth = AUTH_ALGO_ED25519;
490
491 result = send_crypto_capabilities_packet(socket, &client_caps);
492 if (result != 0) {
493 log_error("Failed to send crypto capabilities to server");
494 STOP_TIMER("client_crypto_handshake");
495 return -1;
496 }
497 log_debug("CLIENT_CRYPTO_HANDSHAKE: Crypto capabilities sent successfully");
498
499 // Step 0d: Receive server's crypto parameters
500 log_debug("CLIENT_CRYPTO_HANDSHAKE: Receiving server crypto parameters");
501 payload = NULL;
502 payload_len = 0;
503
504 result = receive_packet(socket, &packet_type, &payload, &payload_len);
505 if (result != ASCIICHAT_OK || packet_type != PACKET_TYPE_CRYPTO_PARAMETERS) {
506 log_error("Failed to receive server crypto parameters (got type %u)", packet_type);
507 if (payload) {
508 buffer_pool_free(NULL, payload, payload_len);
509 }
510 STOP_TIMER("client_crypto_handshake");
511 return -1;
512 }
513
514 if (payload_len != sizeof(crypto_parameters_packet_t)) {
515 log_error("Invalid crypto parameters packet size: %zu, expected %zu", payload_len,
517 buffer_pool_free(NULL, payload, payload_len);
518 STOP_TIMER("client_crypto_handshake");
519 return -1;
520 }
521
522 crypto_parameters_packet_t server_params;
523 memcpy(&server_params, payload, sizeof(crypto_parameters_packet_t));
524 buffer_pool_free(NULL, payload, payload_len);
525
526 // Convert from network byte order
527 uint16_t kex_pubkey_size = NET_TO_HOST_U16(server_params.kex_public_key_size);
528 uint16_t auth_pubkey_size = NET_TO_HOST_U16(server_params.auth_public_key_size);
529 uint16_t signature_size = NET_TO_HOST_U16(server_params.signature_size);
530 uint16_t shared_secret_size = NET_TO_HOST_U16(server_params.shared_secret_size);
531
532 log_info("Server crypto parameters: KEX=%u, Auth=%u, Cipher=%u (key_size=%u, auth_size=%u, sig_size=%u, "
533 "secret_size=%u, verification=%u)",
534 server_params.selected_kex, server_params.selected_auth, server_params.selected_cipher, kex_pubkey_size,
535 auth_pubkey_size, signature_size, shared_secret_size, server_params.verification_enabled);
536 log_debug("Raw server_params.kex_public_key_size = %u (network byte order)", server_params.kex_public_key_size);
537
538 // Set the crypto parameters in the handshake context
539 result = crypto_handshake_set_parameters(&g_crypto_ctx, &server_params);
540 if (result != ASCIICHAT_OK) {
541 FATAL(result, "Failed to set crypto parameters");
542 }
543
544 // Store verification flag - server will verify client identity (whitelist check)
545 // This is independent of whether server provides its own identity
546 if (server_params.verification_enabled) {
549 log_info("Server will verify client identity (whitelist enabled)");
550 }
551
552 // Validate that server chose algorithms we support
553 if (server_params.selected_kex != KEX_ALGO_X25519) {
554 log_error("Server selected unsupported KEX algorithm: %u", server_params.selected_kex);
555 STOP_TIMER("client_crypto_handshake");
557 }
558
559 if (server_params.selected_cipher != CIPHER_ALGO_XSALSA20_POLY1305) {
560 log_error("Server selected unsupported cipher algorithm: %u", server_params.selected_cipher);
561 STOP_TIMER("client_crypto_handshake");
563 }
564
565 log_debug("CLIENT_CRYPTO_HANDSHAKE: Protocol negotiation completed successfully");
566
567 // Step 1: Receive server's public key and send our public key
568 log_debug("CLIENT_CRYPTO_HANDSHAKE: Starting key exchange");
570 if (result != ASCIICHAT_OK) {
571#ifdef _WIN32
572 // On Windows: Cleanup capture resources before exiting to prevent Media Foundation threads from hanging exit()
573 // Media Foundation creates background COM threads that can block exit() if not properly shut down
575#endif
576 FATAL(result, "Crypto key exchange failed");
577 }
578 log_debug("CLIENT_CRYPTO_HANDSHAKE: Key exchange completed successfully");
579
580 // SECURITY: Warn when server requires client verification but client has no identity key
581 bool client_has_identity = (g_crypto_ctx.client_public_key.type == KEY_TYPE_ED25519);
582
583 if (g_crypto_ctx.require_client_auth && !client_has_identity) {
584 // Server requires client verification but client has no identity key
585 log_warn("Server requires client verification but client has no identity key");
586
587 // Check if we're running interactively (stdin is a terminal)
588 // In debug builds with CLAUDECODE, skip interactive prompts (LLM can't type)
589#ifndef NDEBUG
590 bool skip_interactive = platform_getenv("CLAUDECODE") != NULL;
591#else
592 bool skip_interactive = false;
593#endif
594 if (!skip_interactive && platform_is_interactive()) {
595 // Interactive mode - prompt user for confirmation
596 // Lock terminal for the warning message
597 bool previous_terminal_state = log_lock_terminal();
598
599 log_plain("\n"
600 "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"
601 "@ WARNING: CLIENT AUTHENTICATION REQUIRED @\n"
602 "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"
603 "\n"
604 "The server requires client authentication (--client-keys enabled),\n"
605 "but you have not provided a client identity key with --key.\n"
606 "\n"
607 "To connect to this server, you need to:\n"
608 " 1. Generate an Ed25519 key: ssh-keygen -t ed25519\n"
609 " 2. Add the public key to the server's --client-keys list\n"
610 " 3. Connect with: ascii-chat client --key /path/to/private/key\n");
611
612 // Unlock before prompt (prompt_yes_no handles its own terminal locking)
613 log_unlock_terminal(previous_terminal_state);
614
615 // Prompt user - default is No since this will likely fail
616 if (!platform_prompt_yes_no("Do you want to continue anyway (this will likely fail)", false)) {
617 log_plain("Connection aborted by user.");
618 exit(0); // User declined - exit cleanly
619 }
620
621 log_plain("Warning: Continuing without client identity key (connection may fail).\n");
622 } else {
623 // Non-interactive mode (background/script) - just log warning and continue
624 log_warn("Non-interactive mode: Continuing without client identity key (connection may fail)");
625 }
626 }
627
628 // Step 2: Receive auth challenge and send response
629 log_debug("CLIENT_CRYPTO: Sending auth response to server...");
630 log_debug("CLIENT_CRYPTO_HANDSHAKE: Starting auth response");
632 if (result != ASCIICHAT_OK) {
633 FATAL(result, "Crypto authentication failed");
634 }
635 log_debug("CLIENT_CRYPTO: Auth response sent successfully");
636 log_debug("CLIENT_CRYPTO_HANDSHAKE: Auth response completed successfully");
637
638 // Check if handshake completed during auth response (no authentication needed)
640 STOP_TIMER_AND_LOG("client_crypto_handshake", log_info,
641 "Crypto handshake completed successfully (no authentication)");
642 return 0;
643 }
644
645 // Step 3: Receive handshake complete message
646 log_debug("CLIENT_CRYPTO_HANDSHAKE: Waiting for handshake complete message");
648 if (result != ASCIICHAT_OK) {
649 FATAL(result, "Crypto handshake completion failed");
650 }
651
652 STOP_TIMER_AND_LOG("client_crypto_handshake", log_info, "Crypto handshake completed successfully");
653 log_debug("CLIENT_CRYPTO_HANDSHAKE: Handshake completed successfully, state=%d", g_crypto_ctx.state);
654 return 0;
655}
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.
#define HOST_TO_NET_U16(val)
Definition endian.h:101
#define NET_TO_HOST_U16(val)
Definition endian.h:116
void buffer_pool_free(buffer_pool_t *pool, void *data, size_t size)
Free a buffer back to the pool (lock-free)
void capture_cleanup()
Cleanup capture subsystem.
Definition capture.c:526
unsigned short uint16_t
Definition common.h:57
#define FATAL(code,...)
Exit with error code and custom message, with stack trace in debug builds.
Definition common.h:151
@ ASCIICHAT_OK
Definition error_codes.h:48
@ CRYPTO_HANDSHAKE_READY
key_type_t type
Definition key_types.h:70
@ KEY_TYPE_ED25519
Definition key_types.h:52
bool log_lock_terminal(void)
Lock terminal output for exclusive access by the calling thread.
#define log_debug(...)
Log a DEBUG message.
#define log_plain(...)
Plain logging - writes to both log file and stderr without timestamps or log levels.
void log_unlock_terminal(bool previous_state)
Release terminal lock and flush buffered messages.
#define START_TIMER(name_fmt,...)
Start a timer with formatted name.
Definition time.h:141
#define STOP_TIMER(name_fmt,...)
Stop a timer with formatted name and return elapsed time.
Definition time.h:165
#define STOP_TIMER_AND_LOG(timer_name, log_func, msg_fmt,...)
Stop a timer and log the result with a custom message.
Definition time.h:271
uint8_t preferred_auth
Preferred authentication algorithm (AUTH_ALGO_*)
Definition packet.h:856
uint16_t supported_auth_algorithms
Supported authentication algorithms bitmask (AUTH_ALGO_*)
Definition packet.h:848
uint8_t selected_kex
Selected key exchange algorithm (KEX_ALGO_*)
Definition packet.h:875
uint16_t supported_kex_algorithms
Supported key exchange algorithms bitmask (KEX_ALGO_*)
Definition packet.h:846
#define AUTH_ALGO_ED25519
Ed25519 authentication (Edwards-curve signatures)
Definition packet.h:950
uint8_t preferred_cipher
Preferred cipher algorithm (CIPHER_ALGO_*)
Definition packet.h:858
uint8_t selected_cipher
Selected cipher algorithm (CIPHER_ALGO_*)
Definition packet.h:879
uint8_t compression_threshold
Compression threshold percentage (0-100, e.g., 80 = compress if >80% size reduction)
Definition packet.h:720
uint16_t auth_public_key_size
Authentication public key size in bytes (e.g., 32 for Ed25519, 1952 for Dilithium3)
Definition packet.h:885
uint8_t selected_auth
Selected authentication algorithm (AUTH_ALGO_*)
Definition packet.h:877
int send_protocol_version_packet(socket_t sockfd, const protocol_version_packet_t *version)
Send protocol version packet.
Definition packet.c:1016
#define KEX_ALGO_X25519
X25519 key exchange (Curve25519)
Definition packet.h:949
uint8_t verification_enabled
Server verification enabled flag (1=enabled, 0=disabled)
Definition packet.h:881
uint16_t protocol_revision
Minor protocol revision (server can be newer)
Definition packet.h:714
uint16_t protocol_version
Major protocol version (must match for compatibility)
Definition packet.h:712
uint16_t supported_cipher_algorithms
Supported cipher algorithms bitmask (CIPHER_ALGO_*)
Definition packet.h:850
uint16_t signature_size
Signature size in bytes (e.g., 64 for Ed25519, 3309 for Dilithium3)
Definition packet.h:887
int receive_packet(socket_t sockfd, packet_type_t *type, void **data, size_t *len)
Receive a basic packet without encryption.
Definition packet.c:767
#define AUTH_ALGO_NONE
No authentication (plaintext mode)
Definition packet.h:951
uint16_t feature_flags
Feature flags bitmask (FEATURE_RLE_ENCODING, etc.)
Definition packet.h:722
uint8_t preferred_kex
Preferred key exchange algorithm (KEX_ALGO_*)
Definition packet.h:854
int send_crypto_capabilities_packet(socket_t sockfd, const crypto_capabilities_packet_t *caps)
Send crypto capabilities packet.
Definition packet.c:1030
uint8_t requires_verification
Server verification requirement flag (1=required, 0=optional)
Definition packet.h:852
uint8_t compression_algorithms
Supported compression algorithms bitmask (COMPRESS_ALGO_*)
Definition packet.h:718
uint16_t shared_secret_size
Shared secret size in bytes (e.g., 32 for X25519)
Definition packet.h:889
uint16_t kex_public_key_size
Key exchange public key size in bytes (e.g., 32 for X25519, 1568 for Kyber1024)
Definition packet.h:883
uint8_t supports_encryption
Encryption support flag (1=support encryption, 0=plaintext only)
Definition packet.h:716
#define CIPHER_ALGO_XSALSA20_POLY1305
XSalsa20-Poly1305 authenticated encryption.
Definition packet.h:952
#define GET_OPTION(field)
Safely get a specific option field (lock-free read)
Definition options.h:644
packet_type_t
Network protocol packet type enumeration.
Definition packet.h:281
@ PACKET_TYPE_PROTOCOL_VERSION
Protocol version and capabilities negotiation.
Definition packet.h:283
@ PACKET_TYPE_CRYPTO_PARAMETERS
Server -> Client: Chosen algorithms + data sizes (UNENCRYPTED)
Definition packet.h:315
bool platform_prompt_yes_no(const char *prompt, bool default_yes)
Prompt the user for a yes/no answer.
bool platform_is_interactive(void)
Check if interactive prompting is available.
const char * platform_getenv(const char *name)
Get an environment variable value.
asciichat_error_t crypto_handshake_client_auth_response(crypto_handshake_context_t *ctx, socket_t client_socket)
Client: Process auth challenge and send response.
asciichat_error_t crypto_handshake_client_key_exchange(crypto_handshake_context_t *ctx, socket_t client_socket)
Client: Process server's public key and send our public key.
asciichat_error_t crypto_handshake_client_complete(crypto_handshake_context_t *ctx, socket_t client_socket)
Client: Wait for handshake complete confirmation.
Crypto capabilities packet structure (Packet Type 14)
Definition packet.h:844
crypto_handshake_state_t state
Crypto parameters packet structure (Packet Type 15)
Definition packet.h:873
Protocol version negotiation packet structure (Packet Type 1)
Definition packet.h:710

References ASCIICHAT_OK, AUTH_ALGO_ED25519, AUTH_ALGO_NONE, crypto_parameters_packet_t::auth_public_key_size, buffer_pool_free(), capture_cleanup(), CIPHER_ALGO_XSALSA20_POLY1305, crypto_handshake_context_t::client_public_key, protocol_version_packet_t::compression_algorithms, protocol_version_packet_t::compression_threshold, CONNECTION_ERROR_AUTH_FAILED, crypto_handshake_client_auth_response(), crypto_handshake_client_complete(), crypto_handshake_client_key_exchange(), CRYPTO_HANDSHAKE_READY, crypto_handshake_set_parameters(), FATAL, protocol_version_packet_t::feature_flags, g_crypto_ctx, GET_OPTION, HOST_TO_NET_U16, KEX_ALGO_X25519, crypto_parameters_packet_t::kex_public_key_size, KEY_TYPE_ED25519, log_debug, log_error, log_info, log_lock_terminal(), log_plain, log_unlock_terminal(), log_warn, NET_TO_HOST_U16, PACKET_TYPE_CRYPTO_PARAMETERS, PACKET_TYPE_PROTOCOL_VERSION, platform_getenv(), platform_is_interactive(), platform_prompt_yes_no(), crypto_capabilities_packet_t::preferred_auth, crypto_capabilities_packet_t::preferred_cipher, crypto_capabilities_packet_t::preferred_kex, protocol_version_packet_t::protocol_revision, protocol_version_packet_t::protocol_version, receive_packet(), crypto_handshake_context_t::require_client_auth, crypto_capabilities_packet_t::requires_verification, crypto_parameters_packet_t::selected_auth, crypto_parameters_packet_t::selected_cipher, crypto_parameters_packet_t::selected_kex, send_crypto_capabilities_packet(), send_protocol_version_packet(), crypto_handshake_context_t::server_uses_client_auth, crypto_parameters_packet_t::shared_secret_size, crypto_parameters_packet_t::signature_size, START_TIMER, crypto_handshake_context_t::state, STOP_TIMER, STOP_TIMER_AND_LOG, crypto_capabilities_packet_t::supported_auth_algorithms, crypto_capabilities_packet_t::supported_cipher_algorithms, crypto_capabilities_packet_t::supported_kex_algorithms, protocol_version_packet_t::supports_encryption, public_key_t::type, and crypto_parameters_packet_t::verification_enabled.

Referenced by server_connection_establish().

◆ client_crypto_init()

int client_crypto_init ( void  )

#include <crypto.c>

Initialize client crypto handshake.

Initialize client crypto handshake

Returns
0 on success, -1 on failure

Sets up the client-side cryptographic context with authentication credentials. Supports SSH key, password, and passwordless modes.

Returns
0 on success, -1 on failure

Definition at line 194 of file src/client/crypto.c.

194 {
195 log_debug("CLIENT_CRYPTO_INIT: Starting crypto initialization");
196 if (g_crypto_initialized) {
197 log_debug("CLIENT_CRYPTO_INIT: Already initialized, cleaning up and reinitializing");
199 g_crypto_initialized = false;
200 }
201
202 // Check if encryption is disabled
203 if (GET_OPTION(no_encrypt)) {
204 log_info("Encryption disabled via --no-encrypt");
205 log_debug("CLIENT_CRYPTO_INIT: Encryption disabled, returning 0");
206 return 0;
207 }
208
209 log_debug("CLIENT_CRYPTO_INIT: Initializing crypto handshake context");
210
211 // Check if we have an SSH key, password, or neither
212 int result;
213 bool is_ssh_key = false;
214 private_key_t private_key;
215
216 // Get string options safely
217 const options_t *opts = options_get();
218 const char *encrypt_key = opts && opts->encrypt_key[0] != '\0' ? opts->encrypt_key : "";
219 const char *password = opts && opts->password[0] != '\0' ? opts->password : "";
220 const char *address = opts && opts->address[0] != '\0' ? opts->address : "localhost";
221 const char *port = opts && opts->port[0] != '\0' ? opts->port : "27224";
222 const char *server_key = opts && opts->server_key[0] != '\0' ? opts->server_key : "";
223
224 // Load client private key if provided via --key
225 if (strlen(encrypt_key) > 0) {
226 // --key supports file-based authentication (SSH keys, GPG keys via gpg:keyid)
227
228 // For SSH key files (not gpg:keyid format), validate the file exists
229 if (strncmp(encrypt_key, "gpg:", 4) != 0) {
230 if (validate_ssh_key_file(encrypt_key) != 0) {
231 return -1;
232 }
233 }
234
235 // Parse key (handles SSH files and gpg:keyid format)
236 log_debug("CLIENT_CRYPTO_INIT: Loading private key for authentication: %s", encrypt_key);
237 if (parse_private_key(encrypt_key, &private_key) == ASCIICHAT_OK) {
238 log_info("Successfully parsed SSH private key");
239 log_debug("CLIENT_CRYPTO_INIT: Parsed key type=%d, KEY_TYPE_ED25519=%d", private_key.type, KEY_TYPE_ED25519);
240 is_ssh_key = true;
241 } else {
242 log_error("Failed to parse SSH key file: %s", encrypt_key);
243 log_error("This may be due to:");
244 log_error(" - Wrong password for encrypted key");
245 log_error(" - Unsupported key type (only Ed25519 is currently supported)");
246 log_error(" - Corrupted key file");
247 log_error("");
248 log_error("Note: RSA and ECDSA keys are not yet supported");
249 log_error("To generate an Ed25519 key: ssh-keygen -t ed25519");
250 return -1;
251 }
252 }
253
254 if (is_ssh_key) {
255 // Use SSH private key for authentication
256 log_debug("CLIENT_CRYPTO_INIT: Using SSH key for authentication");
257
258 // Initialize crypto context (generates ephemeral X25519 keys)
259 result = crypto_handshake_init(&g_crypto_ctx, false); // false = client
260 if (result != ASCIICHAT_OK) {
261 FATAL(result, "Failed to initialize crypto handshake");
262 }
263
264 // Store the Ed25519 keys for authentication
265 memcpy(&g_crypto_ctx.client_private_key, &private_key, sizeof(private_key_t));
266
267 // Extract Ed25519 public key from private key
272
273 // Extract GPG key ID if this is a GPG key (format: "gpg:KEYID")
274 if (strncmp(encrypt_key, "gpg:", 4) == 0) {
275 const char *key_id = encrypt_key + 4;
276 size_t key_id_len = strlen(key_id);
277 // Accept 8, 16, or 40 character GPG key IDs (short/long/full fingerprint)
278 if (key_id_len == 8 || key_id_len == 16 || key_id_len == 40) {
280 log_debug("CLIENT_CRYPTO_INIT: Extracted client GPG key ID (%zu chars): %s", key_id_len,
282 } else {
283 log_warn("CLIENT_CRYPTO_INIT: Invalid GPG key ID length: %zu (expected 8, 16, or 40)", key_id_len);
285 }
286 } else {
287 // Not a GPG key, clear the field
289 }
290
291 // SSH key is already configured in the handshake context above
292 // No additional setup needed - SSH keys are used only for authentication
293
294 // Clear the temporary private_key variable (we've already copied it to g_crypto_ctx)
295 sodium_memzero(&private_key, sizeof(private_key));
296
297 // If password is also provided, derive password key for dual authentication
298 if (strlen(password) > 0) {
299 log_debug("CLIENT_CRYPTO_INIT: Password also provided, deriving password key");
301 if (crypto_result != CRYPTO_OK) {
302 log_error("Failed to derive password key: %s", crypto_result_to_string(crypto_result));
303 return -1;
304 }
306 log_info("Password authentication enabled alongside SSH key");
307 }
308
309 } else if (strlen(GET_OPTION(password)) > 0) {
310 // Password provided - use password-based initialization
311 log_debug("CLIENT_CRYPTO_INIT: Using password authentication");
312 result = crypto_handshake_init_with_password(&g_crypto_ctx, false, GET_OPTION(password)); // false = client
313 if (result != ASCIICHAT_OK) {
314 FATAL(result, "Failed to initialize crypto handshake with password");
315 }
316 } else {
317 // No password or SSH key - use standard initialization with random keys
318 log_debug("CLIENT_CRYPTO_INIT: Using standard initialization");
319 result = crypto_handshake_init(&g_crypto_ctx, false); // false = client
320 if (result != ASCIICHAT_OK) {
321 FATAL(result, "Failed to initialize crypto handshake");
322 }
323 }
324
325 log_debug("CLIENT_CRYPTO_INIT: crypto_handshake_init succeeded");
326
327 // Set up server connection info for known_hosts
329 const char *server_ip = server_connection_get_ip();
330 log_debug("CLIENT_CRYPTO_INIT: server_connection_get_ip() returned: '%s'", server_ip ? server_ip : "NULL");
331 SAFE_STRNCPY(g_crypto_ctx.server_ip, server_ip ? server_ip : "", sizeof(g_crypto_ctx.server_ip) - 1);
333 log_debug("CLIENT_CRYPTO_INIT: Set server_ip='%s', server_port=%u", g_crypto_ctx.server_ip, g_crypto_ctx.server_port);
334
335 // Configure server key verification if specified
336 if (strlen(server_key) > 0) {
339 log_info("Server key verification enabled: %s", server_key);
340 }
341
342 // If --require-client-verify is set, perform ACDS session lookup for server identity
343 if (GET_OPTION(require_client_verify) && strlen(GET_OPTION(session_string)) > 0) {
344 log_info("--require-client-verify enabled: performing ACDS session lookup for '%s'", GET_OPTION(session_string));
345
346 // Connect to ACDS server (configurable via --acds-server and --acds-port options)
347 acds_client_config_t acds_config;
349 SAFE_STRNCPY(acds_config.server_address, GET_OPTION(acds_server), sizeof(acds_config.server_address));
350 acds_config.server_port = GET_OPTION(acds_port);
351 acds_config.timeout_ms = 5000;
352
353 acds_client_t acds_client;
354 asciichat_error_t acds_result = acds_client_connect(&acds_client, &acds_config);
355 if (acds_result != ASCIICHAT_OK) {
356 log_error("Failed to connect to ACDS server at %s:%d", acds_config.server_address, acds_config.server_port);
357 return -1;
358 }
359
360 // Perform SESSION_LOOKUP to get server's identity
361 acds_session_lookup_result_t lookup_result;
362 acds_result = acds_session_lookup(&acds_client, GET_OPTION(session_string), &lookup_result);
363 acds_client_disconnect(&acds_client);
364
365 if (acds_result != ASCIICHAT_OK || !lookup_result.found) {
366 log_error("ACDS session lookup failed for '%s': %s", GET_OPTION(session_string),
367 lookup_result.found ? "session not found" : "lookup error");
368 return -1;
369 }
370
371 // Convert server's Ed25519 public key (32 bytes) to hex string
372 char server_key_hex[65]; // 32 bytes * 2 + null terminator
373 for (size_t i = 0; i < 32; i++) {
374 SAFE_SNPRINTF(&server_key_hex[i * 2], 3, "%02x", lookup_result.host_pubkey[i]);
375 }
376 server_key_hex[64] = '\0';
377
378 // Set expected server key for verification during handshake
381 log_info("ACDS session lookup succeeded - server identity will be verified");
382 log_debug("Expected server key (from ACDS): %s", server_key_hex);
383 }
384
385 g_crypto_initialized = true;
386 log_info("Client crypto handshake initialized");
387 log_debug("CLIENT_CRYPTO_INIT: Initialization complete, g_crypto_initialized=true");
388 return 0;
389}
asciichat_error_t acds_session_lookup(acds_client_t *client, const char *session_string, acds_session_lookup_result_t *result)
Look up session by string.
void acds_client_config_init_defaults(acds_client_config_t *config)
Initialize ACDS client configuration with defaults.
Definition acds_client.c:38
asciichat_error_t acds_client_connect(acds_client_t *client, const acds_client_config_t *config)
Connect to ACDS server.
Definition acds_client.c:53
void acds_client_disconnect(acds_client_t *client)
Disconnect from ACDS server.
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.
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.
const char * server_connection_get_ip()
Get resolved server IP address.
#define SAFE_STRNCPY(dst, src, size)
Definition common.h:358
#define SAFE_SNPRINTF(buffer, buffer_size,...)
Definition common.h:412
const char * crypto_result_to_string(crypto_result_t result)
Convert crypto result to human-readable string.
crypto_result_t
Cryptographic operation result codes.
#define ED25519_PUBLIC_KEY_SIZE
Ed25519 public key size in bytes.
crypto_result_t crypto_derive_password_key(crypto_context_t *ctx, const char *password)
Derive key from password using Argon2id.
@ CRYPTO_OK
asciichat_error_t
Error and exit codes - unified status values (0-255)
Definition error_codes.h:46
uint8_t key[32]
Definition key_types.h:71
asciichat_error_t parse_private_key(const char *key_path, private_key_t *key_out)
Parse SSH private key from file.
Definition keys.c:108
char comment[256]
Definition key_types.h:72
key_type_t type
Definition key_types.h:92
char key_comment[256]
Definition key_types.h:100
uint8_t public_key[32]
Definition key_types.h:99
asciichat_error_t validate_ssh_key_file(const char *key_path)
Validate SSH key file before parsing.
Definition ssh_keys.c:977
int strtoint_safe(const char *str)
Safely parse string to integer with validation.
const options_t * options_get(void)
Get current options (lock-free read)
Definition rcu.c:222
ACDS client connection configuration.
Definition acds_client.h:44
char server_address[256]
ACDS server address (e.g., "discovery.ascii.chat" or "127.0.0.1")
Definition acds_client.h:45
uint32_t timeout_ms
Connection timeout in milliseconds.
Definition acds_client.h:47
uint16_t server_port
ACDS server port (default: 27225)
Definition acds_client.h:46
ACDS client connection handle.
Definition acds_client.h:53
Session lookup result.
bool found
Session exists.
uint8_t host_pubkey[32]
Host's Ed25519 public key.
Consolidated options structure.
Definition options.h:439
char port[256]
Server port number.
Definition options.h:464
char password[256]
Password string.
Definition options.h:543
char server_key[256]
Expected server public key (client)
Definition options.h:546
char encrypt_key[256]
SSH/GPG key file path.
Definition options.h:542
char address[256]
Server address (client) or bind address (server)
Definition options.h:462
Private key structure (for server –ssh-key)
Definition key_types.h:91

References acds_client_config_init_defaults(), acds_client_connect(), acds_client_disconnect(), acds_session_lookup(), options_state::address, ASCIICHAT_OK, crypto_handshake_context_t::client_gpg_key_id, crypto_handshake_context_t::client_private_key, crypto_handshake_context_t::client_public_key, public_key_t::comment, crypto_handshake_context_t::crypto_ctx, crypto_derive_password_key(), crypto_handshake_cleanup(), crypto_handshake_init(), crypto_handshake_init_with_password(), CRYPTO_OK, crypto_result_to_string(), ED25519_PUBLIC_KEY_SIZE, options_state::encrypt_key, crypto_handshake_context_t::expected_server_key, FATAL, acds_session_lookup_result_t::found, g_crypto_ctx, GET_OPTION, crypto_context_t::has_password, acds_session_lookup_result_t::host_pubkey, public_key_t::key, private_key_t::key_comment, KEY_TYPE_ED25519, log_debug, log_error, log_info, log_warn, options_get(), parse_private_key(), options_state::password, options_state::port, private_key_t::public_key, SAFE_SNPRINTF, SAFE_STRNCPY, acds_client_config_t::server_address, server_connection_get_ip(), crypto_handshake_context_t::server_hostname, crypto_handshake_context_t::server_ip, options_state::server_key, crypto_handshake_context_t::server_port, acds_client_config_t::server_port, strtoint_safe(), acds_client_config_t::timeout_ms, public_key_t::type, private_key_t::type, validate_ssh_key_file(), and crypto_handshake_context_t::verify_server_key.

Referenced by server_connection_establish().

◆ crypto_client_cleanup()

void crypto_client_cleanup ( void  )

#include <crypto.c>

Cleanup crypto client resources.

Cleanup crypto client resources

Definition at line 728 of file src/client/crypto.c.

728 {
729 if (g_crypto_initialized) {
731 g_crypto_initialized = false;
732 log_debug("Client crypto handshake cleaned up");
733 }
734}

References crypto_handshake_cleanup(), g_crypto_ctx, and log_debug.

◆ crypto_client_decrypt_packet()

int crypto_client_decrypt_packet ( const uint8_t ciphertext,
size_t  ciphertext_len,
uint8_t plaintext,
size_t  plaintext_size,
size_t *  plaintext_len 
)

#include <crypto.c>

Decrypt a received packet.

Decrypt a received packet

Parameters
ciphertextEncrypted data to decrypt
ciphertext_lenLength of encrypted data
plaintextOutput buffer for decrypted data
plaintext_sizeSize of output buffer
plaintext_lenOutput length of decrypted data
Returns
0 on success, -1 on failure
Parameters
ciphertextEncrypted data to decrypt
ciphertext_lenLength of encrypted data
plaintextOutput buffer for decrypted data
plaintext_sizeSize of output buffer
plaintext_lenOutput length of decrypted data
Returns
0 on success, -1 on failure

Definition at line 717 of file src/client/crypto.c.

718 {
719 return crypto_decrypt_packet_or_passthrough(&g_crypto_ctx, crypto_client_is_ready(), ciphertext, ciphertext_len,
720 plaintext, plaintext_size, plaintext_len);
721}
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.
bool crypto_client_is_ready(void)
Check if crypto handshake is ready.

References crypto_client_is_ready(), crypto_decrypt_packet_or_passthrough(), and g_crypto_ctx.

◆ crypto_client_encrypt_packet()

int crypto_client_encrypt_packet ( const uint8_t plaintext,
size_t  plaintext_len,
uint8_t ciphertext,
size_t  ciphertext_size,
size_t *  ciphertext_len 
)

#include <crypto.c>

Encrypt a packet for transmission.

Encrypt a packet for transmission

Parameters
plaintextPlaintext data to encrypt
plaintext_lenLength of plaintext data
ciphertextOutput buffer for encrypted data
ciphertext_sizeSize of output buffer
ciphertext_lenOutput length of encrypted data
Returns
0 on success, -1 on failure
Parameters
plaintextPlaintext data to encrypt
plaintext_lenLength of plaintext data
ciphertextOutput buffer for encrypted data
ciphertext_sizeSize of output buffer
ciphertext_lenOutput length of encrypted data
Returns
0 on success, -1 on failure

Definition at line 699 of file src/client/crypto.c.

700 {
702 ciphertext, ciphertext_size, ciphertext_len);
703}
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.

References crypto_client_is_ready(), crypto_encrypt_packet_or_passthrough(), and g_crypto_ctx.

◆ crypto_client_get_context()

const crypto_context_t * crypto_client_get_context ( void  )

#include <crypto.c>

Get crypto context for encryption/decryption.

Get crypto context for encryption/decryption

Returns
crypto context or NULL if not ready
crypto context or NULL if not ready

Definition at line 679 of file src/client/crypto.c.

679 {
680 if (!crypto_client_is_ready()) {
681 return NULL;
682 }
683
685}
const crypto_context_t * crypto_handshake_get_context(const crypto_handshake_context_t *ctx)
Get the crypto context for encryption/decryption.

References crypto_client_is_ready(), crypto_handshake_get_context(), and g_crypto_ctx.

Referenced by server_connection_establish(), threaded_send_audio_batch_packet(), and threaded_send_client_join_packet().

◆ crypto_client_initiate_rekey()

int crypto_client_initiate_rekey ( void  )

#include <crypto.c>

Initiate session rekeying (client-initiated)

Initiate session rekeying (client-initiated)

Returns
0 on success, -1 on failure
0 on success, -1 on failure

Definition at line 761 of file src/client/crypto.c.

761 {
762 if (!g_crypto_initialized || !crypto_client_is_ready()) {
763 log_error("Cannot initiate rekey: crypto not initialized or not ready");
764 return -1;
765 }
766
768 if (socket == INVALID_SOCKET_VALUE) {
769 log_error("Cannot initiate rekey: invalid socket");
770 return -1;
771 }
772
774 if (result != ASCIICHAT_OK) {
775 log_error("Failed to send REKEY_REQUEST: %d", result);
776 return -1;
777 }
778
779 return 0;
780}
asciichat_error_t crypto_handshake_rekey_request(crypto_handshake_context_t *ctx, socket_t socket)
Send REKEY_REQUEST packet (initiator side)
socket_t server_connection_get_socket()
Get current socket file descriptor.
#define INVALID_SOCKET_VALUE
Invalid socket value (POSIX: -1)
Definition socket.h:52

References ASCIICHAT_OK, crypto_client_is_ready(), crypto_handshake_rekey_request(), g_crypto_ctx, INVALID_SOCKET_VALUE, log_error, and server_connection_get_socket().

Referenced by __attribute__().

◆ crypto_client_is_ready()

bool crypto_client_is_ready ( void  )

#include <crypto.c>

Check if crypto handshake is ready.

Check if crypto handshake is ready

Returns
true if encryption is ready, false otherwise
true if encryption is ready, false otherwise

Definition at line 664 of file src/client/crypto.c.

664 {
665 if (!g_crypto_initialized || GET_OPTION(no_encrypt)) {
666 return false;
667 }
668
670}
bool crypto_handshake_is_ready(const crypto_handshake_context_t *ctx)
Check if handshake is complete and encryption is ready.

References crypto_handshake_is_ready(), g_crypto_ctx, and GET_OPTION.

Referenced by crypto_client_decrypt_packet(), crypto_client_encrypt_packet(), crypto_client_get_context(), crypto_client_initiate_rekey(), crypto_client_process_rekey_request(), crypto_client_process_rekey_response(), crypto_client_send_rekey_complete(), crypto_client_send_rekey_response(), crypto_client_should_rekey(), server_connection_establish(), threaded_send_audio_batch_packet(), and threaded_send_client_join_packet().

◆ crypto_client_process_rekey_request()

int crypto_client_process_rekey_request ( const uint8_t packet,
size_t  packet_len 
)

#include <crypto.c>

Process received REKEY_REQUEST packet from server.

Process received REKEY_REQUEST packet from server

Parameters
packetPacket data
packet_lenPacket length
Returns
0 on success, -1 on failure
Parameters
packetPacket data
packet_lenPacket length
Returns
0 on success, -1 on failure

Definition at line 791 of file src/client/crypto.c.

791 {
792 if (!g_crypto_initialized || !crypto_client_is_ready()) {
793 log_error("Cannot process rekey request: crypto not initialized or not ready");
794 return -1;
795 }
796
798 if (result != ASCIICHAT_OK) {
799 log_error("Failed to process REKEY_REQUEST: %d", result);
800 return -1;
801 }
802
803 return 0;
804}
asciichat_error_t crypto_handshake_process_rekey_request(crypto_handshake_context_t *ctx, const uint8_t *packet, size_t packet_len)
Process received REKEY_REQUEST packet (responder side)

References ASCIICHAT_OK, crypto_client_is_ready(), crypto_handshake_process_rekey_request(), g_crypto_ctx, and log_error.

◆ crypto_client_process_rekey_response()

int crypto_client_process_rekey_response ( const uint8_t packet,
size_t  packet_len 
)

#include <crypto.c>

Process received REKEY_RESPONSE packet from server.

Process received REKEY_RESPONSE packet from server

Parameters
packetPacket data
packet_lenPacket length
Returns
0 on success, -1 on failure
Parameters
packetPacket data
packet_lenPacket length
Returns
0 on success, -1 on failure

Definition at line 843 of file src/client/crypto.c.

843 {
844 if (!g_crypto_initialized || !crypto_client_is_ready()) {
845 log_error("Cannot process rekey response: crypto not initialized or not ready");
846 return -1;
847 }
848
850 if (result != ASCIICHAT_OK) {
851 log_error("Failed to process REKEY_RESPONSE: %d", result);
852 return -1;
853 }
854
855 return 0;
856}
asciichat_error_t crypto_handshake_process_rekey_response(crypto_handshake_context_t *ctx, const uint8_t *packet, size_t packet_len)
Process received REKEY_RESPONSE packet (initiator side)

References ASCIICHAT_OK, crypto_client_is_ready(), crypto_handshake_process_rekey_response(), g_crypto_ctx, and log_error.

◆ crypto_client_send_rekey_complete()

int crypto_client_send_rekey_complete ( void  )

#include <crypto.c>

Send REKEY_COMPLETE packet to server and commit to new key.

Send REKEY_COMPLETE packet to server and commit to new key

Returns
0 on success, -1 on failure
0 on success, -1 on failure

Definition at line 865 of file src/client/crypto.c.

865 {
866 if (!g_crypto_initialized || !crypto_client_is_ready()) {
867 log_error("Cannot send rekey complete: crypto not initialized or not ready");
868 return -1;
869 }
870
872 if (socket == INVALID_SOCKET_VALUE) {
873 log_error("Cannot send rekey complete: invalid socket");
874 return -1;
875 }
876
878 if (result != ASCIICHAT_OK) {
879 log_error("Failed to send REKEY_COMPLETE: %d", result);
880 return -1;
881 }
882
883 return 0;
884}
asciichat_error_t crypto_handshake_rekey_complete(crypto_handshake_context_t *ctx, socket_t socket)
Send REKEY_COMPLETE packet (initiator side)

References ASCIICHAT_OK, crypto_client_is_ready(), crypto_handshake_rekey_complete(), g_crypto_ctx, INVALID_SOCKET_VALUE, log_error, and server_connection_get_socket().

◆ crypto_client_send_rekey_response()

int crypto_client_send_rekey_response ( void  )

#include <crypto.c>

Send REKEY_RESPONSE packet to server.

Send REKEY_RESPONSE packet to server

Returns
0 on success, -1 on failure
0 on success, -1 on failure

Definition at line 813 of file src/client/crypto.c.

813 {
814 if (!g_crypto_initialized || !crypto_client_is_ready()) {
815 log_error("Cannot send rekey response: crypto not initialized or not ready");
816 return -1;
817 }
818
820 if (socket == INVALID_SOCKET_VALUE) {
821 log_error("Cannot send rekey response: invalid socket");
822 return -1;
823 }
824
826 if (result != ASCIICHAT_OK) {
827 log_error("Failed to send REKEY_RESPONSE: %d", result);
828 return -1;
829 }
830
831 return 0;
832}
asciichat_error_t crypto_handshake_rekey_response(crypto_handshake_context_t *ctx, socket_t socket)
Send REKEY_RESPONSE packet (responder side)

References ASCIICHAT_OK, crypto_client_is_ready(), crypto_handshake_rekey_response(), g_crypto_ctx, INVALID_SOCKET_VALUE, log_error, and server_connection_get_socket().

◆ crypto_client_should_rekey()

bool crypto_client_should_rekey ( void  )

#include <crypto.c>

Check if session rekeying should be triggered.

Check if session rekeying should be triggered

Returns
true if rekey should be initiated, false otherwise
true if rekey should be initiated, false otherwise

Definition at line 747 of file src/client/crypto.c.

747 {
748 if (!g_crypto_initialized || !crypto_client_is_ready()) {
749 return false;
750 }
752}
bool crypto_handshake_should_rekey(const crypto_handshake_context_t *ctx)
Check if rekeying should be triggered for this handshake context.

References crypto_client_is_ready(), crypto_handshake_should_rekey(), and g_crypto_ctx.

Referenced by __attribute__().