use std::backtrace::Backtrace;
use sha1::{Digest, Sha1};
use snafu::Snafu;
#[derive(Clone)]
pub struct HmacSha1 {
inner_pad: [u8; 64],
outer_pad: [u8; 64],
}
impl HmacSha1 {
pub fn new(key: [u8; 64]) -> Self {
let mut inner_pad = [0x36; 64];
let mut outer_pad = [0x5c; 64];
inner_pad.iter_mut().zip(key.iter()).for_each(|(i, k)| *i ^= *k);
outer_pad.iter_mut().zip(key.iter()).for_each(|(o, k)| *o ^= *k);
Self { inner_pad, outer_pad }
}
pub fn compute(&self, data: &[u8]) -> [u8; 20] {
let mut sha1 = Sha1::new();
sha1.update(self.inner_pad);
sha1.update(data);
let inner_hash = sha1.finalize_reset();
sha1.update(self.outer_pad);
sha1.update(inner_hash);
let outer_hash = sha1.finalize();
outer_hash.into()
}
}
#[derive(Debug, Snafu)]
pub enum HmacSha1FromBytesError {
#[snafu(display("key must be 64 bytes long, but got {} bytes:\n{backtrace}", length))]
InvalidKeyLength {
length: usize,
backtrace: Backtrace,
},
}
impl TryFrom<&[u8]> for HmacSha1 {
type Error = HmacSha1FromBytesError;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
if value.len() != 64 {
return InvalidKeyLengthSnafu { length: value.len() }.fail();
}
let mut key = [0; 64];
key.copy_from_slice(value);
Ok(Self::new(key))
}
}