use crate::utils::*;
use botan_sys::*;
#[derive(Debug)]
#[allow(clippy::upper_case_acronyms)]
pub struct HOTP {
obj: botan_hotp_t,
}
botan_impl_drop!(HOTP, botan_hotp_destroy);
#[derive(Debug)]
#[allow(clippy::upper_case_acronyms)]
pub struct TOTP {
obj: botan_totp_t,
}
botan_impl_drop!(TOTP, botan_totp_destroy);
impl HOTP {
pub fn new(key: &[u8], hash_algo: &str, digits: usize) -> Result<HOTP> {
let hash_algo = make_cstr(hash_algo)?;
let obj = botan_init!(
botan_hotp_init,
key.as_ptr(),
key.len(),
hash_algo.as_ptr(),
digits
)?;
Ok(HOTP { obj })
}
pub fn generate(&self, counter: u64) -> Result<u32> {
let mut code = 0;
botan_call!(botan_hotp_generate, self.obj, &mut code, counter)?;
Ok(code)
}
pub fn check(&self, code: u32, counter: u64) -> Result<bool> {
let cmp_code = self.generate(counter)?;
Ok(cmp_code == code)
}
pub fn check_with_resync(
&self,
code: u32,
counter: u64,
resync_range: usize,
) -> Result<(bool, u64)> {
let mut new_ctr = 0;
let res = botan_bool_in_rc!(
botan_hotp_check,
self.obj,
&mut new_ctr,
code,
counter,
resync_range
)?;
if !res {
Ok((true, new_ctr))
} else {
Ok((false, counter))
}
}
}
impl TOTP {
pub fn new(key: &[u8], hash_algo: &str, digits: usize, time_step: usize) -> Result<TOTP> {
let hash_algo = make_cstr(hash_algo)?;
let obj = botan_init!(
botan_totp_init,
key.as_ptr(),
key.len(),
hash_algo.as_ptr(),
digits,
time_step
)?;
Ok(TOTP { obj })
}
pub fn generate(&self, timestamp: u64) -> Result<u32> {
let mut code = 0;
botan_call!(botan_totp_generate, self.obj, &mut code, timestamp)?;
Ok(code)
}
pub fn check(&self, code: u32, timestamp: u64, allowed_drift: usize) -> Result<bool> {
Ok(!botan_bool_in_rc!(
botan_totp_check,
self.obj,
code,
timestamp,
allowed_drift
)?)
}
}