diff options
| author | Igor Tolmachev <me@igorek.dev> | 2024-07-16 17:24:33 +0900 |
|---|---|---|
| committer | Igor Tolmachev <me@igorek.dev> | 2024-07-16 17:24:33 +0900 |
| commit | cc18a545a87ca616f05114d174690e5cc9614669 (patch) | |
| tree | 51ec845115754bb1d8b41d82e5349db5343a40ec /src/zip/file | |
| parent | a83767f9fbd51df654901b52bdba7838f6a10bf9 (diff) | |
| download | archivator-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.rs | 16 | ||||
| -rw-r--r-- | src/zip/file/read.rs | 88 | ||||
| -rw-r--r-- | src/zip/file/write.rs | 6 |
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; | |||
| 2 | use crate::zip::{ZipError, ZipResult}; | 2 | use crate::zip::{ZipError, ZipResult}; |
| 3 | use chrono::{DateTime, Local}; | 3 | use chrono::{DateTime, Local}; |
| 4 | 4 | ||
| 5 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | 5 | #[derive(Debug, PartialEq, Eq, Clone)] |
| 6 | pub enum CompressionMethod { | 6 | pub 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)] |
| 32 | pub enum EncryptionMethod { | 32 | pub enum EncryptionMethod { |
| 33 | None, | 33 | None, |
| 34 | Weak, | 34 | Weak(u8), |
| 35 | Unsupported, | 35 | Unsupported, |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | impl EncryptionMethod { | 38 | impl 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 | ||
| 54 | pub mod bit { | 58 | pub 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 | ||
| 19 | impl<Io: Read> Encryption<Io> { | 19 | impl<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 | ||
| 63 | impl<Io: Read + Seek> Compression<Io> { | 64 | impl<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> { | |||
| 108 | impl<'d, Io: Read> FileDriver for ZipFileReader<'d, Io> { | 126 | impl<'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 | ||
| 117 | impl<'d, Io: Read + Seek> ZipFileReader<'d, Io> { | 131 | impl<'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; | |||
| 2 | use crate::zip::ZipFileInfo; | 2 | use crate::zip::ZipFileInfo; |
| 3 | use std::io::Write; | 3 | use std::io::Write; |
| 4 | 4 | ||
| 5 | #[allow(dead_code)] | ||
| 5 | pub struct ZipFileWriter<'d, Io: Write> { | 6 | pub 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> { | |||
| 11 | impl<'d, Io: Write> FileDriver for ZipFileWriter<'d, Io> { | 11 | impl<'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 | } |
