[codestyle] turn on every lint, document everything
This commit is contained in:
parent
04e25fa5b3
commit
4a87313da5
|
@ -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)?;
|
||||||
|
|
|
@ -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;
|
|
@ -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
|
||||||
}
|
}
|
|
@ -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;
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
|
@ -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--";
|
|
@ -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)
|
||||||
}
|
}
|
|
@ -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")]);
|
||||||
}
|
}
|
Loading…
Reference in New Issue