shoes 0.3.2

A multi-protocol proxy server.
Documentation
use aws_lc_rs::aead::{Nonce, NonceSequence};
use aws_lc_rs::error::Unspecified;

pub struct VmessNonceSequence {
    count: u16,
    nonce: [u8; 12],
}

impl VmessNonceSequence {
    pub fn new(data: &[u8]) -> Self {
        let mut nonce = [0u8; 12];
        nonce[2..].copy_from_slice(&data[2..12]);
        Self { count: 0, nonce }
    }
}

impl NonceSequence for VmessNonceSequence {
    fn advance(&mut self) -> Result<Nonce, Unspecified> {
        // the nonce is correct for the first packet since the first two
        // bytes are already zero.
        let ret = Nonce::assume_unique_for_key(self.nonce);
        self.count = self.count.wrapping_add(1);
        self.nonce[0] = (self.count >> 8) as u8;
        self.nonce[1] = (self.count & 0xff) as u8;
        Ok(ret)
    }
}

pub struct SingleUseNonce {
    nonce: [u8; 12],
    used: bool,
}

impl SingleUseNonce {
    pub fn new(data: &[u8]) -> Self {
        let mut nonce = [0u8; 12];
        nonce.copy_from_slice(data);
        Self { nonce, used: false }
    }
}

impl NonceSequence for SingleUseNonce {
    fn advance(&mut self) -> Result<Nonce, Unspecified> {
        if self.used {
            panic!("SingleUseNonce used twice");
        }
        self.used = true;
        Nonce::try_assume_unique_for_key(&self.nonce)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    // Helper function to convert Nonce to [u8; 12]
    fn nonce_to_bytes(nonce: Nonce) -> [u8; 12] {
        let slice: &[u8] = nonce.as_ref();
        let mut arr = [0u8; 12];
        arr.copy_from_slice(slice);
        arr
    }

    #[test]
    fn test_vmess_nonce_sequence_initial() {
        // Initial nonce should have first two bytes as zero (count = 0)
        let data = [
            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
        ];
        let mut seq = VmessNonceSequence::new(&data);

        // First advance returns the nonce with counter=0 (first two bytes are 0)
        let nonce = seq.advance().unwrap();
        let nonce_bytes = nonce_to_bytes(nonce);
        // First two bytes should be 0 (counter before increment)
        assert_eq!(&nonce_bytes[0..2], &[0x00, 0x00]);
        // Remaining 10 bytes should be from data[2..12]
        assert_eq!(&nonce_bytes[2..], &data[2..12]);
    }

    #[test]
    fn test_vmess_nonce_sequence_increment() {
        let data = [0x00u8; 12];
        let mut seq = VmessNonceSequence::new(&data);

        // First nonce: counter = 0
        let _n1 = seq.advance().unwrap();

        // Second nonce: counter = 1
        let n2 = seq.advance().unwrap();
        let n2_bytes = nonce_to_bytes(n2);
        // Big-endian counter = 1: [0x00, 0x01]
        assert_eq!(&n2_bytes[0..2], &[0x00, 0x01]);

        // Third nonce: counter = 2
        let n3 = seq.advance().unwrap();
        let n3_bytes = nonce_to_bytes(n3);
        assert_eq!(&n3_bytes[0..2], &[0x00, 0x02]);
    }

    #[test]
    fn test_vmess_nonce_sequence_big_endian() {
        // Verify counter is stored as big-endian
        let data = [0x00u8; 12];
        let mut seq = VmessNonceSequence::new(&data);

        // Advance 256 times to get counter = 256 (0x0100 big-endian)
        for _ in 0..256 {
            let _ = seq.advance().unwrap();
        }

        let nonce = seq.advance().unwrap();
        let nonce_bytes = nonce_to_bytes(nonce);
        // Counter = 256 in big-endian: [0x01, 0x00]
        assert_eq!(&nonce_bytes[0..2], &[0x01, 0x00]);
    }

    #[test]
    fn test_vmess_nonce_sequence_wrapping() {
        // Test that counter wraps around at u16::MAX
        let data = [0x00u8; 12];
        let mut seq = VmessNonceSequence::new(&data);

        // Set internal state to just before wraparound
        // We need to advance 65535 times, but that's slow
        // Instead, just verify the wraparound behavior conceptually
        // by checking a few iterations work correctly
        for i in 0..10 {
            let nonce = seq.advance().unwrap();
            let nonce_bytes = nonce_to_bytes(nonce);
            let counter = ((nonce_bytes[0] as u16) << 8) | (nonce_bytes[1] as u16);
            assert_eq!(counter, i);
        }
    }

    #[test]
    fn test_vmess_nonce_sequence_preserves_iv_bytes() {
        // The last 10 bytes should always be from the original IV
        let data = [
            0x11, 0x22, // These are overwritten by counter
            0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // These are preserved
        ];
        let mut seq = VmessNonceSequence::new(&data);

        for _ in 0..5 {
            let nonce = seq.advance().unwrap();
            let nonce_bytes = nonce_to_bytes(nonce);
            // Bytes 2-11 should always be the same
            assert_eq!(
                &nonce_bytes[2..],
                &[0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc]
            );
        }
    }

    #[test]
    fn test_single_use_nonce_first_use() {
        let data = [
            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
        ];
        let mut nonce = SingleUseNonce::new(&data);

        let result = nonce.advance().unwrap();
        let result_bytes = nonce_to_bytes(result);
        assert_eq!(result_bytes, data);
    }

    #[test]
    #[should_panic(expected = "SingleUseNonce used twice")]
    fn test_single_use_nonce_panics_on_second_use() {
        let data = [0x00u8; 12];
        let mut nonce = SingleUseNonce::new(&data);

        let _ = nonce.advance().unwrap(); // First use: OK
        let _ = nonce.advance().unwrap(); // Second use: should panic
    }

    #[test]
    fn test_single_use_nonce_preserves_bytes() {
        // All 12 bytes should be preserved exactly
        let data = [
            0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe, 0x12, 0x34, 0x56, 0x78,
        ];
        let mut nonce = SingleUseNonce::new(&data);

        let result = nonce.advance().unwrap();
        let result_bytes = nonce_to_bytes(result);
        assert_eq!(result_bytes, data);
    }

    #[test]
    fn test_vmess_nonce_matches_sing_vmess() {
        // Verify our nonce format matches sing-vmess behavior
        // sing-vmess uses: binary.BigEndian.PutUint16(nonce, nonceCount)
        // Then increments nonceCount after
        let iv = [
            0x00, 0x00, // initial counter bytes (overwritten)
            0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x11, 0x22, 0x33, 0x44, // IV[2:12]
        ];
        let mut seq = VmessNonceSequence::new(&iv);

        // First packet: counter = 0
        let n1 = seq.advance().unwrap();
        let n1_bytes = nonce_to_bytes(n1);
        assert_eq!(n1_bytes[0], 0x00);
        assert_eq!(n1_bytes[1], 0x00);

        // Second packet: counter = 1
        let n2 = seq.advance().unwrap();
        let n2_bytes = nonce_to_bytes(n2);
        assert_eq!(n2_bytes[0], 0x00);
        assert_eq!(n2_bytes[1], 0x01);
    }
}