Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Harden constant-time equality on arrays and slices #120

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 7 additions & 19 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,12 +289,6 @@ pub trait ConstantTimeEq {
impl<T: ConstantTimeEq> ConstantTimeEq for [T] {
/// Check whether two slices of `ConstantTimeEq` types are equal.
///
/// # Note
///
/// This function short-circuits if the lengths of the input slices
/// are different. Otherwise, it should execute in time independent
/// of the slice contents.
///
/// Since arrays coerce to slices, this function works with fixed-size arrays:
///
/// ```
Expand All @@ -311,23 +305,17 @@ impl<T: ConstantTimeEq> ConstantTimeEq for [T] {
/// ```
#[inline]
fn ct_eq(&self, _rhs: &[T]) -> Choice {
let len = self.len();

// Short-circuit on the *lengths* of the slices, not their
// contents.
if len != _rhs.len() {
return Choice::from(0);
}
// Determine if the lengths are equal in constant time
let len_ct_eq = self.len().ct_eq(&_rhs.len());

// This loop shouldn't be shortcircuitable, since the compiler
// shouldn't be able to reason about the value of the `u8`
// unwrapped from the `ct_eq` result.
let mut x = 1u8;
// Check each byte for equality in constant time
let mut contents_ct_eq = 1u8;
for (ai, bi) in self.iter().zip(_rhs.iter()) {
x &= ai.ct_eq(bi).unwrap_u8();
contents_ct_eq &= ai.ct_eq(bi).unwrap_u8();
}

x.into()
// Now check that the length and bytes are both equal in constant time
len_ct_eq & contents_ct_eq.into()
}
}

Expand Down
5 changes: 2 additions & 3 deletions tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@ use rand::RngCore;
use subtle::*;

#[test]
#[should_panic]
fn slices_equal_different_lengths() {
fn slices_different_lengths() {
let a: [u8; 3] = [0, 0, 0];
let b: [u8; 4] = [0, 0, 0, 0];

assert_eq!((&a).ct_eq(&b).unwrap_u8(), 1);
assert_eq!((&a).ct_eq(&b).unwrap_u8(), 0);
}

#[test]
Expand Down
Loading