use thiserror::Error;
pub mod crypto;
pub mod initiator;
pub mod messages;
pub mod protocol;
pub mod replay;
pub mod responder;
#[cfg(feature = "transport")]
pub mod connection;
#[derive(Error, Debug)]
pub enum WireGuardError {
#[error("Cryptographic error: {0}")]
CryptoError(String),
#[error("Protocol error: {0}")]
ProtocolError(String),
#[error("Invalid key length")]
InvalidKeyLength,
#[error("Authentication failed")]
AuthenticationFailed,
}
pub type Result<T> = std::result::Result<T, WireGuardError>;
#[cfg(test)]
mod tests {
use super::*;
use crypto::{aead_decrypt, aead_encrypt, dh_generate};
use protocol::{PeerInfo, WireGuardProtocol};
#[test]
fn test_full_handshake_and_message_exchange() {
let (alice_private, alice_public) = dh_generate();
let (bob_private, bob_public) = dh_generate();
let mut alice = WireGuardProtocol::new(Some(alice_private));
let mut bob = WireGuardProtocol::new(Some(bob_private));
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,
});
let initiation = alice.initiate_handshake(&bob_public).unwrap();
println!(
"Alice created initiation with sender ID: {}",
initiation.sender
);
let response = bob.process_initiation(&initiation).unwrap();
println!("Bob created response with sender ID: {}", response.sender);
let peer_key = alice.process_response(&response).unwrap();
assert_eq!(peer_key, bob_public);
let alice_session = alice.get_session(response.sender).unwrap();
let bob_session = bob.get_session(response.sender).unwrap();
println!("Handshake complete!");
println!(
"Alice session keys: send={:?}, recv={:?}",
&alice_session.keys.send_key[..8],
&alice_session.keys.recv_key[..8]
);
println!(
"Bob session keys: send={:?}, recv={:?}",
&bob_session.keys.send_key[..8],
&bob_session.keys.recv_key[..8]
);
let message = b"Hello from Alice to Bob!";
let counter = 0u64;
let encrypted = aead_encrypt(&alice_session.keys.send_key, counter, message, &[]).unwrap();
println!("Alice encrypted message: {} bytes", encrypted.len());
let decrypted = aead_decrypt(&bob_session.keys.recv_key, counter, &encrypted, &[]).unwrap();
assert_eq!(decrypted, message);
println!("Bob decrypted: {:?}", String::from_utf8_lossy(&decrypted));
let reply = b"Hello back from Bob to Alice!";
let reply_counter = 0u64;
let encrypted_reply =
aead_encrypt(&bob_session.keys.send_key, reply_counter, reply, &[]).unwrap();
let decrypted_reply = aead_decrypt(
&alice_session.keys.recv_key,
reply_counter,
&encrypted_reply,
&[],
)
.unwrap();
assert_eq!(decrypted_reply, reply);
println!(
"Alice decrypted reply: {:?}",
String::from_utf8_lossy(&decrypted_reply)
);
println!("Bidirectional message exchange successful!");
}
#[test]
fn test_handshake_with_preshared_key() {
let psk = [42u8; 32];
let (alice_private, alice_public) = dh_generate();
let (bob_private, bob_public) = dh_generate();
let mut alice = WireGuardProtocol::new(Some(alice_private));
let mut bob = WireGuardProtocol::new(Some(bob_private));
alice.add_peer(PeerInfo {
public_key: bob_public,
preshared_key: Some(psk),
endpoint: None,
allowed_ips: Vec::new(),
persistent_keepalive: None,
});
bob.add_peer(PeerInfo {
public_key: alice_public,
preshared_key: Some(psk),
endpoint: None,
allowed_ips: Vec::new(),
persistent_keepalive: None,
});
let initiation = alice.initiate_handshake(&bob_public).unwrap();
let response = bob.process_initiation(&initiation).unwrap();
let _peer_key = alice.process_response(&response).unwrap();
assert!(alice.get_session(response.sender).is_some());
assert!(bob.get_session(response.sender).is_some());
println!("PSK handshake successful!");
}
#[test]
fn test_replay_protection() {
let (alice_private, alice_public) = dh_generate();
let (bob_private, bob_public) = dh_generate();
let mut alice = WireGuardProtocol::new(Some(alice_private));
let mut bob = WireGuardProtocol::new(Some(bob_private));
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,
});
let initiation = alice.initiate_handshake(&bob_public).unwrap();
let response = bob.process_initiation(&initiation).unwrap();
alice.process_response(&response).unwrap();
let session_id = response.sender;
assert!(bob.check_replay(session_id, 1).is_ok());
assert!(bob.check_replay(session_id, 2).is_ok());
assert!(bob.check_replay(session_id, 3).is_ok());
assert!(bob.check_replay(session_id, 2).is_err()); assert!(bob.check_replay(session_id, 1).is_err());
assert!(bob.check_replay(session_id, 10).is_ok());
assert!(bob.check_replay(session_id, 5).is_ok());
assert!(bob.check_replay(session_id, 8).is_ok());
assert!(bob.check_replay(session_id, 5).is_err());
assert!(bob.check_replay(session_id, 8).is_err());
assert!(bob.check_replay(session_id, 3000).is_ok());
assert!(bob.check_replay(session_id, 500).is_err());
println!("Replay protection test successful!");
}
}