use happy_cracking::crypto::hash_ext;
use sha2::{Digest, Sha256};
fn verify_extension(secret: &[u8], message: &[u8], append: &[u8]) {
let mut hasher = Sha256::new();
hasher.update(secret);
hasher.update(message);
let original_hash = hex::encode(hasher.finalize());
let original_len = (secret.len() + message.len()) as u64;
let result = hash_ext::sha256_extend(&original_hash, original_len, append).unwrap();
let mut full_message = Vec::new();
full_message.extend_from_slice(secret);
full_message.extend_from_slice(message);
full_message.extend_from_slice(&result.forged_suffix);
let mut expected_hasher = Sha256::new();
expected_hasher.update(&full_message);
let expected_hash = hex::encode(expected_hasher.finalize());
assert_eq!(
result.new_hash, expected_hash,
"Extension hash does not match direct SHA-256 computation"
);
let suffix_len = result.forged_suffix.len();
assert!(suffix_len > append.len());
assert_eq!(&result.forged_suffix[suffix_len - append.len()..], append);
assert_eq!(result.forged_suffix[0], 0x80);
}
#[test]
fn extend_basic() {
verify_extension(b"secret", b"data", b"append");
}
#[test]
fn extend_empty_message() {
verify_extension(b"secretkey", b"", b"admin=true");
}
#[test]
fn extend_long_secret() {
verify_extension(b"a_very_long_secret_key_for_testing", b"msg", b"extra");
}
#[test]
fn extend_ctf_style() {
verify_extension(b"key", b"user=guest", b"&admin=true");
}
#[test]
fn extend_single_byte_append() {
verify_extension(b"secret", b"data", b"x");
}
#[test]
fn extend_large_message() {
let message = b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
verify_extension(b"key", message, b"end");
}
#[test]
fn extend_crosses_block_boundary() {
let secret = b"0123456789abcdef0123456789abcdef";
let message = b"0123456789abcdef0123456789abcdef";
verify_extension(secret, message, b"ext");
}
#[test]
fn extend_invalid_hash_length() {
let result = hash_ext::sha256_extend("aabbcc", 10, b"data");
assert!(result.is_err());
}
#[test]
fn extend_invalid_hex() {
let result = hash_ext::sha256_extend(
"zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz",
10,
b"data",
);
assert!(result.is_err());
}
#[test]
fn extend_flag_format() {
verify_extension(b"hmac_secret", b"flag{hash_", b"extension}");
}