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:a.as_ptr() as *const _, |
70 | b: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 | |