webrtc_util/replay_detector/
mod.rs

1#[cfg(test)]
2mod replay_detector_test;
3
4use super::fixed_big_int::*;
5
6// ReplayDetector is the interface of sequence replay detector.
7pub trait ReplayDetector {
8    // Check returns true if given sequence number is not replayed.
9    // Call accept() to mark the packet is received properly.
10    fn check(&mut self, seq: u64) -> bool;
11    fn accept(&mut self);
12}
13
14pub struct SlidingWindowDetector {
15    accepted: bool,
16    seq: u64,
17    latest_seq: u64,
18    max_seq: u64,
19    window_size: usize,
20    mask: FixedBigInt,
21}
22
23impl SlidingWindowDetector {
24    // New creates ReplayDetector.
25    // Created ReplayDetector doesn't allow wrapping.
26    // It can handle monotonically increasing sequence number up to
27    // full 64bit number. It is suitable for DTLS replay protection.
28    pub fn new(window_size: usize, max_seq: u64) -> Self {
29        SlidingWindowDetector {
30            accepted: false,
31            seq: 0,
32            latest_seq: 0,
33            max_seq,
34            window_size,
35            mask: FixedBigInt::new(window_size),
36        }
37    }
38}
39
40impl ReplayDetector for SlidingWindowDetector {
41    fn check(&mut self, seq: u64) -> bool {
42        self.accepted = false;
43
44        if seq > self.max_seq {
45            // Exceeded upper limit.
46            return false;
47        }
48
49        if seq <= self.latest_seq {
50            if self.latest_seq >= self.window_size as u64 + seq {
51                return false;
52            }
53            if self.mask.bit((self.latest_seq - seq) as usize) != 0 {
54                // The sequence number is duplicated.
55                return false;
56            }
57        }
58
59        self.accepted = true;
60        self.seq = seq;
61        true
62    }
63
64    fn accept(&mut self) {
65        if !self.accepted {
66            return;
67        }
68
69        if self.seq > self.latest_seq {
70            // Update the head of the window.
71            self.mask.lsh((self.seq - self.latest_seq) as usize);
72            self.latest_seq = self.seq;
73        }
74        let diff = (self.latest_seq - self.seq) % self.max_seq;
75        self.mask.set_bit(diff as usize);
76    }
77}
78
79pub struct WrappedSlidingWindowDetector {
80    accepted: bool,
81    seq: u64,
82    latest_seq: u64,
83    max_seq: u64,
84    window_size: usize,
85    mask: FixedBigInt,
86    init: bool,
87}
88
89impl WrappedSlidingWindowDetector {
90    // WithWrap creates ReplayDetector allowing sequence wrapping.
91    // This is suitable for short bitwidth counter like SRTP and SRTCP.
92    pub fn new(window_size: usize, max_seq: u64) -> Self {
93        WrappedSlidingWindowDetector {
94            accepted: false,
95            seq: 0,
96            latest_seq: 0,
97            max_seq,
98            window_size,
99            mask: FixedBigInt::new(window_size),
100            init: false,
101        }
102    }
103}
104
105impl ReplayDetector for WrappedSlidingWindowDetector {
106    fn check(&mut self, seq: u64) -> bool {
107        self.accepted = false;
108
109        if seq > self.max_seq {
110            // Exceeded upper limit.
111            return false;
112        }
113        if !self.init {
114            if seq != 0 {
115                self.latest_seq = seq - 1;
116            } else {
117                self.latest_seq = self.max_seq;
118            }
119            self.init = true;
120        }
121
122        let mut diff = self.latest_seq as i64 - seq as i64;
123        // Wrap the number.
124        if diff > self.max_seq as i64 / 2 {
125            diff -= (self.max_seq + 1) as i64;
126        } else if diff <= -(self.max_seq as i64 / 2) {
127            diff += (self.max_seq + 1) as i64;
128        }
129
130        if diff >= self.window_size as i64 {
131            // Too old.
132            return false;
133        }
134        if diff >= 0 && self.mask.bit(diff as usize) != 0 {
135            // The sequence number is duplicated.
136            return false;
137        }
138
139        self.accepted = true;
140        self.seq = seq;
141        true
142    }
143
144    fn accept(&mut self) {
145        if !self.accepted {
146            return;
147        }
148
149        let mut diff = self.latest_seq as i64 - self.seq as i64;
150        // Wrap the number.
151        if diff > self.max_seq as i64 / 2 {
152            diff -= (self.max_seq + 1) as i64;
153        } else if diff <= -(self.max_seq as i64 / 2) {
154            diff += (self.max_seq + 1) as i64;
155        }
156
157        assert!(diff < self.window_size as i64);
158
159        if diff < 0 {
160            // Update the head of the window.
161            self.mask.lsh((-diff) as usize);
162            self.latest_seq = self.seq;
163        }
164        self.mask
165            .set_bit((self.latest_seq as isize - self.seq as isize) as usize);
166    }
167}
168
169#[derive(Default)]
170pub struct NoOpReplayDetector;
171
172impl ReplayDetector for NoOpReplayDetector {
173    fn check(&mut self, _: u64) -> bool {
174        true
175    }
176    fn accept(&mut self) {}
177}