Skip to main content

naive_totp/
lib.rs

1use rand::{Rng, SeedableRng, rngs::StdRng};
2use std::{
3    hash::{DefaultHasher, Hash, Hasher},
4    time::{SystemTime, UNIX_EPOCH},
5};
6
7pub fn new(size: usize) -> Vec<u8> {
8    let mut buf = vec![0; size];
9    rand::rng().fill_bytes(&mut buf);
10    buf
11}
12
13pub fn generate(secret: &[u8], size: usize) -> Vec<u8> {
14    let time = SystemTime::now()
15        .duration_since(UNIX_EPOCH)
16        .unwrap()
17        .as_secs()
18        .to_be_bytes();
19    let mut hasher = DefaultHasher::new();
20    let s = vec![
21        secret, &time,
22    ];
23    s.hash(&mut hasher);
24    let mut rng = StdRng::seed_from_u64(hasher.finish());
25    let mut buf = vec![0; size];
26    rng.fill_bytes(&mut buf);
27    buf
28}
29
30#[cfg(test)]
31mod tests {
32    use std::{thread::sleep, time::Duration};
33
34    use super::*;
35
36    #[test]
37    fn test() {
38        // secret doesnt have to be same size as the generations
39        // but generations needs to be same size as each other
40        const SIZE: usize = 160;
41        let secret = new(SIZE);
42        let gen1 = generate(
43            &secret, SIZE,
44        );
45        let gen2 = generate(
46            &secret, SIZE,
47        );
48        assert_eq!(
49            gen1,
50            gen2
51        );
52    }
53
54    #[test]
55    fn test_different() {
56        const SIZE: usize = 160;
57        let secret = new(SIZE);
58        let gen1 = generate(
59            &secret, SIZE,
60        );
61        sleep(Duration::from_secs(2));
62        let gen2 = generate(
63            &secret, SIZE,
64        );
65        assert_ne!(
66            gen1,
67            gen2
68        );
69    }
70}