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()) } }