Created
December 30, 2022 19:46
-
-
Save duplexsystem/a7ecdc79b4510e58adf3fe3d24e69b87 to your computer and use it in GitHub Desktop.
incomplete code to verify a zlib and gzip header
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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