treewide: migrate to multi-crate layout
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I11a2103f3530f07409177404577b90136a6a6964
This commit is contained in:
parent
f655b133d4
commit
d445b1814a
68 changed files with 247 additions and 72 deletions
|
|
@ -1,169 +0,0 @@
|
|||
use std::{
|
||||
fs::File,
|
||||
io::{BufReader, Read},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
use md5::{Digest as Md5Digest, Md5};
|
||||
use sha1::Sha1;
|
||||
use sha2::{Sha256, Sha512};
|
||||
|
||||
use crate::error::{PakkerError, Result};
|
||||
|
||||
pub fn hash_to_hex(hash: impl AsRef<[u8]>) -> String {
|
||||
use std::fmt::Write;
|
||||
let bytes = hash.as_ref();
|
||||
let mut hex = String::with_capacity(bytes.len() * 2);
|
||||
for byte in bytes {
|
||||
let _ = write!(hex, "{byte:02x}");
|
||||
}
|
||||
hex
|
||||
}
|
||||
|
||||
/// Compute SHA1 hash of a file
|
||||
pub fn compute_sha1<P: AsRef<Path>>(path: P) -> Result<String> {
|
||||
let file = File::open(path)?;
|
||||
let mut reader = BufReader::new(file);
|
||||
let mut hasher = Sha1::new();
|
||||
let mut buffer = [0; 8192];
|
||||
|
||||
loop {
|
||||
let n = reader.read(&mut buffer)?;
|
||||
if n == 0 {
|
||||
break;
|
||||
}
|
||||
hasher.update(&buffer[..n]);
|
||||
}
|
||||
|
||||
Ok(hash_to_hex(hasher.finalize().as_slice()))
|
||||
}
|
||||
|
||||
/// Compute SHA256 hash of a file
|
||||
pub fn compute_sha256<P: AsRef<Path>>(path: P) -> Result<String> {
|
||||
let file = File::open(path)?;
|
||||
let mut reader = BufReader::new(file);
|
||||
let mut hasher = Sha256::new();
|
||||
let mut buffer = [0; 8192];
|
||||
|
||||
loop {
|
||||
let n = reader.read(&mut buffer)?;
|
||||
if n == 0 {
|
||||
break;
|
||||
}
|
||||
hasher.update(&buffer[..n]);
|
||||
}
|
||||
|
||||
Ok(hash_to_hex(hasher.finalize().as_slice()))
|
||||
}
|
||||
|
||||
/// Compute SHA256 hash of byte data
|
||||
pub fn compute_sha256_bytes(data: &[u8]) -> String {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(data);
|
||||
hash_to_hex(hasher.finalize().as_slice())
|
||||
}
|
||||
|
||||
/// Compute SHA512 hash of a file
|
||||
pub fn compute_sha512<P: AsRef<Path>>(path: P) -> Result<String> {
|
||||
let file = File::open(path)?;
|
||||
let mut reader = BufReader::new(file);
|
||||
let mut hasher = Sha512::new();
|
||||
let mut buffer = [0; 8192];
|
||||
|
||||
loop {
|
||||
let n = reader.read(&mut buffer)?;
|
||||
if n == 0 {
|
||||
break;
|
||||
}
|
||||
hasher.update(&buffer[..n]);
|
||||
}
|
||||
|
||||
Ok(hash_to_hex(hasher.finalize().as_slice()))
|
||||
}
|
||||
|
||||
/// Compute MD5 hash of a file
|
||||
pub fn compute_md5<P: AsRef<Path>>(path: P) -> Result<String> {
|
||||
let file = File::open(path)?;
|
||||
let mut reader = BufReader::new(file);
|
||||
let mut hasher = Md5::new();
|
||||
let mut buffer = [0; 8192];
|
||||
|
||||
loop {
|
||||
let n = reader.read(&mut buffer)?;
|
||||
if n == 0 {
|
||||
break;
|
||||
}
|
||||
hasher.update(&buffer[..n]);
|
||||
}
|
||||
|
||||
let hash = hasher.finalize();
|
||||
let mut hex = String::with_capacity(hash.len() * 2);
|
||||
for byte in hash {
|
||||
let _ = std::fmt::write(&mut hex, format_args!("{byte:02x}"));
|
||||
}
|
||||
Ok(hex)
|
||||
}
|
||||
|
||||
/// Verify a file's hash against expected value
|
||||
pub fn verify_hash<P: AsRef<Path>>(
|
||||
path: P,
|
||||
algorithm: &str,
|
||||
expected: &str,
|
||||
) -> Result<bool> {
|
||||
let path = path.as_ref();
|
||||
let actual = match algorithm {
|
||||
"sha1" => compute_sha1(path)?,
|
||||
"sha256" => compute_sha256(path)?,
|
||||
"sha512" => compute_sha512(path)?,
|
||||
"md5" => compute_md5(path)?,
|
||||
_ => {
|
||||
return Err(PakkerError::InternalError(format!(
|
||||
"Unknown hash algorithm: {algorithm}"
|
||||
)));
|
||||
},
|
||||
};
|
||||
|
||||
Ok(actual.eq_ignore_ascii_case(expected))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_sha256_bytes_deterministic() {
|
||||
let data = b"test data";
|
||||
let hash1 = compute_sha256_bytes(data);
|
||||
let hash2 = compute_sha256_bytes(data);
|
||||
assert_eq!(hash1, hash2, "SHA256 must be deterministic");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sha256_bytes_format() {
|
||||
let data = b"hello";
|
||||
let hash = compute_sha256_bytes(data);
|
||||
assert_eq!(hash.len(), 64, "SHA256 hex should be 64 characters");
|
||||
assert!(
|
||||
hash.chars().all(|c| c.is_ascii_hexdigit()),
|
||||
"SHA256 should only contain hex digits"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sha256_bytes_empty() {
|
||||
let hash = compute_sha256_bytes(b"");
|
||||
assert_eq!(
|
||||
hash,
|
||||
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sha256_bytes_known_value() {
|
||||
// SHA256 of "hello" in hex
|
||||
let expected =
|
||||
"2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824";
|
||||
let hash = compute_sha256_bytes(b"hello");
|
||||
assert_eq!(hash, expected);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue