From cc18a545a87ca616f05114d174690e5cc9614669 Mon Sep 17 00:00:00 2001 From: Igor Tolmachev Date: Tue, 16 Jul 2024 17:24:33 +0900 Subject: Optimize encryption - Add archive for testing encryption of compressed files - Implement incorrect password check - Use custom crc32 function --- src/zip/file/info.rs | 16 ++++++---- src/zip/file/read.rs | 88 +++++++++++++++++++++++---------------------------- src/zip/file/write.rs | 6 +--- 3 files changed, 51 insertions(+), 59 deletions(-) (limited to 'src/zip/file') 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; use crate::zip::{ZipError, ZipResult}; use chrono::{DateTime, Local}; -#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone)] pub enum CompressionMethod { Store, Deflate, @@ -28,18 +28,22 @@ impl CompressionMethod { } } -#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone)] pub enum EncryptionMethod { None, - Weak, + Weak(u8), Unsupported, } impl EncryptionMethod { - pub(crate) fn from_bit_flag(bit_flag: BitFlag) -> EncryptionMethod { + pub(crate) fn from_bif_flag(bit_flag: BitFlag, crc: u32, dos_time: u16) -> EncryptionMethod { match (bit_flag.is_encrypted(), bit_flag.is_strong_encryption()) { (false, false) => EncryptionMethod::None, - (true, false) => EncryptionMethod::Weak, + (true, false) => EncryptionMethod::Weak(if bit_flag.is_has_data_descriptor() { + (dos_time >> 8) as u8 // Info-ZIP modification + } else { + (crc >> 24) as u8 + }), (true, true) => EncryptionMethod::Unsupported, _ => panic!("impossible"), } @@ -52,7 +56,7 @@ pub struct BitFlag { } pub mod bit { - #[derive(Debug, PartialEq, Eq, Clone, Copy)] + #[derive(Debug, PartialEq, Eq, Clone)] pub enum DeflateMode { Normal, 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 { } impl Encryption { - pub fn new(io: Io, method: EncryptionMethod, password: Option<&str>) -> ZipResult { - Ok(match method { + pub fn new(io: Io, info: &ZipFileInfo, password: Option<&[u8]>) -> ZipResult { + Ok(match info.encryption_method { EncryptionMethod::None => Self::None(io), - EncryptionMethod::Weak => Self::Weak(WeakDecoder::new( + EncryptionMethod::Weak(check) => Self::Weak(WeakDecoder::new( io, + check, password.ok_or(ZipError::PasswordIsNotSpecified)?, )?), EncryptionMethod::Unsupported => { @@ -61,12 +62,29 @@ enum Compression { } impl Compression { - pub fn new(io: Io, method: CompressionMethod) -> ZipResult { - Ok(match method { + pub fn new(mut io: Io, info: &ZipFileInfo) -> ZipResult { + Ok(match info.compression_method { CompressionMethod::Store => Self::Store(io), CompressionMethod::Deflate => Self::Deflate(DeflateDecoder::new(io)), CompressionMethod::BZip2 => Self::BZip2(BzDecoder::new(io)), - CompressionMethod::Lzma => panic!(), + CompressionMethod::Lzma => { + let buf = io.read_arr::<9>()?; + Compression::Xz(XzDecoder::new_stream( + io, + Stream::new_raw_decoder( + Filters::new().lzma1( + LzmaOptions::new() + .literal_context_bits((buf[4] % 9) as u32) + .literal_position_bits((buf[4] / 9 % 5) as u32) + .position_bits((buf[4] / 45) as u32) + .dict_size( + u32::from_le_bytes(buf[5..9].try_into().unwrap()).max(4096), + ), + ), + ) + .unwrap(), + )) + } CompressionMethod::Zstd => Self::Zstd(ZstdDecoder::new(io)?), CompressionMethod::Xz => Self::Xz(XzDecoder::new(io)), CompressionMethod::Unsupported(id) => { @@ -108,14 +126,14 @@ pub struct ZipFileReader<'d, Io: Read> { impl<'d, Io: Read> FileDriver for ZipFileReader<'d, Io> { type Io = Io; type FileInfo = ZipFileInfo; - - fn info(&self) -> &Self::FileInfo { - self.info - } } impl<'d, Io: Read + Seek> ZipFileReader<'d, Io> { - pub fn new(io: &'d mut Io, info: &'d ZipFileInfo, password: Option<&str>) -> ZipResult { + pub(crate) fn new( + io: &'d mut Io, + info: &'d ZipFileInfo, + password: Option<&[u8]>, + ) -> ZipResult { io.seek(SeekFrom::Start(info.header_pointer))?; let buf = io.read_arr::<30>()?; @@ -127,49 +145,23 @@ impl<'d, Io: Read + Seek> ZipFileReader<'d, Io> { + u16::from_le_bytes(buf[26..28].try_into().unwrap()) as u64 + u16::from_le_bytes(buf[28..30].try_into().unwrap()) as u64; - io.seek(SeekFrom::Start(data_pointer))?; - Ok(Self { - io: match info.compression_method { - CompressionMethod::Lzma => { - let buf = io.read_arr::<9>()?; - Compression::Xz(XzDecoder::new_stream( - Encryption::new( - IoCursor::new( - io, - data_pointer + 9, - data_pointer + info.compressed_size, - )?, - info.encryption_method, - password, - )?, - Stream::new_raw_decoder( - Filters::new().lzma1( - LzmaOptions::new() - .literal_context_bits((buf[4] % 9) as u32) - .literal_position_bits((buf[4] / 9 % 5) as u32) - .position_bits((buf[4] / 45) as u32) - .dict_size( - u32::from_le_bytes(buf[5..9].try_into().unwrap()).max(4096), - ), - ), - ) - .unwrap(), - )) - } - _ => Compression::new( - Encryption::new( - IoCursor::new(io, data_pointer, data_pointer + info.compressed_size)?, - info.encryption_method, - password, - )?, - info.compression_method, + io: Compression::new( + Encryption::new( + IoCursor::new(io, data_pointer, data_pointer + info.compressed_size)?, + info, + password, )?, - }, + info, + )?, info, }) } + pub fn info(&self) -> &ZipFileInfo { + self.info + } + pub fn is_seekable(&self) -> bool { match self.io { 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; use crate::zip::ZipFileInfo; use std::io::Write; +#[allow(dead_code)] pub struct ZipFileWriter<'d, Io: Write> { - #[allow(dead_code)] io: &'d mut Io, info: &'d ZipFileInfo, } @@ -11,8 +11,4 @@ pub struct ZipFileWriter<'d, Io: Write> { impl<'d, Io: Write> FileDriver for ZipFileWriter<'d, Io> { type Io = Io; type FileInfo = ZipFileInfo; - - fn info(&self) -> &Self::FileInfo { - self.info - } } -- cgit v1.2.3