rtc_shared/replay_detector/
mod.rs

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