//! `Noise_IKpsk2` handshake, specifically the way WireGuard defines it use std::fmt::{Debug, Formatter}; use tai64::Tai64N; use x25519_dalek::{EphemeralSecret, PublicKey, StaticSecret}; use crate::qcrypto::timestamp; pub mod initiator; pub mod response; #[cfg(test)] pub mod tests; /// The Blake2s hash of the construction pub const HANDSHAKE_INITIATOR_CHAIN_KEY: [u8; 32] = [ 96, 226, 109, 174, 243, 39, 239, 192, 46, 195, 53, 226, 160, 37, 210, 208, 22, 235, 66, 6, 248, 114, 119, 245, 45, 56, 209, 152, 139, 120, 205, 54, ]; /// The hashed chaining key pub const HANDSHAKE_INITIATOR_CHAIN_KEY_HASH: [u8; 32] = [ 34, 17, 179, 97, 8, 26, 197, 102, 105, 18, 67, 219, 69, 138, 213, 50, 45, 156, 108, 102, 34, 147, 232, 183, 14, 225, 156, 101, 186, 7, 158, 243, ]; /// Represents a cookie we got from the other peer #[derive(Debug)] pub struct Cookie { time: Tai64N, cookie: [u8; 16] } /// Represents the internal handshake state. This does not really need to be messed with by outside users #[allow(missing_docs)] #[allow(clippy::module_name_repetitions)] pub struct HandshakeState { pub h: [u8; 32], pub ck: [u8; 32], pub e_pub_i: PublicKey, pub s_pub_i: PublicKey, pub s_pub_r: PublicKey, pub e_priv_me: EphemeralSecret, pub s_priv_me: StaticSecret, pub s_pub_them: PublicKey, pub i_i: u32, pub i_r: u32, pub cookies: Vec } impl HandshakeState { /// Determines if the state variables of this `HandshakeState` are the same as another #[allow(clippy::suspicious_operation_groupings)] pub fn is_eq(&self, other: &HandshakeState) -> bool { self.h == other.h && self.ck == other.ck && self.e_pub_i == other.e_pub_i && self.s_pub_i == other.s_pub_i && self.s_pub_r == other.s_pub_r && self.i_i == other.i_i && self.i_r == other.i_r } } impl Debug for HandshakeState { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.debug_struct("HandshakeState") .field("h", &self.h) .field("ck", &self.ck) .field("e_pub_i", &self.e_pub_i) .field("s_pub_i", &self.s_pub_i) .field("s_pub_r", &self.s_pub_r) .field("e_priv_me", &"") .field("s_priv_me", &"") .field("s_pub_them", &self.s_pub_them) .field("i_i", &self.i_i) .field("i_r", &self.i_r) .field("cookies", &self.cookies).finish() } } /// Determines if a cookie MAC needs to be added to the packet being sent pub fn needs_cookie(session: &HandshakeState) -> bool { if !session.cookies.is_empty() { let past_cookie_timeout = session.cookies[session.cookies.len()-1].time.duration_since(×tamp()).map_or(true, |t| t.as_secs() >= 120); if !past_cookie_timeout { return true; } } false }