1use std::time::SystemTime;
18
19use hmac::{Hmac, Mac};
20use sha3::Sha3_256;
21
22pub fn epoch_now_s() -> u64 {
23 SystemTime::now()
24 .duration_since(SystemTime::UNIX_EPOCH)
25 .expect("Unable to calculate epoch time")
26 .as_secs()
27}
28
29pub fn epoch_now_ms() -> u128 {
30 SystemTime::now()
31 .duration_since(SystemTime::UNIX_EPOCH)
32 .expect("Unable to calculate epoch time")
33 .as_millis()
34}
35
36pub struct SeqMac {
37 mac: Hmac<Sha3_256>,
38 period: u64,
39}
40
41impl SeqMac {
42 pub fn new(psk: &str, port: u16, period: u64) -> Self {
43 let psk_bytes = psk.as_bytes();
44 let mut port_padded_psk = Vec::with_capacity(psk_bytes.len() + 3);
45
46 let port_bytes = port.to_be_bytes();
48 port_padded_psk.push(port_bytes[0]);
49 port_padded_psk.push(port_bytes[1]);
50 port_padded_psk.push(0);
51
52 for byte in psk_bytes {
54 port_padded_psk.push(*byte);
55 }
56
57 SeqMac {
58 mac: Hmac::new_from_slice(&port_padded_psk).expect("Unable to construct HMAC"),
59 period,
60 }
61 }
62
63 pub fn calc(&self, time: u64) -> u32 {
64 let mut mac = self.mac.clone();
65 mac.update(format!("{}", time / self.period).as_bytes());
66 let result = mac.finalize();
67 let bytes = result.into_bytes();
68 let first = [bytes[0], bytes[1], bytes[2], bytes[3]];
69 u32::from_be_bytes(first)
70 }
71}
72
73#[cfg(test)]
74mod tests {
75
76 use super::SeqMac;
77
78 #[test]
79 fn key_lengths() {
80 let time = 1672531200;
81
82 let mac_1 = SeqMac::new("a", 1, 1);
83 assert_eq!(mac_1.calc(time), 3233246158);
84 let mac_1025 = SeqMac::new("iemumahchua4waihauH4eChe7feonohHeimeubah0Hae1Weyaequiech5ohhufaeRahl9uz4shahv8eiceis5efah6iaw3oph6ievol9ohSeeXiocheishel5tuc4logaluoF7eeraetaiwoe3aih5eetee9hoo0iSh4phietha9aix7nohkaibohv6aesu9Dieviulu9Jeil3Ahmah9Aifohk4ahphae8eiKaechei1cie6aehoor9ofu1goo9ahfoo9shaa4aey2obaechai5oopeig6ailoovaeFouv3kihishaeChohPie8eigeeH2eod9ohvah6zue2ca4eGhaimiethiengoongeethemei9nee0IjieBahlik5riekiyaiphahb3lu0hee6otievie6go8Aijohng8ce5ooshophoda2Eunaepeethaecopae1Thuwaeyahpooz9ez7thi3lieL2Eope5air7iet2voh1lah9Oa5poo0eehohzai7rahPhaeghozaex6Eim4Soo7ChooceeNg8Gai6Air1wi5roogeeweic7ohngiewaiGohphoomee0ahdiree9Bedaibah4ook6sujae1oaxughei1quahphee6mohMeoP8hohaeng8niiXiethohchah1ootie4ibai4zaeceex8Iebaem1gu8keG7ing3rahchahHeihieteeQuohjeib1ia5Zie8so1pou2doohi9eelaejixoje2eegh1lee9ohdingaQueecai1aez0eexaez3el2ieB7ievooleefohg3Aidi4kieRoo9eicheiH0DoBohngaeshaigh6Biey8eecooyahchahgh9yoo8aiSho9Pho1aeWi0ohxohs1Kewah8aey2iho7oboh4jied1Ooquool0uel7eeg6roothai8Ahfoo8deh5ahqua7Zipaish7Rooxae7zeeGa6ja8iecoo4Goo8uequei7bohngiyohFoh2uCu8eingi", 1, 1);
86 assert_eq!(mac_1025.calc(time), 3874154907);
87 let mac_0 = SeqMac::new("", 1, 1);
89 assert_eq!(mac_0.calc(time), 925434999);
90 }
91
92 #[test]
93 fn with_static_macs() {
94 let mac_asdf_29 = SeqMac::new("asdf", 22, 29);
95 let mac_asdf_30 = SeqMac::new("asdf", 22, 30);
96 let mac_asdf_31 = SeqMac::new("asdf", 22, 31);
97 let mac_asde_30 = SeqMac::new("asde", 22, 30);
98 let mac_asdf_23_30 = SeqMac::new("asdf", 23, 30);
99 let mac_asdf_30_2 = SeqMac::new("asdf", 22, 30);
100 let time = 1672531200;
101
102 assert_eq!(mac_asdf_29.calc(time), mac_asdf_29.calc(time));
104 assert_eq!(mac_asdf_30.calc(time), mac_asdf_30.calc(time));
105 assert_eq!(mac_asdf_31.calc(time), mac_asdf_31.calc(time));
106
107 assert_eq!(mac_asdf_30.calc(time), mac_asdf_30_2.calc(time));
109
110 assert_ne!(mac_asdf_30.calc(time), mac_asde_30.calc(time));
112
113 assert_ne!(mac_asdf_30.calc(time), mac_asdf_30.calc(time + 30));
115 assert_ne!(mac_asdf_30.calc(time), mac_asdf_30.calc(time - 30));
116
117 assert_ne!(mac_asdf_30.calc(time), mac_asdf_29.calc(time));
119 assert_ne!(mac_asdf_30.calc(time), mac_asdf_31.calc(time));
120
121 let result0 = mac_asdf_30.calc(time);
123 let mut offset1 = 1;
124 loop {
126 if result0 != mac_asdf_30.calc(time + offset1) {
127 break;
128 }
129 offset1 += 1;
130 }
131 let result1 = mac_asdf_30.calc(time + offset1);
132 let mut offset2 = 1;
133 loop {
135 if result1 != mac_asdf_30.calc(time + offset1 + offset2) {
136 break;
137 }
138 offset2 += 1;
139 }
140 assert_eq!(offset2, 30);
142
143 assert_ne!(mac_asdf_30.calc(time), mac_asdf_23_30.calc(time));
145
146 assert_eq!(mac_asdf_29.calc(time), 390276340);
148 assert_eq!(mac_asdf_30.calc(time), 4262803033);
149 assert_eq!(mac_asdf_31.calc(time), 1960043237);
150 }
151}