1//! Utilities to safely compare cryptographic values. 2//! 3//! Extra care must be taken when comparing values in 4//! cryptographic code. If done incorrectly, it can lead 5//! to a [timing attack](https://en.wikipedia.org/wiki/Timing_attack). 6//! By analyzing the time taken to execute parts of a cryptographic 7//! algorithm, and attacker can attempt to compromise the 8//! cryptosystem. 9//! 10//! The utilities in this module are designed to be resistant 11//! to this type of attack. 12//! 13//! # Examples 14//! 15//! To perform a constant-time comparison of two arrays of the same length but different 16//! values: 17//! 18//! ``` 19//! use openssl::memcmp::eq; 20//! 21//! // We want to compare `a` to `b` and `c`, without giving 22//! // away through timing analysis that `c` is more similar to `a` 23//! // than `b`. 24//! let a = [0, 0, 0]; 25//! let b = [1, 1, 1]; 26//! let c = [0, 0, 1]; 27//! 28//! // These statements will execute in the same amount of time. 29//! assert!(!eq(&a, &b)); 30//! assert!(!eq(&a, &c)); 31//! ``` 32use libc::size_t; 33use openssl_macros::corresponds; 34 35/// Returns `true` iff `a` and `b` contain the same bytes. 36/// 37/// This operation takes an amount of time dependent on the length of the two 38/// arrays given, but is independent of the contents of a and b. 39/// 40/// # Panics 41/// 42/// This function will panic the current task if `a` and `b` do not have the same 43/// length. 44/// 45/// # Examples 46/// 47/// To perform a constant-time comparison of two arrays of the same length but different 48/// values: 49/// 50/// ``` 51/// use openssl::memcmp::eq; 52/// 53/// // We want to compare `a` to `b` and `c`, without giving 54/// // away through timing analysis that `c` is more similar to `a` 55/// // than `b`. 56/// let a = [0, 0, 0]; 57/// let b = [1, 1, 1]; 58/// let c = [0, 0, 1]; 59/// 60/// // These statements will execute in the same amount of time. 61/// assert!(!eq(&a, &b)); 62/// assert!(!eq(&a, &c)); 63/// ``` 64#[corresponds(CRYPTO_memcmp)] 65pub fn eq(a: &[u8], b: &[u8]) -> bool { 66 assert!(a.len() == b.len()); 67 let ret = unsafe { 68 ffi::CRYPTO_memcmp( 69 a.as_ptr() as *const _, 70 b.as_ptr() as *const _, 71 a.len() as size_t, 72 ) 73 }; 74 ret == 0 75} 76 77#[cfg(test)] 78mod tests { 79 use super::eq; 80 81 #[test] 82 fn test_eq() { 83 assert!(eq(&[], &[])); 84 assert!(eq(&[1], &[1])); 85 assert!(!eq(&[1, 2, 3], &[1, 2, 4])); 86 } 87 88 #[test] 89 #[should_panic] 90 fn test_diff_lens() { 91 eq(&[], &[1]); 92 } 93} 94