90 lines
2.0 KiB
Rust
90 lines
2.0 KiB
Rust
use blake3::{Hash, Hasher};
|
|
|
|
use crate::errors::ApiError;
|
|
|
|
pub trait CustomHash {
|
|
fn updater(&self, hasher: &mut Hasher);
|
|
|
|
fn hash(&self) -> Hash {
|
|
let mut hasher = Hasher::new();
|
|
Self::updater(&self, &mut hasher);
|
|
hasher.finalize()
|
|
}
|
|
}
|
|
|
|
pub struct IntegrityVerifier {
|
|
mac: Hasher,
|
|
}
|
|
|
|
impl IntegrityVerifier {
|
|
pub fn new() -> Result<Self, ApiError> {
|
|
Ok(Self {
|
|
mac: Hasher::new_derive_key(include_str!("./verification_secret")),
|
|
})
|
|
}
|
|
|
|
pub fn sign<T>(&self, data: &T) -> Result<Hash, ApiError>
|
|
where
|
|
T: CustomHash,
|
|
{
|
|
let mut mac = self.mac.clone();
|
|
|
|
mac.update(data.hash().as_bytes());
|
|
let signature = mac.finalize();
|
|
mac.reset();
|
|
|
|
Ok(signature)
|
|
}
|
|
|
|
pub fn verify<T>(&self, data: &T, signature: Hash) -> Result<(), ApiError>
|
|
where
|
|
T: CustomHash,
|
|
{
|
|
let mut mac = self.mac.clone();
|
|
mac.update(data.hash().as_bytes());
|
|
let verify = mac.finalize();
|
|
mac.reset();
|
|
|
|
match verify == signature {
|
|
true => Ok(()),
|
|
false => Err(ApiError::AccessDenied),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
|
|
use blake3::Hasher;
|
|
|
|
use crate::api::backend::integrity_verification::{CustomHash, IntegrityVerifier};
|
|
|
|
#[test]
|
|
fn integrity_verification() {
|
|
struct TestData {
|
|
one: u32,
|
|
two: String,
|
|
}
|
|
|
|
impl CustomHash for TestData {
|
|
fn updater(&self, hasher: &mut Hasher) {
|
|
hasher.update(&self.one.to_be_bytes());
|
|
hasher.update(&self.two.as_bytes());
|
|
}
|
|
}
|
|
|
|
let verifier = IntegrityVerifier::new().unwrap();
|
|
|
|
let mut item = TestData {
|
|
one: 24,
|
|
two: "MyTesting".to_string(),
|
|
};
|
|
|
|
let signature = verifier.sign(&item).unwrap();
|
|
assert!(verifier.verify(&item, signature).is_ok());
|
|
|
|
item.two = "Wrong".to_string();
|
|
assert!(verifier.verify(&item, signature).is_err());
|
|
}
|
|
}
|