diff --git a/performance/examples/basic_test.rs b/performance/examples/basic_test.rs index ea749d4..ecde22c 100644 --- a/performance/examples/basic_test.rs +++ b/performance/examples/basic_test.rs @@ -166,7 +166,7 @@ fn alice_main( alice_app, |b: &mut [u8]| alice_out.send(b.to_vec()).is_ok(), TEST_MTU, - bob_pubkey.clone(), + bob_pubkey, 0, &[], ); diff --git a/performance/examples/benchmark.rs b/performance/examples/benchmark.rs index 513c486..02c060f 100644 --- a/performance/examples/benchmark.rs +++ b/performance/examples/benchmark.rs @@ -136,7 +136,7 @@ fn alice_main( alice_app, |b: &mut [u8]| alice_out.send(alloc(b)).is_ok(), TEST_MTU, - bob_pubkey.clone(), + bob_pubkey, (), &[], ); diff --git a/performance/src/application.rs b/performance/src/application.rs index 250edde..100e418 100644 --- a/performance/src/application.rs +++ b/performance/src/application.rs @@ -182,7 +182,7 @@ pub trait CryptoLayer: Sized { /// /// Templating ZSSP on this trait lets the code here be almost entirely transport, OS, /// and use case independent. -pub trait ApplicationLayer: Sized { +pub trait ApplicationLayer: Sized { /// Should return the current time in milliseconds. Does not have to be monotonic, nor synced /// with remote peers (although both of these properties would help reliability slightly). /// Used to determine if any current handshakes should be resent or timed-out, or if a session @@ -228,7 +228,7 @@ pub trait ApplicationLayer: Sized { /// /// Corresponds to the "Initiator Disallows Downgrade, π_2" security flag of Transition /// Algorithm 3 within the ZSSP whitepaper. - fn initiator_disallows_downgrade(&mut self, session: &Arc>) -> bool; + fn initiator_disallows_downgrade(&mut self, session: &Arc>) -> bool; /// Function to accept sessions after final negotiation. /// /// The implementor must verify that three arguments, `remote_static_key`, `identity` and @@ -244,10 +244,10 @@ pub trait ApplicationLayer: Sized { /// Corresponds to the **Accept** call of Transition Algorithm 4 within the ZSSP whitepaper. fn check_accept_session( &mut self, - remote_static_key: &Crypto::PublicKey, + remote_static_key: &C::PublicKey, identity: &[u8], - fingerprint_data: Option<&Crypto::FingerprintData>, - ) -> AcceptAction; + fingerprint_data: Option<&C::FingerprintData>, + ) -> AcceptAction; /// Lookup a specific ratchet state based on its ratchet fingerprint. /// This function will be called whenever Alice attempts to connect to us with a non-empty @@ -272,7 +272,7 @@ pub trait ApplicationLayer: Sized { fn restore_by_fingerprint( &mut self, ratchet_fingerprint: &[u8; RATCHET_SIZE], - ) -> Result, std::io::Error>; + ) -> Result, std::io::Error>; /// Lookup the specific ratchet states based on the identity of the peer being communicated with. /// This function will be called whenever Alice attempts to open a session, or Bob attempts /// to verify Alice's identity. @@ -291,9 +291,9 @@ pub trait ApplicationLayer: Sized { /// Corresponds to the **Restore** call of Transition Algorithm 1 and 4 within the ZSSP whitepaper. fn restore_by_identity( &mut self, - remote_static_key: &Crypto::PublicKey, - session_data: &Crypto::SessionData, - fingerprint_data: Option<&Crypto::FingerprintData>, + remote_static_key: &C::PublicKey, + session_data: &C::SessionData, + fingerprint_data: Option<&C::FingerprintData>, ) -> Result, std::io::Error>; /// Atomically commit the update specified by `update_data` to storage, or return an error if /// the update could not be made. @@ -313,8 +313,8 @@ pub trait ApplicationLayer: Sized { /// Otherwise, when we restart, we will not be allowed to reconnect. fn save_ratchet_state( &mut self, - remote_static_key: &Crypto::PublicKey, - session_data: &Crypto::SessionData, + remote_static_key: &C::PublicKey, + session_data: &C::SessionData, update_data: RatchetUpdate<'_>, ) -> Result<(), std::io::Error>; @@ -323,7 +323,7 @@ pub trait ApplicationLayer: Sized { /// nothing else. Do not base protocol-level decisions upon the events passed to this function. #[cfg(feature = "logging")] #[allow(unused)] - fn event_log(&mut self, event: crate::LogEvent<'_, Crypto>) {} + fn event_log(&mut self, event: crate::LogEvent<'_, C>) {} } /// Possible responses that can be made to Hello packets from an anonymous peer. @@ -350,10 +350,10 @@ pub enum IncomingSessionAction { /// used by Bob, the responder, at the very last stage of the key exchange. /// /// Corresponds to the *Accept* callback of Transition Algorithm 4. -pub struct AcceptAction { +pub struct AcceptAction { /// The data object to be attached to the session if we successfully connect. /// If this field is None then we will not connect to this remote peer. - pub session_data: Option, + pub session_data: Option, /// Whether or not we will accept a connection with the remote peer when they do not have a /// ratchet key that we think they should have. /// @@ -385,8 +385,8 @@ pub trait Sender { /// A trait to genericize the process of borrowing the resources necessary to repeatedly /// send packet fragments on some socket or network interface. /// -/// Is implemented by `FnMut(&Arc>) -> Option<(Sender, usize)>` closures. -pub trait SendTo { +/// Is implemented by `FnMut(&Arc>) -> Option<(Sender, usize)>` closures. +pub trait SendTo { /// The `Sender` implementation that this `SendTo` implementation will return. /// /// It is allowed to have a lifetime that is borrowed from the `SendTo` instance @@ -394,7 +394,7 @@ pub trait SendTo { /// in situations where that is more efficient. type Sender<'a>: Sender where - Crypto: 'a, + C: 'a, Self: 'a; /// Attempt to process and borrow the resources necessary to repeatedly send fragments of a /// packet to the given session. @@ -405,7 +405,7 @@ pub trait SendTo { /// only called once. /// /// If `None` is returned then sending to this session is cancelled. - fn init_send<'a>(&'a mut self, session: &'a Arc>) -> Option<(Self::Sender<'a>, usize)>; + fn init_send<'a>(&'a mut self, session: &'a Arc>) -> Option<(Self::Sender<'a>, usize)>; } impl bool> Sender for F { @@ -414,9 +414,9 @@ impl bool> Sender for F { } } -impl>) -> Option<(S, usize)>, S: Sender> SendTo for F { - type Sender<'a> = S where Crypto: 'a, F: 'a; - fn init_send<'a>(&'a mut self, session: &'a Arc>) -> Option<(S, usize)> { +impl>) -> Option<(S, usize)>, S: Sender> SendTo for F { + type Sender<'a> = S where C: 'a, F: 'a; + fn init_send<'a>(&'a mut self, session: &'a Arc>) -> Option<(S, usize)> { self(session) } } diff --git a/performance/src/challenge.rs b/performance/src/challenge.rs index 09b14d4..815fc7e 100644 --- a/performance/src/challenge.rs +++ b/performance/src/challenge.rs @@ -26,7 +26,7 @@ pub fn respond_to_challenge_in_place( challenge: &[u8; CHALLENGE_SIZE], pre_response: &mut [u8; CHALLENGE_SIZE], ) { - if &challenge[POW_START..] == &pre_response[POW_START..] { + if challenge[POW_START..] == pre_response[POW_START..] { pre_response.copy_from_slice(challenge); let mut pow = rng.next_u64(); let mut work_buf = [0u8; SHA512_HASH_SIZE]; @@ -79,7 +79,6 @@ impl ChallengeContext { hasher.write(&c.to_be_bytes()); addr.hash(&mut hasher); hasher.write(&self.salt); - drop(hasher); let mut mac = [0u8; SHA512_HASH_SIZE]; hash.finish_and_reset(&mut mac); diff --git a/performance/src/frag_cache.rs b/performance/src/frag_cache.rs index 8f52d54..a8a09ec 100644 --- a/performance/src/frag_cache.rs +++ b/performance/src/frag_cache.rs @@ -16,18 +16,18 @@ struct PacketMetadata { creation_time: i64, } -pub(crate) struct UnassociatedFragCache { +pub(crate) struct UnassociatedFragCache { dos_salt: RandomState, frags_first_unused: usize, frags_unused_size: usize, map: [PacketMetadata; MAX_UNASSOCIATED_PACKETS], - frags: [MaybeUninit; MAX_UNASSOCIATED_FRAGMENTS], + frags: [MaybeUninit; MAX_UNASSOCIATED_FRAGMENTS], map_idx: [u32; MAX_UNASSOCIATED_FRAGMENTS], } /// A combination of a hash table cache and a ring buffer for unassociated fragments. /// Designed specifically to be extremely DDOS resistant. /// This datastructure takes raw unauthenticated fragments straight from the network. -impl UnassociatedFragCache { +impl UnassociatedFragCache { pub(crate) fn new() -> Self { Self { dos_salt: RandomState::new(), @@ -53,11 +53,11 @@ impl UnassociatedFragCache { nonce: &[u8; AES_GCM_NONCE_SIZE], remote_address: impl Hash, fragment_size: usize, - fragment: Crypto::IncomingPacketBuffer, + fragment: C::IncomingPacketBuffer, fragment_no: usize, fragment_count: usize, current_time: i64, - ret_assembled: &mut Assembled, + ret_assembled: &mut Assembled, ) -> Option { debug_assert!(MAX_FRAGMENTS < MAX_UNASSOCIATED_FRAGMENTS); if fragment_no >= fragment_count @@ -95,7 +95,7 @@ impl UnassociatedFragCache { } else if self.map[idx0].key == 0 || self.map[idx1].key == 0 { if fragment_count > self.frags_unused_size { // There are not enough free fragment slots so attempt to expire a bunch of entries. - let _ = self.check_for_expiry_inner(Crypto::SETTINGS.resend_time as i64, current_time); + let _ = self.check_for_expiry_inner(C::SETTINGS.resend_time as i64, current_time); } if self.map[idx0].key == 0 { idx0 @@ -104,7 +104,7 @@ impl UnassociatedFragCache { } } else { // No room for a new entry so attempt to expire a bunch of entries. - let _ = self.check_for_expiry_inner(Crypto::SETTINGS.resend_time as i64, current_time); + let _ = self.check_for_expiry_inner(C::SETTINGS.resend_time as i64, current_time); if self.map[idx0].key == 0 { idx0 } else if self.map[idx1].key == 0 { @@ -118,7 +118,7 @@ impl UnassociatedFragCache { if self.map[idx].key == 0 { // This is a new entry so initialize it. if fragment_count <= self.frags_unused_size { - new_expiry = Some(current_time + Crypto::SETTINGS.fragment_assembly_timeout as i64); + new_expiry = Some(current_time + C::SETTINGS.fragment_assembly_timeout as i64); let entry = &mut self.map[idx]; entry.key = key; entry.frags_idx = self.frags_first_unused as u32; @@ -166,7 +166,7 @@ impl UnassociatedFragCache { } /// Returns the timestamp at which this function should be called again. pub(crate) fn check_for_expiry(&mut self, current_time: i64) -> i64 { - self.check_for_expiry_inner(Crypto::SETTINGS.fragment_assembly_timeout as i64, current_time) + self.check_for_expiry_inner(C::SETTINGS.fragment_assembly_timeout as i64, current_time) } fn check_for_expiry_inner(&mut self, timeout: i64, current_time: i64) -> i64 { while self.frags_unused_size < self.frags.len() { @@ -219,7 +219,7 @@ impl UnassociatedFragCache { } } } -impl Drop for UnassociatedFragCache { +impl Drop for UnassociatedFragCache { fn drop(&mut self) { for i in 0..self.map.len() { if self.map[i].key != 0 { @@ -243,8 +243,8 @@ fn test_cache() { r.wrapping_mul(0x2545F4914F6CDD1Du64) } use crate::crypto_impl::*; - struct Crypto {} - impl CryptoLayer for Crypto { + struct C {} + impl CryptoLayer for C { type Rng = rand_core::OsRng; type PrpEnc = OpenSSLAes256Enc; type PrpDec = OpenSSLAes256Dec; @@ -261,7 +261,7 @@ fn test_cache() { type IncomingPacketBuffer = Vec; } - let mut cache = UnassociatedFragCache::::new(); + let mut cache = UnassociatedFragCache::::new(); let mut assembled = Assembled::new(); let mut time = 0; @@ -317,39 +317,37 @@ fn test_cache() { assert!(assembled.is_empty(), "Cache returned an incomplete packet"); } } - if r > 200 { - if in_progress.len() > 0 { - let to_remain = (xorshift64_random() as usize % in_progress_fragments) + 16; - while in_progress_fragments > to_remain { - let (id, fragment_count, mut packet) = - in_progress.swap_remove(xorshift64_random() as usize % in_progress.len()); - for _ in 0..((xorshift64_random() as usize % packet.len()) + 1) { - let (no, fragment) = packet.swap_remove(xorshift64_random() as usize % packet.len()); + if r > 200 && !in_progress.is_empty() { + let to_remain = (xorshift64_random() as usize % in_progress_fragments) + 16; + while in_progress_fragments > to_remain { + let (id, fragment_count, mut packet) = + in_progress.swap_remove(xorshift64_random() as usize % in_progress.len()); + for _ in 0..((xorshift64_random() as usize % packet.len()) + 1) { + let (no, fragment) = packet.swap_remove(xorshift64_random() as usize % packet.len()); - assembled.clear(); - let mut nonce = [0; 12]; - nonce[..4].copy_from_slice(&id.to_be_bytes()); - cache.assemble( - &nonce, - 0, - fragment.len(), - fragment, - no as usize, - fragment_count as usize, - time, - &mut assembled, - ); - time += 200; - in_progress_fragments -= 1; + assembled.clear(); + let mut nonce = [0; 12]; + nonce[..4].copy_from_slice(&id.to_be_bytes()); + cache.assemble( + &nonce, + 0, + fragment.len(), + fragment, + no as usize, + fragment_count as usize, + time, + &mut assembled, + ); + time += 200; + in_progress_fragments -= 1; - if packet.len() > 0 { - assert!(assembled.is_empty(), "Cache returned an incomplete packet"); - } - } - if packet.len() > 0 { - in_progress.push((id, fragment_count, packet)); + if !packet.is_empty() { + assert!(assembled.is_empty(), "Cache returned an incomplete packet"); } } + if !packet.is_empty() { + in_progress.push((id, fragment_count, packet)); + } } } } diff --git a/performance/src/handshake_cache.rs b/performance/src/handshake_cache.rs index 6c7a7d1..b74b875 100644 --- a/performance/src/handshake_cache.rs +++ b/performance/src/handshake_cache.rs @@ -10,10 +10,10 @@ pub(crate) struct UnassociatedHandshakeCache { cache: RwLock>, } /// SoA format -struct CacheInner { +struct CacheInner { local_ids: [Option; MAX_UNASSOCIATED_HANDSHAKE_STATES], expiries: [i64; MAX_UNASSOCIATED_HANDSHAKE_STATES], - handshakes: [Option>>; MAX_UNASSOCIATED_HANDSHAKE_STATES], + handshakes: [Option>>; MAX_UNASSOCIATED_HANDSHAKE_STATES], } /// Linear-search cache for capping the memory consumption of handshake data. diff --git a/performance/src/indexed_heap.rs b/performance/src/indexed_heap.rs index b37dc70..bd711e4 100644 --- a/performance/src/indexed_heap.rs +++ b/performance/src/indexed_heap.rs @@ -31,7 +31,11 @@ pub struct IndexedBinaryHeap { data: Vec<(T, P, usize)>, map: Vec<(usize, u64)>, } - +impl Default for IndexedBinaryHeap { + fn default() -> Self { + Self::new() + } +} impl IndexedBinaryHeap { /// Create a new, empty binary heap. pub fn new() -> Self { diff --git a/performance/src/lib.rs b/performance/src/lib.rs index cfc6835..4e2f78c 100644 --- a/performance/src/lib.rs +++ b/performance/src/lib.rs @@ -37,6 +37,7 @@ //! - **AES-256**: Single block encryption of header to harden packet fragmentation protocol //! - **AES-256-GCM**: Authenticated encryption //#![warn(missing_docs, rust_2018_idioms)] +#![allow(clippy::too_many_arguments, clippy::type_complexity, clippy::assertions_on_constants)] pub mod crypto; pub mod crypto_impl; diff --git a/performance/src/log_event.rs b/performance/src/log_event.rs index dd14326..efaea8d 100644 --- a/performance/src/log_event.rs +++ b/performance/src/log_event.rs @@ -5,19 +5,19 @@ use crate::zeta::Session; /// ZSSP events that might be interesting to log or aggregate into metrics. #[allow(missing_docs)] -pub enum LogEvent<'a, Crypto: CryptoLayer> { - ResentX1(&'a Arc>), - TimeoutX1(&'a Arc>), +pub enum LogEvent<'a, C: CryptoLayer> { + ResentX1(&'a Arc>), + TimeoutX1(&'a Arc>), TimeoutX2, - ResentX3(&'a Arc>), - TimeoutX3(&'a Arc>), - ResentKeyConfirm(&'a Arc>), - TimeoutKeyConfirm(&'a Arc>), - StartedRekeyingSentK1(&'a Arc>), - ResentK1(&'a Arc>), - TimeoutK1(&'a Arc>), - ResentK2(&'a Arc>), - TimeoutK2(&'a Arc>), + ResentX3(&'a Arc>), + TimeoutX3(&'a Arc>), + ResentKeyConfirm(&'a Arc>), + TimeoutKeyConfirm(&'a Arc>), + StartedRekeyingSentK1(&'a Arc>), + ResentK1(&'a Arc>), + TimeoutK1(&'a Arc>), + ResentK2(&'a Arc>), + TimeoutK2(&'a Arc>), /// `(packet_type, packet_counter, fragment_no, fragment_count)` ReceivedRawFragment(u8, u64, usize, usize), ReceivedRawX1, @@ -25,24 +25,24 @@ pub enum LogEvent<'a, Crypto: CryptoLayer> { X1SucceededChallenge, X1IsAuthSentX2, ReceivedRawChallenge, - ChallengeIsAuth(&'a Arc>), + ChallengeIsAuth(&'a Arc>), ReceivedRawX2, - X2IsAuthSentX3(&'a Arc>), + X2IsAuthSentX3(&'a Arc>), ReceivedRawX3, - X3IsAuthSentKeyConfirm(&'a Arc>), + X3IsAuthSentKeyConfirm(&'a Arc>), ReceivedRawKeyConfirm, - KeyConfirmIsAuthSentAck(&'a Arc>), + KeyConfirmIsAuthSentAck(&'a Arc>), ReceivedRawAck, - AckIsAuth(&'a Arc>), + AckIsAuth(&'a Arc>), ReceivedRawK1, - K1IsAuthSentK2(&'a Arc>), + K1IsAuthSentK2(&'a Arc>), ReceivedRawK2, - K2IsAuthSentKeyConfirm(&'a Arc>), + K2IsAuthSentKeyConfirm(&'a Arc>), ReceivedRawD, - DIsAuthClosedSession(&'a Arc>), + DIsAuthClosedSession(&'a Arc>), } -impl<'a, Crypto: CryptoLayer> std::fmt::Debug for LogEvent<'a, Crypto> { +impl<'a, C: CryptoLayer> std::fmt::Debug for LogEvent<'a, C> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::ResentX1(_) => f.debug_tuple("ResentX1").finish(), diff --git a/performance/src/result.rs b/performance/src/result.rs index 38ee6b7..f138f10 100644 --- a/performance/src/result.rs +++ b/performance/src/result.rs @@ -46,7 +46,7 @@ pub enum SendError { /// Therefore it is no longer capable of sending, receiving or being serviced, /// so it should be dropped. #[derive(Clone)] -pub struct ExpiredError(pub Arc>); +pub struct ExpiredError(pub Arc>); /// A type of fault occurred because we received a bad packet. /// @@ -78,12 +78,12 @@ pub enum FaultType { /// Because an unauthenticated remote peer can force these to occur with specific /// contained information, it is recommended in production to either drop these /// immediately, or log them safely to a local output stream and then drop them. -pub struct ByzantineFault { +pub struct ByzantineFault { /// The session associated with this fault, if there was one. /// /// The sender specified this session within their packet, but they were not authenticated, /// so the sender could theoretically be anyone. - pub session: Option>>, + pub session: Option>>, /// This field is true if this fault caused the session it was attached to to expire. /// An expired session is no longer "owned" by the ZSSP context. /// Therefore it is no longer capable of sending, receiving or being serviced, @@ -123,7 +123,7 @@ pub struct ByzantineFault { /// Keep in mind that when one of these occurs it inherently means that the packet from the remote /// peer has either not been authenticated or has failed authentication. As such, an attacker could /// trigger any of these. These errors should only be used for debugging and tracing. -pub enum ReceiveError { +pub enum ReceiveError { /// A type of fault that can occur because a remote peer sent us a bad packet. /// Such packets will be ignored by ZSSP but a user of ZSSP might want to log /// them for debugging or tracing. @@ -131,11 +131,11 @@ pub enum ReceiveError { /// Because an unauthenticated remote peer can force these to occur with specific /// contained information, it is recommended in production to either drop these /// immediately, or log them safely to a local output stream and then drop them. - ByzantineFault(ByzantineFault), + ByzantineFault(ByzantineFault), /// Rekeying failed and session secret has reached its hard usage count limit. /// The associated session will no longer function and has to be dropped. - MaxKeyLifetimeExceeded(Arc>), + MaxKeyLifetimeExceeded(Arc>), /// Either the `ApplicationLayer::incoming_session` or `ApplicationLayer::check_accept_session` /// callback rejected the remote peer's attempt to establish a new session. @@ -147,7 +147,7 @@ pub enum ReceiveError { /// An error was returned by the `output_buffer` passed to receive. /// The received packet was dropped. - WriteError(std::io::Error, Arc>), + WriteError(std::io::Error, Arc>), } macro_rules! fault { @@ -183,18 +183,18 @@ pub(crate) use fault; /// Result generated by the context packet receive function, with possible payloads. #[derive(Clone)] -pub enum ReceiveOk { +pub enum ReceiveOk { /// The received packet superficially appeared valid but is not associated with a session yet. /// This can occur because the packet was only a fragment of a larger packet, /// or if it was a control packet that does not go through full Noise authentication. Unassociated, /// The received packet was authentic and belongs to this specific session. - Associated(Arc>, SessionEvent), + Associated(Arc>, SessionEvent), /// The received packet was a fragment of a larger packet. /// /// ***The authenticity of this fragment cannot be fully known yet.*** /// This return value should only be used for debugging and tracing purposes. - Fragment(Arc>), + Fragment(Arc>), } /// Something that can occur to an associated session when a packet is received successfully, /// including receiving a payload of decrypted, authenticated data. @@ -270,20 +270,20 @@ impl fmt::Display for SendError { } impl Error for SendError {} -impl fmt::Debug for ExpiredError +impl fmt::Debug for ExpiredError where - Session: fmt::Debug, + Session: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("ExpiredError").field(&self.0).finish() } } -impl fmt::Display for ExpiredError { +impl fmt::Display for ExpiredError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "session expired") } } -impl Error for ExpiredError where Session: fmt::Debug {} +impl Error for ExpiredError where Session: fmt::Debug {} impl fmt::Display for FaultType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -301,7 +301,7 @@ impl Error for FaultType {} // I don't like getter methods but in this case they are the only way to implement // conditionally compiled struct fields without the feature flag causing breaking changes. -impl ByzantineFault { +impl ByzantineFault { /// The file of this implementation of ZSSP from which this error was generated. #[cfg(feature = "debug")] pub fn file(&self) -> &'static str { @@ -316,9 +316,9 @@ impl ByzantineFault { self.line } } -impl fmt::Debug for ByzantineFault +impl fmt::Debug for ByzantineFault where - Session: fmt::Debug, + Session: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ByzantineFault") @@ -331,7 +331,7 @@ where .finish() } } -impl fmt::Display for ByzantineFault { +impl fmt::Display for ByzantineFault { #[cfg(feature = "debug")] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{} ({}:{})", self.error, self.file, self.line) @@ -341,11 +341,11 @@ impl fmt::Display for ByzantineFault { self.error.fmt(f) } } -impl Error for ByzantineFault where Session: fmt::Debug {} +impl Error for ByzantineFault where Session: fmt::Debug {} -impl fmt::Debug for ReceiveError +impl fmt::Debug for ReceiveError where - Crypto::SessionData: fmt::Debug, + C::SessionData: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { @@ -357,7 +357,7 @@ where } } } -impl fmt::Display for ReceiveError { +impl fmt::Display for ReceiveError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { ReceiveError::ByzantineFault(e) => e.fmt(f), @@ -368,4 +368,4 @@ impl fmt::Display for ReceiveError { } } } -impl Error for ReceiveError where Crypto::SessionData: fmt::Debug {} +impl Error for ReceiveError where C::SessionData: fmt::Debug {} diff --git a/performance/src/symmetric_state.rs b/performance/src/symmetric_state.rs index 2b45049..748f064 100644 --- a/performance/src/symmetric_state.rs +++ b/performance/src/symmetric_state.rs @@ -6,15 +6,15 @@ use crate::application::CryptoLayer; use crate::crypto::*; use crate::proto::*; -pub struct SymmetricState { +pub struct SymmetricState { k: Zeroizing<[u8; AES_256_KEY_SIZE]>, ck: Zeroizing<[u8; HASHLEN]>, h: [u8; HASHLEN], /// If anyone knows a better way to get rid of the "parameter `App` is never used" error please /// let me know. - _app: PhantomData Crypto::SessionData>, + _app: PhantomData C::SessionData>, } -impl Clone for SymmetricState { +impl Clone for SymmetricState { fn clone(&self) -> Self { Self { k: self.k.clone(), @@ -25,7 +25,7 @@ impl Clone for SymmetricState { } } -impl SymmetricState { +impl SymmetricState { /// HMAC-SHA512 key derivation based on KBKDF Counter Mode: /// https://csrc.nist.gov/publications/detail/sp/800-108/rev-1/final. /// Cryptographically this isn't meaningfully different from @@ -40,7 +40,7 @@ impl SymmetricState { /// Corresponds to Noise `HKDF`. fn kbkdf( &self, - hmac: &mut Crypto::Hmac, + hmac: &mut C::Hmac, input_key_material: &[u8], label: &[u8; 4], num_outputs: u16, @@ -86,7 +86,7 @@ impl SymmetricState { } } /// Corresponds to Noise `MixKey`. - pub fn mix_key(&mut self, hmac: &mut Crypto::Hmac, input_key_material: &[u8]) { + pub fn mix_key(&mut self, hmac: &mut C::Hmac, input_key_material: &[u8]) { let mut next_ck = Zeroizing::new([0u8; HASHLEN]); let mut temp_k = Zeroizing::new([0u8; HASHLEN]); @@ -104,7 +104,7 @@ impl SymmetricState { self.k.clone_from_slice(&temp_k[..AES_256_KEY_SIZE]); } /// Corresponds to Noise `MixKey`. - pub fn mix_key_no_init(&mut self, hmac: &mut Crypto::Hmac, input_key_material: &[u8]) { + pub fn mix_key_no_init(&mut self, hmac: &mut C::Hmac, input_key_material: &[u8]) { let mut next_ck = Zeroizing::new([0u8; HASHLEN]); self.kbkdf(hmac, input_key_material, LABEL_KBKDF_CHAIN, 2, &mut next_ck, None, None); @@ -112,13 +112,13 @@ impl SymmetricState { *self.ck = *next_ck; } /// Corresponds to Noise `MixHash`. - pub fn mix_hash(&mut self, hash: &mut Crypto::Hash, data: &[u8]) { + pub fn mix_hash(&mut self, hash: &mut C::Hash, data: &[u8]) { hash.update(&self.h); hash.update(data); hash.finish_and_reset(&mut self.h); } /// Corresponds to Noise `MixKeyAndHash`. - pub fn mix_key_and_hash(&mut self, hash: &mut Crypto::Hash, hmac: &mut Crypto::Hmac, input_key_material: &[u8]) { + pub fn mix_key_and_hash(&mut self, hash: &mut C::Hash, hmac: &mut C::Hmac, input_key_material: &[u8]) { let mut next_ck = Zeroizing::new([0u8; HASHLEN]); let mut temp_h = [0u8; HASHLEN]; let mut temp_k = Zeroizing::new([0u8; HASHLEN]); @@ -138,12 +138,7 @@ impl SymmetricState { self.k.clone_from_slice(&temp_k[..AES_256_KEY_SIZE]); } /// Corresponds to Noise `MixKeyAndHash`. - pub fn mix_key_and_hash_no_init( - &mut self, - hash: &mut Crypto::Hash, - hmac: &mut Crypto::Hmac, - input_key_material: &[u8], - ) { + pub fn mix_key_and_hash_no_init(&mut self, hash: &mut C::Hash, hmac: &mut C::Hmac, input_key_material: &[u8]) { let mut next_ck = Zeroizing::new([0u8; HASHLEN]); let mut temp_h = [0u8; HASHLEN]; @@ -164,11 +159,11 @@ impl SymmetricState { #[must_use] pub fn encrypt_and_hash_in_place( &mut self, - hash: &mut Crypto::Hash, + hash: &mut C::Hash, iv: [u8; AES_GCM_NONCE_SIZE], data: &mut [u8], ) -> [u8; AES_GCM_TAG_SIZE] { - let tag = Crypto::Aead::encrypt_in_place(&self.k, &iv, &self.h, data); + let tag = C::Aead::encrypt_in_place(&self.k, &iv, &self.h, data); hash.update(&self.h); hash.update(data); hash.update(&tag); @@ -179,7 +174,7 @@ impl SymmetricState { #[must_use] pub fn decrypt_and_hash_in_place( &mut self, - hash: &mut Crypto::Hash, + hash: &mut C::Hash, iv: [u8; AES_GCM_NONCE_SIZE], data: &mut [u8], tag: [u8; AES_GCM_TAG_SIZE], @@ -187,25 +182,19 @@ impl SymmetricState { hash.update(&self.h); hash.update(data); hash.update(&tag); - let is_auth = Crypto::Aead::decrypt_in_place(&self.k, &iv, &self.h, data, tag.as_ref().try_into().unwrap()); + let is_auth = C::Aead::decrypt_in_place(&self.k, &iv, &self.h, data, tag.as_ref().try_into().unwrap()); hash.finish_and_reset(&mut self.h); is_auth } /// Corresponds to Noise `Split`. - pub fn split(self, hmac: &mut Crypto::Hmac, key1: &mut [u8; HASHLEN], key2: &mut [u8; HASHLEN]) { + pub fn split(self, hmac: &mut C::Hmac, key1: &mut [u8; HASHLEN], key2: &mut [u8; HASHLEN]) { self.kbkdf(hmac, &[], LABEL_KBKDF_CHAIN, 2, key1, Some(key2), None); } /// Get an additional symmetric key (ASK) that is a collision resistant hash of the transcript, /// is forward secrect and is cryptographically independent from all other produced keys. /// Based on Noise's unstable ASK mechanism, using KBKDF instead of HKDF. /// https://github.com/noiseprotocol/noise_wiki/wiki/Additional-Symmetric-Keys. - pub fn get_ask( - &self, - hmac: &mut Crypto::Hmac, - label: &[u8; 4], - key1: &mut [u8; HASHLEN], - key2: &mut [u8; HASHLEN], - ) { + pub fn get_ask(&self, hmac: &mut C::Hmac, label: &[u8; 4], key1: &mut [u8; HASHLEN], key2: &mut [u8; HASHLEN]) { self.kbkdf(hmac, &self.h, label, 2, key1, Some(key2), None); } /// Used for internally debugging a key exchange. diff --git a/performance/src/zeta.rs b/performance/src/zeta.rs index e55c76e..0bcdd60 100644 --- a/performance/src/zeta.rs +++ b/performance/src/zeta.rs @@ -25,63 +25,63 @@ use crate::zssp::{log, ContextInner, SessionQueue}; use crate::LogEvent::*; /// Corresponds to the Zeta State Machine found in Section 4.1. -pub struct Session { - ctx: Weak>, +pub struct Session { + ctx: Weak>, /// An arbitrary, application defined object allocated with each session. /// /// Users of ZSSP are encouraged to use this field extensively to associate ZSSP sessions with /// whatever your application's notion of a "remote peer" is. - pub session_data: Crypto::SessionData, + pub session_data: C::SessionData, /// This field is true if the local peer acted as Bob, the responder in the initial key exchange. pub was_bob: bool, queue_idx: BinaryHeapIndex, - pub(crate) s_remote: Crypto::PublicKey, + pub(crate) s_remote: C::PublicKey, send_counter: AtomicU64, pub(crate) window: Window, - pub(crate) defrag: [Mutex>; SESSION_MAX_FRAGMENTS_OOO], + pub(crate) defrag: [Mutex>; SESSION_MAX_FRAGMENTS_OOO], /// `session_queue -> state_machine_lock -> state -> session_map` state_machine_lock: Mutex<()>, /// `session_queue -> state_machine_lock -> state -> session_map` - pub(crate) state: RwLock>, + pub(crate) state: RwLock>, /// Pre-computed rekeying value. noise_kk_ss: Zeroizing<[u8; P384_ECDH_SHARED_SECRET_SIZE]>, } -pub(crate) struct MutableState { +pub(crate) struct MutableState { ratchet_state1: RatchetState, ratchet_state2: Option, - pub(crate) hk_send: Crypto::PrpEnc, - pub(crate) hk_recv: Crypto::PrpDec, + pub(crate) hk_send: C::PrpEnc, + pub(crate) hk_recv: C::PrpDec, key_creation_counter: u64, key_index: bool, - keys: [DuplexKey; 2], + keys: [DuplexKey; 2], resend_timer: AtomicI64, timeout_timer: i64, - pub(crate) beta: ZetaAutomata, + pub(crate) beta: ZetaAutomata, } /// Corresponds to State B_2 of the Zeta State Machine found in Section 4.1 - Definition 3. -pub(crate) struct StateB2 { +pub(crate) struct StateB2 { ratchet_state: RatchetState, - lookup_data: Option, + lookup_data: Option, kid_send: NonZeroU32, pub kid_recv: NonZeroU32, pub hk_send: Zeroizing<[u8; AES_256_KEY_SIZE]>, pub hk_recv: Zeroizing<[u8; AES_256_KEY_SIZE]>, - e_secret: Crypto::KeyPair, - noise: SymmetricState, - pub defrag: Mutex>, + e_secret: C::KeyPair, + noise: SymmetricState, + pub defrag: Mutex>, } -pub(crate) struct DuplexKey { +pub(crate) struct DuplexKey { send: Keys, recv: Keys, - nk: Option, + nk: Option, } #[derive(Default)] @@ -92,10 +92,10 @@ pub(crate) struct Keys { /// Corresponds to State A_1 of the Zeta State Machine found in Section 4.1. #[derive(Clone)] -pub(crate) struct StateA1 { - noise: SymmetricState, - e_secret: Crypto::KeyPair, - e1_secret: Crypto::Kem, +pub(crate) struct StateA1 { + noise: SymmetricState, + e_secret: C::KeyPair, + e1_secret: C::Kem, identity: ArrayVec, x1: ArrayVec, } @@ -106,15 +106,15 @@ pub(crate) struct StateA3 { } /// Corresponds to the ZKE Automata found in Section 4.1 - Definition 2. -pub(crate) enum ZetaAutomata { +pub(crate) enum ZetaAutomata { Null, - A1(Box>), + A1(Box>), A3(Box), S1, S2, R1 { - noise: SymmetricState, - e_secret: Crypto::KeyPair, + noise: SymmetricState, + e_secret: C::KeyPair, k1: ArrayVec, }, R2 { @@ -122,16 +122,16 @@ pub(crate) enum ZetaAutomata { }, } -impl Default for DuplexKey { +impl Default for DuplexKey { fn default() -> Self { Self { send: Default::default(), recv: Default::default(), nk: None } } } -impl DuplexKey { +impl DuplexKey { fn replace_nk(&mut self, nk_send: &[u8; HASHLEN], nk_recv: &[u8; HASHLEN]) { let nk_send = (&nk_send[..AES_256_KEY_SIZE]).try_into().unwrap(); let nk_recv = (&nk_recv[..AES_256_KEY_SIZE]).try_into().unwrap(); - self.nk = Some(Crypto::AeadPool::new(nk_send, nk_recv)) + self.nk = Some(C::AeadPool::new(nk_send, nk_recv)) } } impl Keys { @@ -143,25 +143,25 @@ impl Keys { } } -impl MutableState { - fn key_ref(&self, is_next: bool) -> &DuplexKey { +impl MutableState { + fn key_ref(&self, is_next: bool) -> &DuplexKey { &self.keys[(self.key_index ^ is_next) as usize] } - fn key_mut(&mut self, is_next: bool) -> &mut DuplexKey { + fn key_mut(&mut self, is_next: bool) -> &mut DuplexKey { &mut self.keys[(self.key_index ^ is_next) as usize] } } -impl SymmetricState { +impl SymmetricState { #[must_use] fn write_e_no_init( &mut self, - hash: &mut Crypto::Hash, - hmac: &mut Crypto::Hmac, - rng: &Mutex, + hash: &mut C::Hash, + hmac: &mut C::Hmac, + rng: &Mutex, packet: &mut ArrayVec, - ) -> Crypto::KeyPair { - let e_secret = Crypto::KeyPair::generate(rng.lock().unwrap().deref_mut()); + ) -> C::KeyPair { + let e_secret = C::KeyPair::generate(rng.lock().unwrap().deref_mut()); let pub_key = e_secret.public_key_bytes(); packet.extend(pub_key); self.mix_hash(hash, &pub_key); @@ -171,24 +171,24 @@ impl SymmetricState { #[must_use] fn read_e_no_init( &mut self, - hash: &mut Crypto::Hash, - hmac: &mut Crypto::Hmac, + hash: &mut C::Hash, + hmac: &mut C::Hmac, i: &mut usize, packet: &[u8], - ) -> Option { + ) -> Option { let j = *i + P384_PUBLIC_KEY_SIZE; let pub_key = &packet[*i..j]; self.mix_hash(hash, pub_key); self.mix_key_no_init(hmac, pub_key); *i = j; - Crypto::PublicKey::from_bytes((pub_key).try_into().unwrap()) + C::PublicKey::from_bytes((pub_key).try_into().unwrap()) } - fn mix_dh(&mut self, hmac: &mut Crypto::Hmac, secret: &Crypto::KeyPair, remote: &Crypto::PublicKey) { + fn mix_dh(&mut self, hmac: &mut C::Hmac, secret: &C::KeyPair, remote: &C::PublicKey) { let mut ecdh_secret = Zeroizing::new([0u8; P384_ECDH_SHARED_SECRET_SIZE]); secret.agree(remote, &mut ecdh_secret); self.mix_key(hmac, ecdh_secret.as_ref()); } - fn mix_dh_no_init(&mut self, hmac: &mut Crypto::Hmac, secret: &Crypto::KeyPair, remote: &Crypto::PublicKey) { + fn mix_dh_no_init(&mut self, hmac: &mut C::Hmac, secret: &C::KeyPair, remote: &C::PublicKey) { let mut ecdh_secret = Zeroizing::new([0u8; P384_ECDH_SHARED_SECRET_SIZE]); secret.agree(remote, &mut ecdh_secret); self.mix_key_no_init(hmac, ecdh_secret.as_ref()); @@ -221,9 +221,9 @@ pub(crate) fn set_header(packet: &mut [u8], kid_send: u32, nonce: &[u8; AES_GCM_ packet[..KID_SIZE].copy_from_slice(&kid_send.to_ne_bytes()); packet[PACKET_NONCE_START..HEADER_SIZE].copy_from_slice(&nonce[NONCE_SIZE_DIFF..]); } -fn create_ratchet_state( - hmac: &mut Crypto::Hmac, - noise: &SymmetricState, +fn create_ratchet_state( + hmac: &mut C::Hmac, + noise: &SymmetricState, pre_chain_len: u64, ) -> RatchetState { let mut rk = Zeroizing::new([0u8; HASHLEN]); @@ -235,12 +235,12 @@ fn create_ratchet_state( pre_chain_len + 1, ) } -fn get_counter(session: &Session, state: &MutableState) -> Option<(u64, bool)> { +fn get_counter(session: &Session, state: &MutableState) -> Option<(u64, bool)> { let c = session.send_counter.fetch_add(1, Ordering::Relaxed); if c > THREAD_SAFE_COUNTER_HARD_EXPIRE || c > state.key_creation_counter + EXPIRE_AFTER_USES { return None; } - let rekey_at = state.key_creation_counter + Crypto::SETTINGS.rekey_after_key_uses; + let rekey_at = state.key_creation_counter + C::SETTINGS.rekey_after_key_uses; Some((c, c > rekey_at)) } @@ -254,11 +254,7 @@ fn gen_kid(session_map: &HashMap, rng: &mut impl RngCore) -> N } } } -fn remap( - ctx: &Arc>, - session: &Arc>, - state: &MutableState, -) -> NonZeroU32 { +fn remap(ctx: &Arc>, session: &Arc>, state: &MutableState) -> NonZeroU32 { let mut session_map = ctx.session_map.write().unwrap(); let weak = if let Some(Some(weak)) = state.key_ref(true).recv.kid.as_ref().map(|kid| session_map.remove(kid)) { weak @@ -270,20 +266,20 @@ fn remap( new_kid_recv } -fn create_a1_state( - hash: &mut Crypto::Hash, - hmac: &mut Crypto::Hmac, - rng: &Mutex, - s_remote: &Crypto::PublicKey, +fn create_a1_state( + hash: &mut C::Hash, + hmac: &mut C::Hmac, + rng: &Mutex, + s_remote: &C::PublicKey, kid_recv: NonZeroU32, ratchet_state1: &RatchetState, ratchet_state2: Option<&RatchetState>, identity: &[u8], -) -> Box> { +) -> Box> { // <- s // ... // -> e, es, e1 - let mut noise = SymmetricState::::initialize(PROTOCOL_NAME_NOISE_XK); + let mut noise = SymmetricState::::initialize(PROTOCOL_NAME_NOISE_XK); let mut x1 = ArrayVec::::new(); x1.extend([0u8; HEADER_SIZE]); // Noise process prologue. @@ -297,7 +293,7 @@ fn create_a1_state( noise.mix_dh(hmac, &e_secret, s_remote); // Process message pattern 1 e1 token. let i = x1.len(); - let (e1_secret, e1_public) = Crypto::Kem::generate(rng.lock().unwrap().deref_mut()); + let (e1_secret, e1_public) = C::Kem::generate(rng.lock().unwrap().deref_mut()); x1.extend(e1_public); let tag = noise.encrypt_and_hash_in_place(hash, to_nonce(PACKET_TYPE_HANDSHAKE_HELLO, 0), &mut x1[i..]); x1.extend(tag); @@ -323,14 +319,14 @@ fn create_a1_state( Box::new(StateA1 { noise, e_secret, e1_secret, identity, x1 }) } /// Corresponds to Transition Algorithm 1 found in Section 4.3. -pub(crate) fn trans_to_a1>( +pub(crate) fn trans_to_a1>( mut app: App, - ctx: &Arc>, - s_remote: Crypto::PublicKey, - session_data: Crypto::SessionData, + ctx: &Arc>, + s_remote: C::PublicKey, + session_data: C::SessionData, identity: &[u8], - send: impl FnOnce(&mut [u8], Option<&Crypto::PrpEnc>), -) -> Result<(Arc>, Option), OpenError> { + send: impl FnOnce(&mut [u8], Option<&C::PrpEnc>), +) -> Result<(Arc>, Option), OpenError> { let RatchetStates { state1, state2 } = app .restore_by_identity(&s_remote, &session_data, None) .map_err(OpenError::StorageError)? @@ -340,8 +336,8 @@ pub(crate) fn trans_to_a1>( let mut session_map = ctx.session_map.write().unwrap(); let kid_recv = gen_kid(session_map.deref(), ctx.rng.lock().unwrap().deref_mut()); - let hash = &mut Crypto::Hash::new(); - let hmac = &mut Crypto::Hmac::new(); + let hash = &mut C::Hash::new(); + let hmac = &mut C::Hmac::new(); let a1 = create_a1_state( hash, hmac, @@ -364,7 +360,7 @@ pub(crate) fn trans_to_a1>( let current_time = app.time(); let queue_idx = session_queue.reserve_index(); - let resend_timer = current_time + Crypto::SETTINGS.resend_time as i64; + let resend_timer = current_time + C::SETTINGS.resend_time as i64; let session = Arc::new(Session { ctx: Arc::downgrade(ctx), session_data, @@ -377,13 +373,13 @@ pub(crate) fn trans_to_a1>( state: RwLock::new(MutableState { ratchet_state1: state1.clone(), ratchet_state2: state2.clone(), - hk_send: Crypto::PrpEnc::new((&hk_send[..AES_256_KEY_SIZE]).try_into().unwrap()), - hk_recv: Crypto::PrpDec::new((&hk_recv[..AES_256_KEY_SIZE]).try_into().unwrap()), + hk_send: C::PrpEnc::new((&hk_send[..AES_256_KEY_SIZE]).try_into().unwrap()), + hk_recv: C::PrpDec::new((&hk_recv[..AES_256_KEY_SIZE]).try_into().unwrap()), key_creation_counter: 0, key_index: true, keys: [DuplexKey::default(), DuplexKey::default()], resend_timer: AtomicI64::new(resend_timer), - timeout_timer: current_time + Crypto::SETTINGS.initial_offer_timeout as i64, + timeout_timer: current_time + C::SETTINGS.initial_offer_timeout as i64, beta: ZetaAutomata::A1(a1), }), noise_kk_ss: noise_kk_ss.clone(), @@ -405,9 +401,9 @@ pub(crate) fn trans_to_a1>( Ok((session, reduced_service_time)) } /// Corresponds to Algorithm 13 found in Section 5. -pub(crate) fn respond_to_challenge( - ctx: &Arc>, - session: &Session, +pub(crate) fn respond_to_challenge( + ctx: &Arc>, + session: &Session, challenge: &[u8; CHALLENGE_SIZE], ) { let mut state = session.state.write().unwrap(); @@ -415,18 +411,18 @@ pub(crate) fn respond_to_challenge( let response_start = a1.x1.len() - CHALLENGE_SIZE; let mut rng = ctx.rng.lock().unwrap(); let response = (&mut a1.x1[response_start..]).try_into().unwrap(); - respond_to_challenge_in_place(rng.deref_mut(), &mut Crypto::Hash::new(), challenge, response); + respond_to_challenge_in_place(rng.deref_mut(), &mut C::Hash::new(), challenge, response); } } /// Corresponds to Transition Algorithm 2 found in Section 4.3. -pub(crate) fn received_x1_trans>( +pub(crate) fn received_x1_trans>( app: &mut App, - ctx: &ContextInner, - hash: &mut Crypto::Hash, + ctx: &ContextInner, + hash: &mut C::Hash, n: &[u8; AES_GCM_NONCE_SIZE], x1: &mut [u8], - send: impl FnOnce(&mut [u8], Option<&Crypto::PrpEnc>), -) -> Result, ReceiveError> { + send: impl FnOnce(&mut [u8], Option<&C::PrpEnc>), +) -> Result, ReceiveError> { use FaultType::*; // <- s // ... @@ -436,11 +432,11 @@ pub(crate) fn received_x1_trans::initialize(PROTOCOL_NAME_NOISE_XK); + let hmac = &mut C::Hmac::new(); + let mut noise = SymmetricState::::initialize(PROTOCOL_NAME_NOISE_XK); let mut i = 0; // Noise process prologue. let j = i + KID_SIZE; @@ -510,7 +506,7 @@ pub(crate) fn received_x1_trans>( +pub(crate) fn received_x2_trans>( app: &mut App, - ctx: &Arc>, - session: &Arc>, + ctx: &Arc>, + session: &Arc>, kid: NonZeroU32, n: &[u8; AES_GCM_NONCE_SIZE], x2: &mut [u8], - send: impl FnOnce(&mut [u8], Option<&Crypto::PrpEnc>), -) -> Result<(bool, Option), ReceiveError> { + send: impl FnOnce(&mut [u8], Option<&C::PrpEnc>), +) -> Result<(bool, Option), ReceiveError> { use FaultType::*; // <- e, ee, ekem1, psk // -> s, se @@ -588,14 +584,14 @@ pub(crate) fn received_x2_trans= COUNTER_WINDOW_MAX_SKIP_AHEAD || &n[AES_GCM_NONCE_SIZE - 3..] != &x2[x2.len() - 3..] { + if c >= COUNTER_WINDOW_MAX_SKIP_AHEAD || n[AES_GCM_NONCE_SIZE - 3..] != x2[x2.len() - 3..] { return Err(fault!(FailedAuth, true, session)); } @@ -645,7 +641,7 @@ pub(crate) fn received_x2_trans Option<(NonZeroU32, SymmetricState)> { + let mut test_ratchet_key = |ratchet_key| -> Option<(NonZeroU32, SymmetricState)> { let mut noise = noise.clone(); let mut payload = payload; // Process message pattern 2 psk token. @@ -694,7 +690,7 @@ pub(crate) fn received_x2_trans( - session: &Arc>, - state: &MutableState, +fn send_control( + session: &Arc>, + state: &MutableState, packet_type: u8, mut payload: ArrayVec, - send: impl FnOnce(&mut [u8], Option<&Crypto::PrpEnc>), + send: impl FnOnce(&mut [u8], Option<&C::PrpEnc>), ) -> Result<(), bool> { if let Some((c, _)) = get_counter(session, state) { if let (Some(kek), Some(kid)) = (state.key_ref(false).send.kek.as_ref(), state.key_ref(false).send.kid) { let nonce = to_nonce(packet_type, c); - let tag = Crypto::Aead::encrypt_in_place(kek, &nonce, &[], &mut payload[HEADER_SIZE..]); + let tag = C::Aead::encrypt_in_place(kek, &nonce, &[], &mut payload[HEADER_SIZE..]); payload.extend(tag); set_header(&mut payload, kid.get(), &nonce); send(&mut payload, Some(&state.hk_send)); @@ -794,14 +790,14 @@ fn send_control( } } /// Corresponds to Transition Algorithm 4 found in Section 4.3. -pub(crate) fn received_x3_trans>( +pub(crate) fn received_x3_trans>( app: &mut App, - ctx: &Arc>, - zeta: Arc>, + ctx: &Arc>, + zeta: Arc>, kid: NonZeroU32, x3: &mut [u8], - send: impl FnOnce(&mut [u8], Option<&Crypto::PrpEnc>), -) -> Result<(Arc>, bool, Option), ReceiveError> { + send: impl FnOnce(&mut [u8], Option<&C::PrpEnc>), +) -> Result<(Arc>, bool, Option), ReceiveError> { use FaultType::*; // -> s, se if x3.len() < HANDSHAKE_COMPLETION_MIN_SIZE { @@ -810,8 +806,8 @@ pub(crate) fn received_x3_trans>( +pub(crate) fn received_c1_trans>( app: &mut App, - ctx: &Arc>, - session: &Arc>, + ctx: &Arc>, + session: &Arc>, kid: NonZeroU32, n: &[u8; AES_GCM_NONCE_SIZE], c1: &[u8], - send: impl FnOnce(&mut [u8], Option<&Crypto::PrpEnc>), -) -> Result<(bool, Option), ReceiveError> { + send: impl FnOnce(&mut [u8], Option<&C::PrpEnc>), +) -> Result<(bool, Option), ReceiveError> { use FaultType::*; if c1.len() != KEY_CONFIRMATION_SIZE { @@ -998,7 +993,7 @@ pub(crate) fn received_c1_trans>( +pub(crate) fn received_c2_trans>( app: &mut App, - ctx: &Arc>, - session: &Arc>, + ctx: &Arc>, + session: &Arc>, kid: NonZeroU32, n: &[u8; AES_GCM_NONCE_SIZE], c2: &[u8], -) -> Result, ReceiveError> { +) -> Result, ReceiveError> { use FaultType::*; if c2.len() != ACKNOWLEDGEMENT_SIZE { @@ -1090,7 +1085,7 @@ pub(crate) fn received_c2_trans( - session: &Arc>, +pub(crate) fn received_d_trans( + session: &Arc>, kid: NonZeroU32, n: &[u8; AES_GCM_NONCE_SIZE], d: &[u8], -) -> Result<(), ReceiveError> { +) -> Result<(), ReceiveError> { use FaultType::*; if d.len() != SESSION_REJECTED_SIZE { @@ -1136,7 +1131,7 @@ pub(crate) fn received_d_trans( } let tag = d[..].try_into().unwrap(); - if !Crypto::Aead::decrypt_in_place(state.key_ref(true).recv.kek.as_ref().unwrap(), n, &[], &mut [], tag) { + if !C::Aead::decrypt_in_place(state.key_ref(true).recv.kek.as_ref().unwrap(), n, &[], &mut [], tag) { return Err(fault!(FailedAuth, true, session)); } let (_, c) = from_nonce(n); @@ -1151,14 +1146,14 @@ pub(crate) fn received_d_trans( } /// Corresponds to the timeout timer Transition Algorithm described in Section 4.1 - Definition 3. /// Returns `Err(())` if this session should be expired. -fn timeout_trans>( +fn timeout_trans>( app: &mut App, - ctx: &Arc>, - session: &Arc>, + ctx: &Arc>, + session: &Arc>, kex_lock: MutexGuard<'_, ()>, - state: RwLockReadGuard<'_, MutableState>, + state: RwLockReadGuard<'_, MutableState>, current_time: i64, - send: impl FnOnce(&mut [u8], Option<&Crypto::PrpEnc>), + send: impl FnOnce(&mut [u8], Option<&C::PrpEnc>), ) -> Result { match &state.beta { ZetaAutomata::Null => Err(()), @@ -1175,8 +1170,8 @@ fn timeout_trans>( } let new_kid_recv = remap(ctx, session, &state); - let hash = &mut Crypto::Hash::new(); - let hmac = &mut Crypto::Hmac::new(); + let hash = &mut C::Hash::new(); + let hmac = &mut C::Hmac::new(); let a1 = create_a1_state( hash, hmac, @@ -1199,9 +1194,9 @@ fn timeout_trans>( state.hk_send.reset((&hk_send[..AES_256_KEY_SIZE]).try_into().unwrap()); *state.key_mut(true) = DuplexKey::default(); state.key_mut(true).recv.kid = Some(new_kid_recv); - let resend_timer = current_time + Crypto::SETTINGS.resend_time as i64; + let resend_timer = current_time + C::SETTINGS.resend_time as i64; state.resend_timer = AtomicI64::new(resend_timer); - state.timeout_timer = current_time + Crypto::SETTINGS.initial_offer_timeout as i64; + state.timeout_timer = current_time + C::SETTINGS.initial_offer_timeout as i64; state.beta = ZetaAutomata::A1(a1); resend_timer }; @@ -1219,8 +1214,8 @@ fn timeout_trans>( // ... // -> psk, e, es, ss let mut noise = SymmetricState::initialize(PROTOCOL_NAME_NOISE_KK); - let hash = &mut Crypto::Hash::new(); - let hmac = &mut Crypto::Hmac::new(); + let hash = &mut C::Hash::new(); + let hmac = &mut C::Hmac::new(); let mut k1 = ArrayVec::::new(); k1.extend([0u8; HEADER_SIZE]); // Noise process prologue. @@ -1244,8 +1239,8 @@ fn timeout_trans>( let resend_timer = { let mut state = session.state.write().unwrap(); state.key_mut(true).recv.kid = Some(new_kid_recv); - state.timeout_timer = current_time + Crypto::SETTINGS.rekey_timeout as i64; - let resend_timer = current_time + Crypto::SETTINGS.resend_time as i64; + state.timeout_timer = current_time + C::SETTINGS.rekey_timeout as i64; + let resend_timer = current_time + C::SETTINGS.resend_time as i64; state.resend_timer = AtomicI64::new(resend_timer); state.beta = ZetaAutomata::R1 { noise, e_secret, k1: k1.clone() }; resend_timer @@ -1274,12 +1269,12 @@ fn timeout_trans>( } /// Corresponds to the timer rules of the Zeta State Machine found in Section 4.1 - Definition 3. /// Returns `Err(())` if this session should be expired. -pub(crate) fn process_timers>( +pub(crate) fn process_timers>( app: &mut App, - ctx: &Arc>, - session: &Arc>, + ctx: &Arc>, + session: &Arc>, current_time: i64, - send: impl FnOnce(&mut [u8], Option<&Crypto::PrpEnc>), + send: impl FnOnce(&mut [u8], Option<&C::PrpEnc>), ) -> Result { let kex_lock = session.state_machine_lock.lock().unwrap(); let state = session.state.read().unwrap(); @@ -1288,7 +1283,7 @@ pub(crate) fn process_timers> timeout_trans(app, ctx, session, kex_lock, state, current_time, send) } else { let ts = state.resend_timer.load(Ordering::Relaxed); - let resend_next = current_time + Crypto::SETTINGS.resend_time as i64; + let resend_next = current_time + C::SETTINGS.resend_time as i64; if ts <= current_time && state.resend_timer.fetch_max(resend_next, Ordering::Relaxed) == ts { // Corresponds to the resend timer rules found in Section 4.1 - Definition 3. @@ -1331,15 +1326,15 @@ pub(crate) fn process_timers> } } /// Corresponds to Transition Algorithm 7 found in Section 4.3. -pub(crate) fn received_k1_trans>( +pub(crate) fn received_k1_trans>( app: &mut App, - ctx: &Arc>, - session: &Arc>, + ctx: &Arc>, + session: &Arc>, kid: NonZeroU32, n: &[u8; AES_GCM_NONCE_SIZE], k1: &mut [u8], - send: impl FnOnce(&mut [u8], Option<&Crypto::PrpEnc>), -) -> Result, ReceiveError> { + send: impl FnOnce(&mut [u8], Option<&C::PrpEnc>), +) -> Result, ReceiveError> { use FaultType::*; // -> s // <- s @@ -1370,7 +1365,7 @@ pub(crate) fn received_k1_trans::initialize(PROTOCOL_NAME_NOISE_KK); - let hash = &mut Crypto::Hash::new(); - let hmac = &mut Crypto::Hmac::new(); + let mut noise = SymmetricState::::initialize(PROTOCOL_NAME_NOISE_KK); + let hash = &mut C::Hash::new(); + let hmac = &mut C::Hmac::new(); // Noise process prologue. noise.mix_hash(hash, &session.s_remote.to_bytes()); noise.mix_hash(hash, &ctx.s_secret.public_key_bytes()); @@ -1454,8 +1449,8 @@ pub(crate) fn received_k1_trans>( +pub(crate) fn received_k2_trans>( app: &mut App, - ctx: &Arc>, - session: &Arc>, + ctx: &Arc>, + session: &Arc>, kid: NonZeroU32, n: &[u8; AES_GCM_NONCE_SIZE], k2: &mut [u8], - send: impl FnOnce(&mut [u8], Option<&Crypto::PrpEnc>), -) -> Result, ReceiveError> { + send: impl FnOnce(&mut [u8], Option<&C::PrpEnc>), +) -> Result, ReceiveError> { use FaultType::*; // <- e, ee, se if k2.len() != REKEY_SIZE { @@ -1510,7 +1505,7 @@ pub(crate) fn received_k2_trans( - ctx: &Arc>, - session: &Session, +pub(crate) fn send_payload( + ctx: &Arc>, + session: &Session, payload: &[u8], mut send: impl Sender, mtu_sized_buffer: &mut [u8], @@ -1713,14 +1708,14 @@ pub(crate) fn send_payload( } } /// Corresponds to Algorithm 10 found in Section 4.3. -pub(crate) fn receive_payload_in_place( - session: &Arc>, - state: RwLockReadGuard<'_, MutableState>, +pub(crate) fn receive_payload_in_place( + session: &Arc>, + state: RwLockReadGuard<'_, MutableState>, kid: NonZeroU32, nonce: &[u8; AES_GCM_NONCE_SIZE], - fragments: &mut [Crypto::IncomingPacketBuffer], + fragments: &mut [C::IncomingPacketBuffer], mut output_buffer: impl Write, -) -> Result<(), ReceiveError> { +) -> Result<(), ReceiveError> { use FaultType::*; debug_assert!(!fragments.is_empty()); @@ -1775,12 +1770,12 @@ pub(crate) fn receive_payload_in_place( Ok(()) } -impl Drop for Session { +impl Drop for Session { fn drop(&mut self) { self.expire(); } } -impl Session { +impl Session { /// Mark a session as expired. This will make it impossible for this session to successfully /// receive or send data or control packets. It is recommended to simply `drop` the session /// instead, but this can provide some reassurance in complex shared ownership situations. @@ -1792,11 +1787,7 @@ impl Session { } } /// Allows us to expire sessions with the correct locking order, preventing deadlock. - pub(crate) fn expire_inner( - &self, - ctx: Option<&Arc>>, - session_queue: Option<&mut SessionQueue>, - ) { + pub(crate) fn expire_inner(&self, ctx: Option<&Arc>>, session_queue: Option<&mut SessionQueue>) { let _kex_lock = self.state_machine_lock.lock().unwrap(); let mut state = self.state.write().unwrap(); if !matches!(&state.beta, ZetaAutomata::Null) { @@ -1852,14 +1843,14 @@ impl Session { matches!(&self.state.read().unwrap().beta, ZetaAutomata::Null) } /// The static public key of the remote peer. - pub fn remote_static_key(&self) -> &Crypto::PublicKey { + pub fn remote_static_key(&self) -> &C::PublicKey { &self.s_remote } } -impl std::fmt::Debug for Session +impl std::fmt::Debug for Session where - Crypto::SessionData: std::fmt::Debug, + C::SessionData: std::fmt::Debug, { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Session") @@ -1869,7 +1860,7 @@ where .finish() } } -impl std::fmt::Debug for ZetaAutomata { +impl std::fmt::Debug for ZetaAutomata { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Null => write!(f, "Expired"), diff --git a/performance/src/zssp.rs b/performance/src/zssp.rs index c63f12e..9d7fc18 100644 --- a/performance/src/zssp.rs +++ b/performance/src/zssp.rs @@ -37,43 +37,43 @@ pub(crate) use log; /// defragment incoming packets that are not yet associated with a session. /// /// Internally this is just a clonable Arc, so it can be safely shared with multiple threads. -pub struct Context(pub Arc>); -impl Clone for Context { +pub struct Context(pub Arc>); +impl Clone for Context { fn clone(&self) -> Self { Self(self.0.clone()) } } -pub(crate) type SessionMap = RwLock>>>; +pub(crate) type SessionMap = RwLock>>>; -pub(crate) type SessionQueue = IndexedBinaryHeap>, Reverse>; +pub(crate) type SessionQueue = IndexedBinaryHeap>, Reverse>; /// The internal memory of the ZSSP context. /// One of these is allocated as an `Arc` to initialize this implementation of ZSSP. /// See `Context::new`. -pub struct ContextInner { +pub struct ContextInner { /// The `CryptoRng` instance that was passed to ZSSP when this context was created. - pub rng: Mutex, + pub rng: Mutex, pub(crate) next_service_time: AtomicI64, - pub(crate) s_secret: Crypto::KeyPair, + pub(crate) s_secret: C::KeyPair, /// `session_queue -> state_machine_lock -> state -> session_map` - pub(crate) session_queue: Mutex>, + pub(crate) session_queue: Mutex>, /// `session_queue -> state_machine_lock -> state -> session_map` - pub(crate) session_map: SessionMap, - pub(crate) unassociated_defrag_cache: Mutex>, - pub(crate) unassociated_handshake_states: UnassociatedHandshakeCache, + pub(crate) session_map: SessionMap, + pub(crate) unassociated_defrag_cache: Mutex>, + pub(crate) unassociated_handshake_states: UnassociatedHandshakeCache, pub(crate) challenge: ChallengeContext, } -impl ContextInner { +impl ContextInner { pub(crate) fn reduce_next_service_time(&self, time: i64) -> Option { (self.next_service_time.fetch_min(time, Ordering::Relaxed) > time).then_some(time) } } -fn parse_fragment_header( +fn parse_fragment_header( incoming_fragment: &[u8], -) -> Result<(usize, usize, [u8; AES_GCM_NONCE_SIZE]), ReceiveError> { +) -> Result<(usize, usize, [u8; AES_GCM_NONCE_SIZE]), ReceiveError> { let fragment_no = incoming_fragment[FRAGMENT_NO_IDX] as usize; let fragment_count = incoming_fragment[FRAGMENT_COUNT_IDX] as usize; if fragment_no >= fragment_count || fragment_count > MAX_FRAGMENTS { @@ -122,9 +122,9 @@ fn send_with_fragmentation( true } -impl Context { +impl Context { /// Create a new session context. - pub fn new(static_secret_key: Crypto::KeyPair, mut rng: Crypto::Rng) -> Self { + pub fn new(static_secret_key: C::KeyPair, mut rng: C::Rng) -> Self { let challenge = ChallengeContext::new(&mut rng); Self(Arc::new(ContextInner { rng: Mutex::new(rng), @@ -160,15 +160,15 @@ impl Context { /// object /// * `identity` - Payload to be sent to Bob that contains the information necessary /// for the upper protocol to authenticate and approve of Alice's identity. - pub fn open>( + pub fn open>( &self, app: App, send: impl Sender, mut mtu: usize, - static_remote_key: Crypto::PublicKey, - session_data: Crypto::SessionData, + static_remote_key: C::PublicKey, + session_data: C::SessionData, identity: &[u8], - ) -> Result<(Arc>, Option), OpenError> { + ) -> Result<(Arc>, Option), OpenError> { mtu = mtu.max(MIN_TRANSPORT_MTU); if identity.len() > IDENTITY_MAX_SIZE { return Err(OpenError::IdentityTooLarge); @@ -199,16 +199,16 @@ impl Context { /// * `remote_address` - Whatever the remote address is, as long as you can Hash it /// * `incoming_fragment_buf` - Buffer containing incoming wire packet (the context takes ownership) /// * `output_buffer` - Buffer to receive decrypted and authenticated object data - pub fn receive<'a, App: ApplicationLayer>( + pub fn receive>( &self, mut app: App, mut send_unassociated_reply: impl Sender, mut send_unassociated_mtu: usize, - mut send_to: impl SendTo, + mut send_to: impl SendTo, remote_address: &impl Hash, - mut incoming_fragment_buf: Crypto::IncomingPacketBuffer, + mut incoming_fragment_buf: C::IncomingPacketBuffer, output_buffer: impl Write, - ) -> Result<(ReceiveOk, Option), ReceiveError> { + ) -> Result<(ReceiveOk, Option), ReceiveError> { use crate::result::FaultType::*; let ctx = &self.0; send_unassociated_mtu = send_unassociated_mtu.max(MIN_TRANSPORT_MTU); @@ -324,7 +324,7 @@ impl Context { &mut incoming_fragment_buf.as_mut()[HEADER_SIZE..] }; - let send_associated = |packet: &mut [u8], hk_send: Option<&Crypto::PrpEnc>| { + let send_associated = |packet: &mut [u8], hk_send: Option<&C::PrpEnc>| { if let Some((sender, mut mtu)) = send_to.init_send(&session) { mtu = mtu.max(MIN_TRANSPORT_MTU); send_with_fragmentation(sender, mtu, packet, hk_send); @@ -416,7 +416,7 @@ impl Context { // Check for and handle PACKET_TYPE_ALICE_NOISE_XK_PATTERN_3 let zeta = self.0.unassociated_handshake_states.get(kid_recv); if let Some(zeta) = zeta { - Crypto::PrpDec::new(&zeta.hk_recv).decrypt_in_place( + C::PrpDec::new(&zeta.hk_recv).decrypt_in_place( (&mut incoming_fragment[HEADER_AUTH_START..HEADER_AUTH_END]) .try_into() .unwrap(), @@ -535,7 +535,7 @@ impl Context { } // Process recv challenge layer. let challenge_start = assembled_packet.len() - CHALLENGE_SIZE; - let hash = &mut Crypto::Hash::new(); + let hash = &mut C::Hash::new(); match app.incoming_session() { IncomingSessionAction::Allow => {} IncomingSessionAction::Challenge => { @@ -616,7 +616,7 @@ impl Context { /// * `data` - Data to send pub fn send( &self, - session: &Session, + session: &Session, send: impl Sender, mtu_sized_buffer: &mut [u8], data: &[u8], @@ -631,7 +631,7 @@ impl Context { /// /// * `app` - Interface to application using ZSSP /// * `send_to` - Function to get a sender and an MTU to send something over an active session - pub fn service>(&self, mut app: App, mut send_to: impl SendTo) -> i64 { + pub fn service>(&self, mut app: App, mut send_to: impl SendTo) -> i64 { let current_time = app.time(); let next_service_time = loop { match self.service_inner(&mut app, send_to, current_time) { @@ -639,10 +639,10 @@ impl Context { Err((_, s)) => send_to = s, } }; - let max_interval = Crypto::SETTINGS + let max_interval = C::SETTINGS .fragment_assembly_timeout - .min(Crypto::SETTINGS.rekey_timeout) - .min(Crypto::SETTINGS.initial_offer_timeout); + .min(C::SETTINGS.rekey_timeout) + .min(C::SETTINGS.initial_offer_timeout); (next_service_time - current_time).min(max_interval as i64) } @@ -667,20 +667,20 @@ impl Context { /// /// * `app` - Interface to application using ZSSP /// * `send_to` - Function to get a sender and an MTU to send something over an active session - pub fn service_scheduled>( + pub fn service_scheduled>( &self, mut app: App, - send_to: impl SendTo, - ) -> Result> { + send_to: impl SendTo, + ) -> Result> { let current_time = app.time(); self.service_inner(&mut app, send_to, current_time).map_err(|e| e.0) } - fn service_inner, F: SendTo>( + fn service_inner, F: SendTo>( &self, app: &mut App, mut send_to: F, current_time: i64, - ) -> Result, F)> { + ) -> Result, F)> { let ctx = &self.0; let mut session_queue = ctx.session_queue.lock().unwrap(); let mut queue_service_time = i64::MAX; diff --git a/reference/Cargo.toml b/reference/Cargo.toml index f134a01..b6438ed 100644 --- a/reference/Cargo.toml +++ b/reference/Cargo.toml @@ -3,7 +3,7 @@ authors = ["ZeroTier, Inc. ", "Adam Ierymenko for &mut TestApplication { fn hello_requires_recognized_ratchet(&mut self) -> bool { false } @@ -159,7 +157,7 @@ fn alice_main( &mut alice_app, |b| alice_out.send(b).is_ok(), TEST_MTU, - bob_pubkey.clone(), + bob_pubkey, 0, Vec::new(), ) diff --git a/reference/examples/ping_pong.rs b/reference/examples/ping_pong.rs index 671be5a..cb007d7 100644 --- a/reference/examples/ping_pong.rs +++ b/reference/examples/ping_pong.rs @@ -44,9 +44,7 @@ impl CryptoLayer for MyApp { /// In this example for simplicity we won't be hooking up ratchet keys to a filesystem backend. /// They are dropped and peers ignore if they are missing. #[allow(unused)] -impl ApplicationLayer for &mut MyApp { - type Crypto = MyApp; - +impl ApplicationLayer for &mut MyApp { fn hello_requires_recognized_ratchet(&mut self) -> bool { false } diff --git a/reference/src/application.rs b/reference/src/application.rs index 5ee301e..5758acc 100644 --- a/reference/src/application.rs +++ b/reference/src/application.rs @@ -139,10 +139,7 @@ pub trait CryptoLayer: Sized { /// /// Templating ZSSP on this trait lets the code here be almost entirely transport, OS, /// and use case independent. -pub trait ApplicationLayer: Sized { - /// Specifies which concrete set of cryptography types will be used by this application. - type Crypto: CryptoLayer; - +pub trait ApplicationLayer: Sized { /// Should return the current time in milliseconds. Does not have to be monotonic, nor synced /// with remote peers (although both of these properties would help reliability slightly). /// Used to determine if any current handshakes should be resent or timed-out, or if a session @@ -174,7 +171,7 @@ pub trait ApplicationLayer: Sized { /// least one party is misconfigured and got their ratchet keys corrupted or lost, or Bob has /// been compromised and is being impersonated. An attacker must at least have Bob's private /// static key to be able to ask Alice to downgrade. - fn initiator_disallows_downgrade(&mut self, session: &Arc>) -> bool; + fn initiator_disallows_downgrade(&mut self, session: &Arc>) -> bool; /// Function to accept sessions after final negotiation. /// The second argument is the identity that the remote peer sent us. The application /// must verify this identity is associated with the remote peer's static key. @@ -183,9 +180,9 @@ pub trait ApplicationLayer: Sized { /// before returning. fn check_accept_session( &mut self, - remote_static_key: &::PublicKey, + remote_static_key: &::PublicKey, identity: &[u8], - ) -> AcceptAction; + ) -> AcceptAction; /// Lookup a specific ratchet state based on its ratchet fingerprint. /// This function will be called whenever Alice attempts to connect to us with a non-empty @@ -213,8 +210,8 @@ pub trait ApplicationLayer: Sized { /// function `ApplicationLayer::check_accept_session`. fn restore_by_identity( &mut self, - remote_static_key: &::PublicKey, - session_data: &::SessionData, + remote_static_key: &::PublicKey, + session_data: &::SessionData, ) -> Result, std::io::Error>; /// Atomically commit the update specified by `update_data` to storage, or return an error if /// the update could not be made. @@ -234,8 +231,8 @@ pub trait ApplicationLayer: Sized { /// Otherwise, when we restart, we will not be allowed to reconnect. fn save_ratchet_state( &mut self, - remote_static_key: &::PublicKey, - session_data: &::SessionData, + remote_static_key: &::PublicKey, + session_data: &::SessionData, update_data: RatchetUpdate<'_>, ) -> Result<(), std::io::Error>; @@ -244,7 +241,7 @@ pub trait ApplicationLayer: Sized { /// nothing else. Do not base protocol-level decisions upon the events passed to this function. #[cfg(feature = "logging")] #[allow(unused)] - fn event_log(&mut self, event: LogEvent<'_, Self::Crypto>) {} + fn event_log(&mut self, event: LogEvent<'_, C>) {} } /// A collection of fields specifying how to complete the key exchange with a specific remote peer, diff --git a/reference/src/challenge.rs b/reference/src/challenge.rs index fa8ccd2..4813cbb 100644 --- a/reference/src/challenge.rs +++ b/reference/src/challenge.rs @@ -24,7 +24,7 @@ pub fn respond_to_challenge_in_place challenge: &[u8; CHALLENGE_SIZE], pre_response: &mut [u8; CHALLENGE_SIZE], ) { - if &challenge[POW_START..] == &pre_response[POW_START..] { + if challenge[POW_START..] == pre_response[POW_START..] { pre_response.copy_from_slice(challenge); let mut pow = rng.next_u64(); loop { @@ -80,7 +80,6 @@ impl ChallengeContext { hasher.write(&c.to_be_bytes()); addr.hash(&mut hasher); hasher.write(&self.salt); - drop(hasher); let mac = h.finish(); mac[..MAC_SIZE].try_into().unwrap() diff --git a/reference/src/context.rs b/reference/src/context.rs index ca441f8..e6cbd58 100644 --- a/reference/src/context.rs +++ b/reference/src/context.rs @@ -31,21 +31,21 @@ pub(crate) use log; /// defragment incoming packets that are not yet associated with a session. /// /// Internally this is just a clonable Arc, so it can be safely shared with multiple threads. -pub struct Context(Arc>); -impl Clone for Context { +pub struct Context(Arc>); +impl Clone for Context { fn clone(&self) -> Self { Self(self.0.clone()) } } -pub(crate) type SessionMap = RefCell>>>; +pub(crate) type SessionMap = RefCell>>>; -pub(crate) struct ContextInner { - pub(crate) rng: RefCell, - pub(crate) s_secret: Crypto::KeyPair, - pub(crate) session_map: SessionMap, - pub(crate) sessions: RefCell, Weak>>>, - pub(crate) b2_map: RefCell>>, +pub(crate) struct ContextInner { + pub(crate) rng: RefCell, + pub(crate) s_secret: C::KeyPair, + pub(crate) session_map: SessionMap, + pub(crate) sessions: RefCell, Weak>>>, + pub(crate) b2_map: RefCell>>, hello_defrag: RefCell, challenge: RefCell, @@ -62,9 +62,9 @@ fn to_packet_nonce(n: &[u8; AES_GCM_NONCE_SIZE]) -> &[u8; PACKET_NONCE_SIZE] { (&n[n.len() - PACKET_NONCE_SIZE..]).try_into().unwrap() } -impl Context { +impl Context { /// Create a new session context. - pub fn new(static_secret_key: Crypto::KeyPair, mut rng: Crypto::Rng) -> Self { + pub fn new(static_secret_key: C::KeyPair, mut rng: C::Rng) -> Self { let challenge = ChallengeContext::new(&mut rng); Self(Arc::new(ContextInner { rng: RefCell::new(rng), @@ -93,18 +93,15 @@ impl Context { /// object /// * `identity` - Payload to be sent to Bob that contains the information necessary /// for the upper protocol to authenticate and approve of Alice's identity - pub fn open( + pub fn open>( &mut self, app: App, send: impl FnMut(Vec) -> bool, mut mtu: usize, - static_remote_key: Crypto::PublicKey, - session_data: Crypto::SessionData, + static_remote_key: C::PublicKey, + session_data: C::SessionData, identity: Vec, - ) -> Result>, OpenError> - where - App: ApplicationLayer, - { + ) -> Result>, OpenError> { mtu = mtu.max(MIN_TRANSPORT_MTU); if identity.len() > IDENTITY_MAX_SIZE { return Err(OpenError::IdentityTooLarge); @@ -120,7 +117,7 @@ impl Context { identity, |Packet(kid, nonce, payload): &Packet| { // Process fragmentation layer. - let _ = send_with_fragmentation::(send, mtu, *kid, to_packet_nonce(&nonce), payload, None); + let _ = send_with_fragmentation::(send, mtu, *kid, to_packet_nonce(nonce), payload, None); }, ) } @@ -133,18 +130,15 @@ impl Context { /// * `send_to` - Function to get senders for existing sessions, permitting MTU and path lookup /// * `remote_address` - Whatever the remote address is, as long as you can Hash it /// * `raw_fragment` - Buffer containing incoming wire packet - pub fn receive) -> bool>( + pub fn receive, SendFn: FnMut(Vec) -> bool>( &mut self, mut app: App, send_unassociated_reply: impl FnMut(Vec) -> bool, mut send_unassociated_mtu: usize, - send_to: impl FnOnce(&Arc>) -> Option<(SendFn, usize)>, + send_to: impl FnOnce(&Arc>) -> Option<(SendFn, usize)>, remote_address: &impl Hash, raw_fragment: Vec, - ) -> Result, ReceiveError> - where - App: ApplicationLayer, - { + ) -> Result, ReceiveError> { use crate::result::FaultType::*; send_unassociated_mtu = send_unassociated_mtu.max(MIN_TRANSPORT_MTU); let ctx = &self.0; @@ -158,7 +152,7 @@ impl Context { let mut zeta = session.0.borrow_mut(); let result = zeta.defrag - .received_fragment::(raw_fragment, app.time(), |n, frag_no, frag_count| { + .received_fragment::(raw_fragment, app.time(), |n, frag_no, frag_count| { let (p, c) = from_nonce(n); if p != PACKET_TYPE_DATA { log!(app, ReceivedRawFragment(p, c, frag_no, frag_count)); @@ -193,11 +187,11 @@ impl Context { |Packet(kid, nonce, payload): &Packet, hk: Option<&[u8; AES_256_KEY_SIZE]>| { if let Some((send_fragment, mut mtu)) = send_to(&session) { mtu = mtu.max(MIN_TRANSPORT_MTU); - let _ = send_with_fragmentation::( + let _ = send_with_fragmentation::( send_fragment, mtu, *kid, - to_packet_nonce(&nonce), + to_packet_nonce(nonce), payload, hk, ); @@ -207,7 +201,7 @@ impl Context { let (p, _) = from_nonce(&pn); let ret = match p { PACKET_TYPE_DATA => { - received_payload_in_place::( + received_payload_in_place::( &mut zeta, kid_recv, to_aes_nonce(&pn), @@ -221,7 +215,7 @@ impl Context { &mut zeta, &session, &mut app, - &ctx, + ctx, kid_recv, to_aes_nonce(&pn), assembled_packet, @@ -297,7 +291,7 @@ impl Context { } PACKET_TYPE_SESSION_REJECTED => { log!(app, ReceivedRawD); - received_d_trans::(&mut zeta, kid_recv, to_aes_nonce(&pn), assembled_packet)?; + received_d_trans::(&mut zeta, kid_recv, to_aes_nonce(&pn), assembled_packet)?; log!(app, DIsAuthClosedSession(&session)); SessionEvent::Rejected } @@ -315,7 +309,7 @@ impl Context { // Process recv fragmentation layer. let result = zeta.defrag - .received_fragment::(raw_fragment, app.time(), |n, frag_no, frag_count| { + .received_fragment::(raw_fragment, app.time(), |n, frag_no, frag_count| { let (p, c) = from_nonce(n); log!(app, ReceivedRawFragment(p, c, frag_no, frag_count)); if p == PACKET_TYPE_HANDSHAKE_COMPLETION && c == 0 { @@ -334,11 +328,11 @@ impl Context { kid_recv, assembled_packet, |Packet(kid, nonce, payload), hk| { - let _ = send_with_fragmentation::( + let _ = send_with_fragmentation::( send_unassociated_reply, send_unassociated_mtu, *kid, - to_packet_nonce(&nonce), + to_packet_nonce(nonce), payload, hk, ); @@ -362,7 +356,7 @@ impl Context { } } else { // Process recv fragmentation layer. - let result = ctx.hello_defrag.borrow_mut().received_fragment::( + let result = ctx.hello_defrag.borrow_mut().received_fragment::( raw_fragment, app.time(), |n, frag_no, frag_count| { @@ -381,7 +375,7 @@ impl Context { log!(app, ReceivedRawX1); // Process recv challenge layer. let challenge_start = assembled_packet.len() - CHALLENGE_SIZE; - let result = ctx.challenge.borrow_mut().process_hello::( + let result = ctx.challenge.borrow_mut().process_hello::( remote_address, (&assembled_packet[challenge_start..]).try_into().unwrap(), ); @@ -391,7 +385,7 @@ impl Context { challenge_packet.extend(&assembled_packet[..KID_SIZE]); challenge_packet.extend(&challenge); let nonce = to_nonce(PACKET_TYPE_CHALLENGE, ctx.rng.borrow_mut().next_u64()); - let _ = send_with_fragmentation::( + let _ = send_with_fragmentation::( send_unassociated_reply, send_unassociated_mtu, 0, @@ -409,15 +403,15 @@ impl Context { // Process recv zeta layer. received_x1_trans( &mut app, - &ctx, + ctx, to_aes_nonce(&n), assembled_packet, |Packet(kid, nonce, payload), hk| { - let _ = send_with_fragmentation::( + let _ = send_with_fragmentation::( send_unassociated_reply, send_unassociated_mtu, *kid, - to_packet_nonce(&nonce), + to_packet_nonce(nonce), payload, Some(hk), ); @@ -436,7 +430,7 @@ impl Context { { if let Some(Some(session)) = ctx.session_map.borrow_mut().get(&kid_recv).map(|r| r.upgrade()) { let mut zeta = session.0.borrow_mut(); - respond_to_challenge::( + respond_to_challenge::( &mut zeta, &ctx.rng, &assembled_packet[KID_SIZE..].try_into().unwrap(), @@ -466,7 +460,7 @@ impl Context { /// * `payload` - Data to send pub fn send( &mut self, - session: &Arc>, + session: &Arc>, send: impl FnMut(Vec) -> bool, mut mtu: usize, payload: Vec, @@ -474,8 +468,8 @@ impl Context { debug_assert_eq!(session.0.borrow().ctx.as_ptr(), Arc::as_ptr(&self.0)); mtu = mtu.max(MIN_TRANSPORT_MTU); let mut zeta = session.0.borrow_mut(); - send_payload::(&mut zeta, payload, |Packet(kid, nonce, payload), hk| { - let result = send_with_fragmentation::(send, mtu, *kid, to_packet_nonce(nonce), &payload, hk); + send_payload::(&mut zeta, payload, |Packet(kid, nonce, payload), hk| { + let result = send_with_fragmentation::(send, mtu, *kid, to_packet_nonce(nonce), payload, hk); if matches!(result, Err(true)) { return Err(SendError::DataTooLarge); } @@ -490,14 +484,11 @@ impl Context { /// a problem. It is completely fine to call this function more often than the returned interval. /// /// * `send_to` - Function to get a sender and an MTU to send something over an active session - pub fn service) -> bool>( + pub fn service, SendFn: FnMut(Vec) -> bool>( &mut self, mut app: App, - mut send_to: impl FnMut(&Arc>) -> Option<(SendFn, usize)>, - ) -> i64 - where - App: ApplicationLayer, - { + mut send_to: impl FnMut(&Arc>) -> Option<(SendFn, usize)>, + ) -> i64 { let ctx = &self.0; let sessions = ctx.sessions.borrow_mut(); let current_time = app.time(); @@ -514,11 +505,11 @@ impl Context { |Packet(kid, nonce, payload): &Packet, hk| { if let Some((send_fragment, mut mtu)) = send_to(&session) { mtu = mtu.max(MIN_TRANSPORT_MTU); - let _ = send_with_fragmentation::( + let _ = send_with_fragmentation::( send_fragment, mtu, *kid, - to_packet_nonce(&nonce), + to_packet_nonce(nonce), payload, hk, ); @@ -530,6 +521,6 @@ impl Context { } } ctx.hello_defrag.borrow_mut().service(current_time); - (Crypto::SETTINGS.resend_time as i64).min(next_timer - current_time) + (C::SETTINGS.resend_time as i64).min(next_timer - current_time) } } diff --git a/reference/src/crypto_impl/aes_impl.rs b/reference/src/crypto_impl/aes_impl.rs index 5160ef4..25428b6 100644 --- a/reference/src/crypto_impl/aes_impl.rs +++ b/reference/src/crypto_impl/aes_impl.rs @@ -29,9 +29,9 @@ impl AesGcmAead for AesGcmCrate { buffer: &mut [u8], ) -> [u8; AES_GCM_TAG_SIZE] { let key = Key::::from_slice(key); - let mut cipher = Aes256Gcm::new(&key); + let mut cipher = Aes256Gcm::new(key); cipher - .encrypt_in_place_detached(&Nonce::from_slice(iv), aad.unwrap_or(&[]), buffer) + .encrypt_in_place_detached(Nonce::from_slice(iv), aad.unwrap_or(&[]), buffer) .unwrap() .try_into() .unwrap() @@ -45,14 +45,9 @@ impl AesGcmAead for AesGcmCrate { tag: &[u8; AES_GCM_TAG_SIZE], ) -> bool { let key = Key::::from_slice(key); - let mut cipher = Aes256Gcm::new(&key); + let mut cipher = Aes256Gcm::new(key); cipher - .decrypt_in_place_detached( - &Nonce::from_slice(iv), - aad.unwrap_or(&[]), - buffer, - &Tag::from_slice(tag), - ) + .decrypt_in_place_detached(Nonce::from_slice(iv), aad.unwrap_or(&[]), buffer, Tag::from_slice(tag)) .is_ok() } } diff --git a/reference/src/fragmentation.rs b/reference/src/fragmentation.rs index da1a862..626fc69 100644 --- a/reference/src/fragmentation.rs +++ b/reference/src/fragmentation.rs @@ -4,7 +4,7 @@ use std::collections::HashMap; use zeroize::Zeroizing; -use crate::application::{ApplicationLayer, CryptoLayer}; +use crate::application::CryptoLayer; use crate::crypto::{Aes256Prp, AES_256_KEY_SIZE}; use crate::proto::*; use crate::result::{byzantine_fault, ReceiveError}; @@ -86,7 +86,7 @@ impl DefragBuffer { } /// Corresponds to the authentication and defragmentation algorithm described in Section 6.1. - pub fn received_fragment( + pub fn received_fragment( &self, mut raw_fragment: Vec, current_time: i64, @@ -98,7 +98,7 @@ impl DefragBuffer { } if let Some(hk_recv) = self.hk_recv.as_ref() { - ::Prp::decrypt_in_place( + C::Prp::decrypt_in_place( hk_recv, (&mut raw_fragment[HEADER_AUTH_START..HEADER_AUTH_END]) .try_into() @@ -113,12 +113,9 @@ impl DefragBuffer { } let n = raw_fragment[PACKET_NONCE_START..HEADER_SIZE].try_into().unwrap(); - let result = vrfy(&n, fragment_no, fragment_count); - if let Err(e) = result { - return Err(e); - } + vrfy(&n, fragment_no, fragment_count)?; - let expiration_time = current_time + App::Crypto::SETTINGS.fragment_assembly_timeout as i64; + let expiration_time = current_time + C::SETTINGS.fragment_assembly_timeout as i64; let mut map = self.fragment_map.borrow_mut(); match map.entry(n) { Entry::Occupied(mut entry) => { diff --git a/reference/src/lib.rs b/reference/src/lib.rs index 415fe06..0d656e0 100644 --- a/reference/src/lib.rs +++ b/reference/src/lib.rs @@ -37,6 +37,7 @@ //! - **AES-256**: Single block encryption of header to harden packet fragmentation protocol //! - **AES-256-GCM**: Authenticated encryption #![warn(missing_docs, rust_2018_idioms)] +#![allow(clippy::too_many_arguments, clippy::type_complexity, clippy::assertions_on_constants)] mod challenge; mod context; diff --git a/reference/src/proto.rs b/reference/src/proto.rs index 779ca53..65947e9 100644 --- a/reference/src/proto.rs +++ b/reference/src/proto.rs @@ -119,7 +119,7 @@ pub(crate) const HANDSHAKE_HELLO_MAX_SIZE: usize = HANDSHAKE_HELLO_MIN_SIZE + RA pub(crate) const HANDSHAKE_RESPONSE_SIZE: usize = P384_PUBLIC_KEY_SIZE + KYBER_CIPHERTEXT_SIZE + AES_GCM_TAG_SIZE + KID_SIZE + AES_GCM_TAG_SIZE; -pub(crate) const HANDSHAKE_COMPLETION_MIN_SIZE: usize = P384_PUBLIC_KEY_SIZE + AES_GCM_TAG_SIZE + 0 + AES_GCM_TAG_SIZE; +pub(crate) const HANDSHAKE_COMPLETION_MIN_SIZE: usize = P384_PUBLIC_KEY_SIZE + AES_GCM_TAG_SIZE + AES_GCM_TAG_SIZE; pub(crate) const HANDSHAKE_COMPLETION_MAX_SIZE: usize = HANDSHAKE_COMPLETION_MIN_SIZE + IDENTITY_MAX_SIZE; pub(crate) const KEY_CONFIRMATION_SIZE: usize = AES_GCM_TAG_SIZE; diff --git a/reference/src/symmetric_state.rs b/reference/src/symmetric_state.rs index e061efb..14d4fd6 100644 --- a/reference/src/symmetric_state.rs +++ b/reference/src/symmetric_state.rs @@ -19,7 +19,7 @@ impl Clone for SymmetricState { Self { k: self.k.clone(), ck: self.ck.clone(), - h: self.h.clone(), + h: self.h, _app: PhantomData, } } diff --git a/reference/src/zeta.rs b/reference/src/zeta.rs index ccfde48..3c333db 100644 --- a/reference/src/zeta.rs +++ b/reference/src/zeta.rs @@ -19,14 +19,14 @@ use crate::symmetric_state::SymmetricState; use crate::LogEvent::*; /// Corresponds to the Zeta State Machine found in Section 4.1. -pub(crate) struct Zeta { - pub ctx: Weak>, +pub(crate) struct Zeta { + pub ctx: Weak>, /// An arbitrary application defined object associated with each session. - pub session_data: Crypto::SessionData, + pub session_data: C::SessionData, /// Is true if the local peer acted as Bob, the responder in the initial key exchange. pub was_bob: bool, - s_remote: Crypto::PublicKey, + s_remote: C::PublicKey, send_counter: u64, key_creation_counter: u64, @@ -38,7 +38,7 @@ pub(crate) struct Zeta { resend_timer: i64, timeout_timer: i64, - pub beta: ZetaAutomata, + pub beta: ZetaAutomata, pub counter_antireplay_window: [u64; COUNTER_WINDOW_MAX_OOO], pub defrag: DefragBuffer, @@ -46,16 +46,16 @@ pub(crate) struct Zeta { /// ZeroTier Secure Session Protocol (ZSSP) Session. /// /// A FIPS/NIST compliant variant of Noise_XK with hybrid Kyber1024 PQ data forward secrecy. -pub struct Session(pub(crate) RefCell>); +pub struct Session(pub(crate) RefCell>); /// Corresponds to State B_2 of the Zeta State Machine found in Section 4.1 - Definition 3. -pub(crate) struct StateB2 { +pub(crate) struct StateB2 { ratchet_state: RatchetState, kid_send: NonZeroU32, pub kid_recv: NonZeroU32, pub hk_send: Zeroizing<[u8; AES_256_KEY_SIZE]>, - e_secret: Crypto::KeyPair, - noise: SymmetricState, + e_secret: C::KeyPair, + noise: SymmetricState, pub defrag: DefragBuffer, } @@ -78,18 +78,18 @@ pub(crate) struct Packet(pub u32, pub [u8; AES_GCM_NONCE_SIZE], pub Vec); /// Corresponds to State A_1 of the Zeta State Machine found in Section 4.1. #[derive(Clone)] -pub(crate) struct StateA1 { - noise: SymmetricState, - e_secret: Crypto::KeyPair, - e1_secret: Crypto::Kem, +pub(crate) struct StateA1 { + noise: SymmetricState, + e_secret: C::KeyPair, + e1_secret: C::Kem, identity: Vec, packet: Packet, } /// Corresponds to the ZKE Automata found in Section 4.1 - Definition 2. -pub(crate) enum ZetaAutomata { +pub(crate) enum ZetaAutomata { Null, - A1(StateA1), + A1(StateA1), A3 { identity: Vec, packet: Packet, @@ -97,8 +97,8 @@ pub(crate) enum ZetaAutomata { S1, S2, R1 { - noise: SymmetricState, - e_secret: Crypto::KeyPair, + noise: SymmetricState, + e_secret: C::KeyPair, k1: Vec, }, R2 { @@ -106,25 +106,25 @@ pub(crate) enum ZetaAutomata { }, } -impl SymmetricState { - fn write_e(&mut self, rng: &RefCell, packet: &mut Vec) -> Crypto::KeyPair { - let e_secret = Crypto::KeyPair::generate(rng.borrow_mut().deref_mut()); +impl SymmetricState { + fn write_e(&mut self, rng: &RefCell, packet: &mut Vec) -> C::KeyPair { + let e_secret = C::KeyPair::generate(rng.borrow_mut().deref_mut()); let pub_key = e_secret.public_key_bytes(); packet.extend(&pub_key); self.mix_hash(&pub_key); self.mix_key(&pub_key); e_secret } - fn read_e(&mut self, i: &mut usize, packet: &Vec) -> Option { + fn read_e(&mut self, i: &mut usize, packet: &Vec) -> Option { let j = *i + P384_PUBLIC_KEY_SIZE; let pub_key = &packet[*i..j]; self.mix_hash(pub_key); self.mix_key(pub_key); *i = j; - Crypto::PublicKey::from_bytes((pub_key).try_into().unwrap()) + C::PublicKey::from_bytes((pub_key).try_into().unwrap()) } - fn mix_dh(&mut self, secret: &Crypto::KeyPair, remote: &Crypto::PublicKey) { - let ecdh = Zeroizing::new(secret.agree(&remote)); + fn mix_dh(&mut self, secret: &C::KeyPair, remote: &C::PublicKey) { + let ecdh = Zeroizing::new(secret.agree(remote)); self.mix_key(ecdh.as_ref()); } } @@ -161,24 +161,24 @@ fn gen_kid(session_map: &HashMap, rng: &mut impl RngCore) -> N } } } -fn remap( - session: &Arc>, - zeta: &Zeta, - rng: &RefCell, - session_map: &SessionMap, +fn remap( + session: &Arc>, + zeta: &Zeta, + rng: &RefCell, + session_map: &SessionMap, ) -> NonZeroU32 { let mut session_map = session_map.borrow_mut(); let weak = if let Some(Some(weak)) = zeta.key_ref(true).recv.kid.as_ref().map(|kid| session_map.remove(kid)) { weak } else { - Arc::downgrade(&session) + Arc::downgrade(session) }; let new_kid_recv = gen_kid(session_map.deref(), rng.borrow_mut().deref_mut()); session_map.insert(new_kid_recv, weak); new_kid_recv } -impl Zeta { +impl Zeta { pub(crate) fn check_counter_window(&self, c: u64) -> bool { let slot = &self.counter_antireplay_window[c as usize % self.counter_antireplay_window.len()]; let adj_counter = c.saturating_add(1); @@ -231,23 +231,23 @@ impl Zeta { c, c >= self .key_creation_counter - .saturating_add(Crypto::SETTINGS.rekey_after_key_uses), + .saturating_add(C::SETTINGS.rekey_after_key_uses), )) } } -fn create_a1_state( - rng: &RefCell<::Rng>, - s_remote: &::PublicKey, +fn create_a1_state( + rng: &RefCell, + s_remote: &C::PublicKey, kid_recv: NonZeroU32, ratchet_state1: &RatchetState, ratchet_state2: Option<&RatchetState>, identity: Vec, -) -> StateA1 { +) -> StateA1 { // <- s // ... // -> e, es, e1 - let mut noise = SymmetricState::::initialize(PROTOCOL_NAME_NOISE_XK); + let mut noise = SymmetricState::::initialize(PROTOCOL_NAME_NOISE_XK); let mut x1 = Vec::new(); // Noise process prologue. let kid = kid_recv.get().to_be_bytes(); @@ -260,7 +260,7 @@ fn create_a1_state( noise.mix_dh(&e_secret, s_remote); // Process message pattern 1 e1 token. let i = x1.len(); - let (e1_secret, e1_public) = ::Kem::generate(rng.borrow_mut().deref_mut()); + let (e1_secret, e1_public) = C::Kem::generate(rng.borrow_mut().deref_mut()); x1.extend(&e1_public); noise.encrypt_and_hash_in_place(to_nonce(PACKET_TYPE_HANDSHAKE_HELLO, 0), i, &mut x1); // Process message pattern 1 payload. @@ -285,23 +285,23 @@ fn create_a1_state( } } /// Corresponds to Transition Algorithm 1 found in Section 4.3. -pub(crate) fn trans_to_a1( +pub(crate) fn trans_to_a1>( mut app: App, - ctx: &Arc>, - s_remote: ::PublicKey, - session_data: ::SessionData, + ctx: &Arc>, + s_remote: C::PublicKey, + session_data: C::SessionData, identity: Vec, send: impl FnOnce(&Packet), -) -> Result>, OpenError> { +) -> Result>, OpenError> { let ratchet_states = app .restore_by_identity(&s_remote, &session_data) - .map_err(|e| OpenError::StorageError(e))?; + .map_err(OpenError::StorageError)?; let RatchetStates { state1, state2 } = ratchet_states.unwrap_or_default(); let mut session_map = ctx.session_map.borrow_mut(); let kid_recv = gen_kid(session_map.deref(), ctx.rng.borrow_mut().deref_mut()); - let a1 = create_a1_state::(&ctx.rng, &s_remote, kid_recv, &state1, state2.as_ref(), identity); + let a1 = create_a1_state::(&ctx.rng, &s_remote, kid_recv, &state1, state2.as_ref(), identity); let packet = a1.packet.clone(); let (hk_recv, hk_send) = a1.noise.get_ask(LABEL_HEADER_KEY); @@ -321,8 +321,8 @@ pub(crate) fn trans_to_a1( ratchet_state1: state1, ratchet_state2: state2, hk_send, - resend_timer: current_time + ::SETTINGS.resend_time as i64, - timeout_timer: current_time + ::SETTINGS.initial_offer_timeout as i64, + resend_timer: current_time + C::SETTINGS.resend_time as i64, + timeout_timer: current_time + C::SETTINGS.initial_offer_timeout as i64, beta: ZetaAutomata::A1(a1), }; zeta.key_mut(true).recv.kid = Some(kid_recv); @@ -338,14 +338,14 @@ pub(crate) fn trans_to_a1( Ok(session) } /// Corresponds to Algorithm 13 found in Section 5. -pub(crate) fn respond_to_challenge( - zeta: &mut Zeta, - rng: &RefCell<::Rng>, +pub(crate) fn respond_to_challenge( + zeta: &mut Zeta, + rng: &RefCell, challenge: &[u8; CHALLENGE_SIZE], ) { if let ZetaAutomata::A1(StateA1 { packet: Packet(_, _, x1), .. }) = &mut zeta.beta { let response_start = x1.len() - CHALLENGE_SIZE; - respond_to_challenge_in_place::<::Rng, ::Hash>( + respond_to_challenge_in_place::( rng.borrow_mut().deref_mut(), challenge, (&mut x1[response_start..]).try_into().unwrap(), @@ -353,9 +353,9 @@ pub(crate) fn respond_to_challenge( } } /// Corresponds to Transition Algorithm 2 found in Section 4.3. -pub(crate) fn received_x1_trans( +pub(crate) fn received_x1_trans>( app: &mut App, - ctx: &ContextInner, + ctx: &ContextInner, n: [u8; AES_GCM_NONCE_SIZE], mut x1: Vec, send: impl FnOnce(&Packet, &[u8; AES_256_KEY_SIZE]), @@ -368,10 +368,10 @@ pub(crate) fn received_x1_trans( if !(HANDSHAKE_HELLO_MIN_SIZE..=HANDSHAKE_HELLO_MAX_SIZE).contains(&x1.len()) { return Err(byzantine_fault!(InvalidPacket, true)); } - if &n[AES_GCM_NONCE_SIZE - 8..] != &x1[x1.len() - 8..] { + if n[AES_GCM_NONCE_SIZE - 8..] != x1[x1.len() - 8..] { return Err(byzantine_fault!(FailedAuth, true)); } - let mut noise = SymmetricState::::initialize(PROTOCOL_NAME_NOISE_XK); + let mut noise = SymmetricState::::initialize(PROTOCOL_NAME_NOISE_XK); let mut i = 0; // Noise process prologue. let j = i + KID_SIZE; @@ -432,7 +432,7 @@ pub(crate) fn received_x1_trans( noise.mix_dh(&e_secret, &e_remote); // Process message pattern 2 ekem1 token. let i = x2.len(); - let (ekem1, ekem1_secret) = ::Kem::encapsulate( + let (ekem1, ekem1_secret) = C::Kem::encapsulate( ctx.rng.borrow_mut().deref_mut(), (&x1[e1_start..e1_end]).try_into().unwrap(), ) @@ -479,11 +479,11 @@ pub(crate) fn received_x1_trans( Ok(()) } /// Corresponds to Transition Algorithm 3 found in Section 4.3. -pub(crate) fn received_x2_trans( - zeta: &mut Zeta, - session: &Arc>, +pub(crate) fn received_x2_trans>( + zeta: &mut Zeta, + session: &Arc>, app: &mut App, - ctx: &Arc>, + ctx: &Arc>, kid: NonZeroU32, n: [u8; AES_GCM_NONCE_SIZE], mut x2: Vec, @@ -499,7 +499,7 @@ pub(crate) fn received_x2_trans( return Err(byzantine_fault!(UnknownLocalKeyId, true)); } let (_, c) = from_nonce(&n); - if c >= COUNTER_WINDOW_MAX_SKIP_AHEAD || &n[AES_GCM_NONCE_SIZE - 3..] != &x2[x2.len() - 3..] { + if c >= COUNTER_WINDOW_MAX_SKIP_AHEAD || n[AES_GCM_NONCE_SIZE - 3..] != x2[x2.len() - 3..] { return Err(byzantine_fault!(FailedAuth, true)); } let mut should_warn_missing_ratchet = false; @@ -536,9 +536,9 @@ pub(crate) fn received_x2_trans( let payload: [u8; KID_SIZE] = x2[i..j].try_into().unwrap(); let tag = x2[j..k].try_into().unwrap(); // Check for which ratchet key Bob wants to use. - let test_ratchet_key = |ratchet_key| -> Option<(NonZeroU32, SymmetricState)> { + let test_ratchet_key = |ratchet_key| -> Option<(NonZeroU32, SymmetricState)> { let mut noise = noise.clone(); - let mut payload = payload.clone(); + let mut payload = payload; // Process message pattern 2 psk token. noise.mix_key_and_hash(ratchet_key); // Process message pattern 2 payload. @@ -619,8 +619,8 @@ pub(crate) fn received_x2_trans( zeta.ratchet_state1 = new_ratchet_state; let current_time = app.time(); zeta.key_creation_counter = zeta.send_counter; - zeta.resend_timer = current_time + ::SETTINGS.resend_time as i64; - zeta.timeout_timer = current_time + ::SETTINGS.initial_offer_timeout as i64; + zeta.resend_timer = current_time + C::SETTINGS.resend_time as i64; + zeta.timeout_timer = current_time + C::SETTINGS.initial_offer_timeout as i64; let packet = Packet(kid_send.get(), n, x3); zeta.beta = ZetaAutomata::A3 { identity, packet: packet.clone() }; @@ -639,8 +639,8 @@ pub(crate) fn received_x2_trans( } result.map(|_| should_warn_missing_ratchet) } -fn send_control( - zeta: &mut Zeta, +fn send_control( + zeta: &mut Zeta, packet_type: u8, mut payload: Vec, send: impl FnOnce(&Packet, Option<&[u8; AES_256_KEY_SIZE]>), @@ -648,7 +648,7 @@ fn send_control( if let Some((c, _)) = zeta.get_counter() { if let (Some(kek), Some(kid)) = (zeta.key_ref(false).send.kek.as_ref(), zeta.key_ref(false).send.kid) { let nonce = to_nonce(packet_type, c); - let tag = ::Aead::encrypt_in_place(kek, &nonce, None, &mut payload); + let tag = C::Aead::encrypt_in_place(kek, &nonce, None, &mut payload); payload.extend(tag); send(&Packet(kid.get(), nonce, payload), Some(&zeta.hk_send)); @@ -661,14 +661,14 @@ fn send_control( } } /// Corresponds to Transition Algorithm 4 found in Section 4.3. -pub(crate) fn received_x3_trans( - zeta: StateB2, +pub(crate) fn received_x3_trans>( + zeta: StateB2, app: &mut App, - ctx: &Arc>, + ctx: &Arc>, kid: NonZeroU32, mut x3: Vec, send: impl FnOnce(&Packet, Option<&[u8; AES_256_KEY_SIZE]>), -) -> Result<(Arc>, bool), ReceiveError> { +) -> Result<(Arc>, bool), ReceiveError> { use FaultType::*; // -> s, se if !(HANDSHAKE_COMPLETION_MIN_SIZE..=HANDSHAKE_COMPLETION_MAX_SIZE).contains(&x3.len()) { @@ -687,8 +687,8 @@ pub(crate) fn received_x3_trans( if !noise.decrypt_and_hash_in_place(to_nonce(PACKET_TYPE_HANDSHAKE_COMPLETION, 1), &mut x3[i..j], tag) { return Err(byzantine_fault!(FailedAuth, true)); } - let s_remote = ::PublicKey::from_bytes((&x3[i..j]).try_into().unwrap()) - .ok_or(byzantine_fault!(FailedAuth, true))?; + let s_remote = + C::PublicKey::from_bytes((&x3[i..j]).try_into().unwrap()).ok_or(byzantine_fault!(FailedAuth, true))?; i = k; // Process message pattern 3 se token. noise.mix_dh(&zeta.e_secret, &s_remote); @@ -712,7 +712,7 @@ pub(crate) fn received_x3_trans( let create_reject = || { let mut d = Vec::::new(); let n = to_nonce(PACKET_TYPE_SESSION_REJECTED, c); - let tag = ::Aead::encrypt_in_place(&kek_send, &n, None, &mut []); + let tag = C::Aead::encrypt_in_place(&kek_send, &n, None, &mut []); d.extend(&tag); // We just used a counter with this key, but we are not storing // the fact we used it in memory. This is currently ok because the @@ -726,7 +726,7 @@ pub(crate) fn received_x3_trans( let RatchetStates { state1, state2 } = rss.unwrap_or_default(); let mut should_warn_missing_ratchet = false; - if (&zeta.ratchet_state != &state1) & (Some(&zeta.ratchet_state) != state2.as_ref()) { + if (zeta.ratchet_state != state1) & (Some(&zeta.ratchet_state) != state2.as_ref()) { if !responder_disallows_downgrade && zeta.ratchet_state.fingerprint().is_none() { should_warn_missing_ratchet = true; } else { @@ -757,7 +757,7 @@ pub(crate) fn received_x3_trans( let mut c1 = Vec::new(); let n = to_nonce(PACKET_TYPE_KEY_CONFIRM, c); - let tag = ::Aead::encrypt_in_place(&kek_send, &n, None, &mut []); + let tag = C::Aead::encrypt_in_place(&kek_send, &n, None, &mut []); c1.extend(&tag); let (nk1, nk2) = noise.split(); @@ -787,8 +787,8 @@ pub(crate) fn received_x3_trans( ratchet_state1: new_ratchet_state, ratchet_state2: None, hk_send: zeta.hk_send.clone(), - resend_timer: current_time + ::SETTINGS.resend_time as i64, - timeout_timer: current_time + ::SETTINGS.rekey_timeout as i64, + resend_timer: current_time + C::SETTINGS.resend_time as i64, + timeout_timer: current_time + C::SETTINGS.rekey_timeout as i64, beta: ZetaAutomata::S1, counter_antireplay_window: std::array::from_fn(|_| 0), defrag: zeta.defrag, @@ -811,10 +811,10 @@ pub(crate) fn received_x3_trans( } } /// Corresponds to Transition Algorithm 5 found in Section 4.3. -pub(crate) fn received_c1_trans( - zeta: &mut Zeta, +pub(crate) fn received_c1_trans>( + zeta: &mut Zeta, app: &mut App, - rng: &RefCell<::Rng>, + rng: &RefCell, kid: NonZeroU32, n: [u8; AES_GCM_NONCE_SIZE], c1: Vec, @@ -842,7 +842,7 @@ pub(crate) fn received_c1_trans( .as_ref() .ok_or(byzantine_fault!(OutOfSequence, true))?; let tag = c1[..].try_into().unwrap(); - if !::Aead::decrypt_in_place(specified_key, &n, None, &mut [], tag) { + if !C::Aead::decrypt_in_place(specified_key, &n, None, &mut [], tag) { return Err(byzantine_fault!(FailedAuth, true)); } let (_, c) = from_nonce(&n); @@ -872,17 +872,14 @@ pub(crate) fn received_c1_trans( zeta.ratchet_state2 = None; zeta.key_index ^= true; - let r = rng.borrow_mut().next_u64() % ::SETTINGS.rekey_time_max_jitter; - zeta.timeout_timer = app.time() - + ::SETTINGS - .rekey_after_time - .saturating_sub(r) as i64; + let r = rng.borrow_mut().next_u64() % C::SETTINGS.rekey_time_max_jitter; + zeta.timeout_timer = app.time() + C::SETTINGS.rekey_after_time.saturating_sub(r) as i64; zeta.resend_timer = i64::MAX; zeta.beta = ZetaAutomata::S2; } } let c2 = Vec::new(); - if !send_control::(zeta, PACKET_TYPE_ACK, c2, send) { + if !send_control::(zeta, PACKET_TYPE_ACK, c2, send) { return Err(byzantine_fault!(OutOfSequence, true)); } @@ -890,10 +887,10 @@ pub(crate) fn received_c1_trans( } /// Corresponds to the trivial Transition Algorithm described for processing C_2 packets found in /// Section 4.3. -pub(crate) fn received_c2_trans( - zeta: &mut Zeta, +pub(crate) fn received_c2_trans>( + zeta: &mut Zeta, app: &mut App, - rng: &RefCell<::Rng>, + rng: &RefCell, kid: NonZeroU32, n: [u8; AES_GCM_NONCE_SIZE], c2: Vec, @@ -913,13 +910,7 @@ pub(crate) fn received_c2_trans( } let tag = c2[..].try_into().unwrap(); - if !::Aead::decrypt_in_place( - zeta.key_ref(false).recv.kek.as_ref().unwrap(), - &n, - None, - &mut [], - tag, - ) { + if !C::Aead::decrypt_in_place(zeta.key_ref(false).recv.kek.as_ref().unwrap(), &n, None, &mut [], tag) { return Err(byzantine_fault!(FailedAuth, true)); } let (_, c) = from_nonce(&n); @@ -927,19 +918,16 @@ pub(crate) fn received_c2_trans( return Err(byzantine_fault!(ExpiredCounter, true)); } - let r = rng.borrow_mut().next_u64() % ::SETTINGS.rekey_time_max_jitter; - zeta.timeout_timer = app.time() - + ::SETTINGS - .rekey_after_time - .saturating_sub(r) as i64; + let r = rng.borrow_mut().next_u64() % C::SETTINGS.rekey_time_max_jitter; + zeta.timeout_timer = app.time() + C::SETTINGS.rekey_after_time.saturating_sub(r) as i64; zeta.resend_timer = i64::MAX; zeta.beta = ZetaAutomata::S2; Ok(()) } /// Corresponds to the trivial Transition Algorithm described for processing D packets found in /// Section 4.3. -pub(crate) fn received_d_trans( - zeta: &mut Zeta, +pub(crate) fn received_d_trans( + zeta: &mut Zeta, kid: NonZeroU32, n: [u8; AES_GCM_NONCE_SIZE], d: Vec, @@ -954,13 +942,7 @@ pub(crate) fn received_d_trans( } let tag = d[..].try_into().unwrap(); - if !::Aead::decrypt_in_place( - zeta.key_ref(true).recv.kek.as_ref().unwrap(), - &n, - None, - &mut [], - tag, - ) { + if !C::Aead::decrypt_in_place(zeta.key_ref(true).recv.kek.as_ref().unwrap(), &n, None, &mut [], tag) { return Err(byzantine_fault!(FailedAuth, true)); } let (_, c) = from_nonce(&n); @@ -972,10 +954,10 @@ pub(crate) fn received_d_trans( Ok(()) } /// Corresponds to the timer rules of the Zeta State Machine found in Section 4.1 - Definition 3. -pub(crate) fn service( - zeta: &mut Zeta, - session: &Arc>, - ctx: &Arc>, +pub(crate) fn service>( + zeta: &mut Zeta, + session: &Arc>, + ctx: &Arc>, app: &mut App, current_time: i64, send: impl FnOnce(&Packet, Option<&[u8; AES_256_KEY_SIZE]>), @@ -984,7 +966,7 @@ pub(crate) fn service( timeout_trans(zeta, session, app, ctx, current_time, send); } else if zeta.resend_timer <= current_time { // Corresponds to the resend timer rules found in Section 4.1 - Definition 3. - zeta.resend_timer = current_time + ::SETTINGS.resend_time as i64; + zeta.resend_timer = current_time + C::SETTINGS.resend_time as i64; let (p, control_payload) = match &zeta.beta { ZetaAutomata::Null => return, @@ -1011,15 +993,15 @@ pub(crate) fn service( } }; - send_control::(zeta, p, control_payload, send); + send_control::(zeta, p, control_payload, send); } } /// Corresponds to the timeout timer Transition Algorithm described in Section 4.1 - Definition 3. -fn timeout_trans( - zeta: &mut Zeta, - session: &Arc>, +fn timeout_trans>( + zeta: &mut Zeta, + session: &Arc>, app: &mut App, - ctx: &Arc>, + ctx: &Arc>, current_time: i64, send: impl FnOnce(&Packet, Option<&[u8; AES_256_KEY_SIZE]>), ) { @@ -1031,9 +1013,9 @@ fn timeout_trans( } else { log!(app, TimeoutX3(session)); } - let new_kid_recv = remap(session, &zeta, &ctx.rng, &ctx.session_map); + let new_kid_recv = remap(session, zeta, &ctx.rng, &ctx.session_map); - let a1 = create_a1_state::( + let a1 = create_a1_state::( &ctx.rng, &zeta.s_remote, new_kid_recv, @@ -1047,8 +1029,8 @@ fn timeout_trans( zeta.hk_send = hk_send; *zeta.key_mut(true) = DuplexKey::default(); zeta.key_mut(true).recv.kid = Some(new_kid_recv); - zeta.resend_timer = current_time + ::SETTINGS.resend_time as i64; - zeta.timeout_timer = current_time + ::SETTINGS.initial_offer_timeout as i64; + zeta.resend_timer = current_time + C::SETTINGS.resend_time as i64; + zeta.timeout_timer = current_time + C::SETTINGS.initial_offer_timeout as i64; zeta.beta = ZetaAutomata::A1(a1); zeta.defrag = DefragBuffer::new(Some(hk_recv)); @@ -1057,7 +1039,7 @@ fn timeout_trans( ZetaAutomata::S2 => { // Corresponds to Transition Algorithm 6 found in Section 4.3. log!(app, StartedRekeyingSentK1(session)); - let new_kid_recv = remap(session, &zeta, &ctx.rng, &ctx.session_map); + let new_kid_recv = remap(session, zeta, &ctx.rng, &ctx.session_map); // -> s // <- s // ... @@ -1081,11 +1063,11 @@ fn timeout_trans( noise.encrypt_and_hash_in_place(to_nonce(PACKET_TYPE_REKEY_INIT, 0), i, &mut k1); zeta.key_mut(true).recv.kid = Some(new_kid_recv); - zeta.timeout_timer = current_time + ::SETTINGS.rekey_timeout as i64; - zeta.resend_timer = current_time + ::SETTINGS.resend_time as i64; + zeta.timeout_timer = current_time + C::SETTINGS.rekey_timeout as i64; + zeta.resend_timer = current_time + C::SETTINGS.resend_time as i64; zeta.beta = ZetaAutomata::R1 { noise, e_secret, k1: k1.clone() }; - send_control::(zeta, PACKET_TYPE_REKEY_INIT, k1, send); + send_control::(zeta, PACKET_TYPE_REKEY_INIT, k1, send); } ZetaAutomata::S1 { .. } => { log!(app, TimeoutKeyConfirm(session)); @@ -1102,13 +1084,13 @@ fn timeout_trans( } } /// Corresponds to Transition Algorithm 7 found in Section 4.3. -pub(crate) fn received_k1_trans( - zeta: &mut Zeta, - session: &Arc>, +pub(crate) fn received_k1_trans>( + zeta: &mut Zeta, + session: &Arc>, app: &mut App, - rng: &RefCell<::Rng>, - session_map: &SessionMap, - s_secret: &::KeyPair, + rng: &RefCell, + session_map: &SessionMap, + s_secret: &C::KeyPair, kid: NonZeroU32, n: [u8; AES_GCM_NONCE_SIZE], mut k1: Vec, @@ -1139,7 +1121,7 @@ pub(crate) fn received_k1_trans( let i = k1.len() - AES_GCM_TAG_SIZE; let tag = k1[i..].try_into().unwrap(); - if !::Aead::decrypt_in_place( + if !C::Aead::decrypt_in_place( zeta.key_ref(false).recv.kek.as_ref().unwrap(), &n, None, @@ -1156,7 +1138,7 @@ pub(crate) fn received_k1_trans( let result = (|| { let mut i = 0; - let mut noise = SymmetricState::::initialize(PROTOCOL_NAME_NOISE_KK); + let mut noise = SymmetricState::::initialize(PROTOCOL_NAME_NOISE_KK); // Noise process prologue. noise.mix_hash(&zeta.s_remote.to_bytes()); noise.mix_hash(&s_secret.public_key_bytes()); @@ -1184,10 +1166,10 @@ pub(crate) fn received_k1_trans( // Process message pattern 2 ee token. noise.mix_dh(&e_secret, &e_remote); // Process message pattern 2 se token. - noise.mix_dh(&s_secret, &e_remote); + noise.mix_dh(s_secret, &e_remote); // Process message pattern 2 payload. let i = k2.len(); - let new_kid_recv = remap(session, &zeta, rng, session_map); + let new_kid_recv = remap(session, zeta, rng, session_map); k2.extend(&new_kid_recv.get().to_be_bytes()); noise.encrypt_and_hash_in_place(to_nonce(PACKET_TYPE_REKEY_COMPLETE, 0), i, &mut k2); @@ -1220,11 +1202,11 @@ pub(crate) fn received_k1_trans( zeta.ratchet_state1 = new_ratchet_state; let current_time = app.time(); zeta.key_creation_counter = zeta.send_counter; - zeta.timeout_timer = current_time + ::SETTINGS.rekey_timeout as i64; - zeta.resend_timer = current_time + ::SETTINGS.resend_time as i64; + zeta.timeout_timer = current_time + C::SETTINGS.rekey_timeout as i64; + zeta.resend_timer = current_time + C::SETTINGS.resend_time as i64; zeta.beta = ZetaAutomata::R2 { k2: k2.clone() }; - send_control::(zeta, PACKET_TYPE_REKEY_COMPLETE, k2, send); + send_control::(zeta, PACKET_TYPE_REKEY_COMPLETE, k2, send); Ok(()) })(); if matches!(result, Err(ReceiveError::ByzantineFault { .. })) { @@ -1233,8 +1215,8 @@ pub(crate) fn received_k1_trans( result } /// Corresponds to Transition Algorithm 8 found in Section 4.3. -pub(crate) fn received_k2_trans( - zeta: &mut Zeta, +pub(crate) fn received_k2_trans>( + zeta: &mut Zeta, app: &mut App, kid: NonZeroU32, n: [u8; AES_GCM_NONCE_SIZE], @@ -1257,7 +1239,7 @@ pub(crate) fn received_k2_trans( let i = k2.len() - AES_GCM_TAG_SIZE; let tag = k2[i..].try_into().unwrap(); - if !::Aead::decrypt_in_place( + if !C::Aead::decrypt_in_place( zeta.key_ref(false).recv.kek.as_ref().unwrap(), &n, None, @@ -1319,12 +1301,12 @@ pub(crate) fn received_k2_trans( zeta.key_index ^= true; let current_time = app.time(); zeta.key_creation_counter = zeta.send_counter; - zeta.timeout_timer = current_time + ::SETTINGS.rekey_timeout as i64; - zeta.resend_timer = current_time + ::SETTINGS.resend_time as i64; + zeta.timeout_timer = current_time + C::SETTINGS.rekey_timeout as i64; + zeta.resend_timer = current_time + C::SETTINGS.resend_time as i64; zeta.beta = ZetaAutomata::S1; let c1 = Vec::new(); - send_control::(zeta, PACKET_TYPE_KEY_CONFIRM, c1, send); + send_control::(zeta, PACKET_TYPE_KEY_CONFIRM, c1, send); Ok(()) } else { unreachable!() @@ -1336,8 +1318,8 @@ pub(crate) fn received_k2_trans( result } /// Corresponds to Algorithm 9 found in Section 4.3. -pub(crate) fn send_payload( - zeta: &mut Zeta, +pub(crate) fn send_payload( + zeta: &mut Zeta, mut payload: Vec, send: impl FnOnce(&Packet, Option<&[u8; AES_256_KEY_SIZE]>) -> Result<(), SendError>, ) -> Result<(), SendError> { @@ -1359,7 +1341,7 @@ pub(crate) fn send_payload( } let n = to_nonce(PACKET_TYPE_DATA, c); - let tag = Crypto::Aead::encrypt_in_place(zeta.key_ref(false).send.nk.as_ref().unwrap(), &n, None, &mut payload); + let tag = C::Aead::encrypt_in_place(zeta.key_ref(false).send.nk.as_ref().unwrap(), &n, None, &mut payload); payload.extend(&tag); send( @@ -1372,8 +1354,8 @@ pub(crate) fn send_payload( } } /// Corresponds to Algorithm 10 found in Section 4.3. -pub(crate) fn received_payload_in_place( - zeta: &mut Zeta, +pub(crate) fn received_payload_in_place( + zeta: &mut Zeta, kid: NonZeroU32, n: [u8; AES_GCM_NONCE_SIZE], payload: &mut Vec, @@ -1397,7 +1379,7 @@ pub(crate) fn received_payload_in_place( let specified_key = zeta.key_ref(is_other).recv.nk.as_ref(); let specified_key = specified_key.ok_or(byzantine_fault!(OutOfSequence, true))?; let tag = payload[i..].try_into().unwrap(); - if !::Aead::decrypt_in_place(specified_key, &n, None, &mut payload[..i], &tag) { + if !C::Aead::decrypt_in_place(specified_key, &n, None, &mut payload[..i], &tag) { return Err(byzantine_fault!(FailedAuth, true)); } let (_, c) = from_nonce(&n); @@ -1411,7 +1393,7 @@ pub(crate) fn received_payload_in_place( Ok(()) } -impl Session { +impl Session { /// Mark a session as expired. This will make it impossible for this session to successfully /// receive or send data or control packets. It is recommended to simply `drop` the session /// instead, but this can provide some reassurance in complex shared ownership situations. @@ -1420,7 +1402,7 @@ impl Session { } } -impl Drop for Session { +impl Drop for Session { fn drop(&mut self) { self.expire(); } diff --git a/whitepaper/zssp.pdf b/whitepaper/zssp.pdf index 2170db8..b0e7680 100644 Binary files a/whitepaper/zssp.pdf and b/whitepaper/zssp.pdf differ