7 releases
Uses new Rust 2024
| 0.2.1 | Oct 11, 2025 |
|---|---|
| 0.1.5 | Oct 7, 2025 |
#422 in Cryptography
Used in 3 crates
(2 directly)
120KB
2.5K
SLoC
hightower-wireguard
A Rust implementation of the WireGuard cryptographic handshake protocol (Noise_IK).
What is this?
This crate implements the core cryptographic handshake protocol used by WireGuard. It provides the building blocks for establishing secure sessions between peers using the Noise_IK pattern with pre-shared key support.
What's Implemented
- Noise_IK Handshake Protocol: Full implementation of the WireGuard handshake
- Handshake initiation (Message Type 1)
- Handshake response (Message Type 2)
- Session key derivation using HKDF
- Pre-shared key (PSK) support for post-quantum security
- Cryptographic Primitives:
- X25519 Diffie-Hellman key exchange
- ChaCha20-Poly1305 AEAD encryption
- BLAKE2s hashing
- HKDF key derivation
- Protocol State Management:
- Initiator state machine
- Responder state machine
- Session key management
- Peer configuration
- Replay protection (anti-replay window)
- Automatic session rekeying (REKEY_AFTER_TIME)
- Keep-alive packet support
- Endpoint roaming for mobile devices
What's NOT Implemented
This is not a complete VPN implementation. The following components are not included:
- TUN/TAP Interface: No virtual network interface creation or management
- Routing: No IP routing, forwarding, or allowed-IPs enforcement
- Cookie Mechanism: No DoS protection via cookies (Message Type 3)
This library is suitable for:
- Learning WireGuard's cryptographic protocol
- Building custom WireGuard-based protocols
- Testing and experimentation
- Integration into larger VPN implementations
Installation
Add to your Cargo.toml:
[dependencies]
# For handshake protocol only
hightower-wireguard = "0.2.1"
# For transport layer (UDP Connection and Stream)
hightower-wireguard = { version = "0.2.1", features = ["transport"] }
Usage
use hightower_wireguard::protocol::{WireGuardProtocol, PeerInfo};
use hightower_wireguard::crypto::dh_generate;
// Generate keys for both peers
let (alice_private, alice_public) = dh_generate();
let (bob_private, bob_public) = dh_generate();
// Create protocol instances
let mut alice = WireGuardProtocol::new(Some(alice_private));
let mut bob = WireGuardProtocol::new(Some(bob_private));
// Configure peers
alice.add_peer(PeerInfo {
public_key: bob_public,
preshared_key: None,
endpoint: None,
allowed_ips: Vec::new(),
persistent_keepalive: None,
});
bob.add_peer(PeerInfo {
public_key: alice_public,
preshared_key: None,
endpoint: None,
allowed_ips: Vec::new(),
persistent_keepalive: None,
});
// Perform handshake
let initiation = alice.initiate_handshake(&bob_public)?;
let response = bob.process_initiation(&initiation)?;
let peer_key = alice.process_response(&response)?;
// Now both sides have active sessions with transport keys
let alice_session = alice.get_session(response.sender).unwrap();
let bob_session = bob.get_session(response.sender).unwrap();
// Use session keys for encryption/decryption
// alice_session.keys.send_key and alice_session.keys.recv_key
Pre-Shared Key Support
let psk = [42u8; 32]; // Your pre-shared key
alice.add_peer(PeerInfo {
public_key: bob_public,
preshared_key: Some(psk),
// ... other fields
});
bob.add_peer(PeerInfo {
public_key: alice_public,
preshared_key: Some(psk),
// ... other fields
});
// Handshake will now use PSK for additional security
Message Serialization
Messages can be serialized to and from wire format for network transmission:
use hightower_wireguard::messages::HandshakeInitiation;
// After creating a handshake initiation message
let initiation = alice.initiate_handshake(&bob_public)?;
// Serialize to wire format (148 bytes)
let bytes = initiation.to_bytes()?;
// Send over network...
// let socket.send_to(&bytes, peer_addr)?;
// On the receiving side, deserialize from bytes
let received = HandshakeInitiation::from_bytes(&bytes)?;
let response = bob.process_initiation(&received)?;
// Serialize the response (92 bytes)
let response_bytes = response.to_bytes()?;
The following message types support serialization:
HandshakeInitiation: 148 bytesHandshakeResponse: 92 bytesTransportData: 16 bytes + variable packet length
Transport Layer
With the transport feature enabled, you can use the high-level UDP-based transport layer:
use hightower_wireguard::crypto::dh_generate;
use hightower_wireguard::connection::Connection;
#[tokio::main]
async fn main() {
// Generate keys
let (alice_private, alice_public) = dh_generate();
let (bob_private, bob_public) = dh_generate();
// Create connections
let alice = Connection::new("127.0.0.1:0".parse().unwrap(), alice_private)
.await
.unwrap();
let bob = Connection::new("127.0.0.1:0".parse().unwrap(), bob_private)
.await
.unwrap();
let alice_addr = alice.local_addr();
let bob_addr = bob.local_addr();
// Add peers
alice.add_peer(bob_public, Some(bob_addr)).await.unwrap();
bob.add_peer(alice_public, Some(alice_addr)).await.unwrap();
// Bob listens for incoming connections
let mut bob_incoming = bob.listen().await.unwrap();
// Alice connects to Bob
let mut alice_stream = alice.connect(bob_addr, bob_public).await.unwrap();
// Bob accepts the connection
let mut bob_stream = bob_incoming.recv().await.unwrap();
// Send and receive data
alice_stream.send(b"Hello from Alice!").await.unwrap();
let received = bob_stream.recv().await.unwrap();
println!("Bob received: {}", String::from_utf8_lossy(&received));
}
Keep-Alive Configuration
Configure persistent keep-alive to maintain NAT mappings and detect dead peers:
// Add peer with keep-alive packets sent every 25 seconds
alice.add_peer_with_keepalive(
bob_public,
Some(bob_addr),
Some(25) // send keep-alive every 25 seconds
).await.unwrap();
The transport layer provides:
- Connection: UDP socket management, packet routing, and session management
- Stream: Bidirectional encrypted communication channel to a peer
- Automatic handshake handling
- Message encryption/decryption using session keys
- Automatic keep-alive packets (configurable per-peer)
- Automatic session rekeying after 120 seconds (initiator only)
- Endpoint roaming support for mobile devices
- Session cleanup and timeout handling
Testing
Run the test suite:
# Test handshake protocol only
cargo test
# Test with transport layer
cargo test --features transport
References
Dependencies
~3–16MB
~161K SLoC