Replay Protection
DocsProtocol ConceptsReplay Protection

Replay Protection

The sliding window algorithm

Replay attacks occur when an attacker captures a valid encrypted packet on the wire and retransmits it later. Since the packet has a valid ciphertext and authentication tag, a naive receiver would decrypt and process it twice.

The 1024-bit Sliding Window

KSP implements a sliding window algorithm based on monotonically increasing sequence numbers. Unlike a strict increment counter which rejects out-of-order packets (breaking on lossy networks), the sliding window allows packet reordering while strictly rejecting duplicates.

Sliding Window State: - highest_seq: The largest sequence number validated so far. - bitmap: A 1024-bit bitmask representing [highest_seq - 1023, highest_seq].

Rust Implementation Logic

pub struct ReplayWindow {
    highest_seq: u64,
    bitmap: [u64; 16], // 16 * 64 bits = 1024 bits
}

impl ReplayWindow {
    pub fn check_and_update(&mut self, seq: u64) -> bool {
        if seq > self.highest_seq {
            // Packets ahead of current window
            let diff = seq - self.highest_seq;
            if diff >= 1024 {
                self.bitmap = [0; 16];
            } else {
                self.shift_bitmap(diff);
            }
            self.highest_seq = seq;
            self.set_bit(0); // Bit 0 represents highest_seq
            return true;
        }

        let age = self.highest_seq - seq;
        if age >= 1024 {
            // Packet is too old, outside sliding window
            return false;
        }

        if self.is_bit_set(age) {
            // Already processed (replay attack)
            return false;
        }

        self.set_bit(age);
        true
    }
}
Security Warning

Replay-rejected frames MUST be discarded silentlywithout returning an error code. Generating error packets for invalid sequences allows side-channel analysis, helping attackers map the receiver's current sliding window.