diff options
| author | Igor Tolmachev <me@igorek.dev> | 2024-07-20 16:52:39 +0900 |
|---|---|---|
| committer | Igor Tolmachev <me@igorek.dev> | 2024-07-20 16:52:39 +0900 |
| commit | 7bcdc3b4ca460aec2b98fb2dca6165788c562b05 (patch) | |
| tree | 63f9616fc1b7f9ca6e414a4d32910720e155690c /src/zip/file/read.rs | |
| parent | 5f4ceda88c7299deb317f8d22a99ab2521c5a380 (diff) | |
| download | archivator-7bcdc3b4ca460aec2b98fb2dca6165788c562b05.tar.gz archivator-7bcdc3b4ca460aec2b98fb2dca6165788c562b05.zip | |
Partial aes implementation and others improvements
Diffstat (limited to 'src/zip/file/read.rs')
| -rw-r--r-- | src/zip/file/read.rs | 99 |
1 files changed, 87 insertions, 12 deletions
diff --git a/src/zip/file/read.rs b/src/zip/file/read.rs index c26b304..80bdcfb 100644 --- a/src/zip/file/read.rs +++ b/src/zip/file/read.rs | |||
| @@ -1,11 +1,16 @@ | |||
| 1 | use crate::driver::FileDriver; | 1 | use crate::driver::FileDriver; |
| 2 | use crate::utils::{IoCursor, ReadUtils}; | 2 | use crate::utils::{IoCursor, ReadUtils}; |
| 3 | use crate::zip::encryption::WeakDecoder; | 3 | use crate::zip::encryption::{AesDecoder, Keys, WeakDecoder}; |
| 4 | use crate::zip::structs::FILE_HEADER_SIGNATURE; | ||
| 4 | use crate::zip::{CompressionMethod, EncryptionMethod, ZipError, ZipFileInfo, ZipResult}; | 5 | use crate::zip::{CompressionMethod, EncryptionMethod, ZipError, ZipFileInfo, ZipResult}; |
| 6 | use aes::cipher::KeyInit; | ||
| 7 | use aes::{Aes128, Aes192, Aes256}; | ||
| 5 | use bzip2::read::BzDecoder; | 8 | use bzip2::read::BzDecoder; |
| 6 | use flate2::read::DeflateDecoder; | 9 | use flate2::read::DeflateDecoder; |
| 7 | use liblzma::read::XzDecoder; | 10 | use liblzma::read::XzDecoder; |
| 8 | use liblzma::stream::{Filters, LzmaOptions, Stream}; | 11 | use liblzma::stream::{Filters, LzmaOptions, Stream}; |
| 12 | use pbkdf2::pbkdf2_hmac_array; | ||
| 13 | use sha1::Sha1; | ||
| 9 | use std::io::{ | 14 | use std::io::{ |
| 10 | BufReader, Error as IoError, ErrorKind as IoErrorKind, Read, Result as IoResult, Seek, SeekFrom, | 15 | BufReader, Error as IoError, ErrorKind as IoErrorKind, Read, Result as IoResult, Seek, SeekFrom, |
| 11 | }; | 16 | }; |
| @@ -14,34 +19,101 @@ use zstd::stream::Decoder as ZstdDecoder; | |||
| 14 | enum Encryption<Io: Read> { | 19 | enum Encryption<Io: Read> { |
| 15 | None(Io), | 20 | None(Io), |
| 16 | Weak(WeakDecoder<Io>), | 21 | Weak(WeakDecoder<Io>), |
| 22 | Aes128(AesDecoder<Io, Aes128>), | ||
| 23 | Aes192(AesDecoder<Io, Aes192>), | ||
| 24 | Aes256(AesDecoder<Io, Aes256>), | ||
| 17 | } | 25 | } |
| 18 | 26 | ||
| 19 | impl<Io: Read> Encryption<Io> { | 27 | impl<Io: Read> Encryption<Io> { |
| 20 | pub fn new(io: Io, info: &ZipFileInfo, password: Option<&[u8]>) -> ZipResult<Self> { | 28 | #[inline] |
| 29 | pub fn new(mut io: Io, info: &ZipFileInfo, password: Option<&[u8]>) -> ZipResult<Self> { | ||
| 21 | Ok(match info.encryption_method { | 30 | Ok(match info.encryption_method { |
| 22 | EncryptionMethod::None => Self::None(io), | 31 | EncryptionMethod::None => Self::None(io), |
| 23 | EncryptionMethod::Weak(check) => Self::Weak(WeakDecoder::new( | 32 | EncryptionMethod::Weak => { |
| 24 | io, | 33 | let mut keys = Keys::new(); |
| 25 | check, | 34 | keys.set_password(password.ok_or(ZipError::PasswordIsNotSpecified)?); |
| 26 | password.ok_or(ZipError::PasswordIsNotSpecified)?, | 35 | |
| 27 | )?), | 36 | let check = keys.set_header(io.read_arr()?); |
| 28 | EncryptionMethod::Unsupported => { | 37 | if check != info.password_check() { |
| 29 | return Err(ZipError::UnsupportedEncryptionMethod.into()) | 38 | return Err(ZipError::IncorrectPassword); |
| 39 | } | ||
| 40 | |||
| 41 | Self::Weak(WeakDecoder::new(io, keys)) | ||
| 42 | } | ||
| 43 | EncryptionMethod::Aes128 => { | ||
| 44 | let header = io.read_arr::<10>()?; | ||
| 45 | let salt = &header[..8]; | ||
| 46 | let check = &header[8..]; | ||
| 47 | |||
| 48 | let hash = pbkdf2_hmac_array::<Sha1, 34>( | ||
| 49 | password.ok_or(ZipError::PasswordIsNotSpecified)?, | ||
| 50 | salt, | ||
| 51 | 1000, | ||
| 52 | ); | ||
| 53 | let key = &hash[..16]; | ||
| 54 | |||
| 55 | if check != &hash[32..] { | ||
| 56 | return Err(ZipError::IncorrectPassword); | ||
| 57 | } | ||
| 58 | |||
| 59 | Self::Aes128(AesDecoder::new(io, Aes128::new(key.into()))?) | ||
| 60 | } | ||
| 61 | EncryptionMethod::Aes192 => { | ||
| 62 | let header = io.read_arr::<14>()?; | ||
| 63 | let salt = &header[..12]; | ||
| 64 | let check = &header[12..]; | ||
| 65 | |||
| 66 | let hash = pbkdf2_hmac_array::<Sha1, 50>( | ||
| 67 | password.ok_or(ZipError::PasswordIsNotSpecified)?, | ||
| 68 | salt, | ||
| 69 | 1000, | ||
| 70 | ); | ||
| 71 | let key = &hash[..24]; | ||
| 72 | |||
| 73 | if check != &hash[48..] { | ||
| 74 | return Err(ZipError::IncorrectPassword); | ||
| 75 | } | ||
| 76 | |||
| 77 | Self::Aes192(AesDecoder::new(io, Aes192::new(key.into()))?) | ||
| 78 | } | ||
| 79 | EncryptionMethod::Aes256 => { | ||
| 80 | let header = io.read_arr::<18>()?; | ||
| 81 | let salt = &header[..16]; | ||
| 82 | let check = &header[16..]; | ||
| 83 | |||
| 84 | let hash = pbkdf2_hmac_array::<Sha1, 66>( | ||
| 85 | password.ok_or(ZipError::PasswordIsNotSpecified)?, | ||
| 86 | salt, | ||
| 87 | 1000, | ||
| 88 | ); | ||
| 89 | let key = &hash[..32]; | ||
| 90 | |||
| 91 | if check != &hash[64..] { | ||
| 92 | return Err(ZipError::IncorrectPassword); | ||
| 93 | } | ||
| 94 | |||
| 95 | Self::Aes256(AesDecoder::new(io, Aes256::new(key.into()))?) | ||
| 30 | } | 96 | } |
| 97 | EncryptionMethod::Unsupported => return Err(ZipError::UnsupportedEncryptionMethod), | ||
| 31 | }) | 98 | }) |
| 32 | } | 99 | } |
| 33 | } | 100 | } |
| 34 | 101 | ||
| 35 | impl<Io: Read> Read for Encryption<Io> { | 102 | impl<Io: Read> Read for Encryption<Io> { |
| 103 | #[inline] | ||
| 36 | fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> { | 104 | fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> { |
| 37 | match self { | 105 | match self { |
| 38 | Self::None(io) => io.read(buf), | 106 | Self::None(io) => io.read(buf), |
| 39 | Self::Weak(io) => io.read(buf), | 107 | Self::Weak(io) => io.read(buf), |
| 108 | Self::Aes128(io) => io.read(buf), | ||
| 109 | Self::Aes192(io) => io.read(buf), | ||
| 110 | Self::Aes256(io) => io.read(buf), | ||
| 40 | } | 111 | } |
| 41 | } | 112 | } |
| 42 | } | 113 | } |
| 43 | 114 | ||
| 44 | impl<Io: Read + Seek> Seek for Encryption<Io> { | 115 | impl<Io: Read + Seek> Seek for Encryption<Io> { |
| 116 | #[inline] | ||
| 45 | fn seek(&mut self, pos: SeekFrom) -> IoResult<u64> { | 117 | fn seek(&mut self, pos: SeekFrom) -> IoResult<u64> { |
| 46 | match self { | 118 | match self { |
| 47 | Self::None(io) => io.seek(pos), | 119 | Self::None(io) => io.seek(pos), |
| @@ -62,6 +134,7 @@ enum Compression<Io: Read> { | |||
| 62 | } | 134 | } |
| 63 | 135 | ||
| 64 | impl<Io: Read + Seek> Compression<Io> { | 136 | impl<Io: Read + Seek> Compression<Io> { |
| 137 | #[inline] | ||
| 65 | pub fn new(mut io: Io, info: &ZipFileInfo) -> ZipResult<Self> { | 138 | pub fn new(mut io: Io, info: &ZipFileInfo) -> ZipResult<Self> { |
| 66 | Ok(match info.compression_method { | 139 | Ok(match info.compression_method { |
| 67 | CompressionMethod::Store => Self::Store(io), | 140 | CompressionMethod::Store => Self::Store(io), |
| @@ -88,13 +161,14 @@ impl<Io: Read + Seek> Compression<Io> { | |||
| 88 | CompressionMethod::Zstd => Self::Zstd(ZstdDecoder::new(io)?), | 161 | CompressionMethod::Zstd => Self::Zstd(ZstdDecoder::new(io)?), |
| 89 | CompressionMethod::Xz => Self::Xz(XzDecoder::new(io)), | 162 | CompressionMethod::Xz => Self::Xz(XzDecoder::new(io)), |
| 90 | CompressionMethod::Unsupported(id) => { | 163 | CompressionMethod::Unsupported(id) => { |
| 91 | return Err(ZipError::UnsupportedCompressionMethod(id).into()) | 164 | return Err(ZipError::UnsupportedCompressionMethod(id)) |
| 92 | } | 165 | } |
| 93 | }) | 166 | }) |
| 94 | } | 167 | } |
| 95 | } | 168 | } |
| 96 | 169 | ||
| 97 | impl<Io: Read> Read for Compression<Io> { | 170 | impl<Io: Read> Read for Compression<Io> { |
| 171 | #[inline] | ||
| 98 | fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> { | 172 | fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> { |
| 99 | match self { | 173 | match self { |
| 100 | Compression::Store(io) => io.read(buf), | 174 | Compression::Store(io) => io.read(buf), |
| @@ -107,6 +181,7 @@ impl<Io: Read> Read for Compression<Io> { | |||
| 107 | } | 181 | } |
| 108 | 182 | ||
| 109 | impl<Io: Read + Seek> Seek for Compression<Io> { | 183 | impl<Io: Read + Seek> Seek for Compression<Io> { |
| 184 | #[inline] | ||
| 110 | fn seek(&mut self, pos: SeekFrom) -> IoResult<u64> { | 185 | fn seek(&mut self, pos: SeekFrom) -> IoResult<u64> { |
| 111 | match self { | 186 | match self { |
| 112 | Compression::Store(io) => io.seek(pos), | 187 | Compression::Store(io) => io.seek(pos), |
| @@ -137,8 +212,8 @@ impl<'d, Io: Read + Seek> ZipFileReader<'d, Io> { | |||
| 137 | io.seek(SeekFrom::Start(info.header_pointer))?; | 212 | io.seek(SeekFrom::Start(info.header_pointer))?; |
| 138 | 213 | ||
| 139 | let buf = io.read_arr::<30>()?; | 214 | let buf = io.read_arr::<30>()?; |
| 140 | if u32::from_le_bytes(buf[..4].try_into().unwrap()) != 0x04034b50 { | 215 | if buf[..4] != FILE_HEADER_SIGNATURE { |
| 141 | return Err(ZipError::InvalidFileHeaderSignature.into()); | 216 | return Err(ZipError::InvalidFileHeaderSignature); |
| 142 | } | 217 | } |
| 143 | let data_pointer = info.header_pointer | 218 | let data_pointer = info.header_pointer |
| 144 | + 30 | 219 | + 30 |
