mtotp-lib 0.1.4

Totp manager
Documentation
extern crate hmac;

use std::time::{SystemTime, UNIX_EPOCH};
use hmac::{Hmac, Mac};
use sha1::Sha1;

use crate::error::*;

pub fn hotp(secret: &[u8], counter: u64, digits: usize) -> Result<String> {
    let counter = counter.to_be_bytes();
    let mut hmac = Hmac::<Sha1>::new_from_slice(secret.as_ref())?;
    hmac.update(&counter);
    let finalize = hmac.finalize().into_bytes();
    let slice = finalize.as_slice();
    let offset = (slice[19] & 0xf) as usize;
    let code = ((slice[offset] & 0x7f) as u32) << 24 |
        ((slice[offset + 1] & 0xff) as u32) << 16 |
        ((slice[offset + 2] & 0xff) as u32) << 8 |
        ((slice[offset + 3] & 0xff) as u32);
    let code = code % 10u32.pow(digits as u32);
    Ok(format!("{:0>width$}", code, width = digits))
}

pub fn totp(secret: &str, time_step: u64, digits: usize) -> Result<String> {
    let counter = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() / time_step;
    let secret = match base32::decode(base32::Alphabet::Rfc4648 { padding: false }, secret) {
        None => return Err(Error::message("secret not base32")),
        Some(data) => data,
    };
    hotp(secret.as_slice(), counter, digits)
}