ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
Crypto Module

Crypto Module - lib/crypto/

End-to-end encrypted communication for ascii-chat using modern cryptography (X25519, XSalsa20-Poly1305, Ed25519).

Quick Overview

Core Crypto (libsodium)
├── X25519 key exchange (Diffie-Hellman)
├── XSalsa20-Poly1305 encryption/decryption
├── HMAC-SHA256 authentication
└── Argon2id password-based KDF
Key Management
├── SSH keys + SSH agent support
├── GPG keys + GPG agent support
├── GitHub/GitLab key fetching
└── Known hosts verification (TOFU)
Handshake Protocol
├── Client-side state machine (handshake/client.c)
├── Server-side state machine (handshake/server.c)
└── Shared utilities (handshake/common.c)

File Organization

Core Cryptography

SSH Integration

GPG Integration

HTTPS & Discovery

Handshake Protocol

Key Management

Usage Examples

Basic Key Exchange

// Step 1: Send our ephemeral public key
uint8_t our_pubkey[32];
crypto_get_public_key(&ctx, our_pubkey);
// Step 2: Receive peer's ephemeral public key and compute shared secret
uint8_t peer_pubkey[32]; // Received from peer
crypto_set_peer_public_key(&ctx, peer_pubkey);
// Step 3: Check if ready for encryption
if (crypto_is_ready(&ctx)) {
printf("Key exchange complete, ready for encryption\n");
}
// Encrypt data
uint8_t plaintext[] = "Hello, World!";
uint8_t ciphertext[1024];
size_t ciphertext_len;
crypto_encrypt(&ctx, plaintext, strlen((char*)plaintext),
ciphertext, sizeof(ciphertext), &ciphertext_len);
// Decrypt data
uint8_t decrypted[1024];
size_t decrypted_len;
crypto_decrypt(&ctx, ciphertext, ciphertext_len,
decrypted, sizeof(decrypted), &decrypted_len);
unsigned char uint8_t
Definition common.h:60
crypto_result_t crypto_set_peer_public_key(crypto_context_t *ctx, const uint8_t *peer_public_key)
Set peer's public key and compute shared secret (step 2 of handshake).
crypto_result_t crypto_encrypt(crypto_context_t *ctx, const uint8_t *plaintext, size_t plaintext_len, uint8_t *ciphertext_out, size_t ciphertext_out_size, size_t *ciphertext_len_out)
Encrypt data using XSalsa20-Poly1305.
crypto_result_t crypto_init(crypto_context_t *ctx)
Initialize libsodium and crypto context.
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).
bool crypto_is_ready(const crypto_context_t *ctx)
Check if key exchange is complete and ready for encryption.
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.
void crypto_destroy(crypto_context_t *ctx)
Cleanup crypto context with secure memory wiping.
Endpoint cryptographic state for handshake, packet protection, authentication, and rekeying.

SSH Key Authentication

// Load SSH key
uint8_t key_data[4096];
size_t key_len = read_file("~/.ssh/id_ed25519", key_data, sizeof(key_data));
ssh_keys_t key;
ssh_keys_parse(key_data, key_len, &key);
// Check if SSH agent is available
// Use agent for signing (no passphrase prompt)
uint8_t signature[64];
ssh_agent_sign(&key, data_to_sign, sizeof(data_to_sign), signature);
}
bool ssh_agent_is_available(void)
Check if ssh-agent is running and available.
Definition ssh_agent.c:42
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.
Definition ssh_agent.c:260

GPG Key Authentication

// Export public key from GPG keyring
uint8_t pubkey[32];
gpg_export_public_key("zfogg", pubkey);
// Sign with GPG agent (no passphrase prompt if agent is running)
uint8_t signature[64];
gpg_agent_sign("zfogg", data_to_sign, sizeof(data_to_sign), signature);
GPG operations - main header.
int gpg_agent_sign(int handle_as_int, 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.
Definition agent.c:161

Known Hosts Verification

// Verify server identity key
uint8_t server_key[32]; // Received from server during handshake
if (!known_hosts_verify("localhost:27224", server_key)) {
if (known_hosts_key_changed("localhost:27224", server_key)) {
printf("ERROR: Server key has changed! Possible MITM attack!\n");
return -1;
}
// New server: Ask user to trust
if (user_confirms_server_key("localhost:27224", server_key)) {
known_hosts_add("localhost:27224", server_key);
}
}
Known hosts management for MITM attack prevention.

GitHub Key Fetching

// Fetch SSH public keys from GitHub
uint8_t github_keys[8192];
size_t keys_len;
https_keys_fetch_github("zfogg", github_keys, sizeof(github_keys), &keys_len);
// Verify server identity against GitHub key
uint8_t server_identity_key[32]; // From handshake
if (verify_key_in_buffer(server_identity_key, github_keys, keys_len)) {
printf("Server identity verified via GitHub!\n");
}

Key Concepts

X25519 Key Exchange

  • Ephemeral: New key pair for each connection
  • Perfect Forward Secrecy: Old connections safe even if long-term key compromised
  • 32-byte keys: Compact, secure
  • libsodium: Hardware-optimized, constant-time

XSalsa20-Poly1305 Encryption

  • Authenticated encryption: Detects tampering
  • Nonce-based: Different nonce per packet avoids reuse; replay detection requires additional receive state
  • MAC verification: Automatic, returns error on mismatch
  • Speed: ~20μs per KB on modern CPUs

HMAC-SHA256 Authentication

  • Challenge-response: Server sends random nonce
  • Password binding: HMAC includes shared secret (MITM protection)
  • Constant-time verification: No timing attacks

Argon2id Password KDF

  • Memory-hard: Resists GPU/ASIC brute-force
  • Interactive limits: ~0.1s, ~64MB memory
  • Deterministic salt: Same password produces same key

Session Rekeying

  • Automatic: After 1 hour or 1M packets (whichever first)
  • DH re-exchange: New ephemeral keys generated
  • Seamless: No interruption to connection
  • Test mode: 30 seconds / 1000 packets for fast testing

Configuration

Environment Variables

  • SSH_AUTH_SOCK - SSH agent socket (Unix domain socket or named pipe)
  • GNUPGHOME - GPG home directory (default: ~/.gnupg)
  • CRITERION_TEST / TESTING - Enable test mode (reduced rekeying thresholds)

Configuration Files

  • ~/.ascii-chat/authorized_clients.txt - Server whitelist (one key per line)
  • ~/.ascii-chat/known_hosts - SSH-style known hosts (hostname:port ssh-ed25519 <key>)
  • ~/.ascii-chat/acds_keys/ - Cached ACDS server keys

Dependencies

  • libsodium - Modern cryptography (X25519, XSalsa20-Poly1305, Argon2id, Ed25519)
  • BearSSL - TLS for HTTPS key fetching (OpenSSL compatibility)
  • OpenSSL (optional) - For gpg-agent communication

Building

# Configure and build
cmake --preset default -B build
cmake --build build
# Build just the crypto library
cmake --build build --target ascii-chat-lib-crypto
# Run crypto tests
ctest --test-dir build -R crypto

Performance

Operation Time Notes
crypto_init() ~100μs libsodium init + key gen
Key exchange ~500μs X25519 computation
Encrypt 1KB ~20μs XSalsa20
Decrypt 1KB ~20μs XSalsa20 + Poly1305 verify
SSH agent sign ~1ms IPC + SSH protocol
GPG agent sign ~50ms IPC + GPG protocol
HTTPS key fetch ~200ms Network + TLS

Testing

# Unit tests
ctest --test-dir build -R crypto
# Handshake tests
ctest --test-dir build -R handshake
# SSH key tests
ctest --test-dir build -R ssh
# All crypto-related tests
ctest --test-dir build -R crypto

Security Properties

✅ Encryption:

  • XSalsa20-Poly1305 (AEAD)
  • Unique nonces per packet (session_id || counter)
  • Automatic MAC verification
  • Constant-time comparison

✅ Key Exchange:

  • X25519 ephemeral keys
  • Forward secrecy
  • Optional authentication via SSH/GPG

✅ Authentication:

  • HMAC-SHA256 challenge-response
  • Ed25519 signatures
  • SSH agent integration (keys never in memory)
  • GPG agent integration (keys never in memory)

⚠️ Known Limitations:

  • TOFU (Trust On First Use) for known_hosts - first connection vulnerable to MITM
  • No post-quantum cryptography (planned for future)
  • No Certificate Authority (planned: verification server)

Debugging

Enable Verbose Logging

./build/bin/ascii-chat --log-level debug server --grep "/crypto|handshake/i"

Inspect Known Hosts

cat ~/.ascii-chat/known_hosts

Check SSH Agent

ssh-add -L # List available keys

Check GPG Agent

gpg --list-keys
echo "test" | gpg -s # Test agent availability

Further Reading

Contributing

When modifying crypto code:

  1. Always use sodium_memcmp() for comparing sensitive data (keys, MACs)
  2. Use SAFE_MALLOC/FREE for all memory allocation
  3. Add comprehensive comments - cryptography is complex
  4. Test timing - ensure no timing variations in comparisons
  5. Update Doxygen docs - keep inline documentation current

License

Same as ascii-chat project.