From 611ae059130f0f0b076894884674fed88e1e6cbf Mon Sep 17 00:00:00 2001 From: c0repwn3r Date: Mon, 12 Dec 2022 20:24:48 -0500 Subject: [PATCH] *most* cryptography functions finished --- quicktap-cli/src/main.rs | 2 +- quicktap/Cargo.toml | 11 ++++++- quicktap/src/crypto/hashes.rs | 10 ------ quicktap/src/drivers/linux.rs | 2 +- quicktap/src/drivers/tungeneric.rs | 2 +- quicktap/src/lib.rs | 2 +- quicktap/src/qcrypto/aead.rs | 38 +++++++++++++++++++++ quicktap/src/qcrypto/hashes.rs | 30 +++++++++++++++++ quicktap/src/qcrypto/hkdf.rs | 17 ++++++++++ quicktap/src/{crypto => qcrypto}/mod.rs | 12 +++++++ quicktap/src/qcrypto/pki.rs | 14 ++++++++ quicktap/src/qcrypto/tests.rs | 44 +++++++++++++++++++++++++ 12 files changed, 169 insertions(+), 15 deletions(-) delete mode 100644 quicktap/src/crypto/hashes.rs create mode 100644 quicktap/src/qcrypto/aead.rs create mode 100644 quicktap/src/qcrypto/hashes.rs create mode 100644 quicktap/src/qcrypto/hkdf.rs rename quicktap/src/{crypto => qcrypto}/mod.rs (62%) create mode 100644 quicktap/src/qcrypto/pki.rs create mode 100644 quicktap/src/qcrypto/tests.rs diff --git a/quicktap-cli/src/main.rs b/quicktap-cli/src/main.rs index ab3699e..8c74578 100644 --- a/quicktap-cli/src/main.rs +++ b/quicktap-cli/src/main.rs @@ -1,4 +1,4 @@ -use std::net::{IpAddr, Ipv4Addr}; +use std::net::{Ipv4Addr}; use quicktap::cidr::{IpInet, Ipv4Inet}; use quicktap::drivers::tun::TunDevice; use quicktap::drivers::tungeneric::{GenericDriver, GenericInterface}; diff --git a/quicktap/Cargo.toml b/quicktap/Cargo.toml index f57e36a..0463f51 100644 --- a/quicktap/Cargo.toml +++ b/quicktap/Cargo.toml @@ -9,6 +9,15 @@ edition = "2021" cidr = "0.2.1" etherparse = "0.13.0" blake2 = "0.10.5" +tai64 = "4.0.0" +x25519-dalek = "2.0.0-pre.1" +rand = "0.8.5" +hmac = "0.12.1" +chacha20poly1305 = "0.10.1" [target.'cfg(unix)'.dependencies] -tun = "0.5.4" \ No newline at end of file +tun = "0.5.4" + +[dev-dependencies] +hex_lit = "0.1.1" +hex = "0.4.3" \ No newline at end of file diff --git a/quicktap/src/crypto/hashes.rs b/quicktap/src/crypto/hashes.rs deleted file mode 100644 index 0a77555..0000000 --- a/quicktap/src/crypto/hashes.rs +++ /dev/null @@ -1,10 +0,0 @@ -use std::error::Error; -use blake2::Blake2sVar; - -pub fn crypto_hash(input: &[u8]) -> Result<[u8; 32], Box> { - let mut hasher = Blake2sVar::new(32)?; - hasher.update(input); - let mut result_buf = [0u8; 32]; - hasher.finalize_variable(&mut result_buf)?; - Ok(result_buf) -} \ No newline at end of file diff --git a/quicktap/src/drivers/linux.rs b/quicktap/src/drivers/linux.rs index 510f79a..b99aa62 100644 --- a/quicktap/src/drivers/linux.rs +++ b/quicktap/src/drivers/linux.rs @@ -36,7 +36,7 @@ impl GenericDriver for TunDevice { /// 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 read_amt = self.device.read(&mut self.packet_buf)?; + let _ = self.device.read(&mut self.packet_buf)?; let ip_header = IpHeader::from_slice(&self.packet_buf); if let Ok((packet_header, _, _)) = ip_header { // Found a packet. Clear read buffers diff --git a/quicktap/src/drivers/tungeneric.rs b/quicktap/src/drivers/tungeneric.rs index df9b209..c9c666f 100644 --- a/quicktap/src/drivers/tungeneric.rs +++ b/quicktap/src/drivers/tungeneric.rs @@ -1,6 +1,6 @@ use std::error::Error; use cidr::IpInet; -use etherparse::{IpHeader, SlicedPacket}; +use etherparse::{IpHeader}; #[derive(Debug)] pub struct TunPacket { diff --git a/quicktap/src/lib.rs b/quicktap/src/lib.rs index 0ef9924..b2bae85 100644 --- a/quicktap/src/lib.rs +++ b/quicktap/src/lib.rs @@ -1,3 +1,3 @@ pub mod drivers; // Baremetal network drivers for various platforms pub use cidr; -pub mod crypto; +pub mod qcrypto; diff --git a/quicktap/src/qcrypto/aead.rs b/quicktap/src/qcrypto/aead.rs new file mode 100644 index 0000000..9ce3cf8 --- /dev/null +++ b/quicktap/src/qcrypto/aead.rs @@ -0,0 +1,38 @@ +use chacha20poly1305::{ChaCha20Poly1305, Error, Key, KeyInit, XChaCha20Poly1305}; +use chacha20poly1305::aead::{Aead, Payload, Nonce}; + +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]; + nonce_bytes[4..].copy_from_slice(&counter.to_le_bytes()); + let mut payload = Payload::from(plaintext); + payload.aad = authtext; + + cipher.encrypt(&Nonce::::from(nonce_bytes), payload) +} + +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]; + nonce_bytes[4..].copy_from_slice(&counter.to_le_bytes()); + let mut payload = Payload::from(ciphertext); + payload.aad = authtext; + + cipher.decrypt(&Nonce::::from(nonce_bytes), payload) +} + +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); + payload.aad = authtext; + + cipher.encrypt(Nonce::::from_slice(nonce), payload) +} + +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); + payload.aad = authtext; + + cipher.decrypt(Nonce::::from_slice(nonce), payload) +} \ No newline at end of file diff --git a/quicktap/src/qcrypto/hashes.rs b/quicktap/src/qcrypto/hashes.rs new file mode 100644 index 0000000..1e2338b --- /dev/null +++ b/quicktap/src/qcrypto/hashes.rs @@ -0,0 +1,30 @@ +use blake2::{Blake2s256, Blake2sMac, Digest}; +use blake2::digest::{KeyInit, FixedOutput, Update}; +use hmac::SimpleHmac; + +type HmacBlake2s = SimpleHmac; + +pub fn qcrypto_hash(input: &[u8]) -> [u8; 32] { + let mut hasher = Blake2s256::new(); + Update::update(&mut hasher, input); + hasher.finalize().into() +} + +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() +} + +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() +} + +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); + Update::update(&mut hasher, input2); + hasher.finalize_fixed().into() +} \ No newline at end of file diff --git a/quicktap/src/qcrypto/hkdf.rs b/quicktap/src/qcrypto/hkdf.rs new file mode 100644 index 0000000..b8af21d --- /dev/null +++ b/quicktap/src/qcrypto/hkdf.rs @@ -0,0 +1,17 @@ +use std::error::Error; +use crate::qcrypto::hashes::{qcrypto_hmac, qcrypto_hmac_twice}; + +pub fn qcrypto_hkdf(key: &[u8], input: &[u8]) -> Result<[[u8; 32]; N], Box> { + let mut result_array = [[0u8; 32]; N]; + + let t0 = qcrypto_hmac(key, input); + let t1 = qcrypto_hmac(&t0, &[1u8]); + + result_array[0] = t1; + + for n in 0..N { + result_array[n-1] = qcrypto_hmac_twice(&t0, &result_array[n-2], &[n as u8]); + } + + Ok(result_array) +} \ No newline at end of file diff --git a/quicktap/src/crypto/mod.rs b/quicktap/src/qcrypto/mod.rs similarity index 62% rename from quicktap/src/crypto/mod.rs rename to quicktap/src/qcrypto/mod.rs index d28851c..4acc30c 100644 --- a/quicktap/src/crypto/mod.rs +++ b/quicktap/src/qcrypto/mod.rs @@ -1,4 +1,16 @@ +use tai64::Tai64N; + pub mod hashes; +pub mod pki; +pub mod aead; + +#[cfg(test)] +pub mod tests; +pub mod hkdf; + +pub fn timestamp() -> Tai64N { + Tai64N::now() +} pub const CONSTURCTION: &str = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"; pub const IDENTIFIER: &str = "WireGuard v1 zx2c4 Jason@zx2c4.com"; diff --git a/quicktap/src/qcrypto/pki.rs b/quicktap/src/qcrypto/pki.rs new file mode 100644 index 0000000..75a7389 --- /dev/null +++ b/quicktap/src/qcrypto/pki.rs @@ -0,0 +1,14 @@ +use rand::rngs::OsRng; +use x25519_dalek::{PublicKey, SharedSecret, StaticSecret}; + +type Keypair = (StaticSecret, PublicKey); + +pub fn qcrypto_dh_generate() -> Keypair { + let secret = StaticSecret::new(OsRng); + let public = PublicKey::from(&secret); + (secret, public) +} + +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 new file mode 100644 index 0000000..51c9f43 --- /dev/null +++ b/quicktap/src/qcrypto/tests.rs @@ -0,0 +1,44 @@ +use hex_lit::hex; +use x25519_dalek::PublicKey; +use crate::qcrypto::aead::{qcrypto_aead, qcrypto_aead_decrypt, qcrypto_xaead, qcrypto_xaead_decrypt}; +use crate::qcrypto::hashes::{qcrypto_hash, qcrypto_hmac, qcrypto_mac}; +use crate::qcrypto::pki::{qcrypto_dh, qcrypto_dh_generate}; + +#[test] +fn qcrypto_hash_test() { + assert_eq!(qcrypto_hash(&[0u8; 32]), hex!("320b5ea99e653bc2b593db4130d10a4efd3a0b4cc2e1a6672b678d71dfbd33ad")) +} +#[test] +fn qcrypto_mac_test() { + assert_eq!(qcrypto_mac(&[0u8; 32], &[0u8; 32]), hex!("086de86cfb256a2bc40740062bcf4dcc")) +} +#[test] +fn qcrypto_hmac_test() { + assert_eq!(qcrypto_hmac(&[0u8; 32], &[0u8; 32]), hex!("025108dc4694cac66d549e152b967e41e516cc7568111822bf1ca44cb89bcbca")); +} + +#[test] +fn qcrypto_pki_generate_test() { + let keypair = qcrypto_dh_generate(); + assert_eq!(keypair.1, PublicKey::from(&keypair.0)) +} +#[test] +fn qcrypto_dh_test() { + let alice = qcrypto_dh_generate(); + let bob = qcrypto_dh_generate(); + + let secret = qcrypto_dh(&alice.0, &bob.1); + let secret2 = qcrypto_dh(&bob.0, &alice.1); + + assert_eq!(secret.as_bytes(), secret2.as_bytes()) +} +#[test] +fn qcrypto_aead_test() { + let ciphertext = qcrypto_aead(&[0u8; 32], 0, &[0u8; 32], &[0u8; 32]).unwrap(); + assert_eq!(qcrypto_aead_decrypt(&[0u8; 32], 0, &ciphertext, &[0u8; 32]).unwrap(), [0u8; 32].to_vec()) +} +#[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()) +} \ No newline at end of file