1use std::fmt::{Debug, Formatter};
7use std::hash::Hash;
8use std::num::Wrapping;
9
10use crate::result::ZipError;
11
12#[cfg_attr(fuzzing, derive(arbitrary::Arbitrary))]
14#[derive(Clone, Copy, Hash, Ord, PartialOrd, Eq, PartialEq)]
15pub(crate) struct ZipCryptoKeys {
16 key_0: Wrapping<u32>,
17 key_1: Wrapping<u32>,
18 key_2: Wrapping<u32>,
19}
20
21impl Debug for ZipCryptoKeys {
22 #[allow(unreachable_code)]
23 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
24 #[cfg(not(any(test, fuzzing)))]
25 {
26 use std::collections::hash_map::DefaultHasher;
27 use std::hash::Hasher;
28 let mut t = DefaultHasher::new();
29 self.hash(&mut t);
30 f.write_fmt(format_args!("ZipCryptoKeys(hash {})", t.finish()))
31 }
32 #[cfg(any(test, fuzzing))]
33 f.write_fmt(format_args!(
34 "ZipCryptoKeys::of({:#10x},{:#10x},{:#10x})",
35 self.key_0, self.key_1, self.key_2
36 ))
37 }
38}
39
40impl ZipCryptoKeys {
41 const fn new() -> ZipCryptoKeys {
42 ZipCryptoKeys {
43 key_0: Wrapping(0x12345678),
44 key_1: Wrapping(0x23456789),
45 key_2: Wrapping(0x34567890),
46 }
47 }
48
49 #[allow(unused)]
50 pub const fn of(key_0: u32, key_1: u32, key_2: u32) -> ZipCryptoKeys {
51 ZipCryptoKeys {
52 key_0: Wrapping(key_0),
53 key_1: Wrapping(key_1),
54 key_2: Wrapping(key_2),
55 }
56 }
57
58 fn update(&mut self, input: u8) {
59 self.key_0 = ZipCryptoKeys::crc32(self.key_0, input);
60 self.key_1 =
61 (self.key_1 + (self.key_0 & Wrapping(0xff))) * Wrapping(0x08088405) + Wrapping(1);
62 self.key_2 = ZipCryptoKeys::crc32(self.key_2, (self.key_1 >> 24).0 as u8);
63 }
64
65 fn stream_byte(&mut self) -> u8 {
66 let temp: Wrapping<u16> = Wrapping(self.key_2.0 as u16) | Wrapping(3);
67 ((temp * (temp ^ Wrapping(1))) >> 8).0 as u8
68 }
69
70 fn decrypt_byte(&mut self, cipher_byte: u8) -> u8 {
71 let plain_byte: u8 = self.stream_byte() ^ cipher_byte;
72 self.update(plain_byte);
73 plain_byte
74 }
75
76 #[allow(dead_code)]
77 fn encrypt_byte(&mut self, plain_byte: u8) -> u8 {
78 let cipher_byte: u8 = self.stream_byte() ^ plain_byte;
79 self.update(plain_byte);
80 cipher_byte
81 }
82
83 fn crc32(crc: Wrapping<u32>, input: u8) -> Wrapping<u32> {
84 (crc >> 8) ^ Wrapping(CRCTABLE[((crc & Wrapping(0xff)).0 as u8 ^ input) as usize])
85 }
86 pub(crate) fn derive(password: &[u8]) -> ZipCryptoKeys {
87 let mut keys = ZipCryptoKeys::new();
88 for byte in password.iter() {
89 keys.update(*byte);
90 }
91 keys
92 }
93}
94
95pub struct ZipCryptoReader<R> {
97 file: R,
98 keys: ZipCryptoKeys,
99}
100
101pub enum ZipCryptoValidator {
102 PkzipCrc32(u32),
103 InfoZipMsdosTime(u16),
104}
105
106impl<R: std::io::Read> ZipCryptoReader<R> {
107 pub fn new(file: R, password: &[u8]) -> ZipCryptoReader<R> {
114 ZipCryptoReader {
115 file,
116 keys: ZipCryptoKeys::derive(password),
117 }
118 }
119
120 pub fn validate(
122 mut self,
123 validator: ZipCryptoValidator,
124 ) -> Result<ZipCryptoReaderValid<R>, ZipError> {
125 let mut header_buf = [0u8; 12];
127 self.file.read_exact(&mut header_buf)?;
128 for byte in header_buf.iter_mut() {
129 *byte = self.keys.decrypt_byte(*byte);
130 }
131
132 match validator {
133 ZipCryptoValidator::PkzipCrc32(crc32_plaintext) => {
134 if (crc32_plaintext >> 24) as u8 != header_buf[11] {
139 return Err(ZipError::InvalidPassword);
140 }
141 }
142 ZipCryptoValidator::InfoZipMsdosTime(last_mod_time) => {
143 if (last_mod_time >> 8) as u8 != header_buf[11] {
151 return Err(ZipError::InvalidPassword);
152 }
153 }
154 }
155
156 Ok(ZipCryptoReaderValid { reader: self })
157 }
158}
159#[allow(unused)]
160pub(crate) struct ZipCryptoWriter<W> {
161 pub(crate) writer: W,
162 pub(crate) buffer: Vec<u8>,
163 pub(crate) keys: ZipCryptoKeys,
164}
165impl<W: std::io::Write> ZipCryptoWriter<W> {
166 #[allow(unused)]
167 pub(crate) fn finish(mut self, crc32: u32) -> std::io::Result<W> {
168 self.buffer[11] = (crc32 >> 24) as u8;
169 for byte in self.buffer.iter_mut() {
170 *byte = self.keys.encrypt_byte(*byte);
171 }
172 self.writer.write_all(&self.buffer)?;
173 self.writer.flush()?;
174 Ok(self.writer)
175 }
176}
177impl<W: std::io::Write> std::io::Write for ZipCryptoWriter<W> {
178 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
179 self.buffer.extend_from_slice(buf);
180 Ok(buf.len())
181 }
182 fn flush(&mut self) -> std::io::Result<()> {
183 Ok(())
184 }
185}
186
187pub struct ZipCryptoReaderValid<R> {
189 reader: ZipCryptoReader<R>,
190}
191
192impl<R: std::io::Read> std::io::Read for ZipCryptoReaderValid<R> {
193 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
194 let n = self.reader.file.read(buf)?;
198 for byte in buf.iter_mut().take(n) {
199 *byte = self.reader.keys.decrypt_byte(*byte);
200 }
201 Ok(n)
202 }
203}
204
205impl<R: std::io::Read> ZipCryptoReaderValid<R> {
206 pub fn into_inner(self) -> R {
208 self.reader.file
209 }
210}
211
212static CRCTABLE: [u32; 256] = [
213 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
214 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
215 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
216 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
217 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
218 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
219 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
220 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
221 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
222 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
223 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
224 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
225 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
226 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
227 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
228 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
229 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
230 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
231 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
232 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
233 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
234 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
235 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
236 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
237 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
238 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
239 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
240 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
241 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
242 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
243 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
244 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
245];