t-rust-less-lib 0.1.11

Password manager library
Documentation
use super::OTPAlgorithm;
use byteorder::{BigEndian, ByteOrder};
use hmac::digest::generic_array::ArrayLength;
use hmac::digest::{BlockInput, FixedOutput, Reset, Update};
use hmac::{Hmac, Mac, NewMac};
use sha1::Sha1;
use sha2::{Sha256, Sha512};

#[derive(Debug)]
pub struct HOTPGenerator<'a> {
  pub algorithm: OTPAlgorithm,
  pub counter: u64,
  pub digits: u8,
  pub secret: &'a [u8],
}

impl<'a> HOTPGenerator<'a> {
  fn calculate<D>(&mut self) -> String
  where
    D: Update + BlockInput + FixedOutput + Reset + Default + Clone,
    D::BlockSize: ArrayLength<u8> + Clone,
    D::OutputSize: ArrayLength<u8>,
  {
    let mut mac = Hmac::<D>::new_varkey(&self.secret).unwrap();
    mac.update(&self.counter.to_be_bytes());

    self.counter += 1;

    let result = mac.finalize();
    let digest = result.into_bytes();

    let offset: usize = (digest[digest.len() - 1] & 0xf) as usize;

    let base = BigEndian::read_u32(&digest[offset..offset + 4]) & 0x7fff_ffff;

    format!(
      "{:01$}",
      base % (10 as u32).pow(u32::from(self.digits)),
      self.digits as usize
    )
  }

  pub fn generate(&mut self) -> (String, u64) {
    let otp = match self.algorithm {
      OTPAlgorithm::SHA1 => self.calculate::<Sha1>(),
      OTPAlgorithm::SHA256 => self.calculate::<Sha256>(),
      OTPAlgorithm::SHA512 => self.calculate::<Sha512>(),
    };
    (otp, self.counter)
  }
}