aboutsummaryrefslogtreecommitdiff
path: root/src/zip/file/read.rs
diff options
context:
space:
mode:
authorIgor Tolmachev <me@igorek.dev>2024-07-20 16:52:39 +0900
committerIgor Tolmachev <me@igorek.dev>2024-07-20 16:52:39 +0900
commit7bcdc3b4ca460aec2b98fb2dca6165788c562b05 (patch)
tree63f9616fc1b7f9ca6e414a4d32910720e155690c /src/zip/file/read.rs
parent5f4ceda88c7299deb317f8d22a99ab2521c5a380 (diff)
downloadarchivator-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.rs99
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 @@
1use crate::driver::FileDriver; 1use crate::driver::FileDriver;
2use crate::utils::{IoCursor, ReadUtils}; 2use crate::utils::{IoCursor, ReadUtils};
3use crate::zip::encryption::WeakDecoder; 3use crate::zip::encryption::{AesDecoder, Keys, WeakDecoder};
4use crate::zip::structs::FILE_HEADER_SIGNATURE;
4use crate::zip::{CompressionMethod, EncryptionMethod, ZipError, ZipFileInfo, ZipResult}; 5use crate::zip::{CompressionMethod, EncryptionMethod, ZipError, ZipFileInfo, ZipResult};
6use aes::cipher::KeyInit;
7use aes::{Aes128, Aes192, Aes256};
5use bzip2::read::BzDecoder; 8use bzip2::read::BzDecoder;
6use flate2::read::DeflateDecoder; 9use flate2::read::DeflateDecoder;
7use liblzma::read::XzDecoder; 10use liblzma::read::XzDecoder;
8use liblzma::stream::{Filters, LzmaOptions, Stream}; 11use liblzma::stream::{Filters, LzmaOptions, Stream};
12use pbkdf2::pbkdf2_hmac_array;
13use sha1::Sha1;
9use std::io::{ 14use 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;
14enum Encryption<Io: Read> { 19enum 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
19impl<Io: Read> Encryption<Io> { 27impl<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
35impl<Io: Read> Read for Encryption<Io> { 102impl<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
44impl<Io: Read + Seek> Seek for Encryption<Io> { 115impl<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
64impl<Io: Read + Seek> Compression<Io> { 136impl<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
97impl<Io: Read> Read for Compression<Io> { 170impl<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
109impl<Io: Read + Seek> Seek for Compression<Io> { 183impl<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