#[cfg(feature = "legacy-crypto")]
use crate::utils::{compute_md5, compute_sha1};
use crate::utils::{compute_sha256, compute_sha384, compute_sha512};
use crate::Result;
use std::fmt::Write;
fn bytes_to_hex(bytes: &[u8]) -> String {
let mut hex_string = String::with_capacity(bytes.len() * 2);
for byte in bytes {
let _ = write!(&mut hex_string, "{byte:02x}");
}
hex_string
}
#[derive(Debug)]
pub struct AssemblyRefHash {
data: Vec<u8>,
}
impl AssemblyRefHash {
pub fn new(data: &[u8]) -> Result<AssemblyRefHash> {
if data.is_empty() {
return Err(malformed_error!(
"AssemblyRefHash entries are not allowed to be empty"
));
}
Ok(AssemblyRefHash {
data: data.to_vec(),
})
}
#[must_use]
pub fn data(&self) -> &[u8] {
&self.data
}
#[must_use]
pub fn hex(&self) -> String {
bytes_to_hex(&self.data)
}
#[must_use]
pub fn to_string_pretty(&self) -> String {
let hex = self.hex();
let algorithm = match self.data.len() {
16 => "MD5",
20 => "SHA1",
32 => "SHA256",
48 => "SHA384",
64 => "SHA512",
_ => "Unknown",
};
format!("{algorithm}: {hex}")
}
#[must_use]
#[cfg(feature = "legacy-crypto")]
pub fn verify_md5(&self, expected: &[u8]) -> bool {
if self.data.len() != 16 {
return false;
}
self.data == compute_md5(expected)
}
#[must_use]
#[cfg(not(feature = "legacy-crypto"))]
pub fn verify_md5(&self, _expected: &[u8]) -> bool {
false }
#[must_use]
#[cfg(feature = "legacy-crypto")]
pub fn verify_sha1(&self, expected: &[u8]) -> bool {
if self.data.len() != 20 {
return false;
}
self.data == compute_sha1(expected)
}
#[must_use]
#[cfg(not(feature = "legacy-crypto"))]
pub fn verify_sha1(&self, _expected: &[u8]) -> bool {
false }
#[must_use]
pub fn verify_sha256(&self, expected: &[u8]) -> bool {
if self.data.len() != 32 {
return false;
}
self.data == compute_sha256(expected)
}
#[must_use]
pub fn verify_sha384(&self, expected: &[u8]) -> bool {
if self.data.len() != 48 {
return false;
}
self.data == compute_sha384(expected)
}
#[must_use]
pub fn verify_sha512(&self, expected: &[u8]) -> bool {
if self.data.len() != 64 {
return false;
}
self.data == compute_sha512(expected)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn create_test_sha256_hash() -> Vec<u8> {
compute_sha256(b"test data")
}
fn create_test_sha384_hash() -> Vec<u8> {
compute_sha384(b"test data")
}
fn create_test_sha512_hash() -> Vec<u8> {
compute_sha512(b"test data")
}
#[test]
fn test_new_with_valid_data() {
let data = vec![1, 2, 3, 4, 5];
let hash = AssemblyRefHash::new(&data).unwrap();
assert_eq!(hash.data(), &data);
}
#[test]
fn test_new_with_empty_data_fails() {
let result = AssemblyRefHash::new(&[]);
assert!(result.is_err());
let error_msg = result.unwrap_err().to_string();
assert!(error_msg.contains("not allowed to be empty"));
}
#[test]
fn test_data_getter() {
let test_data = vec![0x12, 0x34, 0x56, 0x78];
let hash = AssemblyRefHash::new(&test_data).unwrap();
assert_eq!(hash.data(), &test_data);
}
#[test]
fn test_hex_formatting() {
let test_data = vec![0x12, 0x34, 0x56, 0x78, 0xab, 0xcd, 0xef];
let hash = AssemblyRefHash::new(&test_data).unwrap();
assert_eq!(hash.hex(), "12345678abcdef");
}
#[test]
fn test_hex_formatting_with_zeros() {
let test_data = vec![0x00, 0x01, 0x0a, 0xff];
let hash = AssemblyRefHash::new(&test_data).unwrap();
assert_eq!(hash.hex(), "00010aff");
}
#[test]
fn test_to_string_pretty_md5_length() {
let md5_length_hash = vec![0x42; 16];
let hash = AssemblyRefHash::new(&md5_length_hash).unwrap();
let pretty = hash.to_string_pretty();
assert!(pretty.starts_with("MD5: "));
assert_eq!(pretty.len(), 5 + 32); }
#[test]
fn test_to_string_pretty_sha1_length() {
let sha1_length_hash = vec![0x42; 20];
let hash = AssemblyRefHash::new(&sha1_length_hash).unwrap();
let pretty = hash.to_string_pretty();
assert!(pretty.starts_with("SHA1: "));
assert_eq!(pretty.len(), 6 + 40); }
#[test]
fn test_to_string_pretty_unknown_length() {
let unknown_hash = vec![1, 2, 3, 4, 5]; let hash = AssemblyRefHash::new(&unknown_hash).unwrap();
let pretty = hash.to_string_pretty();
assert!(pretty.starts_with("Unknown: "));
assert_eq!(pretty, "Unknown: 0102030405");
}
#[test]
fn test_to_string_pretty_sha256() {
let sha256_hash = create_test_sha256_hash();
let hash = AssemblyRefHash::new(&sha256_hash).unwrap();
let pretty = hash.to_string_pretty();
assert!(pretty.starts_with("SHA256: "));
assert_eq!(pretty.len(), 8 + 64); }
#[test]
fn test_to_string_pretty_sha384() {
let sha384_hash = create_test_sha384_hash();
let hash = AssemblyRefHash::new(&sha384_hash).unwrap();
let pretty = hash.to_string_pretty();
assert!(pretty.starts_with("SHA384: "));
assert_eq!(pretty.len(), 8 + 96); }
#[test]
fn test_to_string_pretty_sha512() {
let sha512_hash = create_test_sha512_hash();
let hash = AssemblyRefHash::new(&sha512_hash).unwrap();
let pretty = hash.to_string_pretty();
assert!(pretty.starts_with("SHA512: "));
assert_eq!(pretty.len(), 8 + 128); }
#[test]
fn test_verify_sha256_success() {
let test_input = b"test data";
let expected_hash = create_test_sha256_hash();
let hash = AssemblyRefHash::new(&expected_hash).unwrap();
assert!(hash.verify_sha256(test_input));
}
#[test]
fn test_verify_sha256_failure_wrong_data() {
let expected_hash = create_test_sha256_hash();
let hash = AssemblyRefHash::new(&expected_hash).unwrap();
assert!(!hash.verify_sha256(b"wrong data"));
}
#[test]
fn test_verify_sha256_failure_wrong_length() {
let wrong_length_hash = vec![0x42; 20];
let hash = AssemblyRefHash::new(&wrong_length_hash).unwrap();
assert!(!hash.verify_sha256(b"test data"));
}
#[test]
fn test_verify_sha384_success() {
let test_input = b"test data";
let expected_hash = create_test_sha384_hash();
let hash = AssemblyRefHash::new(&expected_hash).unwrap();
assert!(hash.verify_sha384(test_input));
}
#[test]
fn test_verify_sha384_failure_wrong_data() {
let expected_hash = create_test_sha384_hash();
let hash = AssemblyRefHash::new(&expected_hash).unwrap();
assert!(!hash.verify_sha384(b"wrong data"));
}
#[test]
fn test_verify_sha384_failure_wrong_length() {
let sha256_hash = create_test_sha256_hash(); let hash = AssemblyRefHash::new(&sha256_hash).unwrap();
assert!(!hash.verify_sha384(b"test data"));
}
#[test]
fn test_verify_sha512_success() {
let test_input = b"test data";
let expected_hash = create_test_sha512_hash();
let hash = AssemblyRefHash::new(&expected_hash).unwrap();
assert!(hash.verify_sha512(test_input));
}
#[test]
fn test_verify_sha512_failure_wrong_data() {
let expected_hash = create_test_sha512_hash();
let hash = AssemblyRefHash::new(&expected_hash).unwrap();
assert!(!hash.verify_sha512(b"wrong data"));
}
#[test]
fn test_verify_sha512_failure_wrong_length() {
let sha384_hash = create_test_sha384_hash(); let hash = AssemblyRefHash::new(&sha384_hash).unwrap();
assert!(!hash.verify_sha512(b"test data"));
}
#[test]
fn test_with_real_sha256_hash() {
let input = b"The quick brown fox jumps over the lazy dog";
let expected_hash = compute_sha256(input);
let hash = AssemblyRefHash::new(&expected_hash).unwrap();
assert_eq!(hash.data().len(), 32);
assert!(hash.verify_sha256(input));
let pretty = hash.to_string_pretty();
assert!(pretty.starts_with("SHA256: "));
}
#[test]
fn test_with_real_sha384_hash() {
let input = b"The quick brown fox jumps over the lazy dog";
let expected_hash = compute_sha384(input);
let hash = AssemblyRefHash::new(&expected_hash).unwrap();
assert_eq!(hash.data().len(), 48);
assert!(hash.verify_sha384(input));
assert!(!hash.verify_sha256(input));
let pretty = hash.to_string_pretty();
assert!(pretty.starts_with("SHA384: "));
}
#[test]
fn test_with_real_sha512_hash() {
let input = b"The quick brown fox jumps over the lazy dog";
let expected_hash = compute_sha512(input);
let hash = AssemblyRefHash::new(&expected_hash).unwrap();
assert_eq!(hash.data().len(), 64);
assert!(hash.verify_sha512(input));
assert!(!hash.verify_sha384(input));
let pretty = hash.to_string_pretty();
assert!(pretty.starts_with("SHA512: "));
}
#[test]
fn test_bytes_to_hex_helper() {
let bytes = vec![0x00, 0x01, 0x0a, 0x10, 0xff];
let hex = bytes_to_hex(&bytes);
assert_eq!(hex, "00010a10ff");
}
#[test]
fn test_bytes_to_hex_empty() {
let hex = bytes_to_hex(&[]);
assert_eq!(hex, "");
}
#[test]
fn test_edge_case_single_byte() {
let single_byte = vec![0x42];
let hash = AssemblyRefHash::new(&single_byte).unwrap();
assert_eq!(hash.hex(), "42");
assert_eq!(hash.to_string_pretty(), "Unknown: 42");
}
#[test]
fn test_edge_case_max_byte_values() {
let max_bytes = vec![0xff; 31];
let hash = AssemblyRefHash::new(&max_bytes).unwrap();
assert_eq!(hash.hex(), "f".repeat(62));
assert!(hash.to_string_pretty().starts_with("Unknown: "));
}
#[test]
fn test_case_sensitivity_in_hex() {
let test_data = vec![0xab, 0xcd, 0xef];
let hash = AssemblyRefHash::new(&test_data).unwrap();
let hex = hash.hex();
assert_eq!(hex, "abcdef");
assert!(!hex.contains('A'));
assert!(!hex.contains('B'));
assert!(!hex.contains('C'));
assert!(!hex.contains('D'));
assert!(!hex.contains('E'));
assert!(!hex.contains('F'));
}
}
#[cfg(all(test, feature = "legacy-crypto"))]
mod legacy_tests {
use super::*;
fn create_test_md5_hash() -> Vec<u8> {
compute_md5(b"test data")
}
fn create_test_sha1_hash() -> Vec<u8> {
compute_sha1(b"test data")
}
#[test]
fn test_verify_md5_success() {
let test_input = b"test data";
let expected_hash = create_test_md5_hash();
let hash = AssemblyRefHash::new(&expected_hash).unwrap();
assert!(hash.verify_md5(test_input));
}
#[test]
fn test_verify_md5_failure_wrong_data() {
let expected_hash = create_test_md5_hash();
let hash = AssemblyRefHash::new(&expected_hash).unwrap();
assert!(!hash.verify_md5(b"wrong data"));
}
#[test]
fn test_verify_md5_failure_wrong_length() {
let sha1_hash = create_test_sha1_hash(); let hash = AssemblyRefHash::new(&sha1_hash).unwrap();
assert!(!hash.verify_md5(b"test data"));
}
#[test]
fn test_verify_sha1_success() {
let test_input = b"test data";
let expected_hash = create_test_sha1_hash();
let hash = AssemblyRefHash::new(&expected_hash).unwrap();
assert!(hash.verify_sha1(test_input));
}
#[test]
fn test_verify_sha1_failure_wrong_data() {
let expected_hash = create_test_sha1_hash();
let hash = AssemblyRefHash::new(&expected_hash).unwrap();
assert!(!hash.verify_sha1(b"wrong data"));
}
#[test]
fn test_verify_sha1_failure_wrong_length() {
let md5_hash = create_test_md5_hash(); let hash = AssemblyRefHash::new(&md5_hash).unwrap();
assert!(!hash.verify_sha1(b"test data"));
}
#[test]
fn test_with_real_md5_hash() {
let input = b"The quick brown fox jumps over the lazy dog";
let expected_hash = compute_md5(input);
let hash = AssemblyRefHash::new(&expected_hash).unwrap();
assert_eq!(hash.data().len(), 16);
assert!(hash.verify_md5(input));
assert!(!hash.verify_sha1(input));
let pretty = hash.to_string_pretty();
assert!(pretty.starts_with("MD5: "));
}
#[test]
fn test_with_real_sha1_hash() {
let input = b"The quick brown fox jumps over the lazy dog";
let expected_hash = compute_sha1(input);
let hash = AssemblyRefHash::new(&expected_hash).unwrap();
assert_eq!(hash.data().len(), 20);
assert!(hash.verify_sha1(input));
assert!(!hash.verify_md5(input));
let pretty = hash.to_string_pretty();
assert!(pretty.starts_with("SHA1: "));
}
#[test]
fn test_edge_case_single_byte_legacy() {
let single_byte = vec![0x42];
let hash = AssemblyRefHash::new(&single_byte).unwrap();
assert!(!hash.verify_md5(b"anything"));
assert!(!hash.verify_sha1(b"anything"));
}
}