19static _Atomic
bool g_libsodium_initialized =
false;
24static const uint32_t CRYPTO_PACKET_PUBLIC_KEY = 100;
25static const uint32_t CRYPTO_PACKET_ENCRYPTED_DATA = 102;
26static const uint32_t CRYPTO_PACKET_AUTH_CHALLENGE = 103;
27static const uint32_t CRYPTO_PACKET_AUTH_RESPONSE = 104;
36 if (atomic_load(&g_libsodium_initialized)) {
43 if (sodium_init() < 0) {
48 atomic_store(&g_libsodium_initialized,
true);
66 (counter_size <
sizeof(counter)) ? counter_size : sizeof(counter));
70static void secure_memzero(
void *ptr,
size_t len) {
71 sodium_memzero(ptr, len);
135 if (is_test_environment()) {
138 char duration_str[32];
140 log_info(
"Crypto context initialized with X25519 key exchange (TEST MODE rekey thresholds: %llu packets, %s)",
145 char duration_str[32];
147 log_info(
"Crypto context initialized with X25519 key exchange (rekey thresholds: %llu packets, %s)",
154 if (!ctx || !password) {
159 if (strlen(password) == 0) {
179 log_info(
"Crypto context initialized with password-based encryption");
213 log_debug(
"Generated X25519 key pair for key exchange");
222 if (!ctx || !ctx->
initialized || !public_key_out) {
224 "crypto_get_public_key: Invalid parameters (ctx=%p, initialized=%d, public_key_out=%p)", ctx,
236 if (!ctx || !ctx->
initialized || !peer_public_key) {
238 "crypto_set_peer_public_key: Invalid parameters (ctx=%p, initialized=%d, peer_public_key=%p)", ctx,
257 log_debug(
"Key exchange completed - shared secret computed");
280 size_t password_len = strlen(password);
300 "crypto_derive_password_key: Invalid parameters (ctx=%p, initialized=%d, password=%p)", ctx,
308 return validation_result;
314 const char *deterministic_salt =
"ascii-chat-password-salt-v1";
315 size_t salt_str_len = strlen(deterministic_salt);
321 memcpy(ctx->
password_salt, deterministic_salt, (salt_str_len < ctx->salt_size) ? salt_str_len : ctx->
salt_size);
325 crypto_pwhash_OPSLIMIT_INTERACTIVE,
326 crypto_pwhash_MEMLIMIT_INTERACTIVE,
327 crypto_pwhash_ALG_DEFAULT) != 0) {
332 log_debug(
"Password key derived successfully using Argon2id with deterministic salt");
345 const char *deterministic_salt =
"ascii-chat-password-salt-v1";
347 size_t salt_str_len = strlen(deterministic_salt);
353 memcpy(salt, deterministic_salt, (salt_str_len < ctx->salt_size) ? salt_str_len : ctx->
salt_size);
357 crypto_pwhash_OPSLIMIT_INTERACTIVE, crypto_pwhash_MEMLIMIT_INTERACTIVE,
358 crypto_pwhash_ALG_DEFAULT) != 0) {
359 secure_memzero(test_key,
sizeof(test_key));
366 secure_memzero(test_key,
sizeof(test_key));
373 if (!password || !encryption_key) {
375 "crypto_derive_password_encryption_key: Invalid parameters (password=%p, encryption_key=%p)", password,
383 return validation_result;
388 const char *deterministic_salt =
"ascii-chat-password-salt-v1";
390 size_t salt_str_len = strlen(deterministic_salt);
399 if (crypto_pwhash(encryption_key,
SECRETBOX_KEY_SIZE, password, strlen(password), salt,
400 crypto_pwhash_OPSLIMIT_INTERACTIVE,
401 crypto_pwhash_MEMLIMIT_INTERACTIVE,
402 crypto_pwhash_ALG_DEFAULT) != 0) {
407 log_debug(
"Password encryption key derived successfully using Argon2id");
416 uint8_t *ciphertext_out,
size_t ciphertext_out_size,
size_t *ciphertext_len_out) {
417 if (!ctx || !ctx->
initialized || !plaintext || !ciphertext_out || !ciphertext_len_out) {
419 "Invalid parameters: ctx=%p, initialized=%d, plaintext=%p, ciphertext_out=%p, ciphertext_len_out=%p", ctx,
420 ctx ? ctx->
initialized : 0, plaintext, ciphertext_out, ciphertext_len_out);
436 if (ciphertext_out_size < required_size) {
437 SET_ERRNO(
ERROR_BUFFER,
"Ciphertext buffer too small: %zu < %zu", ciphertext_out_size, required_size);
452 generate_nonce(ctx, nonce);
456 const uint8_t *encryption_key = NULL;
467 if (crypto_secretbox_easy(ciphertext_out + ctx->
nonce_size, plaintext, plaintext_len, nonce, encryption_key) != 0) {
472 *ciphertext_len_out = required_size;
482 uint8_t *plaintext_out,
size_t plaintext_out_size,
size_t *plaintext_len_out) {
483 if (!ctx || !ctx->
initialized || !ciphertext || !plaintext_out || !plaintext_len_out) {
485 "Invalid parameters: ctx=%p, initialized=%d, ciphertext=%p, plaintext_out=%p, plaintext_len_out=%p", ctx,
486 ctx ? ctx->
initialized : 0, ciphertext, plaintext_out, plaintext_len_out);
497 if (ciphertext_len < min_ciphertext_size) {
503 if (plaintext_out_size < plaintext_len) {
509 const uint8_t *nonce = ciphertext;
513 const uint8_t *decryption_key = NULL;
524 if (crypto_secretbox_open_easy(plaintext_out, encrypted_data, ciphertext_len - ctx->
nonce_size, nonce,
525 decryption_key) != 0) {
530 *plaintext_len_out = plaintext_len;
545 return "Initialization failed";
547 return "Invalid parameters";
549 return "Memory allocation failed";
551 return "Libsodium error";
553 return "Key generation failed";
555 return "Password derivation failed";
557 return "Encryption failed";
559 return "Decryption failed";
561 return "Invalid MAC or corrupted data";
563 return "Buffer too small";
565 return "Key exchange not complete";
567 return "Nonce counter exhausted";
569 return "Rekey already in progress";
571 return "Rekey failed";
573 return "Rekey rate limited";
575 return "Unknown error";
580 if (!ctx || !status_buffer || buffer_size == 0) {
585 SAFE_SNPRINTF(status_buffer, buffer_size,
"Not initialized");
590 "Initialized: %s, Password: %s, Key Exchange: %s, Ready: %s, "
591 "Encrypted: %" PRIu64
" bytes, Decrypted: %" PRIu64
" bytes, Nonce: %" PRIu64,
601 return sodium_memcmp(lhs, rhs, len) == 0;
605 if (!buffer || len == 0) {
615 randombytes_buf(buffer, len);
624 size_t *packet_len_out) {
625 if (!ctx || !ctx->
initialized || !packet_out || !packet_len_out) {
627 "crypto_create_public_key_packet: Invalid parameters (ctx=%p, initialized=%d, packet_out=%p, "
628 "packet_len_out=%p)",
629 ctx, ctx ? ctx->
initialized : 0, packet_out, packet_len_out);
634 if (packet_size < required_size) {
635 SET_ERRNO(
ERROR_BUFFER,
"crypto_create_public_key_packet: Buffer too small (size=%zu, required=%zu)", packet_size,
641 uint32_t packet_type = CRYPTO_PACKET_PUBLIC_KEY;
642 SAFE_MEMCPY(packet_out,
sizeof(packet_type), &packet_type,
sizeof(packet_type));
647 *packet_len_out = required_size;
654 "crypto_process_public_key_packet: Invalid parameters (ctx=%p, initialized=%d, packet=%p)", ctx,
660 if (packet_len != expected_size) {
662 expected_size, packet_len);
668 SAFE_MEMCPY(&packet_type,
sizeof(packet_type), packet,
sizeof(packet_type));
670 if (packet_type != CRYPTO_PACKET_PUBLIC_KEY) {
672 CRYPTO_PACKET_PUBLIC_KEY, packet_type);
676 const uint8_t *peer_public_key = packet +
sizeof(packet_type);
681 uint8_t *packet_out,
size_t packet_size,
size_t *packet_len_out) {
682 if (!ctx || !data || !packet_out || !packet_len_out) {
684 "crypto_create_encrypted_packet: Invalid parameters (ctx=%p, data=%p, packet_out=%p, packet_len_out=%p)",
685 ctx, data, packet_out, packet_len_out);
710 if (encrypted_size > SIZE_MAX - header_size) {
714 size_t required_size = header_size + encrypted_size;
716 if (packet_size < required_size) {
717 SET_ERRNO(
ERROR_BUFFER,
"crypto_create_encrypted_packet: Buffer too small (size=%zu, required=%zu)", packet_size,
723 size_t ciphertext_len;
732 uint32_t packet_type = CRYPTO_PACKET_ENCRYPTED_DATA;
735 SAFE_MEMCPY(packet_out,
sizeof(packet_type), &packet_type,
sizeof(packet_type));
736 SAFE_MEMCPY(packet_out +
sizeof(packet_type),
sizeof(data_length), &data_length,
sizeof(data_length));
738 *packet_len_out = required_size;
743 uint8_t *data_out,
size_t data_size,
size_t *data_len_out) {
744 if (!ctx || !packet || !data_out || !data_len_out) {
746 "crypto_process_encrypted_packet: Invalid parameters (ctx=%p, packet=%p, data_out=%p, data_len_out=%p)",
747 ctx, packet, data_out, data_len_out);
764 SAFE_MEMCPY(&packet_type,
sizeof(packet_type), packet,
sizeof(packet_type));
765 SAFE_MEMCPY(&data_length,
sizeof(data_length), packet +
sizeof(packet_type),
sizeof(data_length));
767 if (packet_type != CRYPTO_PACKET_ENCRYPTED_DATA) {
769 CRYPTO_PACKET_ENCRYPTED_DATA, packet_type);
780 return crypto_decrypt(ctx, encrypted_data, data_length, data_out, data_size, data_len_out);
798 randombytes_buf(nonce, 32);
804 if (!ctx || !key || !data || !hmac) {
806 ctx, key, data, hmac);
814 crypto_auth_hmacsha256(hmac, data, 32, key);
819 size_t data_len,
uint8_t hmac[32]) {
820 if (!ctx || !key || !data || !hmac || data_len == 0) {
822 "crypto_compute_hmac_ex: Invalid parameters (ctx=%p, key=%p, data=%p, data_len=%zu, hmac=%p)", ctx,
823 key, data, data_len, hmac);
831 crypto_auth_hmacsha256(hmac, data, data_len, key);
836 if (!key || !data || !expected_hmac) {
838 data, expected_hmac);
843 if (crypto_auth_hmacsha256(computed_hmac, data, 32, key) != 0) {
847 return sodium_memcmp(computed_hmac, expected_hmac, 32) == 0;
851 const uint8_t expected_hmac[32]) {
852 if (!key || !data || !expected_hmac || data_len == 0) {
854 "crypto_verify_hmac_ex: Invalid parameters (key=%p, data=%p, data_len=%zu, expected_hmac=%p)", key, data,
855 data_len, expected_hmac);
860 if (crypto_auth_hmacsha256(computed_hmac, data, data_len, key) != 0) {
864 return sodium_memcmp(computed_hmac, expected_hmac, 32) == 0;
873 if (!ctx || !nonce || !hmac_out) {
875 ctx, nonce, hmac_out);
889 memcpy(combined_data, nonce, 32);
890 memcpy(combined_data + 32, ctx->
shared_key, 32);
898 sodium_memzero(combined_data,
sizeof(combined_data));
904 const uint8_t expected_hmac[32]) {
905 if (!ctx || !nonce || !expected_hmac) {
907 "crypto_verify_auth_response: Invalid parameters (ctx=%p, nonce=%p, expected_hmac=%p)", ctx, nonce,
922 memcpy(combined_data, nonce, 32);
923 memcpy(combined_data + 32, ctx->
shared_key, 32);
928 log_debug(
"Verifying auth response: has_password=%d, key_exchange_complete=%d, using_password_key=%d",
934 sodium_memzero(combined_data,
sizeof(combined_data));
940 size_t *packet_len_out) {
941 if (!ctx || !ctx->
initialized || !packet_out || !packet_len_out) {
944 "crypto_create_auth_challenge: Invalid parameters (ctx=%p, initialized=%d, packet_out=%p, packet_len_out=%p)",
945 ctx, ctx ? ctx->
initialized : 0, packet_out, packet_len_out);
950 if (packet_size < required_size) {
951 SET_ERRNO(
ERROR_BUFFER,
"crypto_create_auth_challenge: Buffer too small (size=%zu, required=%zu)", packet_size,
963 uint32_t packet_type = CRYPTO_PACKET_AUTH_CHALLENGE;
964 SAFE_MEMCPY(packet_out,
sizeof(packet_type), &packet_type,
sizeof(packet_type));
967 *packet_len_out = required_size;
974 "crypto_process_auth_challenge: Invalid parameters (ctx=%p, initialized=%d, packet=%p)", ctx,
980 if (packet_len != expected_size) {
982 expected_size, packet_len);
988 SAFE_MEMCPY(&packet_type,
sizeof(packet_type), packet,
sizeof(packet_type));
990 if (packet_type != CRYPTO_PACKET_AUTH_CHALLENGE) {
992 CRYPTO_PACKET_AUTH_CHALLENGE, packet_type);
999 log_debug(
"Auth challenge received and processed");
1006 "crypto_process_auth_response: Invalid context or packet (ctx=%p, initialized=%d, packet=%p)", ctx,
1011 size_t expected_size =
sizeof(
uint32_t) + 32;
1012 if (packet_len != expected_size) {
1014 expected_size, packet_len);
1020 SAFE_MEMCPY(&packet_type,
sizeof(packet_type), packet,
sizeof(packet_type));
1022 if (packet_type != CRYPTO_PACKET_AUTH_RESPONSE) {
1024 CRYPTO_PACKET_AUTH_RESPONSE, packet_type);
1028 const uint8_t *received_hmac = packet +
sizeof(packet_type);
1037 log_debug(
"Authentication successful - handshake complete");
1047 if (!ctx || !password_key || !nonce || !shared_secret || !hmac_out) {
1049 "Invalid parameters: ctx=%p, password_key=%p, nonce=%p, shared_secret=%p, hmac_out=%p", ctx,
1050 password_key, nonce, shared_secret, hmac_out);
1056 memcpy(combined_data, nonce, 32);
1057 memcpy(combined_data + 32, shared_secret, 32);
1062 sodium_memzero(combined_data,
sizeof(combined_data));
1067 sodium_memzero(combined_data,
sizeof(combined_data));
1073 size_t ephemeral_key_size,
const uint8_t *signature) {
1074 if (!peer_public_key || !ephemeral_key || !signature) {
1076 peer_public_key, ephemeral_key, signature);
1079 if (ephemeral_key_size == 0) {
1084 if (crypto_sign_verify_detached(signature, ephemeral_key, ephemeral_key_size, peer_public_key) != 0) {
1092 size_t ephemeral_key_size,
uint8_t *signature_out) {
1093 if (!private_key || !ephemeral_key || !signature_out) {
1095 private_key, ephemeral_key, signature_out);
1098 if (ephemeral_key_size == 0) {
1105 if (crypto_sign_detached(signature_out, NULL, ephemeral_key, ephemeral_key_size, private_key->
key.
ed25519) != 0) {
1116 if (!hmac || !challenge_nonce || !combined_out) {
1118 challenge_nonce, combined_out);
1123 memcpy(combined_out, hmac, 32);
1124 memcpy(combined_out + 32, challenge_nonce, 32);
1128 if (!combined_data || !hmac_out || !challenge_out) {
1130 hmac_out, challenge_out);
1135 memcpy(hmac_out, combined_data, 32);
1136 memcpy(challenge_out, combined_data + 32, 32);
1166 time_t now = time(NULL);
1169 log_debug(
"Rekey triggered: time elapsed (%ld sec) >= threshold (%ld sec)", (
long)elapsed,
1189 time_t now = time(NULL);
1192 char elapsed_str[32], min_str[32];
1195 log_warn(
"Rekey rate limited: %s since last rekey (minimum: %s)", elapsed_str, min_str);
1214 log_info(
"Rekey initiated (packets: %llu, time elapsed: %ld sec, attempt %d)",
1221 if (!ctx || !ctx->
initialized || !peer_new_public_key) {
1243 log_debug(
"Rekey request processed (responder side), new shared secret computed");
1249 if (!ctx || !ctx->
initialized || !peer_new_public_key) {
1266 log_debug(
"Rekey response processed (initiator side), new shared secret computed");
1309 log_info(
"Rekey committed successfully (rekey #%llu, nonce reset to 1, new session_id generated)",
1338 if (!ctx || !status_buffer || buffer_size == 0) {
1342 time_t now = time(NULL);
1349 snprintf(status_buffer, buffer_size,
1350 "Rekey status: %s | "
1351 "Packets: %llu/%llu (%llu remaining) | "
1352 "Time: %ld/%ld sec (%ld sec remaining) | "
1353 "Rekeys: %llu | Failures: %d",
⚠️‼️ Error and/or exit() when things go bad.
#define SAFE_SNPRINTF(buffer, buffer_size,...)
unsigned long long uint64_t
#define SAFE_MEMCPY(dest, dest_size, src, count)
crypto_result_t crypto_rekey_commit(crypto_context_t *ctx)
Commit to new keys after successful REKEY_COMPLETE.
crypto_result_t crypto_create_auth_challenge(const crypto_context_t *ctx, uint8_t *packet_out, size_t packet_size, size_t *packet_len_out)
Create authentication challenge packet.
crypto_result_t crypto_process_public_key_packet(crypto_context_t *ctx, const uint8_t *packet, size_t packet_len)
Process received public key packet from peer.
void crypto_cleanup(crypto_context_t *ctx)
Cleanup crypto context with secure memory wiping.
crypto_result_t crypto_compute_hmac_ex(const crypto_context_t *ctx, const uint8_t key[32], const uint8_t *data, size_t data_len, uint8_t hmac[32])
Compute HMAC-SHA256 for variable-length data.
#define REKEY_MIN_INTERVAL
Minimum time interval between rekey requests (3 seconds for testing, 60 for production)
crypto_result_t crypto_set_peer_public_key(crypto_context_t *ctx, const uint8_t *peer_public_key)
Set peer's public key and compute shared secret (step 2 of handshake)
crypto_result_t crypto_encrypt(crypto_context_t *ctx, const uint8_t *plaintext, size_t plaintext_len, uint8_t *ciphertext_out, size_t ciphertext_out_size, size_t *ciphertext_len_out)
Encrypt data using XSalsa20-Poly1305.
#define ED25519_SIGNATURE_SIZE
Ed25519 signature size in bytes.
#define AUTH_CHALLENGE_SIZE
Challenge nonce size (32 bytes)
crypto_result_t crypto_compute_auth_response(const crypto_context_t *ctx, const uint8_t nonce[32], uint8_t hmac_out[32])
Compute authentication response HMAC bound to DH shared_secret.
crypto_result_t crypto_init(crypto_context_t *ctx)
Initialize libsodium and crypto context.
#define HMAC_SHA256_SIZE
HMAC-SHA256 output size in bytes.
crypto_result_t crypto_generate_nonce(uint8_t nonce[32])
Generate random nonce for authentication.
asciichat_error_t crypto_compute_password_hmac(crypto_context_t *ctx, const uint8_t *password_key, const uint8_t *nonce, const uint8_t *shared_secret, uint8_t *hmac_out)
Compute password-based HMAC for authentication.
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 REKEY_DEFAULT_TIME_THRESHOLD
Default rekey time threshold (1 hour in seconds)
#define REKEY_MAX_FAILURE_COUNT
Maximum consecutive rekey failures before giving up.
#define SECRETBOX_KEY_SIZE
Secretbox key size in bytes.
asciichat_error_t crypto_verify_peer_signature(const uint8_t *peer_public_key, const uint8_t *ephemeral_key, size_t ephemeral_key_size, const uint8_t *signature)
Verify peer's signature on ephemeral key.
bool crypto_verify_hmac_ex(const uint8_t key[32], const uint8_t *data, size_t data_len, const uint8_t expected_hmac[32])
Verify HMAC-SHA256 for variable-length data.
bool crypto_verify_password(const crypto_context_t *ctx, const char *password)
Verify password matches stored salt/key.
crypto_result_t crypto_get_public_key(const crypto_context_t *ctx, uint8_t *public_key_out)
Get public key for sending to peer (step 1 of handshake)
crypto_result_t crypto_create_encrypted_packet(crypto_context_t *ctx, const uint8_t *data, size_t data_len, uint8_t *packet_out, size_t packet_size, size_t *packet_len_out)
Create encrypted data packet for network transmission.
void crypto_get_rekey_status(const crypto_context_t *ctx, char *status_buffer, size_t buffer_size)
Get the current rekeying state for debugging/logging.
bool crypto_should_rekey(const crypto_context_t *ctx)
Check if rekeying should be triggered based on time or packet count thresholds.
crypto_result_t crypto_process_auth_response(crypto_context_t *ctx, const uint8_t *packet, size_t packet_len)
Process authentication response packet.
crypto_result_t crypto_generate_keypair(crypto_context_t *ctx)
Generate new X25519 key pair for key exchange.
#define MIN_PASSWORD_LENGTH
Minimum password length (8 characters)
void crypto_combine_auth_data(const uint8_t *hmac, const uint8_t *challenge_nonce, uint8_t *combined_out)
Combine HMAC and challenge nonce for transmission.
bool crypto_verify_hmac(const uint8_t key[32], const uint8_t data[32], const uint8_t expected_hmac[32])
Verify HMAC-SHA256 for fixed 32-byte data.
crypto_result_t crypto_process_auth_challenge(crypto_context_t *ctx, const uint8_t *packet, size_t packet_len)
Process authentication challenge packet.
#define X25519_KEY_SIZE
X25519 key size in bytes.
void crypto_extract_auth_data(const uint8_t *combined_data, uint8_t *hmac_out, uint8_t *challenge_out)
Extract HMAC and challenge nonce from combined data.
#define MAX_PASSWORD_LENGTH
Maximum password length (256 characters)
void crypto_get_status(const crypto_context_t *ctx, char *status_buffer, size_t buffer_size)
Get crypto context status information for debugging.
void crypto_rekey_abort(crypto_context_t *ctx)
Abort rekeying and fallback to old keys.
bool crypto_is_ready(const crypto_context_t *ctx)
Check if key exchange is complete and ready for encryption.
crypto_result_t crypto_validate_password(const char *password)
Validate password length requirements.
crypto_result_t crypto_rekey_process_request(crypto_context_t *ctx, const uint8_t *peer_new_public_key)
Process REKEY_REQUEST from peer (responder side)
#define XSALSA20_NONCE_SIZE
XSalsa20 nonce size in bytes.
asciichat_error_t crypto_sign_ephemeral_key(const private_key_t *private_key, const uint8_t *ephemeral_key, size_t ephemeral_key_size, uint8_t *signature_out)
Sign ephemeral key with private key.
bool crypto_secure_compare(const uint8_t *lhs, const uint8_t *rhs, size_t len)
Secure constant-time comparison of byte arrays.
#define REKEY_TEST_PACKET_THRESHOLD
Test mode rekey packet threshold (1000 packets)
crypto_result_t crypto_compute_hmac(crypto_context_t *ctx, const uint8_t key[32], const uint8_t data[32], uint8_t hmac[32])
Compute HMAC-SHA256 for fixed 32-byte data.
crypto_result_t crypto_derive_password_key(crypto_context_t *ctx, const char *password)
Derive key from password using Argon2id.
#define ARGON2ID_SALT_SIZE
Argon2id salt size in bytes.
#define REKEY_TEST_TIME_THRESHOLD
Test mode rekey time threshold (30 seconds)
crypto_result_t crypto_decrypt(crypto_context_t *ctx, const uint8_t *ciphertext, size_t ciphertext_len, uint8_t *plaintext_out, size_t plaintext_out_size, size_t *plaintext_len_out)
Decrypt data using XSalsa20-Poly1305.
crypto_result_t crypto_derive_password_encryption_key(const char *password, uint8_t encryption_key[32])
Derive deterministic encryption key from password for handshake.
crypto_result_t crypto_init_with_password(crypto_context_t *ctx, const char *password)
Initialize with password-based encryption.
crypto_result_t crypto_create_public_key_packet(const crypto_context_t *ctx, uint8_t *packet_out, size_t packet_size, size_t *packet_len_out)
Create public key packet for network transmission.
#define REKEY_DEFAULT_PACKET_THRESHOLD
Default rekey packet threshold (1 million packets)
crypto_result_t crypto_rekey_init(crypto_context_t *ctx)
Initiate rekeying by generating new ephemeral keys.
crypto_result_t crypto_random_bytes(uint8_t *buffer, size_t len)
Generate cryptographically secure random bytes.
crypto_result_t crypto_process_encrypted_packet(crypto_context_t *ctx, const uint8_t *packet, size_t packet_len, uint8_t *data_out, size_t data_size, size_t *data_len_out)
Process received encrypted packet from peer.
bool crypto_verify_auth_response(const crypto_context_t *ctx, const uint8_t nonce[32], const uint8_t expected_hmac[32])
Verify authentication response HMAC bound to DH shared_secret.
crypto_result_t crypto_rekey_process_response(crypto_context_t *ctx, const uint8_t *peer_new_public_key)
Process REKEY_RESPONSE from peer (initiator side)
#define POLY1305_MAC_SIZE
Poly1305 MAC size in bytes.
#define CRYPTO_MAX_PLAINTEXT_SIZE
Maximum plaintext size (1MB)
@ CRYPTO_ERROR_REKEY_IN_PROGRESS
@ CRYPTO_ERROR_KEY_GENERATION
@ CRYPTO_ERROR_REKEY_RATE_LIMITED
@ CRYPTO_ERROR_PASSWORD_DERIVATION
@ CRYPTO_ERROR_INVALID_MAC
@ CRYPTO_ERROR_DECRYPTION
@ CRYPTO_ERROR_ENCRYPTION
@ CRYPTO_ERROR_KEY_EXCHANGE_INCOMPLETE
@ CRYPTO_ERROR_REKEY_FAILED
@ CRYPTO_ERROR_INVALID_PARAMS
@ CRYPTO_ERROR_BUFFER_TOO_SMALL
@ CRYPTO_ERROR_NONCE_EXHAUSTED
@ CRYPTO_ERROR_INIT_FAILED
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it.
asciichat_error_t
Error and exit codes - unified status values (0-255)
union private_key_t::@1 key
#define log_warn(...)
Log a WARN message.
#define log_error(...)
Log an ERROR message.
#define log_info(...)
Log an INFO message.
#define log_debug(...)
Log a DEBUG message.
int format_duration_s(double seconds, char *buffer, size_t buffer_size)
Format seconds as human-readable duration string.
Server cryptographic operations and per-client handshake management.
Cryptographic context structure.
uint8_t encryption_key_size
uint8_t temp_public_key[32]
time_t rekey_time_threshold
uint64_t rekey_packet_count
uint8_t rekey_failure_count
uint8_t temp_private_key[32]
bool key_exchange_complete
uint64_t rekey_packet_threshold
uint16_t private_key_size
uint8_t auth_challenge_size
time_t rekey_last_request_time
uint8_t peer_public_key[32]
uint8_t temp_shared_key[32]
uint8_t password_salt[32]
Private key structure (for server –ssh-key)
Test environment detection utilities.
⏱️ High-precision timing utilities using sokol_time.h and uthash