| 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 | //! ``` |
| 32 | use libc::size_t; |
| 33 | use 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)] |
| 65 | pub fn eq(a: &[u8], b: &[u8]) -> bool { |
| 66 | assert!(a.len() == b.len()); |
| 67 | let ret: i32 = 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)] |
| 78 | mod 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 | |