use super::*;
use digest::{
block_buffer::Eager,
core_api::{BufferKindUser, CoreProxy, FixedOutputCore, UpdateCore},
crypto_common::BlockSizeUser,
typenum::{IsLess, Le, NonZero, U256},
FixedOutput, HashMarker, Update,
};
pub use sha1::Sha1;
pub use sha2::{Sha256, Sha512};
pub fn otp_custom<H>(secret: &[u8], nonce: u64, digits: u8) -> Result<String, ThotpError>
where
H: Update + FixedOutput + CoreProxy,
H::Core: HashMarker
+ UpdateCore
+ FixedOutputCore
+ BufferKindUser<BufferKind = Eager>
+ Default
+ Clone,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
let nonce = &nonce.to_be_bytes();
let mut hmac = hmac_digest::<H>(secret, nonce)?;
let trunc = dynamic_trunc(&mut hmac);
let mut result = (trunc % 10_u32.pow(digits as u32)).to_string();
for i in 0..(digits as usize - result.len() as usize) {
result.insert(i, '0');
}
Ok(result)
}
pub fn verify_totp_custom<H>(
password: &str,
secret: &[u8],
timestamp: u64,
digits: u8,
step: u8,
allowed_drift: u8,
) -> Result<(bool, i16), ThotpError>
where
H: Update + FixedOutput + CoreProxy,
H::Core: HashMarker
+ UpdateCore
+ FixedOutputCore
+ BufferKindUser<BufferKind = Eager>
+ Default
+ Clone,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
let nonce = if timestamp == 0 {
SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs() / step as u64
} else {
timestamp / step as u64
};
let start = nonce.saturating_sub(allowed_drift as u64);
let end = nonce.saturating_add(allowed_drift as u64);
let mut i = -(ALLOWED_DRIFT as i16);
for n in start..=end {
let pass = otp_custom::<H>(secret, n, digits)?;
if pass.eq(password) {
return Ok((true, i));
}
i += 1;
}
Ok((false, 0))
}
pub fn verify_hotp_custom<H>(
password: &str,
secret: &[u8],
counter: u64,
lookahead: u8,
digits: u8,
) -> Result<(bool, u64), ThotpError>
where
H: Update + FixedOutput + CoreProxy,
H::Core: HashMarker
+ UpdateCore
+ FixedOutputCore
+ BufferKindUser<BufferKind = Eager>
+ Default
+ Clone,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
for current in 0..lookahead + 1 {
let current = (counter as u128 + current as u128) as u64;
let pass = otp_custom::<H>(secret, current, digits)?;
if pass.eq(password) {
return Ok((true, (current as u128 + 1) as u64));
}
}
Ok((false, counter))
}