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