A whimsical STROBE based encryption protocol
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

Constant time more things, minor consistency fixes

+26 -19
+1
src/opflags.rs
··· 5 5 use crate::strobe::Role; 6 6 7 7 #[derive(Clone, Copy, PartialEq, Eq, Hash)] 8 + #[repr(transparent)] 8 9 pub struct OpFlags(u8); 9 10 10 11 impl OpFlags {
+25 -19
src/strobe.rs
··· 1 - use subtle::{Choice, ConstantTimeEq}; 1 + use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeLess}; 2 2 3 3 use crate::{ 4 4 GarbledError, STROBE_VERSION, ··· 162 162 fn increment_position(&mut self, increment: usize) { 163 163 self.position += increment; 164 164 165 - if self.position == self.rate { 165 + if self.position.ct_eq(&self.rate).into() { 166 166 self.permutation_f(); 167 167 } 168 168 } ··· 240 240 /// input, and like `overwrite` in that we do not mutate (or take) any input. 241 241 fn zero_state(&mut self, mut bytes_to_zero: usize) { 242 242 // Do the zero-writing in chunks 243 - while bytes_to_zero > 0 { 244 - let slice_len = core::cmp::min(self.rate - self.position, bytes_to_zero); 243 + while bytes_to_zero.ct_ne(&0).into() { 244 + let min_slice = (self.rate - self.position) as u32; 245 + let to_zero = bytes_to_zero as u32; 246 + 247 + let slice_len = ConditionallySelectable::conditional_select( 248 + &min_slice, 249 + &to_zero, 250 + to_zero.ct_lt(&min_slice), 251 + ) as usize; 245 252 246 253 self.state.0[self.position..(self.position + slice_len)].fill(0); 247 254 ··· 282 289 /// Performs the state / data transformation that corresponds to the given flags. If `more` is 283 290 /// given, this will treat `data` as a continuation of the data given in the previous 284 291 /// call to `operate`. 285 - fn operate(&mut self, flags: OpFlags, data: &mut [u8], more: Choice) { 292 + fn operate(&mut self, mut flags: OpFlags, data: &mut [u8], more: Choice) { 286 293 self.prev_flags = flags; 287 294 288 295 // If `more` isn't set, this is a new operation. Do the begin_op sequence ··· 291 298 } 292 299 293 300 // Meta-ness is only relevant for `begin_op`. Remove it to simplify the below logic. 294 - let flags = flags & !OpFlags::META; 301 + flags &= !OpFlags::META; 295 302 296 303 // Flags that don't pass this assertion should normally call `absorb`, but `absorb` does not mutate, 297 304 // so the implementor should have used operate_no_mutate instead ··· 309 316 /// Performs the state transformation that corresponds to the given flags. If `more` is given, 310 317 /// this will treat `data` as a continuation of the data given in the previous call to 311 318 /// `operate`. This uses non-mutating variants of the specializations of the `duplex` function. 312 - fn operate_no_mutate(&mut self, flags: OpFlags, data: &[u8], more: Choice) { 319 + fn operate_no_mutate(&mut self, mut flags: OpFlags, data: &[u8], more: Choice) { 313 320 self.prev_flags = flags; 314 321 315 322 // If `more` isn't set, this is a new operation. Do the begin_op sequence ··· 318 325 } 319 326 320 327 // Meta-ness is only relevant for `begin_op`. Remove it to simplify the below logic. 321 - let flags = flags & !OpFlags::META; 328 + flags &= !OpFlags::META; 322 329 323 330 // Flags that trigger the assertion to fail are mutating operations. 324 331 // RATCHET is special cased to never call operate/operate_no_mutate directly 325 - debug_assert!( 326 - flags != ops::PRF && !bool::from(flags.contains(OpFlags::CIPHER | OpFlags::TRANSPORT)) 327 - || bool::from(flags.contains(OpFlags::INBOUND)) 328 - ); 332 + debug_assert!(flags == ops::KEY || !bool::from(flags.contains(OpFlags::CIPHER))); 329 333 330 334 // There are no non-mutating variants of things with flags & (C | T | I) == C | T 331 335 if flags.contains(OpFlags::CIPHER).into() { ··· 339 343 } 340 344 } 341 345 342 - fn recv_mac_inner(&mut self, mac_copy: &mut [u8], flags: OpFlags) -> Result<(), GarbledError> { 346 + fn recv_mac_inner(&mut self, flags: OpFlags, mac_copy: &mut [u8]) -> Result<(), GarbledError> { 343 347 // recv_mac can never be streamed 344 348 self.operate(flags, mac_copy, Choice::from(0u8)); 345 349 ··· 355 359 pub fn recv_mac<const N: usize>(&mut self, mac: &[u8; N]) -> Result<(), GarbledError> { 356 360 let mut mac_copy = *mac; 357 361 358 - self.recv_mac_inner(&mut mac_copy, ops::RECV_MAC) 362 + self.recv_mac_inner(ops::RECV_MAC, &mut mac_copy) 359 363 } 360 364 361 365 pub fn meta_recv_mac<const N: usize>(&mut self, mac: &[u8; N]) -> Result<(), GarbledError> { 362 366 let mut mac_copy = *mac; 363 367 364 - self.recv_mac_inner(&mut mac_copy, ops::META_RECV_MAC) 368 + self.recv_mac_inner(ops::META_RECV_MAC, &mut mac_copy) 365 369 } 366 370 367 - fn ratchet_inner(&mut self, num_bytes_to_zero: usize, flags: OpFlags) { 368 - let more = self.prev_flags.bits().ct_eq(&flags.bits()); 371 + fn ratchet_inner(&mut self, mut flags: OpFlags, num_bytes_to_zero: usize) { 372 + let more = self.prev_flags.ct_eq(&flags); 369 373 370 374 // We don't make an `operate` call, since this is a super special case. That means we have 371 375 // to make the `begin_op` call manually. ··· 375 379 self.begin_op(flags); 376 380 } 377 381 382 + flags &= !OpFlags::META; 383 + 378 384 self.zero_state(num_bytes_to_zero); 379 385 } 380 386 381 387 pub fn ratchet(&mut self, num_bytes_to_zero: usize) { 382 - self.ratchet_inner(num_bytes_to_zero, ops::RATCHET); 388 + self.ratchet_inner(ops::RATCHET, num_bytes_to_zero); 383 389 } 384 390 385 391 pub fn meta_ratchet(&mut self, num_bytes_to_zero: usize) { 386 - self.ratchet_inner(num_bytes_to_zero, ops::META_RATCHET); 392 + self.ratchet_inner(ops::META_RATCHET, num_bytes_to_zero); 387 393 } 388 394 389 395 define_mut_operations! {