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> {
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::*;
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() {
let data = [
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
];
let mut seq = VmessNonceSequence::new(&data);
let nonce = seq.advance().unwrap();
let nonce_bytes = nonce_to_bytes(nonce);
assert_eq!(&nonce_bytes[0..2], &[0x00, 0x00]);
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);
let _n1 = seq.advance().unwrap();
let n2 = seq.advance().unwrap();
let n2_bytes = nonce_to_bytes(n2);
assert_eq!(&n2_bytes[0..2], &[0x00, 0x01]);
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() {
let data = [0x00u8; 12];
let mut seq = VmessNonceSequence::new(&data);
for _ in 0..256 {
let _ = seq.advance().unwrap();
}
let nonce = seq.advance().unwrap();
let nonce_bytes = nonce_to_bytes(nonce);
assert_eq!(&nonce_bytes[0..2], &[0x01, 0x00]);
}
#[test]
fn test_vmess_nonce_sequence_wrapping() {
let data = [0x00u8; 12];
let mut seq = VmessNonceSequence::new(&data);
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() {
let data = [
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, ];
let mut seq = VmessNonceSequence::new(&data);
for _ in 0..5 {
let nonce = seq.advance().unwrap();
let nonce_bytes = nonce_to_bytes(nonce);
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(); let _ = nonce.advance().unwrap(); }
#[test]
fn test_single_use_nonce_preserves_bytes() {
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() {
let iv = [
0x00, 0x00, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x11, 0x22, 0x33, 0x44, ];
let mut seq = VmessNonceSequence::new(&iv);
let n1 = seq.advance().unwrap();
let n1_bytes = nonce_to_bytes(n1);
assert_eq!(n1_bytes[0], 0x00);
assert_eq!(n1_bytes[1], 0x00);
let n2 = seq.advance().unwrap();
let n2_bytes = nonce_to_bytes(n2);
assert_eq!(n2_bytes[0], 0x00);
assert_eq!(n2_bytes[1], 0x01);
}
}