1use std::time::{SystemTime};
2
3use crypto::hmac::Hmac;
4use crypto::mac::Mac;
5use crypto::sha1::Sha1;
6
7const INTERVAL : u64 = 30;
8const ALPHABET : &str = "23456789BCDFGHJKMNPQRTVWXY";
9
10pub fn generate(shared_secret: &str) -> Result<String, &'static str> {
21 let counter : u64 = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs() / INTERVAL;
22 let decoded_shared_secret = match base64::decode(shared_secret) {
23 Ok(decoded) => decoded,
24 Err(_) => return Err("Error decoding base64 shared secret"),
25 };
26
27 let mut hmac = Hmac::new(Sha1::new(), decoded_shared_secret.as_slice());
28 hmac.input(counter.to_be_bytes().as_slice());
29 let code = hmac.result().code().to_vec();
30 let start = (code[19] & 0xf) as usize;
31 let mut fullcode = (((code[start] & 0x7f) as u32) << 24) |
32 ((code[start + 1] as u32) << 16) |
33 ((code[start + 2] as u32) << 8) |
34 (code[start + 3] as u32);
35
36 let mut otp : [u8; 5] = [0; 5];
37 for i in 0..5 {
38 otp[i] = ALPHABET.as_bytes()[fullcode as usize % ALPHABET.len()];
39 fullcode /= ALPHABET.len() as u32;
40 }
41
42 Ok(String::from_utf8(otp.to_vec()).unwrap())
43}