ytls_util/
nonce.rs

1use crypto_bigint::Encoding;
2
3use crypto_bigint::U128;
4
5/// Running 12-byte (U96) Nonce for ChaCha20Poly1305 / AES GCM AEADs
6pub struct Nonce12 {
7    iv: U128,
8    seq_id: u64,
9}
10
11impl Nonce12 {
12    /// Start Nonce12 with TLS1.2 Key Schedule derived 12-byte "IV"
13    #[inline]
14    pub fn from_ks_iv(i: &[u8; 12]) -> Self {
15        let iv = U128::from_be_bytes([
16            0, 0, 0, 0, i[0], i[1], i[2], i[3], i[4], i[5], i[6], i[7], i[8], i[9], i[10], i[11],
17        ]);
18        let seq_id = 0u64;
19
20        Self { iv, seq_id }
21    }
22    /// Use current and return it whilst incrementing the packet sequence counter.
23    #[inline]
24    pub fn use_and_incr(&mut self) -> Option<[u8; 12]> {
25        let seq_id = U128::from_u64(self.seq_id);
26        let nonce_u128 = self.iv.wrapping_xor(&seq_id);
27        let b: [u8; 16] = nonce_u128.to_be_bytes();
28
29        if self.seq_id == u64::MAX {
30            return None;
31        }
32
33        self.seq_id += 1;
34
35        Some([
36            b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15],
37        ])
38    }
39    /// Through fast forward to X for testing purposes
40    #[inline]
41    #[cfg(test)]
42    pub fn hazmat_fast_forward_with_incr(&mut self, fast_forward: u64) -> Option<[u8; 12]> {
43        self.seq_id = fast_forward;
44        self.use_and_incr()
45    }
46}
47
48#[cfg(test)]
49mod test {
50
51    use super::*;
52    use hex_literal::hex;
53
54    #[test]
55    fn cur() {
56        let iv_bytes: [u8; 12] = hex!("6fac81d4f2c3bebe02b8b375");
57        let mut running_nonce = Nonce12::from_ks_iv(&iv_bytes);
58        let cur = running_nonce.use_and_incr();
59
60        assert_eq!(cur, Some(iv_bytes));
61    }
62
63    #[test]
64    fn packet_seq_1() {
65        let iv_bytes: [u8; 12] = hex!("6fac81d4f2c3bebe02b8b375");
66        let mut running_nonce = Nonce12::from_ks_iv(&iv_bytes);
67        let _cur = running_nonce.use_and_incr();
68        let seq_1 = running_nonce.use_and_incr();
69
70        assert_eq!(seq_1, Some(hex!("6fac81d4f2c3bebe02b8b374")));
71    }
72
73    // Wrapping u64 is not allowed, ensure it returns None
74    #[test]
75    fn packet_seq_max() {
76        let iv_bytes: [u8; 12] = hex!("6fac81d4f2c3bebe02b8b375");
77        let mut running_nonce = Nonce12::from_ks_iv(&iv_bytes);
78        let cur = running_nonce.hazmat_fast_forward_with_incr(u64::MAX);
79
80        assert_eq!(cur, None);
81    }
82}