返回 CodeWhale
secret_eq.rs
根目录 / crates / core / src / secret_eq.rs
1 //! The one constant-time comparison for bearer tokens, nonces and proofs.
2 //!
3 //! Every credential check in the engine (Runtime API token, web and mobile
4 //! session proofs, computer-display tokens, the app-server bearer) goes
5 //! through [`constant_time_eq`], so a timing fix lands once.
6
7 /// Compares the full length of both inputs regardless of where they first
8 /// differ, so an auth failure leaks neither the matching prefix length nor,
9 /// beyond the loop bound, which input was shorter.
10 #[must_use]
11 pub fn constant_time_eq(a: &[u8], b: &[u8]) -> bool {
12 let mut diff = a.len() ^ b.len();
13 for i in 0..a.len().max(b.len()) {
14 let x = a.get(i).copied().unwrap_or(0);
15 let y = b.get(i).copied().unwrap_or(0);
16 diff |= usize::from(x ^ y);
17 }
18 std::hint::black_box(diff) == 0
19 }
20
21 #[cfg(test)]
22 mod tests {
23 use super::constant_time_eq;
24
25 #[test]
26 fn equal_inputs_match() {
27 assert!(constant_time_eq(b"", b""));
28 assert!(constant_time_eq(b"secret-token", b"secret-token"));
29 }
30
31 #[test]
32 fn different_inputs_do_not_match() {
33 assert!(!constant_time_eq(b"secret-token", b"secret-tokem"));
34 assert!(!constant_time_eq(b"secret", b"secret-token"));
35 assert!(!constant_time_eq(b"secret-token", b"secret"));
36 assert!(!constant_time_eq(b"", b"x"));
37 // A zero-padded prefix must not collide with the shorter input.
38 assert!(!constant_time_eq(b"abc", b"abc\0"));
39 }
40 }
41
41 lines RUST