192f3ab15Sopenharmony_ci//! Utilities to safely compare cryptographic values.
292f3ab15Sopenharmony_ci//!
392f3ab15Sopenharmony_ci//! Extra care must be taken when comparing values in
492f3ab15Sopenharmony_ci//! cryptographic code. If done incorrectly, it can lead
592f3ab15Sopenharmony_ci//! to a [timing attack](https://en.wikipedia.org/wiki/Timing_attack).
692f3ab15Sopenharmony_ci//! By analyzing the time taken to execute parts of a cryptographic
792f3ab15Sopenharmony_ci//! algorithm, and attacker can attempt to compromise the
892f3ab15Sopenharmony_ci//! cryptosystem.
992f3ab15Sopenharmony_ci//!
1092f3ab15Sopenharmony_ci//! The utilities in this module are designed to be resistant
1192f3ab15Sopenharmony_ci//! to this type of attack.
1292f3ab15Sopenharmony_ci//!
1392f3ab15Sopenharmony_ci//! # Examples
1492f3ab15Sopenharmony_ci//!
1592f3ab15Sopenharmony_ci//! To perform a constant-time comparison of two arrays of the same length but different
1692f3ab15Sopenharmony_ci//! values:
1792f3ab15Sopenharmony_ci//!
1892f3ab15Sopenharmony_ci//! ```
1992f3ab15Sopenharmony_ci//! use openssl::memcmp::eq;
2092f3ab15Sopenharmony_ci//!
2192f3ab15Sopenharmony_ci//! // We want to compare `a` to `b` and `c`, without giving
2292f3ab15Sopenharmony_ci//! // away through timing analysis that `c` is more similar to `a`
2392f3ab15Sopenharmony_ci//! // than `b`.
2492f3ab15Sopenharmony_ci//! let a = [0, 0, 0];
2592f3ab15Sopenharmony_ci//! let b = [1, 1, 1];
2692f3ab15Sopenharmony_ci//! let c = [0, 0, 1];
2792f3ab15Sopenharmony_ci//!
2892f3ab15Sopenharmony_ci//! // These statements will execute in the same amount of time.
2992f3ab15Sopenharmony_ci//! assert!(!eq(&a, &b));
3092f3ab15Sopenharmony_ci//! assert!(!eq(&a, &c));
3192f3ab15Sopenharmony_ci//! ```
3292f3ab15Sopenharmony_ciuse libc::size_t;
3392f3ab15Sopenharmony_ciuse openssl_macros::corresponds;
3492f3ab15Sopenharmony_ci
3592f3ab15Sopenharmony_ci/// Returns `true` iff `a` and `b` contain the same bytes.
3692f3ab15Sopenharmony_ci///
3792f3ab15Sopenharmony_ci/// This operation takes an amount of time dependent on the length of the two
3892f3ab15Sopenharmony_ci/// arrays given, but is independent of the contents of a and b.
3992f3ab15Sopenharmony_ci///
4092f3ab15Sopenharmony_ci/// # Panics
4192f3ab15Sopenharmony_ci///
4292f3ab15Sopenharmony_ci/// This function will panic the current task if `a` and `b` do not have the same
4392f3ab15Sopenharmony_ci/// length.
4492f3ab15Sopenharmony_ci///
4592f3ab15Sopenharmony_ci/// # Examples
4692f3ab15Sopenharmony_ci///
4792f3ab15Sopenharmony_ci/// To perform a constant-time comparison of two arrays of the same length but different
4892f3ab15Sopenharmony_ci/// values:
4992f3ab15Sopenharmony_ci///
5092f3ab15Sopenharmony_ci/// ```
5192f3ab15Sopenharmony_ci/// use openssl::memcmp::eq;
5292f3ab15Sopenharmony_ci///
5392f3ab15Sopenharmony_ci/// // We want to compare `a` to `b` and `c`, without giving
5492f3ab15Sopenharmony_ci/// // away through timing analysis that `c` is more similar to `a`
5592f3ab15Sopenharmony_ci/// // than `b`.
5692f3ab15Sopenharmony_ci/// let a = [0, 0, 0];
5792f3ab15Sopenharmony_ci/// let b = [1, 1, 1];
5892f3ab15Sopenharmony_ci/// let c = [0, 0, 1];
5992f3ab15Sopenharmony_ci///
6092f3ab15Sopenharmony_ci/// // These statements will execute in the same amount of time.
6192f3ab15Sopenharmony_ci/// assert!(!eq(&a, &b));
6292f3ab15Sopenharmony_ci/// assert!(!eq(&a, &c));
6392f3ab15Sopenharmony_ci/// ```
6492f3ab15Sopenharmony_ci#[corresponds(CRYPTO_memcmp)]
6592f3ab15Sopenharmony_cipub fn eq(a: &[u8], b: &[u8]) -> bool {
6692f3ab15Sopenharmony_ci    assert!(a.len() == b.len());
6792f3ab15Sopenharmony_ci    let ret = unsafe {
6892f3ab15Sopenharmony_ci        ffi::CRYPTO_memcmp(
6992f3ab15Sopenharmony_ci            a.as_ptr() as *const _,
7092f3ab15Sopenharmony_ci            b.as_ptr() as *const _,
7192f3ab15Sopenharmony_ci            a.len() as size_t,
7292f3ab15Sopenharmony_ci        )
7392f3ab15Sopenharmony_ci    };
7492f3ab15Sopenharmony_ci    ret == 0
7592f3ab15Sopenharmony_ci}
7692f3ab15Sopenharmony_ci
7792f3ab15Sopenharmony_ci#[cfg(test)]
7892f3ab15Sopenharmony_cimod tests {
7992f3ab15Sopenharmony_ci    use super::eq;
8092f3ab15Sopenharmony_ci
8192f3ab15Sopenharmony_ci    #[test]
8292f3ab15Sopenharmony_ci    fn test_eq() {
8392f3ab15Sopenharmony_ci        assert!(eq(&[], &[]));
8492f3ab15Sopenharmony_ci        assert!(eq(&[1], &[1]));
8592f3ab15Sopenharmony_ci        assert!(!eq(&[1, 2, 3], &[1, 2, 4]));
8692f3ab15Sopenharmony_ci    }
8792f3ab15Sopenharmony_ci
8892f3ab15Sopenharmony_ci    #[test]
8992f3ab15Sopenharmony_ci    #[should_panic]
9092f3ab15Sopenharmony_ci    fn test_diff_lens() {
9192f3ab15Sopenharmony_ci        eq(&[], &[1]);
9292f3ab15Sopenharmony_ci    }
9392f3ab15Sopenharmony_ci}
94