use openssl::{
hash::MessageDigest,
pkey::{PKey, Private},
sign::Signer,
};
use crate::Digest;
pub struct Hmac {
digest: MessageDigest,
key: PKey<Private>,
}
impl Hmac {
#[cfg(test)]
#[inline]
pub fn num_bytes(&self) -> usize {
self.digest.size()
}
pub fn from_key(algorithm: Digest, key: &[u8]) -> Self {
let digest = match algorithm {
Digest::Sha256 => MessageDigest::sha256(),
Digest::Sha512 => MessageDigest::sha512(),
};
let key = PKey::hmac(key).expect("init openssl hmac ctx fail");
Hmac { digest, key }
}
#[cfg(test)]
pub fn sign(&mut self, crypted_data: &[u8]) -> Vec<u8> {
let mut sign = Signer::new(self.digest, &self.key).expect("init openssl signer ctx fail");
sign.update(crypted_data).expect("openssl hmac update fail");
sign.sign_to_vec().expect("hmac sign oneshot fail")
}
#[cfg(test)]
pub fn verify(&mut self, crypted_data: &[u8], expected_hash: &[u8]) -> bool {
let n = self.sign(crypted_data);
if n.len() != expected_hash.len() {
return false;
}
openssl::memcmp::eq(&n, expected_hash)
}
pub fn context(&self) -> Context<'_> {
Context(Signer::new(self.digest, &self.key).expect("init openssl signer ctx fail"))
}
}
pub struct Context<'a>(Signer<'a>);
impl Context<'_> {
pub fn update(&mut self, data: &[u8]) {
self.0.update(data).expect("openssl hmac update fail")
}
pub fn sign(self) -> Vec<u8> {
self.0.sign_to_vec().expect("hmac sign oneshot fail")
}
}