# Codive Tunnel - Secure Tunneling Protocol Library
A Rust library providing end-to-end encrypted tunneling protocol types, cryptographic primitives, and wire format encoding for secure Codive communication.
## Overview
This crate is the shared foundation for the Codive tunneling system:
- **codive-relay** uses it for protocol parsing and message routing
- **codive-cli** uses it for encryption/decryption and tunnel client logic
## Features
### Cryptography
- **XChaCha20-Poly1305**: AEAD encryption with 256-bit keys
- **Random Nonces**: 24-byte nonces generated per message (no reuse risk)
- **Secure Key Handling**: `Zeroize` trait implementation for memory safety
- **URL-Safe Key Encoding**: Base64url encoding for key sharing via URL fragments
### Protocol
- **Control Messages**: Hello, Welcome, Ping, Pong, Close, Error
- **Data Messages**: HttpRequest, HttpResponse, HttpResponseChunk, RequestError
- **Wire Format**: Efficient binary encoding with message type headers
- **Routing Headers**: Request ID routing for encrypted responses
## Usage
Add to your `Cargo.toml`:
```toml
[dependencies]
codive-tunnel = { path = "../codive-tunnel" }
```
### Key Generation and Encryption
```rust
use codive_tunnel::{TunnelKey, TunnelCrypto};
// Generate a new encryption key
let key = TunnelKey::generate();
// Share via URL fragment (never sent to server)
let url = format!("https://tunnel.example.com#E2EKey={}", key.to_base64());
// Create crypto instance
let crypto = TunnelCrypto::new(&key);
// Encrypt data
let plaintext = b"Hello, World!";
let ciphertext = crypto.encrypt(plaintext)?;
// Decrypt data
let decrypted = crypto.decrypt(&ciphertext)?;
assert_eq!(plaintext.as_slice(), decrypted.as_slice());
```
### Protocol Messages
```rust
use codive_tunnel::{ControlMessage, DataMessage, WireMessage, PROTOCOL_VERSION};
// Create a Hello message
let hello = ControlMessage::Hello {
version: PROTOCOL_VERSION,
requested_id: Some("my-tunnel".to_string()),
auth_token: Some("secret".to_string()),
};
// Encode for transmission
let encoded = WireMessage::encode_control(&hello)?;
// Decode received message
let decoded = WireMessage::decode_control(&encoded)?;
```
### HTTP Request/Response
```rust
use codive_tunnel::DataMessage;
use std::collections::HashMap;
// Create an HTTP request
let request = DataMessage::HttpRequest {
request_id: "req-123".to_string(),
method: "GET".to_string(),
path: "/api/status".to_string(),
headers: HashMap::new(),
body: None,
};
// Serialize to JSON
let json = serde_json::to_vec(&request)?;
// Create a response
let response = DataMessage::HttpResponse {
request_id: "req-123".to_string(),
status: 200,
headers: [("Content-Type".to_string(), "application/json".to_string())]
.into_iter().collect(),
body: Some(base64::encode(b"{\"status\":\"ok\"}")),
streaming: false,
};
```
### Wire Message Format
```rust
use codive_tunnel::{WireMessage, message_type};
// Encode encrypted data with routing header
let wire_msg = WireMessage::encode_encrypted_with_routing(
message_type::ENCRYPTED_RESPONSE,
"request-id-123",
encrypted_payload,
);
// Decode with routing header
let (msg_type, request_id, payload) =
WireMessage::decode_encrypted_with_routing(&wire_msg)?;
```
## API Reference
### Types
| `TunnelKey` | 256-bit encryption key with Zeroize |
| `TunnelCrypto` | XChaCha20-Poly1305 encrypt/decrypt |
| `ControlMessage` | Protocol control messages (Hello, Welcome, etc.) |
| `DataMessage` | Data messages (HttpRequest, HttpResponse, etc.) |
| `WireMessage` | Binary wire format encoding/decoding |
### Control Messages
| `Hello` | Agent → Relay | Initial handshake with auth |
| `Welcome` | Relay → Agent | Tunnel ID and URL assignment |
| `Ping` | Both | Keep-alive request |
| `Pong` | Both | Keep-alive response |
| `Close` | Both | Graceful disconnect |
| `Error` | Relay → Agent | Error notification |
| `ClientConnected` | Relay → Agent | Client connected to tunnel |
| `ClientDisconnected` | Relay → Agent | Client disconnected |
### Data Messages
| `HttpRequest` | Relay → Agent | Incoming HTTP request |
| `HttpResponse` | Agent → Relay | HTTP response |
| `HttpResponseChunk` | Agent → Relay | Streaming response chunk |
| `RequestError` | Agent → Relay | Request processing error |
### Message Type Constants
```rust
pub mod message_type {
pub const CONTROL: u8 = 0x00;
pub const ENCRYPTED_REQUEST: u8 = 0x01;
pub const ENCRYPTED_RESPONSE: u8 = 0x02;
pub const ENCRYPTED_CHUNK: u8 = 0x03;
}
```
## Wire Protocol
### Binary Format
```
Control Messages:
┌─────────┬─────────────────────┐
│ 0x00 │ JSON payload │
└─────────┴─────────────────────┘
Encrypted Messages:
┌─────────┬─────────────────────┐
│ type │ encrypted payload │
└─────────┴─────────────────────┘
Encrypted with Routing Header:
┌─────────┬─────────┬───────────────┬─────────────────────┐
│ type │ id_len │ request_id │ encrypted payload │
└─────────┴─────────┴───────────────┴─────────────────────┘
```
### Encryption Format
```
Ciphertext:
┌─────────────────────┬─────────────────────┬─────────────────────┐
│ nonce (24 bytes) │ ciphertext │ auth tag (16 bytes) │
└─────────────────────┴─────────────────────┴─────────────────────┘
```
## Security Considerations
### Key Exchange
- Keys are shared via URL fragment (`#E2EKey=...`)
- Fragments are never sent to the server in HTTP requests
- Keys should be rotated periodically for long-lived tunnels
### Memory Safety
- `TunnelKey` implements `Zeroize` and `ZeroizeOnDrop`
- Key material is cleared from memory when dropped
- No key logging in debug output (`Debug` shows `[REDACTED]`)
### Nonce Safety
- 24-byte random nonces (XChaCha20)
- Extremely low collision probability (2^-96)
- No nonce counter needed
## Testing
```bash
# Run all tests
cargo test -p codive-tunnel
# Run with output
cargo test -p codive-tunnel -- --nocapture
# Run specific test
cargo test -p codive-tunnel test_encrypt_decrypt
```
Test coverage: **62 tests**
- Crypto tests: Key generation, encryption, decryption, tampering detection
- Protocol tests: Message serialization, wire encoding
- Integration tests: Full E2E flows, streaming, error handling
## Dependencies
- `chacha20poly1305` - AEAD encryption
- `zeroize` - Secure memory clearing
- `rand` - Cryptographic RNG
- `base64` - URL-safe encoding
- `serde` / `serde_json` - Serialization
## Contributing
See the [codive-relay README](../codive-relay/README.md) for contribution guidelines.
### Adding New Message Types
1. Add variant to `ControlMessage` or `DataMessage` in `protocol.rs`
2. Update `serde` attributes if needed
3. Add tests for serialization roundtrip
4. Update wire format handling if binary encoding changes
## License
MIT License - see LICENSE file for details.