1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
mod base32;
mod sha1;

pub struct OTP {
    secret: String,
    digits: u8,
    #[allow(dead_code)] digest: String,
    #[allow(dead_code)] name: String,
    #[allow(dead_code)] issuer: String,
}

impl OTP {
    pub fn new(secret: String) -> OTP {
        OTP {
            secret: secret,
            digits: 6,
            digest: String::from("sha1"),
            name: String::new(),
            issuer: String::new(),
        }
    }

    pub fn generate_otp(&self, input: u64) -> String {
        let h = sha1::hmac_sha1(&self.byte_secret(), &self.int_to_bytes(input));
        let offset = h[19] as usize & 0x0f;
        let code = (h[offset] as u32 & 0x7f) << 24 |
            (h[offset + 1] as u32 & 0xff) << 16 |
            (h[offset + 2] as u32 & 0xff) << 8 |
            (h[offset + 3] as u32 & 0xff);
        let code = code % 10u32.pow(self.digits as u32);
        let mut r = code.to_string();
        let pending = ['0' as u8; 10];
        let i = self.digits as usize - r.len();
        use std::str;
        r.insert_str(0, str::from_utf8(&pending[..i]).unwrap());
        r
    }

    fn byte_secret(&self) -> Vec<u8> {
        base32::decode(&self.secret)
    }

    fn int_to_bytes(&self, v: u64) -> [u8; 8] {
        let mut b = [0u8; 8];
        b[0] = (v >> 56) as u8;
        b[1] = (v >> 48) as u8;
        b[2] = (v >> 40) as u8;
        b[3] = (v >> 32) as u8;
        b[4] = (v >> 24) as u8;
        b[5] = (v >> 16) as u8;
        b[6] = (v >> 8) as u8;
        b[7] = v as u8;
        b
    }
}

pub struct TOTP {
    otp : OTP,
    interval: u64,
}

impl TOTP {

    pub fn new(secret: String) -> TOTP {
        TOTP {
            otp : OTP::new(secret),
            interval: 30,
        }
    }

    pub fn at(&self, timestamp: u64) -> String {
        self.otp.generate_otp(timestamp / self.interval)
    }

    pub fn now(&self) -> String {
        use std::time::SystemTime;
        self.at(
            SystemTime::now()
                .duration_since(SystemTime::UNIX_EPOCH)
                .unwrap().as_secs()
        )
    }

    pub fn verfiy(&self, s : &str) -> bool {
        self.now().eq(s)
    }
}

pub struct HOTP {
    otp : OTP,
    init_count: u64,
}

impl HOTP {

    pub fn new(secret: String) -> HOTP {
        HOTP {
            otp : OTP::new(secret),
            init_count: 0,
        }
    }

    pub fn at(&self, count: u64) -> String {
        self.otp.generate_otp(self.init_count + count)
    }

    pub fn verfiy(&self, s : &str, count : u64) -> bool {
        self.at(count).eq(&s)
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_otp() {
        let otp = super::OTP::new(String::from("3O75UXLUVM5NE3HA"));
        assert_eq!(otp.generate_otp(123), "276083");
        assert_eq!(otp.generate_otp(0), "463950");
        assert_eq!(otp.generate_otp(9), "003954");
    }

    #[test]
    fn test_totp() {
        let otp = super::TOTP::new(String::from("3O75UXLUVM5NE3HA"));
        println!("{}", otp.now())
    }
}