use crate::cryptography::hmac_sign::{Operation, Sign, SignType, SignatureData};
use hmac::{Hmac, Mac};
use sha2::{Sha256, Sha512};
impl Sign {
pub fn new(data: Vec<u8>, passphrase: Vec<u8>, status: Operation, hash_type: SignType) -> Self {
let data = SignatureData {
data,
passphrase,
hmac: Vec::new(),
concat_data: Vec::new(),
};
match hash_type {
SignType::Sha512 => Sign {
data,
status,
hash_type,
length: 64,
veryfied: false,
},
SignType::Sha256 => Sign {
data,
status,
hash_type,
length: 32,
veryfied: false,
},
_ => Sign {
data,
status,
hash_type,
length: 64,
veryfied: false,
},
}
}
pub fn hmac(&mut self) -> Vec<u8> {
match &self.status {
Operation::Sign => self.generate_hmac(),
Operation::Verify => self.verify_hmac().unwrap_or_default(),
}
}
pub fn generate_hmac(&self) -> Vec<u8> {
let data = &self.data.data;
match &self.hash_type {
SignType::Sha512 => {
let mut mac = <Hmac<Sha512> as Mac>::new_from_slice(&self.data.passphrase)
.expect("HMAC can take key of any size");
mac.update(data);
let hmac = mac.finalize().into_bytes().to_vec();
let concat_data = [&self.data.data, hmac.as_slice()].concat();
concat_data
}
SignType::Sha256 => {
let mut mac = <Hmac<Sha256> as Mac>::new_from_slice(&self.data.passphrase)
.expect("HMAC can take key of any size");
mac.update(data);
let hmac = mac.finalize().into_bytes().to_vec();
let concat_data = [&self.data.data, hmac.as_slice()].concat();
concat_data
}
_ => vec![],
}
}
fn verify_hmac_sha512(data: &[u8], hmac: &[u8], passphrase: &[u8]) -> bool {
let mut mac = <Hmac<Sha512> as Mac>::new_from_slice(passphrase)
.expect("HMAC can take key of any size");
mac.update(data);
mac.verify_slice(hmac).is_ok()
}
fn verify_hmac_sha256(data: &[u8], hmac: &[u8], passphrase: &[u8]) -> bool {
let mut mac = <Hmac<Sha256> as Mac>::new_from_slice(passphrase)
.expect("HMAC can take key of any size");
mac.update(data);
mac.verify_slice(hmac).is_ok()
}
pub fn verify_hmac(&self) -> Result<Vec<u8>, &'static str> {
if self.data.data.len() < self.length {
return Err("Data is too short for HMAC verification");
}
let (data, hmac) = self.data.data.split_at(self.data.data.len() - self.length);
let verification_success = match &self.hash_type {
SignType::Sha512 => Self::verify_hmac_sha512(data, hmac, &self.data.passphrase),
SignType::Sha256 => Self::verify_hmac_sha256(data, hmac, &self.data.passphrase),
_ => return Err("Unsupported HMAC hash type"),
};
if verification_success {
Ok(data.to_owned())
} else {
Err("HMAC verification failed")
}
}
}