pub mod progress;
pub use crate::progress::*;
pub mod nacl;
pub use crate::nacl::*;
#[cfg(feature = "totp")]
mod totp {
use hmac::{Hmac, Mac};
use sha1::Sha1;
type HmacSha1 = Hmac<Sha1>;
const DIGITS_POWER: [u32; 9]
= [1,10,100,1000,10000,100000,1000000,10000000,100000000];
fn generate_otp<const HASH_LENGTH: usize>(hash: [u8; HASH_LENGTH], code_digits: u8) -> String {
let code_digits = if code_digits > 8 { 8 } else { code_digits };
let offset = (hash[HASH_LENGTH-1] & 0xf) as usize;
let binary : u32 = (((hash[offset] & 0x7f) as u32) << 24) |
((hash[offset + 1] as u32) << 16) |
((hash[offset + 2] as u32) << 8) |
(hash[offset + 3] as u32);
let otp = binary % DIGITS_POWER[code_digits as usize];
format!("{:0code_digits$}", otp, code_digits = code_digits as usize)
}
fn calculate_otp_time(mut time: u64, d: i8) -> u64 {
const T0: u64 = 0;
time = (time - T0) / 30;
time = ((time as i64) + d as i64) as u64;
time
}
pub fn generate_otp_sha1(time: u64, d: i8, secret: &[u8], code_digits: u8) -> String {
let time = calculate_otp_time(time, d);
let mut mac = HmacSha1::new_from_slice(secret).unwrap();
mac.update(&time.to_be_bytes());
let hash = mac.finalize().into_bytes();
generate_otp(hash.into(), code_digits)
}
}
#[cfg(feature = "totp")]
pub use totp::*;
#[cfg(test)]
mod networky {
use super::*;
#[cfg(feature = "totp")]
#[test]
fn totp() {
let seed : [u8; 20] = [0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30];
assert_eq!("94287082", generate_otp_sha1(59, 0, &seed, 8));
assert_eq!("07081804", generate_otp_sha1(1111111109, 0, &seed, 8));
assert_eq!("14050471", generate_otp_sha1(1111111111, 0, &seed, 8));
assert_eq!("89005924", generate_otp_sha1(1234567890, 0, &seed, 8));
assert_eq!("69279037", generate_otp_sha1(2000000000, 0, &seed, 8));
assert_eq!("65353130", generate_otp_sha1(20000000000, 0, &seed, 8));
}
}