[codestyle] turn on every lint, document everything

This commit is contained in:
c0repwn3r 2022-12-13 11:44:45 -05:00
parent 04e25fa5b3
commit 4a87313da5
Signed by: core
GPG Key ID: FDBF740DADDCEECF
10 changed files with 103 additions and 11 deletions

View File

@ -1,3 +1,5 @@
//! A Linux implementation of the traits from `drivers::tungeneric`
use std::error::Error; use std::error::Error;
use std::io; use std::io;
use std::io::{Read, Write}; use std::io::{Read, Write};
@ -5,14 +7,19 @@ use etherparse::IpHeader;
use tun::platform::Device; use tun::platform::Device;
use crate::drivers::tungeneric::{GenericDriver, GenericInterface, TunPacket}; use crate::drivers::tungeneric::{GenericDriver, GenericInterface, TunPacket};
#[allow(clippy::module_name_repetitions)]
/// Represents the internal state of a tun driver.
pub struct TunDevice { pub struct TunDevice {
/// Contains the device handle of the tun device
device: Device, device: Device,
/// A packet read buffer
read_buf: [u8; 4096], read_buf: [u8; 4096],
/// Currently unused, for storing the offset into the read buffer to write to
read_offset: usize, read_offset: usize,
/// Another packet read buffer
packet_buf: [u8; 4096], packet_buf: [u8; 4096],
} }
impl GenericDriver for TunDevice { impl GenericDriver for TunDevice {
/// Create a new TunDevice with the provided generic interface configuration
fn new(config: &GenericInterface) -> Result<Self, Box<dyn Error>> { fn new(config: &GenericInterface) -> Result<Self, Box<dyn Error>> {
let mut device_config = tun::Configuration::default(); 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<TunPacket, Box<dyn Error>> { fn read(&mut self) -> Result<TunPacket, Box<dyn Error>> {
self.packet_buf = [0u8; 4096]; self.packet_buf = [0u8; 4096];
let _ = self.device.read(&mut self.packet_buf)?; let _ = self.device.read(&mut self.packet_buf)?;

View File

@ -1,5 +1,9 @@
//! Cross-platform tun/tap drivers for various platforms.
#[cfg(unix)] #[cfg(unix)]
#[path = "linux.rs"] #[path = "linux.rs"]
pub mod tun; // Tun/tap drivers for Linux pub mod tun; // Tun/tap drivers for Linux
#[cfg(unix)]
pub mod linux;
pub mod tungeneric; pub mod tungeneric;

View File

@ -1,23 +1,46 @@
//! Generic traits and modules to represent a tun/tap device
use std::error::Error; use std::error::Error;
use cidr::IpInet; use cidr::IpInet;
use etherparse::{IpHeader}; use etherparse::{IpHeader};
#[derive(Debug)] #[derive(Debug)]
/// A parsed packet from an interface
pub struct TunPacket { pub struct TunPacket {
/// The parsed IPv4 or IPv6 header
pub header: IpHeader, pub header: IpHeader,
/// The raw packet data
pub packet: [u8; 4096] pub packet: [u8; 4096]
} }
/// A trait to implement R/W on a tun driver
pub trait GenericDriver { 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<Self, Box<dyn Error>> where Self: Sized; fn new(config: &GenericInterface) -> Result<Self, Box<dyn Error>> 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<TunPacket, Box<dyn Error>>; fn read(&mut self) -> Result<TunPacket, Box<dyn Error>>;
/// Clear any internal state of this interface.
fn clear(&mut self); 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<dyn Error>>; fn write(&mut self, packet: TunPacket) -> Result<(), Box<dyn Error>>;
} }
/// Generic interface config
pub struct GenericInterface { pub struct GenericInterface {
/// The ipv4/ipv6 addresses to be assigned to the interface
pub addresses: Vec<IpInet>, pub addresses: Vec<IpInet>,
/// The mtu to be assigned to the interface
pub mtu: Option<i32>, pub mtu: Option<i32>,
/// The name of the virtual interface
pub name: String pub name: String
} }

View File

@ -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 mod drivers; // Baremetal network drivers for various platforms
pub use cidr;
pub mod qcrypto; pub mod qcrypto;
pub use cidr;

View File

@ -1,6 +1,14 @@
//! Various functions for ChaCha20Poly1305 stream ciphers
use chacha20poly1305::{ChaCha20Poly1305, Error, KeyInit, XChaCha20Poly1305}; use chacha20poly1305::{ChaCha20Poly1305, Error, KeyInit, XChaCha20Poly1305};
use chacha20poly1305::aead::{Aead, Payload, Nonce}; 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<Vec<u8>, Error> { pub fn qcrypto_aead(key: &[u8; 32], counter: u64, plaintext: &[u8], authtext: &[u8]) -> Result<Vec<u8>, Error> {
let cipher = ChaCha20Poly1305::new_from_slice(key).unwrap(); let cipher = ChaCha20Poly1305::new_from_slice(key).unwrap();
let mut nonce_bytes = [0u8; 12]; 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::<ChaCha20Poly1305>::from(nonce_bytes), payload) cipher.encrypt(&Nonce::<ChaCha20Poly1305>::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<Vec<u8>, Error> { pub fn qcrypto_aead_decrypt(key: &[u8; 32], counter: u64, ciphertext: &[u8], authtext: &[u8]) -> Result<Vec<u8>, Error> {
let cipher = ChaCha20Poly1305::new_from_slice(key).unwrap(); let cipher = ChaCha20Poly1305::new_from_slice(key).unwrap();
let mut nonce_bytes = [0u8; 12]; 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::<ChaCha20Poly1305>::from(nonce_bytes), payload) cipher.decrypt(&Nonce::<ChaCha20Poly1305>::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<Vec<u8>, Error> { pub fn qcrypto_xaead(key: &[u8; 32], nonce: &[u8; 24], plaintext: &[u8], authtext: &[u8]) -> Result<Vec<u8>, Error> {
let cipher = XChaCha20Poly1305::new_from_slice(key).unwrap(); let cipher = XChaCha20Poly1305::new_from_slice(key).unwrap();
let mut payload = Payload::from(plaintext); 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::<XChaCha20Poly1305>::from_slice(nonce), payload) cipher.encrypt(Nonce::<XChaCha20Poly1305>::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<Vec<u8>, Error> { pub fn qcrypto_xaead_decrypt(key: &[u8; 32], nonce: &[u8; 24], ciphertext: &[u8], authtext: &[u8]) -> Result<Vec<u8>, Error> {
let cipher = XChaCha20Poly1305::new_from_slice(key).unwrap(); let cipher = XChaCha20Poly1305::new_from_slice(key).unwrap();
let mut payload = Payload::from(ciphertext); let mut payload = Payload::from(ciphertext);

View File

@ -1,27 +1,40 @@
//! Various hash functions
use blake2::{Blake2s256, Blake2sMac, Digest}; use blake2::{Blake2s256, Blake2sMac, Digest};
use blake2::digest::{KeyInit, FixedOutput, Update}; use blake2::digest::{KeyInit, FixedOutput, Update};
use hmac::SimpleHmac; use hmac::SimpleHmac;
type HmacBlake2s = SimpleHmac<Blake2s256>; type HmacBlake2s = SimpleHmac<Blake2s256>;
/// Given a varied length input, produce a 32-byte Blake2s hash digest
pub fn qcrypto_hash(input: &[u8]) -> [u8; 32] { pub fn qcrypto_hash(input: &[u8]) -> [u8; 32] {
let mut hasher = Blake2s256::new(); let mut hasher = Blake2s256::new();
Update::update(&mut hasher, input); Update::update(&mut hasher, input);
hasher.finalize().into() 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] { pub fn qcrypto_mac(key: &[u8], input: &[u8]) -> [u8; 16] {
let mut hasher = Blake2sMac::new_from_slice(key).unwrap(); let mut hasher = Blake2sMac::new_from_slice(key).unwrap();
hasher.update(input); hasher.update(input);
hasher.finalize_fixed().into() 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] { pub fn qcrypto_hmac(key: &[u8], input: &[u8]) -> [u8; 32] {
let mut hasher = HmacBlake2s::new_from_slice(key).unwrap(); let mut hasher = HmacBlake2s::new_from_slice(key).unwrap();
Update::update(&mut hasher, input); Update::update(&mut hasher, input);
hasher.finalize_fixed().into() 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] { pub fn qcrypto_hmac_twice(key: &[u8], input: &[u8], input2: &[u8]) -> [u8; 32] {
let mut hasher = HmacBlake2s::new_from_slice(key).unwrap(); let mut hasher = HmacBlake2s::new_from_slice(key).unwrap();
Update::update(&mut hasher, input); Update::update(&mut hasher, input);

View File

@ -1,7 +1,10 @@
use std::error::Error; //! An implementation of the HKDF algorithm
use crate::qcrypto::hashes::{qcrypto_hmac, qcrypto_hmac_twice}; use crate::qcrypto::hashes::{qcrypto_hmac, qcrypto_hmac_twice};
pub fn qcrypto_hkdf<const N: usize>(key: &[u8], input: &[u8]) -> Result<[[u8; 32]; N], Box<dyn Error>> { #[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<const N: usize>(key: &[u8], input: &[u8]) -> [[u8; 32]; N] {
let mut result_array = [[0u8; 32]; N]; let mut result_array = [[0u8; 32]; N];
let t0 = qcrypto_hmac(key, input); let t0 = qcrypto_hmac(key, input);
@ -10,8 +13,8 @@ pub fn qcrypto_hkdf<const N: usize>(key: &[u8], input: &[u8]) -> Result<[[u8; 32
result_array[0] = t1; result_array[0] = t1;
for n in 1..N { 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
} }

View File

@ -1,3 +1,5 @@
//! A module to implement all of the various cryptography constructs required to implement `WireGuard`
use tai64::Tai64N; use tai64::Tai64N;
pub mod hashes; pub mod hashes;
@ -8,11 +10,16 @@ pub mod aead;
pub mod tests; pub mod tests;
pub mod hkdf; pub mod hkdf;
/// Get the current TAI64N timestamp
pub fn timestamp() -> Tai64N { pub fn timestamp() -> Tai64N {
Tai64N::now() Tai64N::now()
} }
/// The cryptography handshake construction identifier
pub const CONSTURCTION: &str = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"; pub const CONSTURCTION: &str = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s";
/// The WireGuard protocol identifier
pub const IDENTIFIER: &str = "WireGuard v1 zx2c4 Jason@zx2c4.com"; pub const IDENTIFIER: &str = "WireGuard v1 zx2c4 Jason@zx2c4.com";
/// The MAC1 cookie label
pub const LABEL_MAC1: &str = "mac1----"; pub const LABEL_MAC1: &str = "mac1----";
/// The COOKIE1 cookie label
pub const LABEL_COOKIE: &str = "cookie--"; pub const LABEL_COOKIE: &str = "cookie--";

View File

@ -1,14 +1,18 @@
//! Various public-key cryptography functions
use rand::rngs::OsRng; use rand::rngs::OsRng;
use x25519_dalek::{PublicKey, SharedSecret, StaticSecret}; use x25519_dalek::{PublicKey, SharedSecret, StaticSecret};
type Keypair = (StaticSecret, PublicKey); type Keypair = (StaticSecret, PublicKey);
/// Generate a X25519 keypair
pub fn qcrypto_dh_generate() -> Keypair { pub fn qcrypto_dh_generate() -> Keypair {
let secret = StaticSecret::new(OsRng); let secret = StaticSecret::new(OsRng);
let public = PublicKey::from(&secret); let public = PublicKey::from(&secret);
(secret, public) (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 { pub fn qcrypto_dh(secret: &StaticSecret, public: &PublicKey) -> SharedSecret {
secret.diffie_hellman(public) secret.diffie_hellman(public)
} }

View File

@ -41,10 +41,10 @@ fn qcrypto_aead_test() {
#[test] #[test]
fn qcrypto_xaead_test() { fn qcrypto_xaead_test() {
let ciphertext = qcrypto_xaead(&[0u8; 32], &[0u8; 24], &[0u8; 32], &[0u8; 32]).unwrap(); 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] #[test]
fn qcrypto_hkdf_test() { fn qcrypto_hkdf_test() {
let derived = qcrypto_hkdf::<1>(&[0u8; 32], &[0u8; 32]).unwrap(); let derived = qcrypto_hkdf::<1>(&[0u8; 32], &[0u8; 32]);
assert_eq!(derived, [hex!("1090894613df8aef670b0b867e222daebc0d3e436cdddbc16c65855ab93cc91a")]) assert_eq!(derived, [hex!("1090894613df8aef670b0b867e222daebc0d3e436cdddbc16c65855ab93cc91a")]);
} }