aboutsummaryrefslogtreecommitdiff
path: root/src/zip/file
diff options
context:
space:
mode:
authorIgor Tolmachev <me@igorek.dev>2024-07-16 17:24:33 +0900
committerIgor Tolmachev <me@igorek.dev>2024-07-16 17:24:33 +0900
commitcc18a545a87ca616f05114d174690e5cc9614669 (patch)
tree51ec845115754bb1d8b41d82e5349db5343a40ec /src/zip/file
parenta83767f9fbd51df654901b52bdba7838f6a10bf9 (diff)
downloadarchivator-cc18a545a87ca616f05114d174690e5cc9614669.tar.gz
archivator-cc18a545a87ca616f05114d174690e5cc9614669.zip
Optimize encryption
- Add archive for testing encryption of compressed files - Implement incorrect password check - Use custom crc32 function
Diffstat (limited to 'src/zip/file')
-rw-r--r--src/zip/file/info.rs16
-rw-r--r--src/zip/file/read.rs88
-rw-r--r--src/zip/file/write.rs6
3 files changed, 51 insertions, 59 deletions
diff --git a/src/zip/file/info.rs b/src/zip/file/info.rs
index f5d4d8a..599dcc3 100644
--- a/src/zip/file/info.rs
+++ b/src/zip/file/info.rs
@@ -2,7 +2,7 @@ use crate::driver::ArchiveFileInfo;
2use crate::zip::{ZipError, ZipResult}; 2use crate::zip::{ZipError, ZipResult};
3use chrono::{DateTime, Local}; 3use chrono::{DateTime, Local};
4 4
5#[derive(Debug, PartialEq, Eq, Clone, Copy)] 5#[derive(Debug, PartialEq, Eq, Clone)]
6pub enum CompressionMethod { 6pub enum CompressionMethod {
7 Store, 7 Store,
8 Deflate, 8 Deflate,
@@ -28,18 +28,22 @@ impl CompressionMethod {
28 } 28 }
29} 29}
30 30
31#[derive(Debug, PartialEq, Eq, Clone, Copy)] 31#[derive(Debug, PartialEq, Eq, Clone)]
32pub enum EncryptionMethod { 32pub enum EncryptionMethod {
33 None, 33 None,
34 Weak, 34 Weak(u8),
35 Unsupported, 35 Unsupported,
36} 36}
37 37
38impl EncryptionMethod { 38impl EncryptionMethod {
39 pub(crate) fn from_bit_flag(bit_flag: BitFlag) -> EncryptionMethod { 39 pub(crate) fn from_bif_flag(bit_flag: BitFlag, crc: u32, dos_time: u16) -> EncryptionMethod {
40 match (bit_flag.is_encrypted(), bit_flag.is_strong_encryption()) { 40 match (bit_flag.is_encrypted(), bit_flag.is_strong_encryption()) {
41 (false, false) => EncryptionMethod::None, 41 (false, false) => EncryptionMethod::None,
42 (true, false) => EncryptionMethod::Weak, 42 (true, false) => EncryptionMethod::Weak(if bit_flag.is_has_data_descriptor() {
43 (dos_time >> 8) as u8 // Info-ZIP modification
44 } else {
45 (crc >> 24) as u8
46 }),
43 (true, true) => EncryptionMethod::Unsupported, 47 (true, true) => EncryptionMethod::Unsupported,
44 _ => panic!("impossible"), 48 _ => panic!("impossible"),
45 } 49 }
@@ -52,7 +56,7 @@ pub struct BitFlag {
52} 56}
53 57
54pub mod bit { 58pub mod bit {
55 #[derive(Debug, PartialEq, Eq, Clone, Copy)] 59 #[derive(Debug, PartialEq, Eq, Clone)]
56 pub enum DeflateMode { 60 pub enum DeflateMode {
57 Normal, 61 Normal,
58 Maximum, 62 Maximum,
diff --git a/src/zip/file/read.rs b/src/zip/file/read.rs
index aa665c3..c26b304 100644
--- a/src/zip/file/read.rs
+++ b/src/zip/file/read.rs
@@ -17,11 +17,12 @@ enum Encryption<Io: Read> {
17} 17}
18 18
19impl<Io: Read> Encryption<Io> { 19impl<Io: Read> Encryption<Io> {
20 pub fn new(io: Io, method: EncryptionMethod, password: Option<&str>) -> ZipResult<Self> { 20 pub fn new(io: Io, info: &ZipFileInfo, password: Option<&[u8]>) -> ZipResult<Self> {
21 Ok(match method { 21 Ok(match info.encryption_method {
22 EncryptionMethod::None => Self::None(io), 22 EncryptionMethod::None => Self::None(io),
23 EncryptionMethod::Weak => Self::Weak(WeakDecoder::new( 23 EncryptionMethod::Weak(check) => Self::Weak(WeakDecoder::new(
24 io, 24 io,
25 check,
25 password.ok_or(ZipError::PasswordIsNotSpecified)?, 26 password.ok_or(ZipError::PasswordIsNotSpecified)?,
26 )?), 27 )?),
27 EncryptionMethod::Unsupported => { 28 EncryptionMethod::Unsupported => {
@@ -61,12 +62,29 @@ enum Compression<Io: Read> {
61} 62}
62 63
63impl<Io: Read + Seek> Compression<Io> { 64impl<Io: Read + Seek> Compression<Io> {
64 pub fn new(io: Io, method: CompressionMethod) -> ZipResult<Self> { 65 pub fn new(mut io: Io, info: &ZipFileInfo) -> ZipResult<Self> {
65 Ok(match method { 66 Ok(match info.compression_method {
66 CompressionMethod::Store => Self::Store(io), 67 CompressionMethod::Store => Self::Store(io),
67 CompressionMethod::Deflate => Self::Deflate(DeflateDecoder::new(io)), 68 CompressionMethod::Deflate => Self::Deflate(DeflateDecoder::new(io)),
68 CompressionMethod::BZip2 => Self::BZip2(BzDecoder::new(io)), 69 CompressionMethod::BZip2 => Self::BZip2(BzDecoder::new(io)),
69 CompressionMethod::Lzma => panic!(), 70 CompressionMethod::Lzma => {
71 let buf = io.read_arr::<9>()?;
72 Compression::Xz(XzDecoder::new_stream(
73 io,
74 Stream::new_raw_decoder(
75 Filters::new().lzma1(
76 LzmaOptions::new()
77 .literal_context_bits((buf[4] % 9) as u32)
78 .literal_position_bits((buf[4] / 9 % 5) as u32)
79 .position_bits((buf[4] / 45) as u32)
80 .dict_size(
81 u32::from_le_bytes(buf[5..9].try_into().unwrap()).max(4096),
82 ),
83 ),
84 )
85 .unwrap(),
86 ))
87 }
70 CompressionMethod::Zstd => Self::Zstd(ZstdDecoder::new(io)?), 88 CompressionMethod::Zstd => Self::Zstd(ZstdDecoder::new(io)?),
71 CompressionMethod::Xz => Self::Xz(XzDecoder::new(io)), 89 CompressionMethod::Xz => Self::Xz(XzDecoder::new(io)),
72 CompressionMethod::Unsupported(id) => { 90 CompressionMethod::Unsupported(id) => {
@@ -108,14 +126,14 @@ pub struct ZipFileReader<'d, Io: Read> {
108impl<'d, Io: Read> FileDriver for ZipFileReader<'d, Io> { 126impl<'d, Io: Read> FileDriver for ZipFileReader<'d, Io> {
109 type Io = Io; 127 type Io = Io;
110 type FileInfo = ZipFileInfo; 128 type FileInfo = ZipFileInfo;
111
112 fn info(&self) -> &Self::FileInfo {
113 self.info
114 }
115} 129}
116 130
117impl<'d, Io: Read + Seek> ZipFileReader<'d, Io> { 131impl<'d, Io: Read + Seek> ZipFileReader<'d, Io> {
118 pub fn new(io: &'d mut Io, info: &'d ZipFileInfo, password: Option<&str>) -> ZipResult<Self> { 132 pub(crate) fn new(
133 io: &'d mut Io,
134 info: &'d ZipFileInfo,
135 password: Option<&[u8]>,
136 ) -> ZipResult<Self> {
119 io.seek(SeekFrom::Start(info.header_pointer))?; 137 io.seek(SeekFrom::Start(info.header_pointer))?;
120 138
121 let buf = io.read_arr::<30>()?; 139 let buf = io.read_arr::<30>()?;
@@ -127,49 +145,23 @@ impl<'d, Io: Read + Seek> ZipFileReader<'d, Io> {
127 + u16::from_le_bytes(buf[26..28].try_into().unwrap()) as u64 145 + u16::from_le_bytes(buf[26..28].try_into().unwrap()) as u64
128 + u16::from_le_bytes(buf[28..30].try_into().unwrap()) as u64; 146 + u16::from_le_bytes(buf[28..30].try_into().unwrap()) as u64;
129 147
130 io.seek(SeekFrom::Start(data_pointer))?;
131
132 Ok(Self { 148 Ok(Self {
133 io: match info.compression_method { 149 io: Compression::new(
134 CompressionMethod::Lzma => { 150 Encryption::new(
135 let buf = io.read_arr::<9>()?; 151 IoCursor::new(io, data_pointer, data_pointer + info.compressed_size)?,
136 Compression::Xz(XzDecoder::new_stream( 152 info,
137 Encryption::new( 153 password,
138 IoCursor::new(
139 io,
140 data_pointer + 9,
141 data_pointer + info.compressed_size,
142 )?,
143 info.encryption_method,
144 password,
145 )?,
146 Stream::new_raw_decoder(
147 Filters::new().lzma1(
148 LzmaOptions::new()
149 .literal_context_bits((buf[4] % 9) as u32)
150 .literal_position_bits((buf[4] / 9 % 5) as u32)
151 .position_bits((buf[4] / 45) as u32)
152 .dict_size(
153 u32::from_le_bytes(buf[5..9].try_into().unwrap()).max(4096),
154 ),
155 ),
156 )
157 .unwrap(),
158 ))
159 }
160 _ => Compression::new(
161 Encryption::new(
162 IoCursor::new(io, data_pointer, data_pointer + info.compressed_size)?,
163 info.encryption_method,
164 password,
165 )?,
166 info.compression_method,
167 )?, 154 )?,
168 }, 155 info,
156 )?,
169 info, 157 info,
170 }) 158 })
171 } 159 }
172 160
161 pub fn info(&self) -> &ZipFileInfo {
162 self.info
163 }
164
173 pub fn is_seekable(&self) -> bool { 165 pub fn is_seekable(&self) -> bool {
174 match self.io { 166 match self.io {
175 Compression::Store(Encryption::None(..)) => true, 167 Compression::Store(Encryption::None(..)) => true,
diff --git a/src/zip/file/write.rs b/src/zip/file/write.rs
index d5b686c..20e53b3 100644
--- a/src/zip/file/write.rs
+++ b/src/zip/file/write.rs
@@ -2,8 +2,8 @@ use crate::driver::FileDriver;
2use crate::zip::ZipFileInfo; 2use crate::zip::ZipFileInfo;
3use std::io::Write; 3use std::io::Write;
4 4
5#[allow(dead_code)]
5pub struct ZipFileWriter<'d, Io: Write> { 6pub struct ZipFileWriter<'d, Io: Write> {
6 #[allow(dead_code)]
7 io: &'d mut Io, 7 io: &'d mut Io,
8 info: &'d ZipFileInfo, 8 info: &'d ZipFileInfo,
9} 9}
@@ -11,8 +11,4 @@ pub struct ZipFileWriter<'d, Io: Write> {
11impl<'d, Io: Write> FileDriver for ZipFileWriter<'d, Io> { 11impl<'d, Io: Write> FileDriver for ZipFileWriter<'d, Io> {
12 type Io = Io; 12 type Io = Io;
13 type FileInfo = ZipFileInfo; 13 type FileInfo = ZipFileInfo;
14
15 fn info(&self) -> &Self::FileInfo {
16 self.info
17 }
18} 14}