|
ascii-chat 0.6.0
Real-time terminal-based video chat with ASCII art conversion
|
🔐 Core cryptographic operations for ascii-chat More...
Files | |
| file | crypto.c |
| 🔐 Core cryptography: encryption/decryption, key exchange, authentication, and session rekeying with BearSSL | |
| file | agent.c |
| GPG agent connection and communication implementation. | |
| file | agent.h |
| GPG agent connection and communication interface. | |
| file | export.c |
| GPG public key export implementation. | |
| file | export.h |
| GPG public key export interface. | |
| file | gpg.h |
| GPG operations - main header. | |
| file | signing.c |
| GPG signing operations implementation. | |
| file | signing.h |
| GPG message signing interface. | |
| file | verification.c |
| GPG signature verification implementation. | |
| file | verification.h |
| GPG signature verification interface. | |
| file | known_hosts.c |
| 📜 SSH known_hosts file parser for host key verification and trust management | |
| file | known_hosts.h |
| Known hosts management for MITM attack prevention. | |
| file | pem_utils.c |
| 📄 PEM format encoding/decoding utilities for certificates and keys (adapted from BearSSL) | |
| file | pem_utils.h |
| BearSSL PEM and trust anchor utilities adapted for in-memory data. | |
Data Structures | |
| struct | crypto_context_t |
| Cryptographic context structure. More... | |
| struct | anchor_list |
| Vector type for trust anchors. More... | |
Macros | |
| #define | SERVER_AUTH_RESPONSE_SIZE AUTH_HMAC_SIZE |
| Server authentication response size (32 bytes) | |
| #define | SSH_KEY_TYPE_LENGTH_SIZE 4 |
| #define | SSH_KEY_TYPE_STRING_SIZE 11 |
| #define | SSH_KEY_PUBLIC_KEY_LENGTH_SIZE 4 |
| #define | SSH_KEY_PUBLIC_KEY_SIZE 32 |
| #define | SSH_KEY_HEADER_SIZE (SSH_KEY_TYPE_LENGTH_SIZE + SSH_KEY_TYPE_STRING_SIZE + SSH_KEY_PUBLIC_KEY_LENGTH_SIZE + SSH_KEY_PUBLIC_KEY_SIZE) |
| #define | CRYPTO_KEY_SIZE 32 |
| Ed25519 key size in bytes. | |
| #define | CRYPTO_FINGERPRINT_SIZE 32 |
| Ed25519 key fingerprint size in bytes. | |
| #define | SSH_KEY_PERMISSIONS_MASK (S_IRWXG | S_IRWXO) |
| #define | SSH_KEY_RECOMMENDED_PERMISSIONS 0600 |
| #define | MAX_COMMENT_LEN 256 |
| #define | MAX_GPG_KEYGRIP_LEN 64 |
Typedefs | |
| typedef struct crypto_context_t | crypto_context_t |
| Cryptographic context structure. | |
Enumerations | |
| enum | crypto_result_t { CRYPTO_OK = 0 , CRYPTO_ERROR_INIT_FAILED = -1 , CRYPTO_ERROR_INVALID_PARAMS = -2 , CRYPTO_ERROR_MEMORY = -3 , CRYPTO_ERROR_LIBSODIUM = -4 , CRYPTO_ERROR_KEY_GENERATION = -5 , CRYPTO_ERROR_PASSWORD_DERIVATION = -6 , CRYPTO_ERROR_ENCRYPTION = -7 , CRYPTO_ERROR_DECRYPTION = -8 , CRYPTO_ERROR_INVALID_MAC = -9 , CRYPTO_ERROR_BUFFER_TOO_SMALL = -10 , CRYPTO_ERROR_KEY_EXCHANGE_INCOMPLETE = -11 , CRYPTO_ERROR_NONCE_EXHAUSTED = -12 , CRYPTO_ERROR_REKEY_IN_PROGRESS = -13 , CRYPTO_ERROR_REKEY_FAILED = -14 , CRYPTO_ERROR_REKEY_RATE_LIMITED = -15 } |
| Cryptographic operation result codes. More... | |
Variables | |
| br_x509_trust_anchor * | anchor_list::buf |
| size_t | anchor_list::ptr |
| size_t | anchor_list::len |
Core Initialization and Setup | |
| crypto_result_t | crypto_init (crypto_context_t *ctx) |
| Initialize libsodium and crypto context. | |
| crypto_result_t | crypto_init_with_password (crypto_context_t *ctx, const char *password) |
| Initialize with password-based encryption. | |
| void | crypto_cleanup (crypto_context_t *ctx) |
| Cleanup crypto context with secure memory wiping. | |
| crypto_result_t | crypto_generate_keypair (crypto_context_t *ctx) |
| Generate new X25519 key pair for key exchange. | |
Key Exchange Protocol | |
Automatic HTTPS-like key exchange using X25519 Diffie-Hellman. Both parties exchange ephemeral public keys and compute a shared secret. | |
| 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_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) | |
| bool | crypto_is_ready (const crypto_context_t *ctx) |
| Check if key exchange is complete and ready for encryption. | |
Password-Based Encryption | |
Optional additional encryption layer using password-derived keys. Uses Argon2id for memory-hard key derivation, providing resistance to offline brute-force attacks. | |
| crypto_result_t | crypto_validate_password (const char *password) |
| Validate password length requirements. | |
| crypto_result_t | crypto_derive_password_key (crypto_context_t *ctx, const char *password) |
| Derive key from password using Argon2id. | |
| bool | crypto_verify_password (const crypto_context_t *ctx, const char *password) |
| Verify password matches stored salt/key. | |
| crypto_result_t | crypto_derive_password_encryption_key (const char *password, uint8_t encryption_key[32]) |
| Derive deterministic encryption key from password for handshake. | |
Encryption/Decryption Operations | |
Encrypt/decrypt data using XSalsa20-Poly1305 (via libsodium secretbox). Automatically handles nonce generation and MAC verification. | |
| 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. | |
| 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. | |
Utility Functions | |
| const char * | crypto_result_to_string (crypto_result_t result) |
| Convert crypto result to human-readable string. | |
| void | crypto_get_status (const crypto_context_t *ctx, char *status_buffer, size_t buffer_size) |
| Get crypto context status information for debugging. | |
| bool | crypto_secure_compare (const uint8_t *lhs, const uint8_t *rhs, size_t len) |
| Secure constant-time comparison of byte arrays. | |
| crypto_result_t | crypto_random_bytes (uint8_t *buffer, size_t len) |
| Generate cryptographically secure random bytes. | |
Authentication and Handshake | |
HMAC-based authentication using HMAC-SHA256. Used for password authentication and challenge-response protocols. | |
| crypto_result_t | crypto_generate_nonce (uint8_t nonce[32]) |
| Generate random nonce for authentication. | |
| 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_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. | |
| 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. | |
| 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. | |
High-Level Authentication Helpers | |
Authentication helpers that bind password/key authentication to the DH key exchange, preventing man-in-the-middle attacks. | |
| 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. | |
| 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_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_auth_challenge (crypto_context_t *ctx, const uint8_t *packet, size_t packet_len) |
| Process authentication challenge packet. | |
| crypto_result_t | crypto_process_auth_response (crypto_context_t *ctx, const uint8_t *packet, size_t packet_len) |
| Process authentication response packet. | |
Network Integration Helpers | |
Packet creation and processing functions for network transmission. Handles packet formatting, encryption, and decryption automatically. | |
| 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. | |
| 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. | |
| 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. | |
| 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. | |
Shared Cryptographic Operations | |
Low-level cryptographic operations used by both client and server for authentication and key exchange. | |
| 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. | |
| 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. | |
| 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. | |
| 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. | |
| 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. | |
Session Rekeying Protocol | |
Periodic key rotation to limit exposure if keys are compromised. Rekeys after time threshold (default: 1 hour) OR packet count threshold (default: 1 million), whichever comes first.
| |
| 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_rekey_init (crypto_context_t *ctx) |
| Initiate rekeying by generating new ephemeral keys. | |
| 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) | |
| 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) | |
| crypto_result_t | crypto_rekey_commit (crypto_context_t *ctx) |
| Commit to new keys after successful REKEY_COMPLETE. | |
| void | crypto_rekey_abort (crypto_context_t *ctx) |
| Abort rekeying and fallback to old keys. | |
| 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. | |
| #define | REKEY_MIN_INTERVAL 3 |
| Minimum time interval between rekey requests (3 seconds for testing, 60 for production) | |
| #define | REKEY_DEFAULT_TIME_THRESHOLD 3600 |
| Default rekey time threshold (1 hour in seconds) | |
| #define | REKEY_DEFAULT_PACKET_THRESHOLD 1000000 |
| Default rekey packet threshold (1 million packets) | |
| #define | REKEY_TEST_TIME_THRESHOLD 30 |
| Test mode rekey time threshold (30 seconds) | |
| #define | REKEY_TEST_PACKET_THRESHOLD 1000 |
| Test mode rekey packet threshold (1000 packets) | |
| #define | REKEY_MAX_FAILURE_COUNT 10 |
| Maximum consecutive rekey failures before giving up. | |
| #define | REKEY_MIN_REQUEST_INTERVAL 60 |
| Minimum interval between rekey requests (60 seconds, DDoS protection) | |
GPG Agent Connection Management | |
| int | gpg_agent_connect (void) |
| Connect to gpg-agent. | |
| void | gpg_agent_disconnect (int sock) |
| Disconnect from gpg-agent. | |
| bool | gpg_agent_is_available (void) |
| Check if GPG agent is available. | |
GPG Agent Signing Operations | |
| int | gpg_agent_sign (int sock, const char *keygrip, const uint8_t *message, size_t message_len, uint8_t *signature_out, size_t *signature_len_out) |
| Sign a message using GPG agent. | |
GPG Key Export | |
| int | gpg_get_public_key (const char *key_id, uint8_t *public_key_out, char *keygrip_out) |
| Get public key from GPG keyring by key ID. | |
GPG Signing Operations | |
| int | gpg_sign_with_key (const char *key_id, const uint8_t *message, size_t message_len, uint8_t *signature_out, size_t *signature_len_out) |
| Sign a message using GPG key and return OpenPGP signature. | |
| int | gpg_sign_detached_ed25519 (const char *key_id, const uint8_t *message, size_t message_len, uint8_t signature_out[64]) |
| Sign message with GPG and extract raw Ed25519 signature. | |
GPG Signature Verification | |
| int | gpg_verify_detached_ed25519 (const char *key_id, const uint8_t *message, size_t message_len, const uint8_t signature[64]) |
| Verify Ed25519 signature using GPG binary. | |
| int | gpg_verify_signature (const uint8_t *public_key, const uint8_t *message, size_t message_len, const uint8_t *signature) |
| Verify Ed25519 signature using libgcrypt (no GPG binary required) | |
| int | gpg_verify_signature_with_binary (const uint8_t *signature, size_t signature_len, const uint8_t *message, size_t message_len, const char *expected_key_id) |
| Verify OpenPGP signature using GPG binary. | |
Known Hosts Management | |
| const char * | get_known_hosts_path (void) |
| Get the path to the known_hosts file. | |
| asciichat_error_t | add_known_host (const char *server_ip, uint16_t port, const uint8_t server_key[32]) |
| Add server to known_hosts. | |
| asciichat_error_t | remove_known_host (const char *server_ip, uint16_t port) |
| Remove server from known_hosts. | |
Known Hosts Verification | |
| asciichat_error_t | check_known_host (const char *server_ip, uint16_t port, const uint8_t server_key[32]) |
| Check if server key is in known_hosts. | |
| asciichat_error_t | check_known_host_no_identity (const char *server_ip, uint16_t port) |
| Check known_hosts for servers without identity key (no-identity entries) | |
User Interaction | |
| bool | display_mitm_warning (const char *server_ip, uint16_t port, const uint8_t expected_key[32], const uint8_t received_key[32]) |
| Display MITM warning with key comparison and prompt user for confirmation. | |
| bool | prompt_unknown_host (const char *server_ip, uint16_t port, const uint8_t server_key[32]) |
| Interactive prompt for unknown host - returns true if user wants to add, false to abort. | |
| bool | prompt_unknown_host_no_identity (const char *server_ip, uint16_t port) |
| Interactive prompt for unknown host without identity key - returns true if user wants to continue, false to abort. | |
Key Fingerprinting | |
| void | compute_key_fingerprint (const uint8_t key[32], char fingerprint[65]) |
| Compute SHA256 fingerprint of Ed25519 key for display. | |
Cleanup | |
| void | known_hosts_cleanup (void) |
| Cleanup function to free cached known_hosts path. | |
Trust Anchor Management | |
| size_t | read_trust_anchors_from_memory (anchor_list *dst, const unsigned char *pem_data, size_t pem_len) |
| Read trust anchors from PEM-encoded data in memory. | |
| void | free_ta_contents (br_x509_trust_anchor *ta) |
| Free the contents of a trust anchor. | |
| #define | ANCHOR_LIST_INIT {NULL, 0, 0} |
| Initializer for anchor_list. | |
SSH Agent Detection | |
| bool | ssh_agent_is_available (void) |
| Check if ssh-agent is running and available. | |
SSH Agent Key Management | |
| asciichat_error_t | ssh_agent_add_key (const private_key_t *private_key, const char *key_path) |
| Add a private key to ssh-agent. | |
| bool | ssh_agent_has_key (const public_key_t *public_key) |
| Check if a public key is already in ssh-agent. | |
| asciichat_error_t | ssh_agent_get_key (const public_key_t *public_key, private_key_t *key_out) |
| Retrieve a private key from ssh-agent by matching public key. | |
| asciichat_error_t | ssh_agent_sign (const public_key_t *public_key, const uint8_t *message, size_t message_len, uint8_t signature[64]) |
| Sign data using SSH agent with the specified public key. | |
Password Requirements | |
| #define | MIN_PASSWORD_LENGTH 8 |
| Minimum password length (8 characters) | |
| #define | MAX_PASSWORD_LENGTH 256 |
| Maximum password length (256 characters) | |
Algorithm-Specific Key Sizes | |
| #define | X25519_KEY_SIZE 32 |
| X25519 key size in bytes. | |
| #define | ED25519_PUBLIC_KEY_SIZE 32 |
| Ed25519 public key size in bytes. | |
| #define | ED25519_PRIVATE_KEY_SIZE 64 |
| Ed25519 private key size (seed + public) in bytes. | |
| #define | ED25519_SIGNATURE_SIZE 64 |
| Ed25519 signature size in bytes. | |
| #define | XSALSA20_NONCE_SIZE 24 |
| XSalsa20 nonce size in bytes. | |
| #define | POLY1305_MAC_SIZE 16 |
| Poly1305 MAC size in bytes. | |
| #define | HMAC_SHA256_SIZE 32 |
| HMAC-SHA256 output size in bytes. | |
| #define | ARGON2ID_SALT_SIZE 32 |
| Argon2id salt size in bytes. | |
| #define | SECRETBOX_KEY_SIZE 32 |
| Secretbox key size in bytes. | |
| #define | AES256_KEY_SIZE 32 |
| AES-256 key size in bytes. | |
| #define | AES_IV_SIZE 16 |
| AES initialization vector (IV) size in bytes. | |
| #define | AES256_DERIVED_SIZE (AES256_KEY_SIZE + AES_IV_SIZE) |
| AES-256 key + IV derived size in bytes (for bcrypt_pbkdf) | |
| #define | SESSION_ID_SIZE 16 |
| Session ID size in bytes. | |
Abstracted Cryptographic Constants | |
These constants abstract the underlying algorithms to allow future changes. | |
| #define | CRYPTO_PUBLIC_KEY_SIZE X25519_KEY_SIZE |
| Public key size (X25519) | |
| #define | CRYPTO_PRIVATE_KEY_SIZE X25519_KEY_SIZE |
| Private key size (X25519) | |
| #define | CRYPTO_SHARED_KEY_SIZE X25519_KEY_SIZE |
| Shared key size (X25519) | |
| #define | CRYPTO_ED25519_PUBLIC_KEY_SIZE ED25519_PUBLIC_KEY_SIZE |
| Ed25519 public key size. | |
| #define | CRYPTO_ED25519_PRIVATE_KEY_SIZE ED25519_PRIVATE_KEY_SIZE |
| Ed25519 private key size. | |
| #define | CRYPTO_ED25519_SIGNATURE_SIZE ED25519_SIGNATURE_SIZE |
| Ed25519 signature size. | |
| #define | CRYPTO_NONCE_SIZE XSALSA20_NONCE_SIZE |
| Nonce size (XSalsa20) | |
| #define | CRYPTO_SALT_SIZE ARGON2ID_SALT_SIZE |
| Salt size (Argon2id) | |
| #define | CRYPTO_ENCRYPTION_KEY_SIZE SECRETBOX_KEY_SIZE |
| Encryption key size (XSalsa20-Poly1305) | |
| #define | CRYPTO_MAC_SIZE POLY1305_MAC_SIZE |
| MAC size (Poly1305) | |
| #define | CRYPTO_HMAC_SIZE HMAC_SHA256_SIZE |
| HMAC size (HMAC-SHA256) | |
Authentication Packet Sizes | |
| #define | AUTH_HMAC_SIZE 32 |
| HMAC size in authentication packets (32 bytes) | |
| #define | AUTH_CHALLENGE_SIZE 32 |
| Challenge nonce size (32 bytes) | |
| #define | AUTH_COMBINED_SIZE (AUTH_HMAC_SIZE + AUTH_CHALLENGE_SIZE) |
| Combined authentication data size (HMAC + challenge, 64 bytes) | |
| #define | AUTH_SIGNATURE_SIZE 64 |
| Ed25519 signature size (64 bytes) | |
| #define | AUTH_SIGNATURE_COMBINED_SIZE (AUTH_SIGNATURE_SIZE + AUTH_CHALLENGE_SIZE) |
| Combined signature + challenge size (96 bytes) | |
Authentication Challenge Packet Structure | |
| #define | AUTH_CHALLENGE_FLAGS_SIZE 1 |
| Authentication flags size (1 byte) | |
| #define | AUTH_CHALLENGE_PACKET_SIZE (AUTH_CHALLENGE_FLAGS_SIZE + AUTH_CHALLENGE_SIZE) |
| Complete authentication challenge packet size (1 + 32 = 33 bytes) | |
Authentication Response Packet Sizes | |
| #define | AUTH_RESPONSE_PASSWORD_SIZE (AUTH_HMAC_SIZE + AUTH_CHALLENGE_SIZE) |
| Password-based authentication response size (HMAC + challenge, 64 bytes) | |
| #define | AUTH_RESPONSE_SIGNATURE_SIZE (AUTH_SIGNATURE_SIZE + AUTH_CHALLENGE_SIZE) |
| Signature-based authentication response size (signature + challenge, 96 bytes) | |
Packet Size Limits | |
| #define | MAX_AUTH_FAILED_PACKET_SIZE 256 |
| Maximum AUTH_FAILED packet size (256 bytes) | |
| #define | MAX_ENCRYPTED_PACKET_SIZE 65536 |
| Maximum encrypted packet size (64KB) | |
Buffer Sizes | |
| #define | HEX_STRING_SIZE_32 (32 * 2 + 1) |
| Hex string size for 32-byte values (64 hex chars + null terminator) | |
| #define | HEX_STRING_SIZE_64 (64 * 2 + 1) |
| Hex string size for 64-byte values (128 hex chars + null terminator) | |
| #define | PASSWORD_BUFFER_SIZE 256 |
| Password input buffer size (256 bytes) | |
| #define | ZERO_KEY_SIZE X25519_KEY_SIZE |
| Zero key array size (32 bytes, used for no-identity entries) | |
Encryption Size Limits | |
| #define | CRYPTO_MAX_PLAINTEXT_SIZE ((size_t)1024 * 1024) |
| Maximum plaintext size (1MB) | |
| #define | CRYPTO_MAX_CIPHERTEXT_SIZE (CRYPTO_MAX_PLAINTEXT_SIZE + CRYPTO_MAC_SIZE) |
| Maximum ciphertext size (plaintext + MAC, ~1MB + 16 bytes) | |
Hex String Size Constants | |
| #define | CRYPTO_HEX_KEY_SIZE 64 |
| Hex string size for 32-byte key (64 hex characters) | |
| #define | CRYPTO_HEX_KEY_SIZE_NULL 65 |
| Hex string size for 32-byte key with null terminator (65 bytes) | |
| #define | CRYPTO_HEX_KEY64_SIZE 128 |
| Hex string size for 64-byte key (128 hex characters) | |
| #define | CRYPTO_HEX_KEY64_SIZE_NULL 129 |
| Hex string size for 64-byte key with null terminator (129 bytes) | |
Cryptographic String Literals | |
| #define | SSH_ED25519_KEY_TYPE "ssh-ed25519" |
| SSH Ed25519 key type string ("ssh-ed25519") | |
| #define | X25519_KEY_TYPE "x25519" |
| X25519 key type string ("x25519") | |
| #define | NO_IDENTITY_MARKER "no-identity" |
| No-identity entry marker ("no-identity") | |
🔐 Core cryptographic operations for ascii-chat
This header provides the core cryptographic operations for secure communication in ascii-chat, including key exchange, encryption/decryption, authentication, and session rekeying.
The interface provides:
This header provides GPG agent (gpg-agent) integration for signing operations with GPG keys. Allows private keys to stay in GPG agent without being loaded into application memory.
This header provides functions for exporting public keys from GPG keyring. Supports retrieving Ed25519 public keys and keygrips for use in authentication and signing operations.
gpg --export to extract public key from local keyring. Parses OpenPGP packet format to extract Ed25519 public key material.This header provides the complete GPG interface by including all submodule headers. Users can include this single header to access all GPG functionality.
Submodules:
This header provides GPG signing operations for creating detached signatures. Supports both OpenPGP-formatted signatures and raw Ed25519 signatures extracted from GPG output.
gpg --detach-sign to create detached signatures. Signatures are separate from message data (not inline signatures).gpg binary in PATH for all operations. Returns error if GPG is not installed or not accessible.This header provides GPG signature verification operations supporting both GPG binary-based verification and direct cryptographic verification via libgcrypt. Handles both raw Ed25519 signatures and OpenPGP-formatted signatures.
gpg --verify for full OpenPGP packet verificationgpg in PATH. libgcrypt-based verification works without GPG binary installed.This header provides known hosts management functionality similar to SSH's known_hosts. Tracks server identity keys to detect man-in-the-middle attacks and key changes.
Known hosts file format:
<IP:port> x25519 <hex_key> [comment]<IP:port> no-identity [comment]192.0.2.1:8080 x25519 1234abcd... ascii-chat[2001:db8::1]:8080 x25519 1234abcd... ascii-chat192.0.2.1:8080 no-identityThis file contains BearSSL tools utilities adapted to work with in-memory PEM data instead of files. Original code from BearSSL tools (ISC license).
These utilities are used for loading system CA certificates for TLS validation.
This header provides SSH agent integration for signing operations. Allows keys to stay in SSH agent (not loaded into memory) for better security.
ascii-chat implements end-to-end encryption by default using modern cryptographic primitives from libsodium. All data packets (headers and payloads) are encrypted after the initial handshake, protecting against eavesdropping and tampering.
❌ Not a replacement for TLS/HTTPS - Different trust model ❌ Not anonymous - Focus is encryption, not anonymity ❌ Not quantum-resistant - Uses elliptic curve cryptography (X25519) - Post-quantum support planned via dynamic algorithm negotiation
ascii-chat faces a fundamental cryptographic challenge: there is no pre-existing trust infrastructure like the Certificate Authority (CA) system used by HTTPS. This creates a security tradeoff:
Without verification:
With verification:
By default, ascii-chat provides privacy but not authentication:
Why this default?
--server-keyThis is similar to Bluetooth pairing or Signal safety numbers - the first connection is vulnerable, but subsequent connections can be verified.
| Mode | Trust Mechanism | MITM Protection | Use Case |
|---|---|---|---|
| Default | None (ephemeral DH) | ❌ | Quick sessions, low-threat environments |
| Password | Shared secret | ✅ | Friends exchanging password out-of-band |
| SSH Keys | Key pinning | ✅ | Tech users with existing SSH keys |
| GPG Keys | Key pinning + gpg-agent | ✅ | GPG users, no passphrase prompts |
| GitHub/GitLab | Social proof + keys | ✅ | Verify identity via public profiles |
| Known Hosts | First-use trust | ⚠️ | Like SSH - detect key changes |
| Whitelist | Pre-approved keys | ✅ | Private servers, access control |
| Protocol | Default Encryption | Trust Model | Verification Difficulty |
|---|---|---|---|
| HTTPS | ✅ Always | CA system | Automatic (OS trust store) |
| SSH | ✅ Always | Known hosts | Manual (first connection prompts) |
| Signal | ✅ Always | Safety numbers | Manual (QR code scanning) |
| ascii-chat | ✅ Always | Ephemeral DH | Optional (–server-key flag) |
| Zoom | ✅ Sometimes | Central server | None (trust Zoom) |
ascii-chat uses libsodium, a modern, portable, easy-to-use crypto library based on NaCl.
crypto_box_beforenm()Why X25519?
crypto_secretbox_easy()Why XSalsa20-Poly1305?
Encryption formula:
crypto_pwhash()Why Argon2id?
crypto_sign_detached(), crypto_sign_verify_detached()Ed25519 to X25519 Conversion:
This allows using existing SSH Ed25519 keys for both signing (authentication) and key exchange (encryption).
Supported OpenSSH Key Encryption:
Native Decryption Process:
Why bcrypt_pbkdf?
The PBKDF Security Tradeoff:
PBKDF creates an asymmetric cost between legitimate users and attackers:
Keyspace vs. Compute Time:
A common observation: "Attackers get a smaller keyspace (passwords) instead of full AES-256 keyspace (2^256), but they sacrifice compute time for it."
This is precisely correct. The tradeoff works as follows:
| Attack Strategy | Keyspace Size | Keys/Second | Time to Exhaust |
|---|---|---|---|
| Try random AES keys | 2^256 (~10^77) | 10^9 | 3.67 × 10^60 years (IMPOSSIBLE) |
| Try passwords (no PBKDF) | ~10^12 common | 60 × 10^9 | 16 minutes ⚠️ |
| Try passwords (bcrypt r=16) | ~10^12 common | 5 | 6,300 years ✅ |
Key insight: The attacker chooses a drastically smaller keyspace (password space instead of full AES keyspace) to make the problem tractable, but PBKDF makes that small keyspace exponentially more expensive to search by adding computational cost to each attempt.
The result: Legitimate users pay ~200ms once, attackers pay years of compute time trying password guesses. This asymmetry is what makes password-based encryption practical and secure.
Tunable security (rounds parameter):
OpenSSH chose rounds=16 as optimal: barely noticeable for users, devastating for attackers.
Why attackers can't skip PBKDF:
Salt prevents rainbow tables:
Implementation verification:
See also:
CSPRNG: randombytes_buf() (libsodium)
/dev/urandomCryptGenRandom() / BCryptGenRandom()arc4random_buf()All packets (encrypted and unencrypted) share a common header:
Note: All multi-byte fields are in network byte order (big-endian).
Protocol Negotiation Packets (Always Unencrypted):
Crypto Handshake Packets (Always Unencrypted):
Encrypted Packets (After Handshake):
All application packets (video, audio, control) are wrapped in PACKET_TYPE_ENCRYPTED after successful handshake.
Dynamic Algorithm Negotiation: The CRYPTO_CAPABILITIES and CRYPTO_PARAMETERS packets enable future-proof algorithm selection:
Why unencrypted? These packets establish the encryption keys - they cannot be encrypted with keys that don't exist yet. This is standard for all key exchange protocols (TLS, SSH, etc.).
Unencrypted Packet (Handshake):
Encrypted Packet (Post-Handshake):
Decryption process:
Result: An attacker sees:
Hidden from attacker:
Phase 0: Dynamic Algorithm Negotiation
**Client Capabilities (CRYPTO_CAPABILITIES):**
**Server Parameters (CRYPTO_PARAMETERS):**
Current Algorithm Constants:
Future-Proofing Design:
Phase 1: Key Exchange Init (Server → Client)
Server sends:
Packet size:
--key SSH key)Client verifies:
--server-key provided: Verify identity key matches expected key → ABORT if mismatchsignature is valid for ephemeral_public_key using identity_public_key~/.ascii-chat/known_hosts, verify identity key matchesSecurity note: The signature binds the ephemeral key to the long-term identity key, preventing an attacker from replacing the DH key while keeping the identity key.
Phase 2: Key Exchange Response (Client → Server)
Client sends:
Server verifies:
--client-keys provided: Check if identity_public_key is in whitelist → REJECT if not foundshared_secret = X25519(server_private, client_public)At this point both sides have:
Phase 3: Authentication Challenge (Server → Client)
Server sends:
Flags:
AUTH_REQUIRE_PASSWORD (0x01): Server has --password, client must prove knowledgeAUTH_REQUIRE_CLIENT_KEY (0x02): Server has --client-keys, client must be whitelistedClient prepares response:
HMAC(password_key, nonce || shared_secret) using Argon2-derived keyHMAC(shared_secret, nonce || shared_secret) using DH shared secretPhase 4: Authentication Response (Client → Server)
Client sends:
Server verifies:
--client-keysPhase 5: Server Authentication Response (Server → Client)
Server sends:
Client verifies:
This provides mutual authentication - both sides prove knowledge of the shared secret.
Phase 6: Handshake Complete or Failed
Success:
Failure:
After HANDSHAKE_COMPLETE, both sides:
Core architecture decision: SSH keys are ONLY used for authentication (identity proof), NEVER for encryption.
Why this matters:
ascii-chat supports SSH agent for encrypted private keys, allowing password-free authentication when your SSH key is already loaded in the agent.
How it works:
When you provide an encrypted SSH key via --key, ascii-chat automatically checks if that specific key is available in the SSH agent:
If the key is not in the ssh-agent and ssh-agent is running, ascii-chat will prompt for the password and decrypt the key and store it in the ssh-agent securely for future use. This is done via ssh-agent's official protocol and is safe for production use - this is the intended usage of ssh-agent.
Fetch SSH keys from public profiles:
How it works:
GET https://github.com/zfogg.keys (using BearSSL)ssh-ed25519 AAAAC3NzaC1lZDI1NTE5... linesSecurity properties:
GitLab support: Same mechanism, https://gitlab.com/username.keys
ascii-chat can use existing SSH Ed25519 keys for authentication (identity proof via signatures):
Key file formats supported:
BEGIN OPENSSH PRIVATE KEY)ssh-ed25519 AAAAC3...)Ed25519 to X25519 conversion:
ascii-chat can convert Ed25519 keys to X25519 format for compatibility, but does NOT use the converted key for encryption:
Why this works: Both Ed25519 and X25519 use the same underlying curve (Curve25519). Ed25519 uses the Edwards form for signing, X25519 uses the Montgomery form for DH. libsodium provides safe conversion functions.
Security architecture:
The SSH key proves identity through signatures. The ephemeral keys provide encryption with forward secrecy. The signature binds them together cryptographically, preventing MITM attacks while maintaining forward secrecy.
How it works:
The signature cryptographically binds the ephemeral encryption key to the long-term identity key. This provides:
Alternative considered and rejected:
Using Ed25519→X25519 conversion for encryption would be simpler code-wise, but:
Result: All modes use ephemeral encryption keys. SSH keys are authentication-only.
Key detection algorithm:
SSH agent signing protocol:
When use_ssh_agent = true, all Ed25519 signatures are delegated to the SSH agent:
Security architecture:
ascii-chat uses a separation of concerns design where SSH keys are ONLY used for authentication, never encryption:
| Component | SSH Agent Mode | In-Memory Mode |
|---|---|---|
| Identity signing | SSH agent (Ed25519) | In-memory Ed25519 |
| Encryption keys | Ephemeral X25519 | Ephemeral X25519 |
| Private key storage | None (agent-only) | Decrypted in memory |
| Password required | No (once in agent) | Yes (every restart) |
| Forward secrecy | ✅ YES | ✅ YES |
Why always ephemeral encryption?
Both modes use ephemeral X25519 keys for encryption to provide forward secrecy:
This matches SSH protocol design: long-term keys for identity, ephemeral keys for encryption.
Handshake signature binding:
The signature cryptographically binds the ephemeral encryption key to the long-term identity key, preventing MITM attacks while maintaining forward secrecy.
Fallback behavior:
Environment variable:
SSH agent communication requires the SSH_AUTH_SOCK environment variable:
Security benefits:
Limitations:
Code locations:
lib/crypto/keys.h:37 - bool use_ssh_agent flag in private_key_tlib/crypto/keys.c:438-524 - ssh_agent_has_specific_key() detectionlib/crypto/keys.c:820-844 - Encrypted key parsing with agent checklib/crypto/keys.c:502-690 - ed25519_sign_message() with agent protocollib/crypto/keys.c:1546-1580 - crypto_setup_ssh_key_for_handshake() architectureSecurity guarantee: Both SSH agent mode and in-memory mode provide identical forward secrecy - ephemeral X25519 keys are used for encryption in all cases. The only difference is where signatures come from (agent vs in-memory).
Problem: Users with encrypted SSH keys had to manually add keys to ssh-agent, or enter their password repeatedly.
Solution: ascii-chat now automatically adds decrypted keys to ssh-agent after successful password entry, eliminating future password prompts.
How it works:
What happens automatically:
$SSH_AUTH_SOCK is setImplementation details:
The auto-add feature uses the SSH agent protocol directly via the pipe.h platform abstraction:
Platform abstraction:
The implementation uses lib/platform/pipe.h for cross-platform agent communication:
SSH_AUTH_SOCK environment variable/tmp/ssh-XXXXXX/agent.XXXXXX (Unix socket)socket(AF_UNIX, SOCK_STREAM) + connect()SSH_AUTH_SOCK environment variable or default path\\.\pipe\openssh-ssh-agent (named pipe)CreateFileA() with GENERIC_READ | GENERIC_WRITEAgent communication flow:
Security considerations:
sodium_memzero() after usePlatform support:
| Platform | Supported | Notes |
|---|---|---|
| Linux | ✅ YES | Requires SSH agent running (check $SSH_AUTH_SOCK) |
| macOS | ✅ YES | Built-in with macOS (ssh-agent auto-starts) |
| Windows | ✅ YES | Uses Windows named pipes (requires OpenSSH for Windows) |
Code locations:
lib/crypto/keys/ssh_keys.c:242 - Check if key already in agent (before decryption)lib/crypto/keys/ssh_keys.c:767 - Auto-add implementation after successful decryptionlib/crypto/ssh_agent.h - SSH agent interface declarationslib/crypto/ssh_agent.c - SSH agent protocol implementationlib/platform/pipe.h - Cross-platform pipe/agent socket abstractionlib/platform/posix/pipe.c - POSIX Unix domain socket implementationlib/platform/windows/pipe.c - Windows named pipe implementationascii-chat supports GPG Ed25519 keys via gpg-agent integration:
Requirements:
gpg binary must be in PATHKey ID formats:
0x prefix is accepted for all formatsHow it works:
gpg --list-keys + keygrip lookupgpg --verify for deterministic Ed25519 signature verificationGraceful fallback:
Code locations:
lib/crypto/gpg.h - GPG interface declarationslib/crypto/gpg.c - GPG protocol implementation and gpg-agent communicationlib/crypto/keys/gpg_keys.c - GPG key parsing and Ed25519 extractionlib/crypto/keys/keys.c:167 - GPG key loading (keygrip stored for agent signing)File location: ~/.ascii-chat/known_hosts
Format:
Security Design: IP Binding (Not Hostnames)
ascii-chat binds server keys to resolved IP addresses, not DNS hostnames, for critical security reasons:
Why IP addresses?
example.com → malicious server IPexample.com's key ❌getaddrinfo(), then IP is used192.0.2.1) and IPv6 (2001:db8::1)[::1]:8080 clearly distinguishes IPv6Example attack scenario (hostname binding):
With IP binding (current implementation):
Behavior:
Trade-offs:
| Aspect | IP Binding (Current) | Hostname Binding (SSH-style) |
|---|---|---|
| DNS Hijacking | ✅ Protected | ❌ Vulnerable |
| Server IP Change | ⚠️ Prompts user (manual verification) | ✅ Transparent |
| Dynamic DNS | ⚠️ New prompt per IP | ✅ Works seamlessly |
| Multi-homed Servers | ⚠️ Separate entry per IP | ✅ Single entry |
| Security Model | Paranoid (explicit trust) | Convenience (implicit trust) |
Recommendation: The security benefit of IP binding outweighs the inconvenience of re-verification when server IPs change. For production servers, IP addresses should be stable (static IPs or fixed cloud instances).
Security model: "Trust on first use" (TOFU) with IP binding - assumes first connection to specific IP:port is legitimate, detects any changes in either IP or key thereafter.
Server:
Client:
Security:
Use case: Quick sessions, low-threat environments
Server:
Client:
Security:
Server with SSH key:
Server with GPG key:
Client (verify using GitHub SSH key):
Client (verify using GitHub GPG key):
Client (verify using GitLab GPG key):
Client (verify using local GPG key):
Security:
Verification flow:
ed25519_verify(signature, ephemeral_key, identity_key)Server:
Client:
Server's authorized_keys format:
Security:
GitHub/GitLab GPG Key Fetching:
Both --server-key (client verifies server) and --client-keys (server whitelists clients) support fetching GPG public keys from GitHub/GitLab:
How it works:
https://github.com/username.gpggpg --import (GitHub users often have multiple keys)gpg --list-keysWhy this is useful:
Server with SSH key:
Server with GPG key:
Client:
Security:
Server:
Client:
Security:
Use case: Debugging, packet inspection with tcpdump
WARNING: Only use in trusted networks or for development!
Password validation:
HMAC challenge/response:
Critical security note: The HMAC binds both the nonce AND the DH shared_secret, preventing MITM attacks even if the attacker knows the password. See Issue 1: Password Mode MITM Vulnerability ⚠️ CRITICAL for details.
For each packet after handshake:
Wire format:
Critical security requirement: Never reuse a nonce with the same key!
Implementation:
Why this is safe:
Replay protection:
Rekeying integration:
ascii-chat implements automatic session rekeying to provide forward secrecy within long-lived connections. After the initial handshake establishes encryption, the system periodically performs new Diffie-Hellman key exchanges to rotate encryption keys.
Security benefits:
Rekeying occurs automatically when either threshold is reached (whichever comes first):
| Trigger Type | Default Threshold | Notes |
|---|---|---|
| Time-based | 3600 seconds (1 hour) | Typical video chat session length |
| Traffic-based | 1,000,000 packets | ~4.6 hours at 60 FPS video |
Configuration options:
Test mode (for development): For testing, use low thresholds to trigger frequent rekeying:
The rekeying protocol uses a 3-packet handshake similar to the initial key exchange:
New Packet Types:
Packet Structures:
REKEY_REQUEST:
REKEY_RESPONSE:
REKEY_COMPLETE:
Before REKEY_COMPLETE:
REKEY_COMPLETE packet:
After REKEY_COMPLETE:
Anti-Denial-of-Service:
Race Condition Handling: If both sides simultaneously initiate rekeying:
Key Confirmation: The REKEY_COMPLETE packet must decrypt successfully:
Failure Handling:
Rekey can fail for several reasons:
Failure recovery:
Important: Rekey failure does NOT disconnect the session. The connection continues with the old key.
Performance impact:
✅ Modern primitives: X25519, XSalsa20-Poly1305, Argon2id (current best practices) ✅ Forward secrecy (connection-level): Ephemeral DH keys per connection ✅ Forward secrecy (session-level): Automatic rekeying within long-lived sessions ✅ Authenticated encryption: XSalsa20-Poly1305 AEAD prevents tampering ✅ Memory-hard passwords: Argon2id resistant to GPU brute-force ✅ Constant-time crypto: libsodium uses constant-time implementations (timing attack resistant) ✅ Large nonce space: 192-bit nonces make collision astronomically unlikely ✅ Intra-session forward secrecy: Rekeying limits exposure from key compromise
⚠️ Default MITM vulnerability:
--server-key or known_hosts verification⚠️ Password quality:
⚠️ No quantum resistance:
All critical security vulnerabilities have been identified and fixed:
| Issue | Severity | Status |
|---|---|---|
| Password Mode MITM | 🔴 Critical | ✅ FIXED - HMACs bound to DH shared_secret |
| No Mutual Auth | 🔴 High | ✅ FIXED - Bidirectional challenge-response |
| Replay Across Sessions | 🟡 Medium | ✅ FIXED - Session IDs implemented |
| No Whitelist Revocation | 🟢 Low | 🟢 Won't Fix - Out of scope, manual restart acceptable |
| TOFU Weakness | 🟢 Info | 🟢 Acceptable - Inherent to TOFU model |
| Code Duplication | 🟢 Low | ✅ FIXED - Shared authentication functions |
| Timing Attack on Keys | 🔴 Critical | ✅ FIXED - Constant-time sodium_memcmp() |
Security Status: ✅ All security vulnerabilities have been addressed
Severity: Medium (mitigated by user choice)
Description: By default, ascii-chat does not verify server identity. An attacker who controls the network can intercept the initial handshake and perform a man-in-the-middle attack.
Attack scenario:
Why this is not a critical bug:
--server-key, --password, or known_hosts provide protectionMitigation:
Severity: Low (practically impossible)
Description: If a single connection sends more than 2^64 packets, the nonce counter wraps to zero, potentially reusing nonces.
Attack scenario:
Likelihood: Astronomically low (would require 58 million years of continuous packets)
Impact: Nonce reuse could allow an attacker to recover plaintext of two packets with the same nonce
Mitigation: Reconnect periodically (every 24 hours is more than sufficient)
Severity: High (if implementation bug exists)
Description: If signature verification is skipped when --server-key is set, attacker could send any identity key.
Attack scenario:
--server-key github:zfoggCurrent status: ✅ Not vulnerable (signature verification is mandatory)
Note: This section documents security issues identified during independent review of the cryptographic implementation. These represent real vulnerabilities that should be addressed before production use.
Severity: Critical (actively exploitable)
Description: Password mode was vulnerable to MITM attacks despite using encryption. An attacker could intercept the key exchange and derive the password-based key themselves because the password HMAC wasn't bound to the DH shared_secret.
Previous attack scenario:
Root cause:
HMAC(password_key, nonce)Status: 🟢 FIXED - Password HMACs now bound to DH shared_secret
Implementation: All password HMAC computations now bind to the DH shared_secret to prevent MITM:
Why this fixes the MITM vulnerability:
HMAC(password_key, nonce || DH_secret_A)HMAC(password_key, nonce || DH_secret_B)HMAC(password_key, nonce || DH_secret_A)Code locations:
lib/crypto/crypto.h:168-172 - Added crypto_compute_hmac_ex() and crypto_verify_hmac_ex() for variable-length HMAClib/crypto/crypto.c:610-648 - Implemented extended HMAC functionslib/crypto/handshake.c:569-582 - Client AUTH_RESPONSE binds to shared_secretlib/crypto/handshake.c:644-657 - Client optional AUTH_RESPONSE binds to shared_secretlib/crypto/handshake.c:706-719 - Client no-server-requirement AUTH_RESPONSE binds to shared_secretlib/crypto/handshake.c:829-841 - Client SERVER_AUTH_RESPONSE verification binds to shared_secretlib/crypto/handshake.c:890-902 - Server AUTH_RESPONSE verification binds to shared_secretlib/crypto/handshake.c:962-974 - Server SERVER_AUTH_RESPONSE computation binds to shared_secretImpact: Critical vulnerability fixed - Password mode now provides true MITM protection, not just passive eavesdropping protection
Severity: High (design flaw)
Description: The challenge-response protocol only authenticated the client to the server, not the other way around. Server never proved it has the shared secret.
Previous handshake flow:
Problem: Client never received proof that server has the correct shared secret. A MITM attacker could:
Status: 🟢 FIXED - Mutual authentication implemented
Implementation: The protocol now includes bidirectional challenge-response:
New packet type:
Code locations:
lib/network.h:97 - Added PACKET_TYPE_SERVER_AUTH_RESPONSElib/crypto/handshake.c:593 - Client sends challenge noncelib/crypto/handshake.c:946 - Server sends AUTH_CONFIRMlib/crypto/handshake.c:834 - Client verifies server's HMACImpact: High - Previously allowed MITM without server authentication, now both sides prove knowledge of shared secret
Severity: Medium (limited exploitation window)
Description: Nonce counter resets to 0 on each connection. An attacker who records packets from Session 1 can replay them into Session 2 if the same shared secret is used.
Attack scenario:
Root cause:
Status: 🟢 FIXED - Session IDs added to nonce generation
Implementation:
This ensures nonces are unique across sessions even if counters reset.
Impact: Medium - Attacker can replay old packets into new sessions, but needs network position and recorded traffic
Severity: Informational (not a security issue)
Description: If a client's SSH key is compromised, the server operator must manually edit the whitelist file and restart the server to revoke access.
Why hot-reload is not needed:
ascii-chat's security model does not require hot revocation:
Revocation workflow (current and sufficient):
Why this is acceptable:
authorized_keys model (also requires service restart for revocation)Status: 🟢 Won't Fix - Out of Scope - Manual restart is the intended design
Impact: None - This is not a security issue, just an operational characteristic
Severity: Informational (inherent to TOFU model)
Description: Trust On First Use (TOFU) means the first connection is always vulnerable. If an attacker MITM's the first connection, their key is saved as "trusted".
This is the same vulnerability as:
Attack scenario:
Why this is acceptable:
Status: 🟢 Acceptable by design (future verification server will improve this)
Impact: Informational - This is an accepted trade-off in the TOFU model
Severity: Low (code quality issue, not a security vulnerability)
Description: The cryptographic protocol is symmetric - both client and server perform identical crypto operations - yet the code duplicates logic between crypto_client_handshake() and crypto_server_handshake().
Problem:
Status: 🟢 FIXED - Shared authentication functions implemented
Implementation: The password HMAC duplication has been eliminated by extracting shared functions:
Code locations:
lib/crypto/crypto.h:182-206 - Function declarations with documentationlib/crypto/crypto.c:655-689 - Implementation of shared functionslib/crypto/handshake.c:572 - Client AUTH_RESPONSE (3 locations) now use shared functionlib/crypto/handshake.c:815 - Client SERVER_AUTH_RESPONSE verification uses shared functionlib/crypto/handshake.c:862 - Server AUTH_RESPONSE verification uses shared functionlib/crypto/handshake.c:923 - Server SERVER_AUTH_RESPONSE computation uses shared functionResults:
Impact: Low - This is technical debt, not a security issue
Severity: Critical (side-channel information leakage)
Description: Public key comparisons used variable-time memcmp() instead of constant-time comparison, allowing timing attacks that could leak information about cryptographic keys through side-channel analysis.
Vulnerability: The standard C library function memcmp() returns early on the first byte difference. This creates timing differences that can be measured by an attacker to learn information about the expected key.
Attack scenario:
Root cause: Three locations used memcmp() for cryptographic key comparisons:
lib/crypto/handshake.c:194 - Server identity verification during client key exchangelib/crypto/handshake.c:363 - Client whitelist verification during server auth challengelib/crypto/known_hosts.c:69 - Known hosts verification (client-side server verification)Why this is critical:
Status: 🟢 FIXED - All comparisons now use constant-time sodium_memcmp()
Implementation: All cryptographic key comparisons now use libsodium's constant-time comparison:
Code locations:
lib/crypto/handshake.c:194 - ✅ Fixed: Server identity verificationlib/crypto/handshake.c:363 - ✅ Fixed: Client whitelist verificationlib/crypto/known_hosts.c:69 - ✅ Fixed: Known hosts verificationHow sodium_memcmp() prevents timing attacks:
Benefits of constant-time comparison:
**Impact:** Critical vulnerability fixed - All cryptographic key comparisons now resistant to timing attacks
**Current:** X25519 (not quantum-resistant)
**Future:** Hybrid key exchange with post-quantum algorithm
**Candidates:**
The dynamic algorithm negotiation system is designed to support post-quantum migration when libsodium adds support.
**Problem:** No global certificate authority like HTTPS
**Proposed solution:** Optional verification server for key registry
**Architecture:**
**Benefits:**
**Trust model:** Similar to Signal's key server - optional, transparency log, user can verify out-of-band
**Status:** RFC in progress (see issue #82 for detailed spec)
**Current:** X25519 (not quantum-resistant)
**Future:** Hybrid key exchange with post-quantum algorithm
**Candidates:**
**Implementation Strategy:** The dynamic algorithm negotiation system is designed to support post-quantum migration:
**Timeline:** Wait for libsodium to add post-quantum support (currently in development)
**Backward compatibility:** Hybrid mode allows gradual migration without breaking existing connections
**Status:** ✅ **IMPLEMENTED** - See Session Rekeying Protocol section above
**Implementation:**
**Future consideration:** Double Ratchet (Signal-style per-message rekeying)
**Inspired by:** Let's Encrypt Certificate Transparency
**Idea:** Public append-only log of all server public keys
**Benefits:**
**Implementation:**
**Status:** Research phase
**Danger:** Reusing a nonce with the same key breaks XSalsa20-Poly1305 security
**How it happens:**
**Fix:**
**Test:** Verify nonce increments in packet capture
**Danger:** Variable-time comparison leaks information
**How it happens:**
**Fix:**
**Test:** Run verification 10,000 times with random HMACs, verify timing is consistent
**Danger:** Skipping signature verification allows impersonation
**How it happens:**
Fix:
Test: Send handshake with random signature bytes → should be rejected
Danger: Old packets can be re-sent by attacker
How it happens:
Fix:
Note: ascii-chat uses nonce-based encryption which provides implicit replay resistance (same nonce won't decrypt to same plaintext due to MAC)
Danger: Using wrong key for operation
How it happens:
Fix:
Test: Verify encrypted packets with password can't be decrypted with DH key and vice versa
Document Version: 2.3 Last Updated: October 2025 (Session rekeying protocol implemented) Maintainer: ascii-chat Development Team License: Same as ascii-chat project (see LICENSE)
| #define AES256_DERIVED_SIZE (AES256_KEY_SIZE + AES_IV_SIZE) |
#include <crypto.h>
AES-256 key + IV derived size in bytes (for bcrypt_pbkdf)
Definition at line 112 of file lib/crypto/crypto.h.
| #define AES256_KEY_SIZE 32 |
| #define AES_IV_SIZE 16 |
#include <crypto.h>
AES initialization vector (IV) size in bytes.
Definition at line 110 of file lib/crypto/crypto.h.
| #define ANCHOR_LIST_INIT {NULL, 0, 0} |
#include <pem_utils.h>
Initializer for anchor_list.
Macro for initializing an empty anchor_list structure. Sets all fields to zero/NULL.
Definition at line 93 of file pem_utils.h.
| #define ARGON2ID_SALT_SIZE 32 |
#include <crypto.h>
Argon2id salt size in bytes.
Definition at line 104 of file lib/crypto/crypto.h.
| #define AUTH_CHALLENGE_FLAGS_SIZE 1 |
#include <crypto.h>
Authentication flags size (1 byte)
Definition at line 174 of file lib/crypto/crypto.h.
| #define AUTH_CHALLENGE_PACKET_SIZE (AUTH_CHALLENGE_FLAGS_SIZE + AUTH_CHALLENGE_SIZE) |
#include <crypto.h>
Complete authentication challenge packet size (1 + 32 = 33 bytes)
Definition at line 176 of file lib/crypto/crypto.h.
| #define AUTH_CHALLENGE_SIZE 32 |
#include <crypto.h>
Challenge nonce size (32 bytes)
Definition at line 158 of file lib/crypto/crypto.h.
| #define AUTH_COMBINED_SIZE (AUTH_HMAC_SIZE + AUTH_CHALLENGE_SIZE) |
#include <crypto.h>
Combined authentication data size (HMAC + challenge, 64 bytes)
Definition at line 160 of file lib/crypto/crypto.h.
| #define AUTH_HMAC_SIZE 32 |
#include <crypto.h>
HMAC size in authentication packets (32 bytes)
Definition at line 156 of file lib/crypto/crypto.h.
| #define AUTH_RESPONSE_PASSWORD_SIZE (AUTH_HMAC_SIZE + AUTH_CHALLENGE_SIZE) |
#include <crypto.h>
Password-based authentication response size (HMAC + challenge, 64 bytes)
Definition at line 186 of file lib/crypto/crypto.h.
| #define AUTH_RESPONSE_SIGNATURE_SIZE (AUTH_SIGNATURE_SIZE + AUTH_CHALLENGE_SIZE) |
#include <crypto.h>
Signature-based authentication response size (signature + challenge, 96 bytes)
Definition at line 188 of file lib/crypto/crypto.h.
| #define AUTH_SIGNATURE_COMBINED_SIZE (AUTH_SIGNATURE_SIZE + AUTH_CHALLENGE_SIZE) |
#include <crypto.h>
Combined signature + challenge size (96 bytes)
Definition at line 164 of file lib/crypto/crypto.h.
| #define AUTH_SIGNATURE_SIZE 64 |
#include <crypto.h>
Ed25519 signature size (64 bytes)
Definition at line 162 of file lib/crypto/crypto.h.
| #define CRYPTO_ED25519_PRIVATE_KEY_SIZE ED25519_PRIVATE_KEY_SIZE |
| #define CRYPTO_ED25519_PUBLIC_KEY_SIZE ED25519_PUBLIC_KEY_SIZE |
| #define CRYPTO_ED25519_SIGNATURE_SIZE ED25519_SIGNATURE_SIZE |
| #define CRYPTO_ENCRYPTION_KEY_SIZE SECRETBOX_KEY_SIZE |
#include <crypto.h>
Encryption key size (XSalsa20-Poly1305)
Definition at line 142 of file lib/crypto/crypto.h.
| #define CRYPTO_FINGERPRINT_SIZE 32 |
#include <crypto.h>
Ed25519 key fingerprint size in bytes.
SHA-256 hash of the key, resulting in 32 bytes.
Definition at line 380 of file lib/crypto/crypto.h.
| #define CRYPTO_HEX_KEY64_SIZE 128 |
#include <crypto.h>
Hex string size for 64-byte key (128 hex characters)
Definition at line 396 of file lib/crypto/crypto.h.
| #define CRYPTO_HEX_KEY64_SIZE_NULL 129 |
#include <crypto.h>
Hex string size for 64-byte key with null terminator (129 bytes)
Definition at line 398 of file lib/crypto/crypto.h.
| #define CRYPTO_HEX_KEY_SIZE 64 |
#include <crypto.h>
Hex string size for 32-byte key (64 hex characters)
Definition at line 392 of file lib/crypto/crypto.h.
| #define CRYPTO_HEX_KEY_SIZE_NULL 65 |
#include <crypto.h>
Hex string size for 32-byte key with null terminator (65 bytes)
Definition at line 394 of file lib/crypto/crypto.h.
| #define CRYPTO_HMAC_SIZE HMAC_SHA256_SIZE |
| #define CRYPTO_KEY_SIZE 32 |
#include <crypto.h>
Ed25519 key size in bytes.
Ed25519 public and private keys are 32 bytes each.
Definition at line 371 of file lib/crypto/crypto.h.
| #define CRYPTO_MAC_SIZE POLY1305_MAC_SIZE |
| #define CRYPTO_MAX_CIPHERTEXT_SIZE (CRYPTO_MAX_PLAINTEXT_SIZE + CRYPTO_MAC_SIZE) |
#include <crypto.h>
Maximum ciphertext size (plaintext + MAC, ~1MB + 16 bytes)
Definition at line 231 of file lib/crypto/crypto.h.
| #define CRYPTO_MAX_PLAINTEXT_SIZE ((size_t)1024 * 1024) |
#include <crypto.h>
Maximum plaintext size (1MB)
Definition at line 229 of file lib/crypto/crypto.h.
| #define CRYPTO_NONCE_SIZE XSALSA20_NONCE_SIZE |
| #define CRYPTO_PRIVATE_KEY_SIZE X25519_KEY_SIZE |
| #define CRYPTO_PUBLIC_KEY_SIZE X25519_KEY_SIZE |
| #define CRYPTO_SALT_SIZE ARGON2ID_SALT_SIZE |
| #define CRYPTO_SHARED_KEY_SIZE X25519_KEY_SIZE |
| #define ED25519_PRIVATE_KEY_SIZE 64 |
#include <crypto.h>
Ed25519 private key size (seed + public) in bytes.
Definition at line 94 of file lib/crypto/crypto.h.
| #define ED25519_PUBLIC_KEY_SIZE 32 |
#include <crypto.h>
Ed25519 public key size in bytes.
Definition at line 92 of file lib/crypto/crypto.h.
| #define ED25519_SIGNATURE_SIZE 64 |
#include <crypto.h>
Ed25519 signature size in bytes.
Definition at line 96 of file lib/crypto/crypto.h.
| #define HEX_STRING_SIZE_32 (32 * 2 + 1) |
#include <crypto.h>
Hex string size for 32-byte values (64 hex chars + null terminator)
Definition at line 213 of file lib/crypto/crypto.h.
| #define HEX_STRING_SIZE_64 (64 * 2 + 1) |
#include <crypto.h>
Hex string size for 64-byte values (128 hex chars + null terminator)
Definition at line 215 of file lib/crypto/crypto.h.
| #define HMAC_SHA256_SIZE 32 |
#include <crypto.h>
HMAC-SHA256 output size in bytes.
Definition at line 102 of file lib/crypto/crypto.h.
| #define MAX_AUTH_FAILED_PACKET_SIZE 256 |
#include <crypto.h>
Maximum AUTH_FAILED packet size (256 bytes)
Definition at line 201 of file lib/crypto/crypto.h.
| #define MAX_COMMENT_LEN 256 |
#include <crypto.h>
Definition at line 433 of file lib/crypto/crypto.h.
| #define MAX_ENCRYPTED_PACKET_SIZE 65536 |
#include <crypto.h>
Maximum encrypted packet size (64KB)
Definition at line 203 of file lib/crypto/crypto.h.
| #define MAX_GPG_KEYGRIP_LEN 64 |
#include <crypto.h>
Definition at line 434 of file lib/crypto/crypto.h.
| #define MAX_PASSWORD_LENGTH 256 |
#include <crypto.h>
Maximum password length (256 characters)
Definition at line 80 of file lib/crypto/crypto.h.
| #define MIN_PASSWORD_LENGTH 8 |
#include <crypto.h>
Minimum password length (8 characters)
Definition at line 78 of file lib/crypto/crypto.h.
| #define NO_IDENTITY_MARKER "no-identity" |
#include <crypto.h>
No-identity entry marker ("no-identity")
Definition at line 416 of file lib/crypto/crypto.h.
| #define PASSWORD_BUFFER_SIZE 256 |
#include <crypto.h>
Password input buffer size (256 bytes)
Definition at line 217 of file lib/crypto/crypto.h.
| #define POLY1305_MAC_SIZE 16 |
| #define REKEY_DEFAULT_PACKET_THRESHOLD 1000000 |
#include <crypto.h>
Default rekey packet threshold (1 million packets)
Definition at line 1242 of file lib/crypto/crypto.h.
| #define REKEY_DEFAULT_TIME_THRESHOLD 3600 |
#include <crypto.h>
Default rekey time threshold (1 hour in seconds)
Definition at line 1240 of file lib/crypto/crypto.h.
| #define REKEY_MAX_FAILURE_COUNT 10 |
#include <crypto.h>
Maximum consecutive rekey failures before giving up.
Definition at line 1248 of file lib/crypto/crypto.h.
| #define REKEY_MIN_INTERVAL 3 |
#include <crypto.h>
Minimum time interval between rekey requests (3 seconds for testing, 60 for production)
Definition at line 1238 of file lib/crypto/crypto.h.
| #define REKEY_MIN_REQUEST_INTERVAL 60 |
#include <crypto.h>
Minimum interval between rekey requests (60 seconds, DDoS protection)
Definition at line 1250 of file lib/crypto/crypto.h.
| #define REKEY_TEST_PACKET_THRESHOLD 1000 |
#include <crypto.h>
Test mode rekey packet threshold (1000 packets)
Definition at line 1246 of file lib/crypto/crypto.h.
| #define REKEY_TEST_TIME_THRESHOLD 30 |
#include <crypto.h>
Test mode rekey time threshold (30 seconds)
Definition at line 1244 of file lib/crypto/crypto.h.
| #define SECRETBOX_KEY_SIZE 32 |
#include <crypto.h>
Secretbox key size in bytes.
Definition at line 106 of file lib/crypto/crypto.h.
| #define SERVER_AUTH_RESPONSE_SIZE AUTH_HMAC_SIZE |
#include <crypto.h>
Server authentication response size (32 bytes)
Definition at line 193 of file lib/crypto/crypto.h.
| #define SESSION_ID_SIZE 16 |
| #define SSH_ED25519_KEY_TYPE "ssh-ed25519" |
#include <crypto.h>
SSH Ed25519 key type string ("ssh-ed25519")
Definition at line 412 of file lib/crypto/crypto.h.
| #define SSH_KEY_HEADER_SIZE (SSH_KEY_TYPE_LENGTH_SIZE + SSH_KEY_TYPE_STRING_SIZE + SSH_KEY_PUBLIC_KEY_LENGTH_SIZE + SSH_KEY_PUBLIC_KEY_SIZE) |
#include <crypto.h>
Definition at line 357 of file lib/crypto/crypto.h.
| #define SSH_KEY_PERMISSIONS_MASK (S_IRWXG | S_IRWXO) |
#include <crypto.h>
Definition at line 425 of file lib/crypto/crypto.h.
| #define SSH_KEY_PUBLIC_KEY_LENGTH_SIZE 4 |
#include <crypto.h>
Definition at line 355 of file lib/crypto/crypto.h.
| #define SSH_KEY_PUBLIC_KEY_SIZE 32 |
#include <crypto.h>
Definition at line 356 of file lib/crypto/crypto.h.
| #define SSH_KEY_RECOMMENDED_PERMISSIONS 0600 |
#include <crypto.h>
Definition at line 426 of file lib/crypto/crypto.h.
| #define SSH_KEY_TYPE_LENGTH_SIZE 4 |
#include <crypto.h>
Definition at line 353 of file lib/crypto/crypto.h.
| #define SSH_KEY_TYPE_STRING_SIZE 11 |
#include <crypto.h>
Definition at line 354 of file lib/crypto/crypto.h.
| #define X25519_KEY_SIZE 32 |
| #define X25519_KEY_TYPE "x25519" |
#include <crypto.h>
X25519 key type string ("x25519")
Definition at line 414 of file lib/crypto/crypto.h.
| #define XSALSA20_NONCE_SIZE 24 |
#include <crypto.h>
XSalsa20 nonce size in bytes.
Definition at line 98 of file lib/crypto/crypto.h.
| #define ZERO_KEY_SIZE X25519_KEY_SIZE |
#include <crypto.h>
Zero key array size (32 bytes, used for no-identity entries)
Definition at line 219 of file lib/crypto/crypto.h.
| typedef struct crypto_context_t crypto_context_t |
#include <crypto.h>
Cryptographic context structure.
Manages all cryptographic state for a single connection, including key exchange, encryption/decryption, authentication, and session rekeying.
session_id || counter where session_id is 16 bytes and counter fills the remaining bytes. This prevents both within-session and cross-session replay attacks.| enum crypto_result_t |
#include <crypto.h>
Cryptographic operation result codes.
Definition at line 329 of file lib/crypto/crypto.h.
| asciichat_error_t add_known_host | ( | const char * | server_ip, |
| uint16_t | port, | ||
| const uint8_t | server_key[32] | ||
| ) |
#include <known_hosts.h>
Add server to known_hosts.
| server_ip | Server IP address (IPv4 or IPv6, must not be NULL) |
| port | Server port number |
| server_key | Server's Ed25519 public key (32 bytes, must not be NULL) |
Adds server identity key to known_hosts file. Creates file if it doesn't exist and creates directory if needed.
<IP:port> x25519 <hex_key> [comment]. Uses proper bracket notation for IPv6 addresses.~/.ascii-chat/known_hosts if it doesn't exist. Creates ~/.ascii-chat/ directory if needed.Definition at line 347 of file known_hosts.c.
References ASCII_CHAT_APP_NAME, ASCIICHAT_OK, BUFFER_SIZE_MEDIUM, CRYPTO_HEX_KEY_SIZE, CRYPTO_HEX_KEY_SIZE_NULL, defer, ED25519_PUBLIC_KEY_SIZE, ERROR_CONFIG, ERROR_INVALID_PARAM, ERROR_MEMORY, FILE_PERM_PRIVATE, format_ip_with_port(), get_known_hosts_path(), log_debug, NO_IDENTITY_MARKER, PATH_DELIM, platform_chmod(), platform_fopen(), SAFE_FCLOSE, safe_fprintf(), SAFE_FREE, SAFE_MALLOC, SET_ERRNO, SET_ERRNO_SYS, and X25519_KEY_TYPE.
Referenced by crypto_handshake_client_key_exchange().
| asciichat_error_t check_known_host | ( | const char * | server_ip, |
| uint16_t | port, | ||
| const uint8_t | server_key[32] | ||
| ) |
#include <known_hosts.h>
Check if server key is in known_hosts.
| server_ip | Server IP address (IPv4 or IPv6, must not be NULL) |
| port | Server port number |
| server_key | Server's Ed25519 public key (32 bytes, must not be NULL) |
Checks if server key matches known hosts entry for the given IP:port. Returns different values based on verification result.
<IP:port> x25519 <hex_key>. Supports both IPv4 and IPv6 addresses with proper bracket notation.~/.ascii-chat/known_hosts (or equivalent on Windows). Returns ASCIICHAT_OK if file doesn't exist (first connection).Definition at line 77 of file known_hosts.c.
References ASCIICHAT_OK, BUFFER_SIZE_MEDIUM, BUFFER_SIZE_XLARGE, CRYPTO_HEX_KEY_SIZE, CRYPTO_HEX_KEY_SIZE_NULL, CRYPTO_KEY_SIZE, defer, ED25519_PUBLIC_KEY_SIZE, ERROR_CRYPTO_VERIFICATION, ERROR_INVALID_PARAM, FILE_PERM_PRIVATE, format_ip_with_port(), get_known_hosts_path(), public_key_t::key, log_debug, log_error, log_info, log_warn, NO_IDENTITY_MARKER, parse_public_key(), platform_close(), platform_fdopen(), PLATFORM_O_RDONLY, platform_open(), SAFE_FCLOSE, safe_snprintf(), and SET_ERRNO.
Referenced by crypto_handshake_client_key_exchange().
| asciichat_error_t check_known_host_no_identity | ( | const char * | server_ip, |
| uint16_t | port | ||
| ) |
#include <known_hosts.h>
Check known_hosts for servers without identity key (no-identity entries)
| server_ip | Server IP address (IPv4 or IPv6, must not be NULL) |
| port | Server port number |
Checks if server has "no-identity" entry in known_hosts. Used for servers that don't have identity keys (ephemeral keys only).
<IP:port> no-identity. Does NOT verify keys (no keys to verify for no-identity servers).Definition at line 223 of file known_hosts.c.
References ASCIICHAT_OK, BUFFER_SIZE_MEDIUM, BUFFER_SIZE_XLARGE, defer, ERROR_CRYPTO_VERIFICATION, ERROR_INVALID_PARAM, FILE_PERM_PRIVATE, format_ip_with_port(), get_known_hosts_path(), log_warn, platform_close(), platform_fdopen(), PLATFORM_O_RDONLY, platform_open(), SAFE_FCLOSE, safe_snprintf(), and SET_ERRNO.
Referenced by crypto_handshake_client_key_exchange().
| void compute_key_fingerprint | ( | const uint8_t | key[32], |
| char | fingerprint[65] | ||
| ) |
#include <known_hosts.h>
Compute SHA256 fingerprint of Ed25519 key for display.
| key | Ed25519 public key (32 bytes, must not be NULL) |
| fingerprint | Output buffer for fingerprint (65 bytes including null terminator) |
Computes SHA256 fingerprint of Ed25519 public key for display. Fingerprint is displayed in hex format (64 hex chars + null terminator).
| void crypto_cleanup | ( | crypto_context_t * | ctx | ) |
#include <crypto.h>
Cleanup crypto context with secure memory wiping.
| ctx | Crypto context to cleanup |
Securely zeroes all sensitive data (keys, salts, etc.) before freeing. Always call this when done with a crypto context.
Definition at line 183 of file lib/crypto/crypto.c.
References crypto_context_t::bytes_decrypted, crypto_context_t::bytes_encrypted, crypto_context_t::initialized, log_debug, crypto_context_t::password_key, crypto_context_t::password_salt, crypto_context_t::private_key, and crypto_context_t::shared_key.
Referenced by crypto_handshake_cleanup(), and crypto_init_with_password().
| void crypto_combine_auth_data | ( | const uint8_t * | hmac, |
| const uint8_t * | challenge_nonce, | ||
| uint8_t * | combined_out | ||
| ) |
#include <crypto.h>
Combine HMAC and challenge nonce for transmission.
| hmac | HMAC to transmit (32 bytes) |
| challenge_nonce | Challenge nonce to transmit (32 bytes) |
| combined_out | Output buffer for combined data (64 bytes) |
Combines HMAC and challenge nonce into a single buffer: [HMAC:32][nonce:32] Used to pack authentication response data for transmission.
Definition at line 1115 of file lib/crypto/crypto.c.
References ERROR_INVALID_PARAM, and SET_ERRNO.
| crypto_result_t crypto_compute_auth_response | ( | const crypto_context_t * | ctx, |
| const uint8_t | nonce[32], | ||
| uint8_t | hmac_out[32] | ||
| ) |
#include <crypto.h>
Compute authentication response HMAC bound to DH shared_secret.
| ctx | Crypto context with keys (must have completed key exchange) |
| nonce | Challenge nonce from server (32 bytes) |
| hmac_out | Output HMAC (32 bytes) |
Computes: HMAC(auth_key, nonce || shared_secret) This binds the password/key authentication to the DH exchange, preventing MITM.
Definition at line 871 of file lib/crypto/crypto.c.
References crypto_compute_hmac_ex(), CRYPTO_ERROR_INVALID_PARAMS, ERROR_CRYPTO, ERROR_INVALID_PARAM, crypto_context_t::has_password, crypto_context_t::key_exchange_complete, crypto_context_t::password_key, SET_ERRNO, and crypto_context_t::shared_key.
Referenced by crypto_handshake_server_complete().
| crypto_result_t crypto_compute_hmac | ( | crypto_context_t * | ctx, |
| const uint8_t | key[32], | ||
| const uint8_t | data[32], | ||
| uint8_t | hmac[32] | ||
| ) |
#include <crypto.h>
Compute HMAC-SHA256 for fixed 32-byte data.
| ctx | Crypto context (for libsodium initialization check) |
| key | HMAC key (32 bytes) |
| data | Data to authenticate (32 bytes) |
| hmac | Output buffer for HMAC (32 bytes) |
Computes HMAC-SHA256 over exactly 32 bytes of data. Useful for authenticating challenge nonces and other fixed-size values.
Definition at line 802 of file lib/crypto/crypto.c.
References CRYPTO_OK, ERROR_INVALID_PARAM, and SET_ERRNO.
| 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] | ||
| ) |
#include <crypto.h>
Compute HMAC-SHA256 for variable-length data.
| ctx | Crypto context (for libsodium initialization check) |
| key | HMAC key (32 bytes) |
| data | Data to authenticate (variable length) |
| data_len | Length of data (must be > 0) |
| hmac | Output buffer for HMAC (32 bytes) |
Computes HMAC-SHA256 over variable-length data. Useful for authenticating combined values (e.g., nonce || shared_secret).
Definition at line 818 of file lib/crypto/crypto.c.
References CRYPTO_OK, ERROR_INVALID_PARAM, and SET_ERRNO.
Referenced by crypto_compute_auth_response(), and crypto_compute_password_hmac().
| 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 | ||
| ) |
#include <crypto.h>
Compute password-based HMAC for authentication.
| ctx | Crypto context |
| password_key | Password-derived key (32 bytes) |
| nonce | Challenge nonce (32 bytes) |
| shared_secret | DH shared secret (32 bytes) |
| hmac_out | Output buffer for HMAC (32 bytes) |
Computes: HMAC(password_key, nonce || shared_secret) Binds password authentication to DH key exchange, preventing MITM.
Definition at line 1045 of file lib/crypto/crypto.c.
References ASCIICHAT_OK, crypto_compute_hmac_ex(), ERROR_CRYPTO, ERROR_INVALID_PARAM, and SET_ERRNO.
| 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 | ||
| ) |
#include <crypto.h>
Create authentication challenge packet.
| ctx | Crypto context (must be initialized) |
| packet_out | Output buffer for challenge packet |
| packet_size | Size of output buffer |
| packet_len_out | Output parameter for actual packet length |
Creates an authentication challenge packet: [type:4][nonce:auth_challenge_size] Generates a random nonce and stores it in ctx->auth_nonce for later verification.
Definition at line 939 of file lib/crypto/crypto.c.
References crypto_context_t::auth_challenge_size, crypto_context_t::auth_nonce, CRYPTO_ERROR_BUFFER_TOO_SMALL, CRYPTO_ERROR_INVALID_PARAMS, crypto_generate_nonce(), CRYPTO_OK, ERROR_BUFFER, ERROR_INVALID_PARAM, crypto_context_t::initialized, SAFE_MEMCPY, and SET_ERRNO.
| 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 | ||
| ) |
#include <crypto.h>
Create encrypted data packet for network transmission.
| ctx | Crypto context (must be initialized and ready) |
| data | Plaintext data to encrypt |
| data_len | Length of plaintext data |
| packet_out | Output buffer for encrypted packet |
| packet_size | Size of output buffer |
| packet_len_out | Output parameter for actual packet length |
Creates an encrypted data packet: [type:4][length:4][encrypted_data:var] Encrypts the data using crypto_encrypt() and prepends packet type and length.
Definition at line 680 of file lib/crypto/crypto.c.
References crypto_encrypt(), CRYPTO_ERROR_BUFFER_TOO_SMALL, CRYPTO_ERROR_INVALID_PARAMS, CRYPTO_ERROR_KEY_EXCHANGE_INCOMPLETE, crypto_is_ready(), CRYPTO_MAX_PLAINTEXT_SIZE, CRYPTO_OK, ERROR_BUFFER, ERROR_CRYPTO, ERROR_INVALID_PARAM, crypto_context_t::mac_size, crypto_context_t::nonce_size, SAFE_MEMCPY, and SET_ERRNO.
| 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 | ||
| ) |
#include <crypto.h>
Create public key packet for network transmission.
| ctx | Crypto context (must be initialized) |
| packet_out | Output buffer for packet |
| packet_size | Size of output buffer |
| packet_len_out | Output parameter for actual packet length |
Creates a public key packet: [type:4][public_key:public_key_size] Used during key exchange handshake to send ephemeral public key to peer.
Definition at line 623 of file lib/crypto/crypto.c.
References CRYPTO_ERROR_BUFFER_TOO_SMALL, CRYPTO_ERROR_INVALID_PARAMS, CRYPTO_OK, ERROR_BUFFER, ERROR_INVALID_PARAM, crypto_context_t::initialized, crypto_context_t::public_key, crypto_context_t::public_key_size, SAFE_MEMCPY, SET_ERRNO, and X25519_KEY_SIZE.
| 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 | ||
| ) |
#include <crypto.h>
Decrypt data using XSalsa20-Poly1305.
| ctx | Crypto context (must be initialized and ready) |
| ciphertext | Ciphertext data to decrypt |
| ciphertext_len | Length of ciphertext (must be >= nonce_size + mac_size) |
| plaintext_out | Output buffer for plaintext |
| plaintext_out_size | Size of output buffer |
| plaintext_len_out | Output parameter for actual plaintext length |
Decrypts data using XSalsa20-Poly1305 authenticated encryption. Uses shared_key if key exchange is complete, otherwise falls back to password_key.
Definition at line 481 of file lib/crypto/crypto.c.
References crypto_context_t::bytes_decrypted, CRYPTO_ERROR_BUFFER_TOO_SMALL, CRYPTO_ERROR_INVALID_MAC, CRYPTO_ERROR_INVALID_PARAMS, CRYPTO_ERROR_KEY_EXCHANGE_INCOMPLETE, crypto_is_ready(), CRYPTO_OK, ERROR_BUFFER, ERROR_CRYPTO, ERROR_INVALID_PARAM, crypto_context_t::has_password, crypto_context_t::initialized, crypto_context_t::key_exchange_complete, crypto_context_t::mac_size, crypto_context_t::nonce_size, crypto_context_t::password_key, SET_ERRNO, and crypto_context_t::shared_key.
Referenced by crypto_handshake_decrypt_packet(), crypto_handshake_process_rekey_complete(), crypto_process_encrypted_packet(), and receive_packet_secure().
| crypto_result_t crypto_derive_password_encryption_key | ( | const char * | password, |
| uint8_t | encryption_key[32] | ||
| ) |
#include <crypto.h>
Derive deterministic encryption key from password for handshake.
| password | Password to derive key from |
| encryption_key | Output buffer for derived key (CRYPTO_ENCRYPTION_KEY_SIZE bytes) |
Derives a deterministic key using a fixed salt (for handshake purposes). This allows password-protected sessions without requiring key exchange to be completed first.
Definition at line 371 of file lib/crypto/crypto.c.
References ARGON2ID_SALT_SIZE, CRYPTO_ERROR_INVALID_PARAMS, CRYPTO_ERROR_PASSWORD_DERIVATION, CRYPTO_OK, crypto_validate_password(), ERROR_CRYPTO, ERROR_INVALID_PARAM, log_debug, SECRETBOX_KEY_SIZE, and SET_ERRNO.
| crypto_result_t crypto_derive_password_key | ( | crypto_context_t * | ctx, |
| const char * | password | ||
| ) |
#include <crypto.h>
Derive key from password using Argon2id.
| ctx | Crypto context (must be initialized) |
| password | Password to derive key from |
Derives a 32-byte encryption key from the password using Argon2id KDF. The salt is deterministic ("ascii-chat-password-salt-v1") for consistent key derivation across client/server.
Definition at line 297 of file lib/crypto/crypto.c.
References CRYPTO_ERROR_INVALID_PARAMS, CRYPTO_ERROR_PASSWORD_DERIVATION, CRYPTO_OK, crypto_validate_password(), crypto_context_t::encryption_key_size, ERROR_CRYPTO, ERROR_INVALID_PARAM, crypto_context_t::initialized, log_debug, crypto_context_t::password_key, crypto_context_t::password_salt, crypto_context_t::salt_size, and SET_ERRNO.
Referenced by client_crypto_init(), crypto_handshake_client_auth_response(), and crypto_init_with_password().
| 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 | ||
| ) |
#include <crypto.h>
Encrypt data using XSalsa20-Poly1305.
| ctx | Crypto context (must be initialized and ready) |
| plaintext | Plaintext data to encrypt |
| plaintext_len | Length of plaintext (must be > 0 and <= CRYPTO_MAX_PLAINTEXT_SIZE) |
| ciphertext_out | Output buffer for ciphertext |
| ciphertext_out_size | Size of output buffer |
| ciphertext_len_out | Output parameter for actual ciphertext length |
Encrypts data using XSalsa20-Poly1305 authenticated encryption. Uses shared_key if key exchange is complete, otherwise falls back to password_key.
session_id || counter. Nonce is prepended to ciphertext: [nonce:24][encrypted_data + MAC]. Counter increments after each encryption to prevent nonce reuse.Definition at line 415 of file lib/crypto/crypto.c.
References crypto_context_t::bytes_encrypted, CRYPTO_ERROR_BUFFER_TOO_SMALL, CRYPTO_ERROR_ENCRYPTION, CRYPTO_ERROR_INVALID_PARAMS, CRYPTO_ERROR_KEY_EXCHANGE_INCOMPLETE, CRYPTO_ERROR_NONCE_EXHAUSTED, crypto_is_ready(), CRYPTO_MAX_PLAINTEXT_SIZE, CRYPTO_OK, ERROR_BUFFER, ERROR_CRYPTO, ERROR_INVALID_PARAM, crypto_context_t::has_password, crypto_context_t::initialized, crypto_context_t::key_exchange_complete, crypto_context_t::mac_size, crypto_context_t::nonce_counter, crypto_context_t::nonce_size, crypto_context_t::password_key, crypto_context_t::rekey_packet_count, SAFE_MEMCPY, SET_ERRNO, crypto_context_t::shared_key, and XSALSA20_NONCE_SIZE.
Referenced by crypto_create_encrypted_packet(), crypto_handshake_encrypt_packet(), crypto_handshake_rekey_complete(), and send_packet_secure().
| void crypto_extract_auth_data | ( | const uint8_t * | combined_data, |
| uint8_t * | hmac_out, | ||
| uint8_t * | challenge_out | ||
| ) |
#include <crypto.h>
Extract HMAC and challenge nonce from combined data.
| combined_data | Combined data received from peer (64 bytes) |
| hmac_out | Output buffer for HMAC (32 bytes) |
| challenge_out | Output buffer for challenge nonce (32 bytes) |
Extracts HMAC and challenge nonce from combined buffer: [HMAC:32][nonce:32] Used to unpack authentication response data received from peer.
Definition at line 1127 of file lib/crypto/crypto.c.
References ERROR_INVALID_PARAM, and SET_ERRNO.
| crypto_result_t crypto_generate_keypair | ( | crypto_context_t * | ctx | ) |
#include <crypto.h>
Generate new X25519 key pair for key exchange.
| ctx | Crypto context |
Generates a new ephemeral X25519 key pair. Called automatically by crypto_init(). Can be called again to regenerate keys (e.g., for rekeying).
Definition at line 201 of file lib/crypto/crypto.c.
References CRYPTO_ERROR_INVALID_PARAMS, CRYPTO_ERROR_KEY_GENERATION, CRYPTO_OK, ERROR_CRYPTO, ERROR_INVALID_PARAM, log_debug, crypto_context_t::private_key, crypto_context_t::public_key, and SET_ERRNO.
Referenced by crypto_init().
| crypto_result_t crypto_generate_nonce | ( | uint8_t | nonce[32] | ) |
#include <crypto.h>
Generate random nonce for authentication.
| nonce | Output buffer for 32-byte random nonce |
Generates a cryptographically secure random nonce for authentication challenges. Uses libsodium's secure random number generator.
Definition at line 787 of file lib/crypto/crypto.c.
References CRYPTO_ERROR_INVALID_PARAMS, CRYPTO_OK, ERROR_INVALID_PARAM, and SET_ERRNO.
Referenced by crypto_create_auth_challenge(), and crypto_handshake_server_auth_challenge().
| crypto_result_t crypto_get_public_key | ( | const crypto_context_t * | ctx, |
| uint8_t * | public_key_out | ||
| ) |
#include <crypto.h>
Get public key for sending to peer (step 1 of handshake)
| ctx | Crypto context |
| public_key_out | Output buffer for public key (must be CRYPTO_PUBLIC_KEY_SIZE bytes) |
Retrieves our ephemeral public key for transmission to the peer. This is the first step in the key exchange handshake.
Definition at line 221 of file lib/crypto/crypto.c.
References CRYPTO_ERROR_INVALID_PARAMS, CRYPTO_OK, ERROR_INVALID_PARAM, crypto_context_t::initialized, crypto_context_t::public_key, crypto_context_t::public_key_size, SAFE_MEMCPY, SET_ERRNO, and X25519_KEY_SIZE.
| void crypto_get_rekey_status | ( | const crypto_context_t * | ctx, |
| char * | status_buffer, | ||
| size_t | buffer_size | ||
| ) |
#include <crypto.h>
Get the current rekeying state for debugging/logging.
| ctx | Crypto context |
| status_buffer | Output buffer for status string |
| buffer_size | Size of status buffer |
Formats a human-readable status string with rekeying state:
Definition at line 1337 of file lib/crypto/crypto.c.
References crypto_context_t::rekey_count, crypto_context_t::rekey_failure_count, crypto_context_t::rekey_in_progress, crypto_context_t::rekey_last_time, crypto_context_t::rekey_packet_count, crypto_context_t::rekey_packet_threshold, and crypto_context_t::rekey_time_threshold.
| void crypto_get_status | ( | const crypto_context_t * | ctx, |
| char * | status_buffer, | ||
| size_t | buffer_size | ||
| ) |
#include <crypto.h>
Get crypto context status information for debugging.
| ctx | Crypto context |
| status_buffer | Output buffer for status string |
| buffer_size | Size of status buffer |
Formats a human-readable status string with context state information:
Definition at line 579 of file lib/crypto/crypto.c.
References crypto_context_t::bytes_decrypted, crypto_context_t::bytes_encrypted, crypto_is_ready(), crypto_context_t::has_password, crypto_context_t::initialized, crypto_context_t::key_exchange_complete, crypto_context_t::nonce_counter, and SAFE_SNPRINTF.
| crypto_result_t crypto_init | ( | crypto_context_t * | ctx | ) |
#include <crypto.h>
Initialize libsodium and crypto context.
| ctx | Crypto context to initialize |
Initializes libsodium (thread-safe, idempotent) and generates a new X25519 key pair for key exchange.
Definition at line 78 of file lib/crypto/crypto.c.
References ARGON2ID_SALT_SIZE, AUTH_CHALLENGE_SIZE, crypto_context_t::auth_challenge_size, crypto_context_t::bytes_decrypted, crypto_context_t::bytes_encrypted, CRYPTO_ERROR_INVALID_PARAMS, crypto_generate_keypair(), CRYPTO_OK, ED25519_SIGNATURE_SIZE, crypto_context_t::encryption_key_size, ERROR_INVALID_PARAM, format_duration_s(), crypto_context_t::handshake_complete, crypto_context_t::has_password, crypto_context_t::has_temp_key, HMAC_SHA256_SIZE, crypto_context_t::hmac_size, crypto_context_t::initialized, crypto_context_t::key_exchange_complete, log_info, crypto_context_t::mac_size, crypto_context_t::nonce_counter, crypto_context_t::nonce_size, crypto_context_t::peer_key_received, POLY1305_MAC_SIZE, crypto_context_t::private_key_size, crypto_context_t::public_key_size, crypto_context_t::rekey_count, REKEY_DEFAULT_PACKET_THRESHOLD, REKEY_DEFAULT_TIME_THRESHOLD, crypto_context_t::rekey_failure_count, crypto_context_t::rekey_in_progress, crypto_context_t::rekey_last_request_time, crypto_context_t::rekey_last_time, crypto_context_t::rekey_packet_count, crypto_context_t::rekey_packet_threshold, REKEY_TEST_PACKET_THRESHOLD, REKEY_TEST_TIME_THRESHOLD, crypto_context_t::rekey_time_threshold, crypto_context_t::salt_size, SECRETBOX_KEY_SIZE, crypto_context_t::session_id, SET_ERRNO, crypto_context_t::shared_key_size, crypto_context_t::signature_size, X25519_KEY_SIZE, and XSALSA20_NONCE_SIZE.
Referenced by crypto_handshake_init(), and crypto_init_with_password().
| crypto_result_t crypto_init_with_password | ( | crypto_context_t * | ctx, |
| const char * | password | ||
| ) |
#include <crypto.h>
Initialize with password-based encryption.
| ctx | Crypto context to initialize |
| password | Password for key derivation |
Initializes context and derives encryption key from password using Argon2id. The password is used as an additional layer on top of DH key exchange.
Definition at line 153 of file lib/crypto/crypto.c.
References crypto_cleanup(), crypto_derive_password_key(), CRYPTO_ERROR_INVALID_PARAMS, crypto_init(), CRYPTO_OK, ERROR_INVALID_PARAM, crypto_context_t::has_password, log_info, and SET_ERRNO.
Referenced by crypto_handshake_init_with_password().
| bool crypto_is_ready | ( | const crypto_context_t * | ctx | ) |
#include <crypto.h>
Check if key exchange is complete and ready for encryption.
| ctx | Crypto context |
Returns true only after both parties have exchanged public keys and the shared secret has been computed.
Definition at line 261 of file lib/crypto/crypto.c.
References crypto_context_t::has_password, crypto_context_t::initialized, and crypto_context_t::key_exchange_complete.
Referenced by crypto_create_encrypted_packet(), crypto_decrypt(), crypto_encrypt(), crypto_get_status(), crypto_handshake_is_ready(), crypto_process_encrypted_packet(), packet_send_error(), packet_send_remote_log(), and send_packet_secure().
| crypto_result_t crypto_process_auth_challenge | ( | crypto_context_t * | ctx, |
| const uint8_t * | packet, | ||
| size_t | packet_len | ||
| ) |
#include <crypto.h>
Process authentication challenge packet.
| ctx | Crypto context (must be initialized) |
| packet | Challenge packet received from peer |
| packet_len | Length of challenge packet |
Processes an authentication challenge packet: [type:4][nonce:auth_challenge_size] Extracts the nonce and stores it in ctx->auth_nonce for generating the response.
Definition at line 971 of file lib/crypto/crypto.c.
References crypto_context_t::auth_challenge_size, crypto_context_t::auth_nonce, CRYPTO_ERROR_INVALID_PARAMS, CRYPTO_OK, ERROR_INVALID_PARAM, crypto_context_t::initialized, log_debug, SAFE_MEMCPY, and SET_ERRNO.
| crypto_result_t crypto_process_auth_response | ( | crypto_context_t * | ctx, |
| const uint8_t * | packet, | ||
| size_t | packet_len | ||
| ) |
#include <crypto.h>
Process authentication response packet.
| ctx | Crypto context (must be initialized and have completed key exchange) |
| packet | Response packet received from peer |
| packet_len | Length of response packet |
Processes an authentication response packet containing HMAC. Verifies the HMAC using crypto_verify_auth_response().
Definition at line 1003 of file lib/crypto/crypto.c.
References crypto_context_t::auth_nonce, CRYPTO_ERROR_INVALID_MAC, CRYPTO_ERROR_INVALID_PARAMS, CRYPTO_OK, crypto_verify_hmac(), ERROR_CRYPTO, ERROR_INVALID_PARAM, crypto_context_t::handshake_complete, crypto_context_t::initialized, log_debug, SAFE_MEMCPY, SET_ERRNO, and crypto_context_t::shared_key.
| 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 | ||
| ) |
#include <crypto.h>
Process received encrypted packet from peer.
| ctx | Crypto context (must be initialized and ready) |
| packet | Encrypted packet received from peer |
| packet_len | Length of packet |
| data_out | Output buffer for decrypted plaintext |
| data_size | Size of output buffer |
| data_len_out | Output parameter for actual plaintext length |
Processes an encrypted data packet: [type:4][length:4][encrypted_data:var] Decrypts the data using crypto_decrypt().
Definition at line 742 of file lib/crypto/crypto.c.
References crypto_decrypt(), CRYPTO_ERROR_INVALID_PARAMS, CRYPTO_ERROR_KEY_EXCHANGE_INCOMPLETE, crypto_is_ready(), ERROR_CRYPTO, ERROR_INVALID_PARAM, SAFE_MEMCPY, and SET_ERRNO.
| crypto_result_t crypto_process_public_key_packet | ( | crypto_context_t * | ctx, |
| const uint8_t * | packet, | ||
| size_t | packet_len | ||
| ) |
#include <crypto.h>
Process received public key packet from peer.
| ctx | Crypto context (must be initialized) |
| packet | Public key packet received from peer |
| packet_len | Length of packet |
Processes a public key packet: [type:4][public_key:public_key_size] Extracts peer's public key and computes shared secret automatically.
Definition at line 651 of file lib/crypto/crypto.c.
References CRYPTO_ERROR_INVALID_PARAMS, crypto_set_peer_public_key(), ERROR_INVALID_PARAM, crypto_context_t::initialized, crypto_context_t::public_key_size, SAFE_MEMCPY, and SET_ERRNO.
| crypto_result_t crypto_random_bytes | ( | uint8_t * | buffer, |
| size_t | len | ||
| ) |
#include <crypto.h>
Generate cryptographically secure random bytes.
| buffer | Output buffer for random bytes |
| len | Number of random bytes to generate (must be > 0) |
Uses libsodium's secure random number generator (randombytes_buf). Suitable for generating nonces, keys, salts, and other cryptographic material.
Definition at line 604 of file lib/crypto/crypto.c.
References CRYPTO_ERROR_INVALID_PARAMS, CRYPTO_OK, ERROR_INVALID_PARAM, and SET_ERRNO.
| void crypto_rekey_abort | ( | crypto_context_t * | ctx | ) |
#include <crypto.h>
Abort rekeying and fallback to old keys.
| ctx | Crypto context |
Aborts ongoing rekey and clears temp_* keys. Called on rekey failure (timeout, bad keys, decryption failure, etc.).
Definition at line 1315 of file lib/crypto/crypto.c.
References crypto_context_t::has_temp_key, log_warn, crypto_context_t::rekey_failure_count, crypto_context_t::rekey_in_progress, crypto_context_t::temp_private_key, crypto_context_t::temp_public_key, and crypto_context_t::temp_shared_key.
Referenced by crypto_handshake_process_rekey_complete(), crypto_handshake_process_rekey_request(), crypto_handshake_process_rekey_response(), crypto_handshake_rekey_complete(), crypto_handshake_rekey_request(), crypto_handshake_rekey_response(), and crypto_rekey_process_response().
| crypto_result_t crypto_rekey_commit | ( | crypto_context_t * | ctx | ) |
#include <crypto.h>
Commit to new keys after successful REKEY_COMPLETE.
| ctx | Crypto context |
Switches from old shared_key to temp_shared_key, resets counters. Called after REKEY_COMPLETE is verified (decrypts successfully with new key).
Definition at line 1271 of file lib/crypto/crypto.c.
References CRYPTO_ERROR_INVALID_PARAMS, CRYPTO_ERROR_REKEY_FAILED, CRYPTO_OK, ERROR_CRYPTO, ERROR_INVALID_PARAM, crypto_context_t::has_temp_key, crypto_context_t::initialized, log_info, crypto_context_t::nonce_counter, crypto_context_t::rekey_count, crypto_context_t::rekey_failure_count, crypto_context_t::rekey_in_progress, crypto_context_t::rekey_last_time, crypto_context_t::rekey_packet_count, SAFE_MEMCPY, crypto_context_t::session_id, SET_ERRNO, crypto_context_t::shared_key, crypto_context_t::temp_private_key, crypto_context_t::temp_public_key, and crypto_context_t::temp_shared_key.
Referenced by crypto_handshake_process_rekey_complete(), and crypto_handshake_rekey_complete().
| crypto_result_t crypto_rekey_init | ( | crypto_context_t * | ctx | ) |
#include <crypto.h>
Initiate rekeying by generating new ephemeral keys.
| ctx | Crypto context |
Generates new ephemeral key pair and stores in temp_* fields. Called by the initiator (client or server) before sending REKEY_REQUEST.
Definition at line 1177 of file lib/crypto/crypto.c.
References CRYPTO_ERROR_INVALID_PARAMS, CRYPTO_ERROR_KEY_GENERATION, CRYPTO_ERROR_REKEY_FAILED, CRYPTO_ERROR_REKEY_IN_PROGRESS, CRYPTO_ERROR_REKEY_RATE_LIMITED, CRYPTO_OK, ERROR_CRYPTO, ERROR_INVALID_PARAM, format_duration_s(), crypto_context_t::has_temp_key, crypto_context_t::initialized, log_error, log_info, log_warn, crypto_context_t::rekey_failure_count, crypto_context_t::rekey_in_progress, crypto_context_t::rekey_last_time, REKEY_MAX_FAILURE_COUNT, REKEY_MIN_INTERVAL, crypto_context_t::rekey_packet_count, SET_ERRNO, crypto_context_t::temp_private_key, and crypto_context_t::temp_public_key.
Referenced by crypto_handshake_process_rekey_request(), and crypto_handshake_rekey_request().
| crypto_result_t crypto_rekey_process_request | ( | crypto_context_t * | ctx, |
| const uint8_t * | peer_new_public_key | ||
| ) |
#include <crypto.h>
Process REKEY_REQUEST from peer (responder side)
| ctx | Crypto context |
| peer_new_public_key | Peer's new ephemeral public key (32 bytes) |
Processes peer's new ephemeral public key from REKEY_REQUEST. Generates our own new ephemeral keys and computes new shared secret.
Definition at line 1220 of file lib/crypto/crypto.c.
References CRYPTO_ERROR_INVALID_PARAMS, CRYPTO_ERROR_KEY_GENERATION, CRYPTO_OK, ERROR_CRYPTO, ERROR_INVALID_PARAM, crypto_context_t::has_temp_key, crypto_context_t::initialized, log_debug, crypto_context_t::rekey_in_progress, SET_ERRNO, crypto_context_t::temp_private_key, crypto_context_t::temp_public_key, and crypto_context_t::temp_shared_key.
Referenced by crypto_handshake_process_rekey_request().
| crypto_result_t crypto_rekey_process_response | ( | crypto_context_t * | ctx, |
| const uint8_t * | peer_new_public_key | ||
| ) |
#include <crypto.h>
Process REKEY_RESPONSE from peer (initiator side)
| ctx | Crypto context |
| peer_new_public_key | Peer's new ephemeral public key (32 bytes) |
Processes peer's new ephemeral public key from REKEY_RESPONSE. Computes new shared secret using our temp_private_key and peer's temp_public_key.
Definition at line 1248 of file lib/crypto/crypto.c.
References CRYPTO_ERROR_INVALID_PARAMS, CRYPTO_ERROR_KEY_GENERATION, CRYPTO_ERROR_REKEY_FAILED, CRYPTO_OK, crypto_rekey_abort(), ERROR_CRYPTO, ERROR_INVALID_PARAM, crypto_context_t::has_temp_key, crypto_context_t::initialized, log_debug, crypto_context_t::rekey_in_progress, SET_ERRNO, crypto_context_t::temp_private_key, and crypto_context_t::temp_shared_key.
Referenced by crypto_handshake_process_rekey_response().
| const char * crypto_result_to_string | ( | crypto_result_t | result | ) |
#include <crypto.h>
Convert crypto result to human-readable string.
| result | Crypto result code |
Returns a descriptive string for each crypto_result_t value. Useful for logging and error reporting.
Definition at line 540 of file lib/crypto/crypto.c.
References CRYPTO_ERROR_BUFFER_TOO_SMALL, CRYPTO_ERROR_DECRYPTION, CRYPTO_ERROR_ENCRYPTION, CRYPTO_ERROR_INIT_FAILED, CRYPTO_ERROR_INVALID_MAC, CRYPTO_ERROR_INVALID_PARAMS, CRYPTO_ERROR_KEY_EXCHANGE_INCOMPLETE, CRYPTO_ERROR_KEY_GENERATION, CRYPTO_ERROR_LIBSODIUM, CRYPTO_ERROR_MEMORY, CRYPTO_ERROR_NONCE_EXHAUSTED, CRYPTO_ERROR_PASSWORD_DERIVATION, CRYPTO_ERROR_REKEY_FAILED, CRYPTO_ERROR_REKEY_IN_PROGRESS, CRYPTO_ERROR_REKEY_RATE_LIMITED, and CRYPTO_OK.
Referenced by client_crypto_init(), crypto_handshake_client_auth_response(), crypto_handshake_client_key_exchange(), crypto_handshake_decrypt_packet(), crypto_handshake_encrypt_packet(), crypto_handshake_init(), crypto_handshake_init_with_password(), crypto_handshake_process_rekey_complete(), crypto_handshake_process_rekey_request(), crypto_handshake_process_rekey_response(), crypto_handshake_rekey_complete(), crypto_handshake_rekey_request(), crypto_handshake_server_auth_challenge(), crypto_handshake_server_complete(), receive_packet_secure(), and send_packet_secure().
#include <crypto.h>
Secure constant-time comparison of byte arrays.
| lhs | First byte array |
| rhs | Second byte array |
| len | Length of arrays to compare |
Uses constant-time comparison (sodium_memcmp) to prevent timing attacks. Always compares all bytes, regardless of where difference is found.
Definition at line 597 of file lib/crypto/crypto.c.
| crypto_result_t crypto_set_peer_public_key | ( | crypto_context_t * | ctx, |
| const uint8_t * | peer_public_key | ||
| ) |
#include <crypto.h>
Set peer's public key and compute shared secret (step 2 of handshake)
| ctx | Crypto context |
| peer_public_key | Peer's ephemeral public key (CRYPTO_PUBLIC_KEY_SIZE bytes) |
Receives peer's public key and computes the shared secret using X25519. After this call, crypto_is_ready() will return true.
Definition at line 235 of file lib/crypto/crypto.c.
References CRYPTO_ERROR_INVALID_PARAMS, CRYPTO_ERROR_KEY_GENERATION, CRYPTO_OK, ERROR_CRYPTO, ERROR_INVALID_PARAM, crypto_context_t::initialized, crypto_context_t::key_exchange_complete, log_debug, crypto_context_t::peer_key_received, crypto_context_t::peer_public_key, crypto_context_t::private_key, crypto_context_t::public_key_size, SAFE_MEMCPY, SET_ERRNO, crypto_context_t::shared_key, and X25519_KEY_SIZE.
Referenced by crypto_handshake_client_key_exchange(), crypto_handshake_server_auth_challenge(), and crypto_process_public_key_packet().
| bool crypto_should_rekey | ( | const crypto_context_t * | ctx | ) |
#include <crypto.h>
Check if rekeying should be triggered based on time or packet count thresholds.
| ctx | Crypto context |
Checks if rekeying should be triggered based on:
Definition at line 1143 of file lib/crypto/crypto.c.
References crypto_context_t::handshake_complete, crypto_context_t::initialized, log_debug, crypto_context_t::rekey_in_progress, crypto_context_t::rekey_last_time, crypto_context_t::rekey_packet_count, crypto_context_t::rekey_packet_threshold, and crypto_context_t::rekey_time_threshold.
Referenced by crypto_handshake_should_rekey().
| 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 | ||
| ) |
#include <crypto.h>
Sign ephemeral key with private key.
| private_key | Ed25519 private key for signing (64 bytes) |
| ephemeral_key | Ephemeral public key to sign (variable size) |
| ephemeral_key_size | Size of ephemeral key (typically 32 bytes for X25519) |
| signature_out | Output buffer for Ed25519 signature (64 bytes) |
Signs ephemeral public key with Ed25519 identity key. Used during authenticated key exchange to prove server identity.
Definition at line 1091 of file lib/crypto/crypto.c.
References ASCIICHAT_OK, private_key_t::ed25519, ERROR_CRYPTO, ERROR_INVALID_PARAM, private_key_t::key, KEY_TYPE_ED25519, SET_ERRNO, and private_key_t::type.
| crypto_result_t crypto_validate_password | ( | const char * | password | ) |
#include <crypto.h>
Validate password length requirements.
| password | Password to validate |
Validates that password meets length requirements (MIN_PASSWORD_LENGTH to MAX_PASSWORD_LENGTH characters).
Definition at line 274 of file lib/crypto/crypto.c.
References CRYPTO_ERROR_INVALID_PARAMS, CRYPTO_OK, ERROR_INVALID_PARAM, MAX_PASSWORD_LENGTH, MIN_PASSWORD_LENGTH, and SET_ERRNO.
Referenced by crypto_derive_password_encryption_key(), and crypto_derive_password_key().
| bool crypto_verify_auth_response | ( | const crypto_context_t * | ctx, |
| const uint8_t | nonce[32], | ||
| const uint8_t | expected_hmac[32] | ||
| ) |
#include <crypto.h>
Verify authentication response HMAC bound to DH shared_secret.
| ctx | Crypto context with keys (must have completed key exchange) |
| nonce | Challenge nonce that was sent (32 bytes) |
| expected_hmac | Expected HMAC to verify (32 bytes) |
Verifies: HMAC(auth_key, nonce || shared_secret)
Definition at line 903 of file lib/crypto/crypto.c.
References crypto_verify_hmac_ex(), ERROR_CRYPTO, ERROR_INVALID_PARAM, crypto_context_t::has_password, crypto_context_t::key_exchange_complete, log_debug, crypto_context_t::password_key, SET_ERRNO, and crypto_context_t::shared_key.
Referenced by crypto_handshake_client_complete(), and crypto_handshake_server_complete().
| bool crypto_verify_hmac | ( | const uint8_t | key[32], |
| const uint8_t | data[32], | ||
| const uint8_t | expected_hmac[32] | ||
| ) |
#include <crypto.h>
Verify HMAC-SHA256 for fixed 32-byte data.
| key | HMAC key (32 bytes) |
| data | Data that was authenticated (32 bytes) |
| expected_hmac | Expected HMAC to verify (32 bytes) |
Verifies HMAC-SHA256 using constant-time comparison. Prevents timing attacks during verification.
Definition at line 835 of file lib/crypto/crypto.c.
References ERROR_INVALID_PARAM, and SET_ERRNO.
Referenced by crypto_process_auth_response().
| bool crypto_verify_hmac_ex | ( | const uint8_t | key[32], |
| const uint8_t * | data, | ||
| size_t | data_len, | ||
| const uint8_t | expected_hmac[32] | ||
| ) |
#include <crypto.h>
Verify HMAC-SHA256 for variable-length data.
| key | HMAC key (32 bytes) |
| data | Data that was authenticated (variable length) |
| data_len | Length of data (must be > 0) |
| expected_hmac | Expected HMAC to verify (32 bytes) |
Verifies HMAC-SHA256 using constant-time comparison. Prevents timing attacks during verification.
Definition at line 850 of file lib/crypto/crypto.c.
References ERROR_INVALID_PARAM, and SET_ERRNO.
Referenced by crypto_verify_auth_response().
| bool crypto_verify_password | ( | const crypto_context_t * | ctx, |
| const char * | password | ||
| ) |
#include <crypto.h>
Verify password matches stored salt/key.
| ctx | Crypto context (must be initialized and have password) |
| password | Password to verify |
Verifies that the provided password, when derived with the stored salt, produces the same key as stored in the context.
Definition at line 336 of file lib/crypto/crypto.c.
References ARGON2ID_SALT_SIZE, crypto_context_t::encryption_key_size, crypto_context_t::has_password, crypto_context_t::initialized, crypto_context_t::password_key, crypto_context_t::salt_size, and SECRETBOX_KEY_SIZE.
| 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 | ||
| ) |
#include <crypto.h>
Verify peer's signature on ephemeral key.
| peer_public_key | Peer's Ed25519 public key (32 bytes) |
| ephemeral_key | Ephemeral public key that was signed (variable size) |
| ephemeral_key_size | Size of ephemeral key (typically 32 bytes for X25519) |
| signature | Ed25519 signature (64 bytes) |
Verifies Ed25519 signature on ephemeral public key using peer's identity key. Used during authenticated key exchange to verify server identity.
Definition at line 1072 of file lib/crypto/crypto.c.
References ASCIICHAT_OK, ERROR_CRYPTO, ERROR_INVALID_PARAM, and SET_ERRNO.
| bool display_mitm_warning | ( | const char * | server_ip, |
| uint16_t | port, | ||
| const uint8_t | expected_key[32], | ||
| const uint8_t | received_key[32] | ||
| ) |
#include <known_hosts.h>
Display MITM warning with key comparison and prompt user for confirmation.
| server_ip | Server IP address (IPv4 or IPv6, must not be NULL) |
| port | Server port number |
| expected_key | Expected server key from known_hosts (32 bytes, must not be NULL) |
| received_key | Received server key from connection (32 bytes, must not be NULL) |
Displays man-in-the-middle warning with key comparison and prompts user for confirmation. Shows both expected and received keys in hex format for comparison.
Definition at line 621 of file known_hosts.c.
References ASCIICHAT_OK, BUFFER_SIZE_MEDIUM, compute_key_fingerprint(), CRYPTO_HEX_KEY_SIZE_NULL, escape_ascii(), format_ip_with_port(), get_known_hosts_path(), log_warn, and safe_snprintf().
Referenced by crypto_handshake_client_key_exchange().
| void free_ta_contents | ( | br_x509_trust_anchor * | ta | ) |
#include <pem_utils.h>
Free the contents of a trust anchor.
| ta | Pointer to trust anchor to free (must not be NULL) |
Releases all dynamically allocated memory within a trust anchor structure, but does not free the structure itself. Call this for each trust anchor before freeing the anchor_list buffer.
Definition at line 419 of file pem_utils.c.
References ERROR_CRYPTO, and SET_ERRNO.
Referenced by https_get(), and read_trust_anchors_from_memory().
| const char * get_known_hosts_path | ( | void | ) |
#include <known_hosts.c>
Get the path to the known_hosts file.
Get known_hosts file path.
Returns the path to the known_hosts file, using the same directory as all other ascii-chat configuration files (get_config_dir()).
PATH RESOLUTION:
Returns path to known_hosts file, expanding user directory if needed. Path is cached after first call.
~/.ascii-chat/known_hosts (or equivalent on Windows). Uses expand_path() to resolve user directory.$XDG_CONFIG_HOME/ascii-chat/known_hosts if set, otherwise ~/.ascii-chat/known_hostsAPPDATA%\ascii-chat\known_hosts if set, otherwise ~\.ascii-chat\known_hostsDefinition at line 46 of file known_hosts.c.
References get_config_dir(), log_debug, log_error, SAFE_FREE, SAFE_MALLOC, and safe_snprintf().
Referenced by add_known_host(), check_known_host(), check_known_host_no_identity(), crypto_handshake_client_key_exchange(), display_mitm_warning(), prompt_unknown_host(), and remove_known_host().
| int gpg_agent_connect | ( | void | ) |
#include <agent.h>
Connect to gpg-agent.
Establishes connection to GPG agent using Assuan protocol. Connects to agent socket/pipe and performs initial handshake.
Definition at line 267 of file agent.c.
References errno, GPG_AGENT_MAX_RESPONSE, log_debug, log_error, log_warn, PLATFORM_MAX_PATH_LENGTH, SAFE_STRERROR, and SAFE_STRNCPY.
Referenced by ed25519_sign_message(), gpg_agent_is_available(), and gpg_get_public_key().
| void gpg_agent_disconnect | ( | int | sock | ) |
#include <agent.h>
Disconnect from gpg-agent.
| sock | Socket/pipe handle from gpg_agent_connect() |
Closes connection to GPG agent and releases socket resources. Safe to call with invalid socket (does nothing if sock < 0).
Definition at line 337 of file agent.c.
Referenced by ed25519_sign_message(), gpg_agent_is_available(), and gpg_get_public_key().
| bool gpg_agent_is_available | ( | void | ) |
#include <agent.h>
Check if GPG agent is available.
Checks if GPG agent is running by attempting to connect and immediately disconnecting. Uses gpg_agent_connect() internally.
Definition at line 539 of file agent.c.
References gpg_agent_connect(), and gpg_agent_disconnect().
| int gpg_agent_sign | ( | int | sock, |
| const char * | keygrip, | ||
| const uint8_t * | message, | ||
| size_t | message_len, | ||
| uint8_t * | signature_out, | ||
| size_t * | signature_len_out | ||
| ) |
#include <agent.h>
Sign a message using GPG agent.
| sock | Socket/pipe handle from gpg_agent_connect() (must be valid) |
| keygrip | GPG keygrip (40-char hex string, must not be NULL) |
| message | Message to sign (must not be NULL) |
| message_len | Message length (must be > 0) |
| signature_out | Output buffer for signature (must be >= 64 bytes for Ed25519) |
| signature_len_out | Output parameter for signature length (must not be NULL) |
Signs message using GPG agent Assuan protocol PKSIGN command. Key stays in GPG agent - private key never enters application memory.
Definition at line 345 of file agent.c.
References GPG_AGENT_MAX_RESPONSE, log_debug, log_error, log_warn, and safe_snprintf().
Referenced by ed25519_sign_message().
| int gpg_get_public_key | ( | const char * | key_id, |
| uint8_t * | public_key_out, | ||
| char * | keygrip_out | ||
| ) |
#include <export.h>
Get public key from GPG keyring by key ID.
| key_id | GPG key ID (8/16/40-char hex string, must not be NULL) |
| public_key_out | Output buffer for 32-byte Ed25519 public key (must not be NULL) |
| keygrip_out | Output buffer for 40-char keygrip + null terminator (can be NULL if not needed) |
Retrieves Ed25519 public key from GPG keyring using gpg --export command. Parses OpenPGP packet format to extract raw 32-byte Ed25519 public key.
gpg --export 0x<KEY_ID> to export public key. Output is in binary OpenPGP packet format, which is then parsed.gpg --with-keygrip --list-keys. Keygrip is 40-char hex string that identifies key in GPG agent. Useful for subsequent gpg_agent_sign() operations.gpg binary not found in PATHgpg binary in PATH. Returns -1 if GPG is not installed or not accessible.gpg --list-keys <KEY_ID>). Definition at line 251 of file export.c.
References BUFFER_SIZE_LARGE, BUFFER_SIZE_MEDIUM, BUFFER_SIZE_XLARGE, BUFFER_SIZE_XXXLARGE, bytes_written, escape_shell_single_quotes(), gpg_agent_connect(), gpg_agent_disconnect(), log_debug, log_error, log_info, log_warn, platform_pipe_read(), platform_pipe_write(), SAFE_PCLOSE, SAFE_POPEN, safe_snprintf(), SAFE_STRNCPY, and validate_shell_safe().
Referenced by extract_ed25519_from_gpg(), and parse_private_key().
| int gpg_sign_detached_ed25519 | ( | const char * | key_id, |
| const uint8_t * | message, | ||
| size_t | message_len, | ||
| uint8_t | signature_out[64] | ||
| ) |
#include <signing.h>
Sign message with GPG and extract raw Ed25519 signature.
| key_id | GPG key ID (8/16/40-char hex string, must not be NULL) |
| message | Message to sign (must not be NULL) |
| message_len | Message length in bytes (must be > 0) |
| signature_out | Output buffer for 64-byte Ed25519 signature (must not be NULL) |
Signs message using gpg --detach-sign, then extracts raw 64-byte Ed25519 signature from OpenPGP packet format. Returns signature in libsodium-compatible format (R||S).
gpg --detach-sign --local-user 0x<KEY_ID> command. Then parses OpenPGP output to extract raw signature bytes.gpg binary not found in PATHgpg binary in PATH. Returns -1 if GPG is not installed or not accessible.gpg --list-keys <KEY_ID>). Definition at line 180 of file signing.c.
References gpg_sign_with_key(), log_debug, log_error, log_info, and safe_snprintf().
Referenced by ed25519_sign_message().
| int gpg_sign_with_key | ( | const char * | key_id, |
| const uint8_t * | message, | ||
| size_t | message_len, | ||
| uint8_t * | signature_out, | ||
| size_t * | signature_len_out | ||
| ) |
#include <signing.h>
Sign a message using GPG key and return OpenPGP signature.
| key_id | GPG key ID (8/16/40-char hex string, must not be NULL) |
| message | Message to sign (must not be NULL) |
| message_len | Message length in bytes (must be > 0) |
| signature_out | Output buffer for OpenPGP signature (must be >= 512 bytes) |
| signature_len_out | Output parameter for actual signature length (must not be NULL) |
Signs message using gpg --detach-sign and returns full OpenPGP signature packet. Signature is in binary OpenPGP format and includes packet headers.
gpg --detach-sign --local-user 0x<KEY_ID> command. Creates detached signature (signature separate from message).gpg as subprocess and reads output. Signature is read from GPG's stdout in binary format.gpg binary not found in PATHgpg binary in PATH. Returns -1 if GPG is not installed or not accessible.gpg --list-keys <KEY_ID>).Sign a message using GPG key and return OpenPGP signature.
This function uses gpg --detach-sign which internally uses gpg-agent, so no passphrase prompt if the key is cached in the agent.
| key_id | GPG key ID (e.g., "7FE90A79F2E80ED3") |
| message | Message to sign |
| message_len | Message length |
| signature_out | Output buffer for signature (caller must provide at least 512 bytes) |
| signature_len_out | Actual signature length written |
Definition at line 44 of file signing.c.
References BUFFER_SIZE_LARGE, errno, escape_path_for_shell(), log_debug, log_error, log_info, platform_open(), safe_snprintf(), and SAFE_STRERROR.
Referenced by gpg_sign_detached_ed25519(), and gpg_verify_detached_ed25519().
| int gpg_verify_detached_ed25519 | ( | const char * | key_id, |
| const uint8_t * | message, | ||
| size_t | message_len, | ||
| const uint8_t | signature[64] | ||
| ) |
#include <verification.h>
Verify Ed25519 signature using GPG binary.
| key_id | GPG key ID to use for verification (8/16/40-char hex, must not be NULL) |
| message | Message that was signed (must not be NULL) |
| message_len | Message length in bytes (must be > 0) |
| signature | 64-byte Ed25519 signature (must not be NULL) |
Verifies raw Ed25519 signature using gpg --verify command. Converts raw signature to OpenPGP format, then uses GPG binary for verification.
gpg --verify command on converted OpenPGP signature. Checks both cryptographic validity and key trust status.gpg --import <public_key_file>.gpg binary not found in PATHgpg binary in PATH. Returns -1 if GPG is not installed or not accessible.gpg --import).Definition at line 35 of file verification.c.
References gpg_sign_with_key(), log_debug, log_error, and log_info.
Referenced by ed25519_verify_signature().
| int gpg_verify_signature | ( | const uint8_t * | public_key, |
| const uint8_t * | message, | ||
| size_t | message_len, | ||
| const uint8_t * | signature | ||
| ) |
#include <verification.h>
Verify Ed25519 signature using libgcrypt (no GPG binary required)
| public_key | 32-byte Ed25519 public key (must not be NULL) |
| message | Message that was signed (must not be NULL) |
| message_len | Message length in bytes (must be > 0) |
| signature | 64-byte Ed25519 signature (must not be NULL) |
Verifies Ed25519 signature directly using libgcrypt cryptographic library. Does not require GPG binary - performs pure cryptographic verification.
Definition at line 131 of file verification.c.
| int gpg_verify_signature_with_binary | ( | const uint8_t * | signature, |
| size_t | signature_len, | ||
| const uint8_t * | message, | ||
| size_t | message_len, | ||
| const char * | expected_key_id | ||
| ) |
#include <verification.h>
Verify OpenPGP signature using GPG binary.
| signature | GPG signature in OpenPGP packet format (must not be NULL) |
| signature_len | Signature length in bytes (must be > 0) |
| message | Message that was signed (must not be NULL) |
| message_len | Message length in bytes (must be > 0) |
| expected_key_id | Expected GPG key ID for signature (optional, can be NULL) |
Verifies OpenPGP-formatted signature using gpg --verify command. Accepts full OpenPGP signature packets from gpg_sign_with_key().
gpg --verify on OpenPGP signature packet. Checks both cryptographic validity and key trust status.gpg --import <public_key_file>.gpg binary not found in PATHgpg binary in PATH. Returns -1 if GPG is not installed or not accessible.gpg --import).Definition at line 223 of file verification.c.
References BUFFER_SIZE_LARGE, BUFFER_SIZE_MEDIUM, bytes_written, errno, log_debug, log_error, log_info, PLATFORM_MAX_PATH_LENGTH, SAFE_PCLOSE, SAFE_POPEN, safe_snprintf(), and SAFE_STRERROR.
| void known_hosts_cleanup | ( | void | ) |
#include <known_hosts.h>
Cleanup function to free cached known_hosts path.
Frees cached known_hosts file path. Should be called at program shutdown to clean up resources.
Definition at line 731 of file known_hosts.c.
References SAFE_FREE.
Referenced by asciichat_shared_init().
#include <known_hosts.h>
Interactive prompt for unknown host - returns true if user wants to add, false to abort.
| server_ip | Server IP address (IPv4 or IPv6, must not be NULL) |
| port | Server port number |
| server_key | Server's Ed25519 public key (32 bytes, must not be NULL) |
Prompts user to add unknown host to known_hosts. Displays server information and key fingerprint for user verification.
Definition at line 550 of file known_hosts.c.
References ASCIICHAT_OK, BUFFER_SIZE_MEDIUM, compute_key_fingerprint(), CRYPTO_HEX_KEY_SIZE_NULL, ERROR_CRYPTO, format_ip_with_port(), get_known_hosts_path(), GET_OPTION, log_error, log_lock_terminal(), log_plain, log_unlock_terminal(), log_warn, platform_getenv(), platform_isatty(), platform_prompt_yes_no(), safe_snprintf(), SET_ERRNO, and STR_ONE.
Referenced by crypto_handshake_client_key_exchange().
#include <known_hosts.h>
Interactive prompt for unknown host without identity key - returns true if user wants to continue, false to abort.
| server_ip | Server IP address (IPv4 or IPv6, must not be NULL) |
| port | Server port number |
Prompts user to accept unknown host without identity key. Displays server information and warns that identity cannot be verified.
Definition at line 679 of file known_hosts.c.
References ASCIICHAT_OK, BUFFER_SIZE_MEDIUM, ERROR_CRYPTO, format_ip_with_port(), GET_OPTION, log_error, log_plain, log_warn, platform_isatty(), platform_prompt_yes_no(), safe_snprintf(), and SET_ERRNO.
Referenced by crypto_handshake_client_key_exchange().
| size_t read_trust_anchors_from_memory | ( | anchor_list * | dst, |
| const unsigned char * | pem_data, | ||
| size_t | pem_len | ||
| ) |
#include <pem_utils.h>
Read trust anchors from PEM-encoded data in memory.
| dst | Pointer to anchor_list to append trust anchors to (must not be NULL) |
| pem_data | Pointer to PEM-encoded certificate data (must not be NULL) |
| pem_len | Length of PEM data in bytes (must be > 0) |
Parses PEM-encoded CA certificates from a memory buffer and converts them to BearSSL trust anchors. The trust anchors are appended to the provided anchor_list.
Definition at line 440 of file pem_utils.c.
References ASCIICHAT_OK, free_ta_contents(), VEC_ADD, VEC_ADDMANY, VEC_CLEAR, VEC_CLEAREXT, VEC_ELT, and VEC_INIT.
Referenced by https_get().
| asciichat_error_t remove_known_host | ( | const char * | server_ip, |
| uint16_t | port | ||
| ) |
#include <known_hosts.h>
Remove server from known_hosts.
| server_ip | Server IP address (IPv4 or IPv6, must not be NULL) |
| port | Server port number |
Removes all entries for server IP:port from known_hosts file. Removes both identity key entries and no-identity entries.
<IP:port> x25519 ... and <IP:port> no-identity .... Uses proper bracket notation for IPv6 addresses.Definition at line 452 of file known_hosts.c.
References ASCIICHAT_OK, BUFFER_SIZE_MEDIUM, BUFFER_SIZE_XLARGE, defer, ERROR_CONFIG, ERROR_INVALID_PARAM, ERROR_MEMORY, FILE_PERM_PRIVATE, format_ip_with_port(), get_known_hosts_path(), log_debug, platform_close(), platform_fdopen(), PLATFORM_O_CREAT, PLATFORM_O_RDONLY, PLATFORM_O_TRUNC, PLATFORM_O_WRONLY, platform_open(), platform_strdup(), SAFE_FCLOSE, SAFE_FREE, SAFE_REALLOC, safe_snprintf(), SET_ERRNO, and SET_ERRNO_SYS.
| asciichat_error_t ssh_agent_add_key | ( | const private_key_t * | private_key, |
| const char * | key_path | ||
| ) |
#include <ssh_agent.h>
Add a private key to ssh-agent.
| private_key | Private key to add (must not be NULL) |
| key_path | Original key file path (for reference, can be NULL) |
Adds private key to SSH agent using the SSH agent protocol.
Message format: uint32: message length byte: SSH2_AGENTC_ADD_IDENTITY (17) string: key type ("ssh-ed25519") string: public key (32 bytes) string: private key (64 bytes) string: comment (key path or empty)
lib/platform/pipe.h abstraction:lib/platform/pipe.h for cross-platform communication:SSH_AUTH_SOCK environment variableSSH_AUTH_SOCK or default \\.\pipe\openssh-ssh-agentDefinition at line 185 of file ssh_agent.c.
References ASCIICHAT_OK, BUFFER_SIZE_SMALL, BUFFER_SIZE_XXLARGE, bytes_written, private_key_t::ed25519, ERROR_BUFFER_OVERFLOW, ERROR_CRYPTO, ERROR_INVALID_PARAM, INVALID_PIPE_VALUE, private_key_t::key, KEY_TYPE_ED25519, log_info, platform_pipe_close(), platform_pipe_read(), platform_pipe_write(), SET_ERRNO, SET_ERRNO_SYS, and private_key_t::type.
Referenced by parse_ssh_private_key().
| asciichat_error_t ssh_agent_get_key | ( | const public_key_t * | public_key, |
| private_key_t * | key_out | ||
| ) |
#include <ssh_agent.h>
Retrieve a private key from ssh-agent by matching public key.
| public_key | Public key to match (must not be NULL) |
| key_out | Output private key structure (must not be NULL) |
Retrieves private key from SSH agent by sending SSH2_AGENTC_SIGN_REQUEST. This doesn't actually retrieve the private key material - instead it proves the key exists in the agent by attempting a signature operation.
| bool ssh_agent_has_key | ( | const public_key_t * | public_key | ) |
#include <ssh_agent.h>
Check if a public key is already in ssh-agent.
| public_key | Public key to check (must not be NULL) |
Checks if public key is already in SSH agent by listing agent keys using SSH agent protocol.
lib/platform/pipe.h abstraction:lib/platform/pipe.h for cross-platform communication:SSH_AUTH_SOCK environment variableSSH_AUTH_SOCK or default \\.\pipe\openssh-ssh-agentDefinition at line 90 of file ssh_agent.c.
References BUFFER_SIZE_XXXLARGE, bytes_written, INVALID_PIPE_VALUE, public_key_t::key, log_debug, log_warn, platform_pipe_close(), platform_pipe_read(), and platform_pipe_write().
Referenced by parse_ssh_private_key().
| bool ssh_agent_is_available | ( | void | ) |
#include <ssh_agent.h>
Check if ssh-agent is running and available.
Checks if SSH agent is running and accessible by verifying SSH_AUTH_SOCK environment variable.
/tmp/ssh-XXXXXXXX/agent.XXXXXX)\\.\pipe\openssh-ssh-agent)Definition at line 52 of file ssh_agent.c.
References INVALID_PIPE_VALUE, log_debug, platform_pipe_close(), and SAFE_GETENV.
| asciichat_error_t ssh_agent_sign | ( | const public_key_t * | public_key, |
| const uint8_t * | message, | ||
| size_t | message_len, | ||
| uint8_t | signature[64] | ||
| ) |
#include <ssh_agent.h>
Sign data using SSH agent with the specified public key.
| public_key | Public key to use for signing (must not be NULL) |
| message | Data to sign (must not be NULL) |
| message_len | Length of data to sign |
| signature | Output buffer for signature (must be 64 bytes for Ed25519) |
Signs message data using SSH agent protocol SSH2_AGENTC_SIGN_REQUEST (message type 13).
Definition at line 295 of file ssh_agent.c.
References ASCIICHAT_OK, BUFFER_SIZE_XXLARGE, ERROR_CRYPTO, ERROR_CRYPTO_KEY, ERROR_INVALID_PARAM, INVALID_PIPE_VALUE, public_key_t::key, KEY_TYPE_ED25519, log_debug, platform_pipe_close(), platform_pipe_read(), platform_pipe_write(), SAFE_FREE, SAFE_MALLOC, SET_ERRNO, and public_key_t::type.
Referenced by ed25519_sign_message().
| br_x509_trust_anchor* anchor_list::buf |
Array of trust anchors (dynamically allocated)
Definition at line 79 of file pem_utils.h.
Referenced by https_get().
| size_t anchor_list::len |
Total capacity of array
Definition at line 81 of file pem_utils.h.
| size_t anchor_list::ptr |
Current number of trust anchors
Definition at line 80 of file pem_utils.h.
Referenced by https_get().