rar_stream/parsing/rar5/
encryption_header.rs1use super::VintReader;
7use crate::error::{RarError, Result};
8
9#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct Rar5EncryptionHeader {
12 pub version: u8,
14 pub flags: u8,
16 pub lg2_count: u8,
18 pub salt: [u8; 16],
20 pub check_value: Option<[u8; 12]>,
22}
23
24impl Rar5EncryptionHeader {
25 pub const FLAG_CHECK_PRESENT: u8 = 0x01;
27}
28
29pub struct Rar5EncryptionHeaderParser;
30
31impl Rar5EncryptionHeaderParser {
32 pub fn parse(data: &[u8]) -> Result<(Rar5EncryptionHeader, usize)> {
35 if data.len() < 4 {
36 return Err(RarError::InvalidHeader);
37 }
38
39 let mut pos = 0;
40
41 let _crc = u32::from_le_bytes([data[0], data[1], data[2], data[3]]);
43 pos += 4;
44
45 let mut reader = VintReader::new(&data[pos..]);
47 let header_size = reader.read().ok_or(RarError::InvalidHeader)?;
48 let header_content_start = pos + reader.position();
49 pos += reader.position();
50
51 let mut reader = VintReader::new(&data[pos..]);
53 let header_type = reader.read().ok_or(RarError::InvalidHeader)?;
54 pos += reader.position();
55
56 if header_type != 4 {
57 return Err(RarError::InvalidHeaderType(header_type as u8));
58 }
59
60 let mut reader = VintReader::new(&data[pos..]);
62 let _header_flags = reader.read().ok_or(RarError::InvalidHeader)?;
63 pos += reader.position();
64
65 let mut reader = VintReader::new(&data[pos..]);
67 let version = reader.read().ok_or(RarError::InvalidHeader)? as u8;
68 pos += reader.position();
69
70 let mut reader = VintReader::new(&data[pos..]);
72 let flags = reader.read().ok_or(RarError::InvalidHeader)? as u8;
73 pos += reader.position();
74
75 if pos >= data.len() {
77 return Err(RarError::InvalidHeader);
78 }
79 let lg2_count = data[pos];
80 pos += 1;
81
82 if pos + 16 > data.len() {
84 return Err(RarError::InvalidHeader);
85 }
86 let mut salt = [0u8; 16];
87 salt.copy_from_slice(&data[pos..pos + 16]);
88 pos += 16;
89
90 let check_value = if flags & Rar5EncryptionHeader::FLAG_CHECK_PRESENT != 0 {
92 if pos + 12 > data.len() {
93 return Err(RarError::InvalidHeader);
94 }
95 let mut check = [0u8; 12];
96 check.copy_from_slice(&data[pos..pos + 12]);
97 Some(check)
99 } else {
100 None
101 };
102
103 let total_consumed = header_content_start + header_size as usize;
104
105 Ok((
106 Rar5EncryptionHeader {
107 version,
108 flags,
109 lg2_count,
110 salt,
111 check_value,
112 },
113 total_consumed,
114 ))
115 }
116
117 pub fn is_encryption_header(data: &[u8]) -> bool {
119 if data.len() < 7 {
120 return false;
121 }
122
123 let mut pos = 4;
125 let mut reader = VintReader::new(&data[pos..]);
126 if reader.read().is_none() {
127 return false;
128 }
129 pos += reader.position();
130
131 let mut reader = VintReader::new(&data[pos..]);
133 matches!(reader.read(), Some(4))
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140
141 #[test]
142 fn test_is_encryption_header() {
143 let mut data = vec![0u8; 20];
145 data[4] = 5; data[5] = 4; assert!(Rar5EncryptionHeaderParser::is_encryption_header(&data));
149 }
150
151 #[test]
152 fn test_is_not_encryption_header() {
153 let mut data = vec![0u8; 20];
155 data[4] = 5; data[5] = 2; assert!(!Rar5EncryptionHeaderParser::is_encryption_header(&data));
159 }
160}