crowdstrike_cloudproto/services/lfo/
file_header.rs1use byteorder::{ReadBytesExt, BE};
2use std::io::{Cursor, Read};
3use tracing::trace;
4
5pub(crate) const LFO_RESP_HDR_LEN: usize = 0x2A;
7pub(crate) const CRC_LEN: usize = 4;
8
9#[repr(u16)]
10#[derive(Debug, Copy, Clone, Eq, PartialEq)]
11pub enum CompressionFormats {
12 None = 0,
14 Xz = 1,
16}
17
18#[derive(Debug, Copy, Clone, Eq, PartialEq)]
21pub struct LfoFileHeader {
22 pub magic: u32,
24 pub unk_cst1: u16,
26 pub comp_format: u16,
28 pub payload_size: u32,
30 pub data_hash: [u8; 32],
32 pub cur_payload_size: u32,
36 pub cur_state: u16,
39 pub unk: u16,
41}
42
43impl TryFrom<&[u8]> for LfoFileHeader {
44 type Error = String;
45
46 fn try_from(lfo_payload: &[u8]) -> Result<Self, Self::Error> {
47 if lfo_payload.len() < LFO_RESP_HDR_LEN + CRC_LEN {
53 return Err("LFO OK header too small".into());
54 }
55 let header = &lfo_payload[..LFO_RESP_HDR_LEN];
56 let payload_data = &lfo_payload[LFO_RESP_HDR_LEN..]; let mut header_reader = Cursor::new(&header);
58 let chunk_start_off = header_reader.read_u32::<BE>().unwrap();
59 let chunk_end_off = header_reader.read_u32::<BE>().unwrap();
60 let mut pkt_unk_buf = [0; 32];
61 header_reader.read_exact(&mut pkt_unk_buf).unwrap();
62 let comp_format = header_reader.read_u16::<BE>().unwrap();
63 trace!("Received LFO header data: {}", hex::encode(header));
64
65 if chunk_start_off > chunk_end_off {
66 return Err(format!(
67 "LFO response start offset {:#x} is past end offset {:#x}",
68 chunk_start_off, chunk_end_off
69 ));
70 }
71
72 let len_without_crc = payload_data.len() - CRC_LEN;
73 if chunk_start_off != 0 {
74 return Err("Unexpected non-0 offset in LFO response".into());
75 }
76 let chunk_size = chunk_end_off - chunk_start_off;
77 if comp_format == 0 && chunk_size != len_without_crc as u32 {
78 return Err(format!(
79 "Expected {:#x} bytes LFO file data, but uncompressed payload is {:#x} bytes",
80 chunk_size, len_without_crc
81 ));
82 }
83
84 let expected_crc = u32::from_be_bytes(payload_data[len_without_crc..].try_into().unwrap());
85 let crc = crc32fast::hash(&payload_data[..len_without_crc]);
86 if crc != expected_crc {
87 return Err(format!(
88 "Expected CRC 0x{:X}, but computed 0x{:X}",
89 expected_crc, crc
90 ));
91 }
92
93 Ok(Self {
94 magic: 0x4C444852, unk_cst1: 1,
96 comp_format,
97 payload_size: chunk_end_off,
98 data_hash: pkt_unk_buf,
99 cur_payload_size: len_without_crc as u32,
100 cur_state: 5,
101 unk: 0,
102 })
103 }
104}