Skip to content

Instantly share code, notes, and snippets.

@duplexsystem
Created December 30, 2022 19:46
Show Gist options
  • Save duplexsystem/a7ecdc79b4510e58adf3fe3d24e69b87 to your computer and use it in GitHub Desktop.
Save duplexsystem/a7ecdc79b4510e58adf3fe3d24e69b87 to your computer and use it in GitHub Desktop.
incomplete code to verify a zlib and gzip header
pub fn from_header(header: &[u8]) -> Option<CompressionType> {}
pub fn valid_zlib_header(header: &[u8]) -> Option<bool> {
if header.len() < 3 {
return None;
}
let compression_type = header[0] & 0b00001111;
if compression_type != 8 {
return Some(false);
}
let compression_info = header[0] >> 4;
if compression_info > 7 {
return Some(false);
}
let fcheck_mask = 0b00011111;
let fcheck = header[1] & fcheck_mask;
let mut index = 2;
Some(Self::valid_deflate_header(header[index]))
}
pub fn valid_gzip_header(header: &[u8]) -> Option<bool> {
//minimum size for gzip header + first DEFLATE chunk header is 11 bytes
let length = header.len();
if length < 11 {
return Some(false);
}
// Check magic bytes and compression method. DEFLATE (08) has been the only valid option for 30+ years so it's safe to assume this won't change. In addition the only valid oses are 0..13 and 255
let os = header[9];
if header[0] != 0x1Fu8
|| header[1] != 0x8Bu8
|| header[2] != 0x08u8
|| (os > 13 && os != 255)
{
return Some(false);
}
// Check reserved bits. These should be 0 or else this is an invalid header.
let freserved_mask = 0b11100000u8;
let freserved = header[3] & freserved_mask > 0;
if freserved {
return Some(false);
}
let ftext_mask = 0b00000001u8;
let ftext = header[3] & ftext_mask > 0;
let fhcrc_mask = 0b00000010u8;
let fhcrc = header[3] & fhcrc_mask > 0;
let fextra_mask = 0b00000100u8;
let fextra = header[3] & fextra_mask > 0;
let fname_mask = 0b00001000u8;
let fname = header[3] & fname_mask > 0;
let fcomment_mask = 0b00010000u8;
let fcomment = header[3] & fcomment_mask > 0;
// If any of these flags are set and we have less than 11 bytes we don't have enough data to check the header of the first DEFLATE chunk
if (ftext | fhcrc | fextra | fname | fcomment) && length < 11 {
return None;
}
let mut index = 9;
if fextra {
if length < 13 {
return None;
}
index += 2;
if header[index] == 0 {
return Some(false);
}
index += 1;
index += ((header[index] as usize) << 8) | (header[index + 1] as usize);
index += 1;
}
if fname {
let valid = check_valid_latin_1_string(header, length, index);
if !valid.eq(&Some(true)) {
return valid;
}
}
if fcomment {
let valid = check_valid_latin_1_string(header, length, index);
if !valid.eq(&Some(true)) {
return valid;
}
}
if fhcrc {
if length < index + 2 {
return None;
}
let header_crc32 = crc32(&header[0..index]);
let header_crc16 = (header_crc32 & 0x00000000000000001111111111111111) as u16;
index += 1;
let crc16 = ((header[index] as u16) << 8) | (header[index + 1] as u16);
if (header_crc16 != crc16) {
return Some(false);
}
index += 1;
}
// Check DEFLATE header
index += 1;
Some(Self::valid_deflate_header(header[index]))
}
pub fn valid_deflate_header(header: u8) -> bool {
// Deflate chunk is invalid if the last two bytes are set to 11
// Mask to get the second and third bits of the byte
let mask = 0b00000110;
// Use bitwise AND to get the value of the second and third bits
let bits = header & mask;
// Return true if the value of the bits is not equal to the mask, which
// indicates that both bits are not set to 1
bits != mask
}
pub fn check_valid_latin_1_string(
string: &[u8],
string_legnth: usize,
mut index: usize,
) -> Option<bool> {
loop {
if index >= string_legnth {
return None;
}
let byte = string[index];
if byte == 0 {
Some(true);
}
let first_char = byte >> 4;
if (first_char == 0x0) || (first_char == 0x1) || (first_char == 0x8) || (first_char == 0x9)
{
return Some(false);
}
index += 1;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment