diff --git a/src/opflags.rs b/src/opflags.rs index 02ff57c..34277c5 100644 --- a/src/opflags.rs +++ b/src/opflags.rs @@ -5,6 +5,7 @@ use subtle::{Choice, ConstantTimeEq}; use crate::strobe::Role; #[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[repr(transparent)] pub struct OpFlags(u8); impl OpFlags { diff --git a/src/strobe.rs b/src/strobe.rs index d3f35ba..20aa4a7 100644 --- a/src/strobe.rs +++ b/src/strobe.rs @@ -1,4 +1,4 @@ -use subtle::{Choice, ConstantTimeEq}; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeLess}; use crate::{ GarbledError, STROBE_VERSION, @@ -162,7 +162,7 @@ impl StrobeState { fn increment_position(&mut self, increment: usize) { self.position += increment; - if self.position == self.rate { + if self.position.ct_eq(&self.rate).into() { self.permutation_f(); } } @@ -240,8 +240,15 @@ impl StrobeState { /// input, and like `overwrite` in that we do not mutate (or take) any input. fn zero_state(&mut self, mut bytes_to_zero: usize) { // Do the zero-writing in chunks - while bytes_to_zero > 0 { - let slice_len = core::cmp::min(self.rate - self.position, bytes_to_zero); + while bytes_to_zero.ct_ne(&0).into() { + let min_slice = (self.rate - self.position) as u32; + let to_zero = bytes_to_zero as u32; + + let slice_len = ConditionallySelectable::conditional_select( + &min_slice, + &to_zero, + to_zero.ct_lt(&min_slice), + ) as usize; self.state.0[self.position..(self.position + slice_len)].fill(0); @@ -282,7 +289,7 @@ impl StrobeState { /// Performs the state / data transformation that corresponds to the given flags. If `more` is /// given, this will treat `data` as a continuation of the data given in the previous /// call to `operate`. - fn operate(&mut self, flags: OpFlags, data: &mut [u8], more: Choice) { + fn operate(&mut self, mut flags: OpFlags, data: &mut [u8], more: Choice) { self.prev_flags = flags; // If `more` isn't set, this is a new operation. Do the begin_op sequence @@ -291,7 +298,7 @@ impl StrobeState { } // Meta-ness is only relevant for `begin_op`. Remove it to simplify the below logic. - let flags = flags & !OpFlags::META; + flags &= !OpFlags::META; // Flags that don't pass this assertion should normally call `absorb`, but `absorb` does not mutate, // so the implementor should have used operate_no_mutate instead @@ -309,7 +316,7 @@ impl StrobeState { /// Performs the state transformation that corresponds to the given flags. If `more` is given, /// this will treat `data` as a continuation of the data given in the previous call to /// `operate`. This uses non-mutating variants of the specializations of the `duplex` function. - fn operate_no_mutate(&mut self, flags: OpFlags, data: &[u8], more: Choice) { + fn operate_no_mutate(&mut self, mut flags: OpFlags, data: &[u8], more: Choice) { self.prev_flags = flags; // If `more` isn't set, this is a new operation. Do the begin_op sequence @@ -318,14 +325,11 @@ impl StrobeState { } // Meta-ness is only relevant for `begin_op`. Remove it to simplify the below logic. - let flags = flags & !OpFlags::META; + flags &= !OpFlags::META; // Flags that trigger the assertion to fail are mutating operations. // RATCHET is special cased to never call operate/operate_no_mutate directly - debug_assert!( - flags != ops::PRF && !bool::from(flags.contains(OpFlags::CIPHER | OpFlags::TRANSPORT)) - || bool::from(flags.contains(OpFlags::INBOUND)) - ); + debug_assert!(flags == ops::KEY || !bool::from(flags.contains(OpFlags::CIPHER))); // There are no non-mutating variants of things with flags & (C | T | I) == C | T if flags.contains(OpFlags::CIPHER).into() { @@ -339,7 +343,7 @@ impl StrobeState { } } - fn recv_mac_inner(&mut self, mac_copy: &mut [u8], flags: OpFlags) -> Result<(), GarbledError> { + fn recv_mac_inner(&mut self, flags: OpFlags, mac_copy: &mut [u8]) -> Result<(), GarbledError> { // recv_mac can never be streamed self.operate(flags, mac_copy, Choice::from(0u8)); @@ -355,17 +359,17 @@ impl StrobeState { pub fn recv_mac(&mut self, mac: &[u8; N]) -> Result<(), GarbledError> { let mut mac_copy = *mac; - self.recv_mac_inner(&mut mac_copy, ops::RECV_MAC) + self.recv_mac_inner(ops::RECV_MAC, &mut mac_copy) } pub fn meta_recv_mac(&mut self, mac: &[u8; N]) -> Result<(), GarbledError> { let mut mac_copy = *mac; - self.recv_mac_inner(&mut mac_copy, ops::META_RECV_MAC) + self.recv_mac_inner(ops::META_RECV_MAC, &mut mac_copy) } - fn ratchet_inner(&mut self, num_bytes_to_zero: usize, flags: OpFlags) { - let more = self.prev_flags.bits().ct_eq(&flags.bits()); + fn ratchet_inner(&mut self, mut flags: OpFlags, num_bytes_to_zero: usize) { + let more = self.prev_flags.ct_eq(&flags); // We don't make an `operate` call, since this is a super special case. That means we have // to make the `begin_op` call manually. @@ -375,15 +379,17 @@ impl StrobeState { self.begin_op(flags); } + flags &= !OpFlags::META; + self.zero_state(num_bytes_to_zero); } pub fn ratchet(&mut self, num_bytes_to_zero: usize) { - self.ratchet_inner(num_bytes_to_zero, ops::RATCHET); + self.ratchet_inner(ops::RATCHET, num_bytes_to_zero); } pub fn meta_ratchet(&mut self, num_bytes_to_zero: usize) { - self.ratchet_inner(num_bytes_to_zero, ops::META_RATCHET); + self.ratchet_inner(ops::META_RATCHET, num_bytes_to_zero); } define_mut_operations! {