From 4a87313da5f173eb56b3f7be234b2b42c8d51f2f Mon Sep 17 00:00:00 2001 From: c0repwn3r Date: Tue, 13 Dec 2022 11:44:45 -0500 Subject: [PATCH] [codestyle] turn on every lint, document everything --- quicktap/src/drivers/linux.rs | 11 ++++++++--- quicktap/src/drivers/mod.rs | 4 ++++ quicktap/src/drivers/tungeneric.rs | 23 +++++++++++++++++++++++ quicktap/src/lib.rs | 12 +++++++++++- quicktap/src/qcrypto/aead.rs | 23 +++++++++++++++++++++++ quicktap/src/qcrypto/hashes.rs | 13 +++++++++++++ quicktap/src/qcrypto/hkdf.rs | 11 +++++++---- quicktap/src/qcrypto/mod.rs | 7 +++++++ quicktap/src/qcrypto/pki.rs | 4 ++++ quicktap/src/qcrypto/tests.rs | 6 +++--- 10 files changed, 103 insertions(+), 11 deletions(-) diff --git a/quicktap/src/drivers/linux.rs b/quicktap/src/drivers/linux.rs index dd7971e..2d25bbf 100644 --- a/quicktap/src/drivers/linux.rs +++ b/quicktap/src/drivers/linux.rs @@ -1,3 +1,5 @@ +//! A Linux implementation of the traits from `drivers::tungeneric` + use std::error::Error; use std::io; use std::io::{Read, Write}; @@ -5,14 +7,19 @@ use etherparse::IpHeader; use tun::platform::Device; use crate::drivers::tungeneric::{GenericDriver, GenericInterface, TunPacket}; +#[allow(clippy::module_name_repetitions)] +/// Represents the internal state of a tun driver. pub struct TunDevice { + /// Contains the device handle of the tun device device: Device, + /// A packet read buffer read_buf: [u8; 4096], + /// Currently unused, for storing the offset into the read buffer to write to read_offset: usize, + /// Another packet read buffer packet_buf: [u8; 4096], } impl GenericDriver for TunDevice { - /// Create a new TunDevice with the provided generic interface configuration fn new(config: &GenericInterface) -> Result> { let mut device_config = tun::Configuration::default(); @@ -32,8 +39,6 @@ impl GenericDriver for TunDevice { }) } - /// Attempt to read a packet from the interface. If no packet is found, append it to an internal buffer and return WouldBlock. - /// Upon finding a successful packet inside the internal buffer, or the .clear() method being called, the internal buffer will be cleared. fn read(&mut self) -> Result> { self.packet_buf = [0u8; 4096]; let _ = self.device.read(&mut self.packet_buf)?; diff --git a/quicktap/src/drivers/mod.rs b/quicktap/src/drivers/mod.rs index f12a700..2b3d588 100644 --- a/quicktap/src/drivers/mod.rs +++ b/quicktap/src/drivers/mod.rs @@ -1,5 +1,9 @@ +//! Cross-platform tun/tap drivers for various platforms. + #[cfg(unix)] #[path = "linux.rs"] pub mod tun; // Tun/tap drivers for Linux +#[cfg(unix)] +pub mod linux; pub mod tungeneric; \ No newline at end of file diff --git a/quicktap/src/drivers/tungeneric.rs b/quicktap/src/drivers/tungeneric.rs index c9c666f..a4fedef 100644 --- a/quicktap/src/drivers/tungeneric.rs +++ b/quicktap/src/drivers/tungeneric.rs @@ -1,23 +1,46 @@ +//! Generic traits and modules to represent a tun/tap device + use std::error::Error; use cidr::IpInet; use etherparse::{IpHeader}; #[derive(Debug)] +/// A parsed packet from an interface pub struct TunPacket { + /// The parsed IPv4 or IPv6 header pub header: IpHeader, + /// The raw packet data pub packet: [u8; 4096] } +/// A trait to implement R/W on a tun driver pub trait GenericDriver { + /// Create a new device with the provided generic interface configuration + /// # Errors + /// This function may error if there is an error creating the device. fn new(config: &GenericInterface) -> Result> where Self: Sized; + /// Attempt to read a packet from the interface. If no packet is found, append it to an internal buffer and return `WouldBlock`. + /// Upon finding a successful packet inside the internal buffer, or the .clear() method being called, the internal buffer will be cleared. + /// # Errors + /// This function will return `WouldBlock` if a packet could not be read. This function may error if there is an error reading the interface. fn read(&mut self) -> Result>; + + /// Clear any internal state of this interface. fn clear(&mut self); + + /// Attempt to write a packet to the interface. + /// # Errors + /// This function will error if an error occured writing to the device. fn write(&mut self, packet: TunPacket) -> Result<(), Box>; } +/// Generic interface config pub struct GenericInterface { + /// The ipv4/ipv6 addresses to be assigned to the interface pub addresses: Vec, + /// The mtu to be assigned to the interface pub mtu: Option, + /// The name of the virtual interface pub name: String } \ No newline at end of file diff --git a/quicktap/src/lib.rs b/quicktap/src/lib.rs index b2bae85..b91e455 100644 --- a/quicktap/src/lib.rs +++ b/quicktap/src/lib.rs @@ -1,3 +1,13 @@ +//! A simple, almost pure-rust, cross-platform `WireGuard` implementation. + +#![warn(clippy::pedantic)] +#![warn(clippy::nursery)] +#![deny(missing_docs)] + +// This is an annoyance +#![allow(clippy::must_use_candidate)] + pub mod drivers; // Baremetal network drivers for various platforms -pub use cidr; pub mod qcrypto; + +pub use cidr; \ No newline at end of file diff --git a/quicktap/src/qcrypto/aead.rs b/quicktap/src/qcrypto/aead.rs index 5077517..990840b 100644 --- a/quicktap/src/qcrypto/aead.rs +++ b/quicktap/src/qcrypto/aead.rs @@ -1,6 +1,14 @@ +//! Various functions for ChaCha20Poly1305 stream ciphers + use chacha20poly1305::{ChaCha20Poly1305, Error, KeyInit, XChaCha20Poly1305}; use chacha20poly1305::aead::{Aead, Payload, Nonce}; +/// Encrypt the plaintext with the given parameters using ChaCha20Poly1305 +/// # Errors +/// This function will error if the encryption was unsuccessful +/// # Panics +/// This function, while having an .unwrap() call, will never panic because the key is a fixed, correctly sized array. +#[allow(clippy::module_name_repetitions)] pub fn qcrypto_aead(key: &[u8; 32], counter: u64, plaintext: &[u8], authtext: &[u8]) -> Result, Error> { let cipher = ChaCha20Poly1305::new_from_slice(key).unwrap(); let mut nonce_bytes = [0u8; 12]; @@ -11,6 +19,11 @@ pub fn qcrypto_aead(key: &[u8; 32], counter: u64, plaintext: &[u8], authtext: &[ cipher.encrypt(&Nonce::::from(nonce_bytes), payload) } +/// Decrypt the ciphertext with the given parameters using ChaCha20Poly1305 +/// # Errors +/// This function will error if the decryption was unsuccessful +/// # Panics +/// This function, while having an .unwrap() call, will never panic because the key is a fixed, correctly sized array. pub fn qcrypto_aead_decrypt(key: &[u8; 32], counter: u64, ciphertext: &[u8], authtext: &[u8]) -> Result, Error> { let cipher = ChaCha20Poly1305::new_from_slice(key).unwrap(); let mut nonce_bytes = [0u8; 12]; @@ -21,6 +34,11 @@ pub fn qcrypto_aead_decrypt(key: &[u8; 32], counter: u64, ciphertext: &[u8], aut cipher.decrypt(&Nonce::::from(nonce_bytes), payload) } +/// Encrypt the ciphertext with the given parameters using XChaCha20Poly1305 +/// # Errors +/// This function will error if the decryption was unsuccessful +/// # Panics +/// This function, while having an .unwrap() call, will never panic because the key is a fixed, correctly sized array. pub fn qcrypto_xaead(key: &[u8; 32], nonce: &[u8; 24], plaintext: &[u8], authtext: &[u8]) -> Result, Error> { let cipher = XChaCha20Poly1305::new_from_slice(key).unwrap(); let mut payload = Payload::from(plaintext); @@ -29,6 +47,11 @@ pub fn qcrypto_xaead(key: &[u8; 32], nonce: &[u8; 24], plaintext: &[u8], authtex cipher.encrypt(Nonce::::from_slice(nonce), payload) } +/// Decrypt the ciphertext with the given parameters using XChaCha20Poly1305 +/// # Errors +/// This function will error if the decryption was unsuccessful +/// # Panics +/// This function, while having an .unwrap() call, will never panic because the key is a fixed, correctly sized array. pub fn qcrypto_xaead_decrypt(key: &[u8; 32], nonce: &[u8; 24], ciphertext: &[u8], authtext: &[u8]) -> Result, Error> { let cipher = XChaCha20Poly1305::new_from_slice(key).unwrap(); let mut payload = Payload::from(ciphertext); diff --git a/quicktap/src/qcrypto/hashes.rs b/quicktap/src/qcrypto/hashes.rs index 1e2338b..f37d6f4 100644 --- a/quicktap/src/qcrypto/hashes.rs +++ b/quicktap/src/qcrypto/hashes.rs @@ -1,27 +1,40 @@ +//! Various hash functions + use blake2::{Blake2s256, Blake2sMac, Digest}; use blake2::digest::{KeyInit, FixedOutput, Update}; use hmac::SimpleHmac; type HmacBlake2s = SimpleHmac; +/// Given a varied length input, produce a 32-byte Blake2s hash digest pub fn qcrypto_hash(input: &[u8]) -> [u8; 32] { let mut hasher = Blake2s256::new(); Update::update(&mut hasher, input); hasher.finalize().into() } +/// Given a varied length MAC key and a varied length input, produce a 16-byte MAC digest using Blake2s +/// # Panics +/// This function will panic if the key is an incorrect size. pub fn qcrypto_mac(key: &[u8], input: &[u8]) -> [u8; 16] { let mut hasher = Blake2sMac::new_from_slice(key).unwrap(); hasher.update(input); hasher.finalize_fixed().into() } +/// Given a varied length HMAC key and a varied length input, produce a 32-byte HMAC digest using Blake2s +/// # Panics +/// This function will panic if the key is an incorrect size. pub fn qcrypto_hmac(key: &[u8], input: &[u8]) -> [u8; 32] { let mut hasher = HmacBlake2s::new_from_slice(key).unwrap(); Update::update(&mut hasher, input); hasher.finalize_fixed().into() } +/// Given a varied length HMAC key and two varied length inputs, produce a 32-byte HMAC digest using Blake2s. +/// This does essentially the same thing as concatenating input2 to input and calling `qcrypto_hmac` on that. +/// # Panics +/// This function will panic if the key is an incorrect size. pub fn qcrypto_hmac_twice(key: &[u8], input: &[u8], input2: &[u8]) -> [u8; 32] { let mut hasher = HmacBlake2s::new_from_slice(key).unwrap(); Update::update(&mut hasher, input); diff --git a/quicktap/src/qcrypto/hkdf.rs b/quicktap/src/qcrypto/hkdf.rs index 83f7681..0d49f65 100644 --- a/quicktap/src/qcrypto/hkdf.rs +++ b/quicktap/src/qcrypto/hkdf.rs @@ -1,7 +1,10 @@ -use std::error::Error; +//! An implementation of the HKDF algorithm + use crate::qcrypto::hashes::{qcrypto_hmac, qcrypto_hmac_twice}; -pub fn qcrypto_hkdf(key: &[u8], input: &[u8]) -> Result<[[u8; 32]; N], Box> { +#[allow(clippy::module_name_repetitions)] +/// Given a constant order N, a varied length key and varied length input, perform the HKDF algorithm and produce an N-array of 32-byte arrays. +pub fn qcrypto_hkdf(key: &[u8], input: &[u8]) -> [[u8; 32]; N] { let mut result_array = [[0u8; 32]; N]; let t0 = qcrypto_hmac(key, input); @@ -10,8 +13,8 @@ pub fn qcrypto_hkdf(key: &[u8], input: &[u8]) -> Result<[[u8; 32 result_array[0] = t1; for n in 1..N { - result_array[n] = qcrypto_hmac_twice(&t0, &result_array[n-1], &[n as u8]); + result_array[n] = qcrypto_hmac_twice(&t0, &result_array[n-1], &n.to_be_bytes()); } - Ok(result_array) + result_array } \ No newline at end of file diff --git a/quicktap/src/qcrypto/mod.rs b/quicktap/src/qcrypto/mod.rs index 4acc30c..2e6e86a 100644 --- a/quicktap/src/qcrypto/mod.rs +++ b/quicktap/src/qcrypto/mod.rs @@ -1,3 +1,5 @@ +//! A module to implement all of the various cryptography constructs required to implement `WireGuard` + use tai64::Tai64N; pub mod hashes; @@ -8,11 +10,16 @@ pub mod aead; pub mod tests; pub mod hkdf; +/// Get the current TAI64N timestamp pub fn timestamp() -> Tai64N { Tai64N::now() } +/// The cryptography handshake construction identifier pub const CONSTURCTION: &str = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"; +/// The WireGuard protocol identifier pub const IDENTIFIER: &str = "WireGuard v1 zx2c4 Jason@zx2c4.com"; +/// The MAC1 cookie label pub const LABEL_MAC1: &str = "mac1----"; +/// The COOKIE1 cookie label pub const LABEL_COOKIE: &str = "cookie--"; \ No newline at end of file diff --git a/quicktap/src/qcrypto/pki.rs b/quicktap/src/qcrypto/pki.rs index 75a7389..e01e2b4 100644 --- a/quicktap/src/qcrypto/pki.rs +++ b/quicktap/src/qcrypto/pki.rs @@ -1,14 +1,18 @@ +//! Various public-key cryptography functions + use rand::rngs::OsRng; use x25519_dalek::{PublicKey, SharedSecret, StaticSecret}; type Keypair = (StaticSecret, PublicKey); +/// Generate a X25519 keypair pub fn qcrypto_dh_generate() -> Keypair { let secret = StaticSecret::new(OsRng); let public = PublicKey::from(&secret); (secret, public) } +/// Perform Elliptic-Curve Diffie-Hellman between a secret and public key to get a shared secret value pub fn qcrypto_dh(secret: &StaticSecret, public: &PublicKey) -> SharedSecret { secret.diffie_hellman(public) } \ No newline at end of file diff --git a/quicktap/src/qcrypto/tests.rs b/quicktap/src/qcrypto/tests.rs index 1246e32..dac8bbc 100644 --- a/quicktap/src/qcrypto/tests.rs +++ b/quicktap/src/qcrypto/tests.rs @@ -41,10 +41,10 @@ fn qcrypto_aead_test() { #[test] fn qcrypto_xaead_test() { let ciphertext = qcrypto_xaead(&[0u8; 32], &[0u8; 24], &[0u8; 32], &[0u8; 32]).unwrap(); - assert_eq!(qcrypto_xaead_decrypt(&[0u8; 32], &[0u8; 24], &ciphertext, &[0u8; 32]).unwrap(), [0u8; 32].to_vec()) + assert_eq!(qcrypto_xaead_decrypt(&[0u8; 32], &[0u8; 24], &ciphertext, &[0u8; 32]).unwrap(), [0u8; 32].to_vec()); } #[test] fn qcrypto_hkdf_test() { - let derived = qcrypto_hkdf::<1>(&[0u8; 32], &[0u8; 32]).unwrap(); - assert_eq!(derived, [hex!("1090894613df8aef670b0b867e222daebc0d3e436cdddbc16c65855ab93cc91a")]) + let derived = qcrypto_hkdf::<1>(&[0u8; 32], &[0u8; 32]); + assert_eq!(derived, [hex!("1090894613df8aef670b0b867e222daebc0d3e436cdddbc16c65855ab93cc91a")]); } \ No newline at end of file