use crate::usize_from_u32;
use crate::{PeOffsetError, PeTrait};
use alloc::vec::Vec;
use digest::Update;
fn authenticode_digest_impl(
pe: &dyn PeTrait,
digest: &mut dyn Update,
) -> Option<()> {
let offsets = pe.offsets().ok()?;
let bytes = &pe.data().get(..offsets.check_sum)?;
digest.update(bytes);
let bytes = &pe
.data()
.get(offsets.after_check_sum..offsets.security_data_dir)?;
digest.update(bytes);
let bytes = &pe
.data()
.get(offsets.after_security_data_dir..offsets.after_header)?;
digest.update(bytes);
let mut sum_of_bytes_hashed = usize_from_u32(offsets.after_header as u32);
let mut sections = (1..=pe.num_sections())
.map(|i| pe.section_data_range(i))
.collect::<Result<Vec<_>, PeOffsetError>>()
.ok()?;
sections.sort_unstable_by_key(|r| r.start);
for section_range in sections {
let bytes = &pe.data().get(section_range)?;
digest.update(bytes);
sum_of_bytes_hashed = sum_of_bytes_hashed.checked_add(bytes.len())?;
}
let mut extra_hash_len =
pe.data().len().checked_sub(sum_of_bytes_hashed)?;
if let Some(security_data_dir) = pe.certificate_table_range().ok()? {
let size =
security_data_dir.end.checked_sub(security_data_dir.start)?;
extra_hash_len = extra_hash_len.checked_sub(size)?;
}
digest.update(pe.data().get(
sum_of_bytes_hashed..sum_of_bytes_hashed.checked_add(extra_hash_len)?,
)?);
Some(())
}
pub fn authenticode_digest(
pe: &dyn PeTrait,
digest: &mut dyn Update,
) -> Result<(), PeOffsetError> {
authenticode_digest_impl(pe, digest).ok_or(PeOffsetError)
}