diff --git a/build.rs b/build.rs index f7b94108b7..ee5423c84c 100644 --- a/build.rs +++ b/build.rs @@ -34,6 +34,7 @@ const ARM: &str = "arm"; #[rustfmt::skip] const RING_SRCS: &[(&[&str], &str)] = &[ + (&[], "crypto/constant_time.c"), (&[], "crypto/curve25519/curve25519.c"), (&[], "crypto/fipsmodule/aes/aes_nohw.c"), (&[], "crypto/fipsmodule/bn/montgomery.c"), @@ -885,7 +886,7 @@ fn prefix_all_symbols(pp: char, prefix_prefix: &str, prefix: &str) -> String { ]; static SYMBOLS_TO_PREFIX: &[&str] = &[ - "CRYPTO_memcmp", + "RING_value_barrier_w", "CRYPTO_poly1305_finish", "CRYPTO_poly1305_finish_neon", "CRYPTO_poly1305_init", diff --git a/crypto/constant_time.c b/crypto/constant_time.c new file mode 100644 index 0000000000..56bfef6288 --- /dev/null +++ b/crypto/constant_time.c @@ -0,0 +1,19 @@ +/* Copyright 2023 Brian Smith. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include "internal.h" + +RING_NOINLINE crypto_word_t RING_value_barrier_w(crypto_word_t a) { + return value_barrier_w(a); +} diff --git a/src/constant_time.rs b/src/constant_time.rs index 3ac6ad4c21..f780c572f8 100644 --- a/src/constant_time.rs +++ b/src/constant_time.rs @@ -14,25 +14,44 @@ //! Constant-time operations. -use crate::{c, error}; +use crate::error; /// Returns `Ok(())` if `a == b` and `Err(error::Unspecified)` otherwise. /// The comparison of `a` and `b` is done in constant time with respect to the /// contents of each, but NOT in constant time with respect to the lengths of /// `a` and `b`. pub fn verify_slices_are_equal(a: &[u8], b: &[u8]) -> Result<(), error::Unspecified> { + verify_all_bytes_are_equal(a.iter().copied(), b.iter().copied()) +} + +// TODO: Use this in internal callers, in favor of `verify_slices_are_equal`. +#[inline] +pub(crate) fn verify_all_bytes_are_equal( + a: impl ExactSizeIterator, + b: impl ExactSizeIterator, +) -> Result<(), error::Unspecified> { if a.len() != b.len() { return Err(error::Unspecified); } - let result = unsafe { CRYPTO_memcmp(a.as_ptr(), b.as_ptr(), a.len()) }; - match result { + let zero_if_equal = a.zip(b).fold(0, |accum, (a, b)| accum | (a ^ b)); + let zero_if_equal = unsafe { RING_value_barrier_w(Word::from(zero_if_equal)) }; + match zero_if_equal { 0 => Ok(()), _ => Err(error::Unspecified), } } +/// The integer type that's the "natural" unsigned machine word size. +pub(crate) type Word = CryptoWord; + +// Keep in sync with `crypto_word_t` in crypto/internal.h. +#[cfg(target_pointer_width = "32")] +type CryptoWord = u32; +#[cfg(target_pointer_width = "64")] +type CryptoWord = u64; + prefixed_extern! { - fn CRYPTO_memcmp(a: *const u8, b: *const u8, len: c::size_t) -> c::int; + fn RING_value_barrier_w(a: CryptoWord) -> CryptoWord; } #[cfg(test)]