diff options
Diffstat (limited to 'src/zip')
| -rw-r--r-- | src/zip/encryption/aes.rs | 49 | ||||
| -rw-r--r-- | src/zip/encryption/weak.rs | 15 | ||||
| -rw-r--r-- | src/zip/error.rs | 4 | ||||
| -rw-r--r-- | src/zip/file/read.rs | 71 |
4 files changed, 85 insertions, 54 deletions
diff --git a/src/zip/encryption/aes.rs b/src/zip/encryption/aes.rs index 6f41aaa..b690482 100644 --- a/src/zip/encryption/aes.rs +++ b/src/zip/encryption/aes.rs | |||
| @@ -1,4 +1,3 @@ | |||
| 1 | use crate::utils::ReadUtils; | ||
| 2 | use aes::cipher::generic_array::GenericArray; | 1 | use aes::cipher::generic_array::GenericArray; |
| 3 | use aes::cipher::BlockEncrypt; | 2 | use aes::cipher::BlockEncrypt; |
| 4 | use std::io::{Read, Result as IoResult}; | 3 | use std::io::{Read, Result as IoResult}; |
| @@ -10,37 +9,63 @@ pub struct AesDecoder<Io: Read, Aes: BlockEncrypt> { | |||
| 10 | 9 | ||
| 11 | counter: u128, | 10 | counter: u128, |
| 12 | block: [u8; 16], | 11 | block: [u8; 16], |
| 13 | cursor: usize, | 12 | lower: usize, |
| 13 | upper: usize, | ||
| 14 | } | 14 | } |
| 15 | 15 | ||
| 16 | impl<Io: Read, Aes: BlockEncrypt> AesDecoder<Io, Aes> { | 16 | impl<Io: Read, Aes: BlockEncrypt> AesDecoder<Io, Aes> { |
| 17 | pub fn new(mut io: Io, aes: Aes) -> IoResult<Self> { | 17 | pub fn new(io: Io, aes: Aes) -> IoResult<Self> { |
| 18 | let block = io.read_arr::<16>()?; | ||
| 19 | let mut decoder = Self { | 18 | let mut decoder = Self { |
| 20 | io, | 19 | io, |
| 21 | aes, | 20 | aes, |
| 22 | counter: 1, | 21 | |
| 23 | block, | 22 | counter: 0, |
| 24 | cursor: 0, | 23 | block: [0; 16], |
| 24 | lower: 0, | ||
| 25 | upper: 0, | ||
| 25 | }; | 26 | }; |
| 26 | decoder.decrypt_block(); | 27 | |
| 28 | decoder.update_block()?; | ||
| 29 | |||
| 27 | Ok(decoder) | 30 | Ok(decoder) |
| 28 | } | 31 | } |
| 29 | 32 | ||
| 30 | #[inline] | 33 | #[inline] |
| 31 | fn decrypt_block(&mut self) { | 34 | fn update_block(&mut self) -> IoResult<()> { |
| 35 | self.upper = self.io.read(&mut self.block)?; | ||
| 36 | self.lower = 0; | ||
| 37 | |||
| 38 | self.counter += 1; | ||
| 32 | let mut mask = self.counter.to_le_bytes(); | 39 | let mut mask = self.counter.to_le_bytes(); |
| 40 | |||
| 33 | self.aes | 41 | self.aes |
| 34 | .encrypt_block(GenericArray::from_mut_slice(&mut mask)); | 42 | .encrypt_block(GenericArray::from_mut_slice(&mut mask)); |
| 43 | |||
| 35 | for (b, m) in self.block.iter_mut().zip(mask) { | 44 | for (b, m) in self.block.iter_mut().zip(mask) { |
| 36 | *b ^= m | 45 | *b ^= m |
| 37 | } | 46 | } |
| 38 | self.counter += 1; | 47 | |
| 48 | Ok(()) | ||
| 39 | } | 49 | } |
| 40 | } | 50 | } |
| 41 | 51 | ||
| 42 | impl<Io: Read, Aes: BlockEncrypt> Read for AesDecoder<Io, Aes> { | 52 | impl<Io: Read, Aes: BlockEncrypt> Read for AesDecoder<Io, Aes> { |
| 43 | fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> { | 53 | fn read(&mut self, mut buf: &mut [u8]) -> IoResult<usize> { |
| 44 | todo!() | 54 | let mut bytes = 0; |
| 55 | while !buf.is_empty() && self.lower != self.upper { | ||
| 56 | for (to, fr) in buf.iter_mut().zip(&self.block[self.lower..self.upper]) { | ||
| 57 | *to = *fr | ||
| 58 | } | ||
| 59 | |||
| 60 | let consumed = buf.len().min(self.upper - self.lower); | ||
| 61 | buf = &mut buf[consumed..]; | ||
| 62 | self.lower += consumed; | ||
| 63 | bytes += consumed; | ||
| 64 | |||
| 65 | if self.lower == 16 { | ||
| 66 | self.update_block()?; | ||
| 67 | } | ||
| 68 | } | ||
| 69 | Ok(bytes) | ||
| 45 | } | 70 | } |
| 46 | } | 71 | } |
diff --git a/src/zip/encryption/weak.rs b/src/zip/encryption/weak.rs index 144cd53..ebddb2d 100644 --- a/src/zip/encryption/weak.rs +++ b/src/zip/encryption/weak.rs | |||
| @@ -45,7 +45,7 @@ impl Keys { | |||
| 45 | } | 45 | } |
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | fn update(&mut self, byte: u8) { | 48 | pub fn update(&mut self, byte: u8) { |
| 49 | self.key0 = crc32(byte, self.key0); | 49 | self.key0 = crc32(byte, self.key0); |
| 50 | self.key1 = self | 50 | self.key1 = self |
| 51 | .key1 | 51 | .key1 |
| @@ -55,19 +55,6 @@ impl Keys { | |||
| 55 | self.key2 = crc32((self.key1 >> 24) as u8, self.key2); | 55 | self.key2 = crc32((self.key1 >> 24) as u8, self.key2); |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | pub fn set_password(&mut self, passwd: &[u8]) { | ||
| 59 | for b in passwd { | ||
| 60 | self.update(*b) | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | pub fn set_header(&mut self, header: [u8; 12]) -> u8 { | ||
| 65 | for b in &header[..11] { | ||
| 66 | self.decode_byte(*b); | ||
| 67 | } | ||
| 68 | self.decode_byte(header[11]) | ||
| 69 | } | ||
| 70 | |||
| 71 | #[allow(dead_code)] | 58 | #[allow(dead_code)] |
| 72 | pub fn encode_bytes(&mut self, byte: u8) -> u8 { | 59 | pub fn encode_bytes(&mut self, byte: u8) -> u8 { |
| 73 | let key = self.key2 | 2; | 60 | let key = self.key2 | 2; |
diff --git a/src/zip/error.rs b/src/zip/error.rs index 5508177..87cd9e9 100644 --- a/src/zip/error.rs +++ b/src/zip/error.rs | |||
| @@ -23,7 +23,7 @@ pub enum ZipError { | |||
| 23 | InvalidFileComment, | 23 | InvalidFileComment, |
| 24 | 24 | ||
| 25 | FileNotFound, | 25 | FileNotFound, |
| 26 | IncorrectPassword, | 26 | WrongPassword, |
| 27 | PasswordIsNotSpecified, | 27 | PasswordIsNotSpecified, |
| 28 | CompressedDataIsUnseekable, | 28 | CompressedDataIsUnseekable, |
| 29 | EncryptedDataIsUnseekable, | 29 | EncryptedDataIsUnseekable, |
| @@ -81,7 +81,7 @@ impl Display for ZipError { | |||
| 81 | Self::InvalidFileComment => write!(f, "Invalid file comment"), | 81 | Self::InvalidFileComment => write!(f, "Invalid file comment"), |
| 82 | 82 | ||
| 83 | Self::FileNotFound => write!(f, "File not found"), | 83 | Self::FileNotFound => write!(f, "File not found"), |
| 84 | Self::IncorrectPassword => write!(f, "Incorrect password"), | 84 | Self::WrongPassword => write!(f, "Wrong password"), |
| 85 | Self::PasswordIsNotSpecified => write!(f, "Password is not specified"), | 85 | Self::PasswordIsNotSpecified => write!(f, "Password is not specified"), |
| 86 | Self::CompressedDataIsUnseekable => write!(f, "Compressed data is unseekable"), | 86 | Self::CompressedDataIsUnseekable => write!(f, "Compressed data is unseekable"), |
| 87 | Self::EncryptedDataIsUnseekable => write!(f, "Encrypted data is unseekable"), | 87 | Self::EncryptedDataIsUnseekable => write!(f, "Encrypted data is unseekable"), |
diff --git a/src/zip/file/read.rs b/src/zip/file/read.rs index 80bdcfb..d25655e 100644 --- a/src/zip/file/read.rs +++ b/src/zip/file/read.rs | |||
| @@ -24,21 +24,34 @@ enum Encryption<Io: Read> { | |||
| 24 | Aes256(AesDecoder<Io, Aes256>), | 24 | Aes256(AesDecoder<Io, Aes256>), |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | impl<Io: Read> Encryption<Io> { | 27 | impl<Io: Read + Seek> Encryption<IoCursor<Io>> { |
| 28 | #[inline] | 28 | #[inline] |
| 29 | pub fn new(mut io: Io, info: &ZipFileInfo, password: Option<&[u8]>) -> ZipResult<Self> { | 29 | pub fn new( |
| 30 | mut io: Io, | ||
| 31 | cursor: u64, | ||
| 32 | end: u64, | ||
| 33 | info: &ZipFileInfo, | ||
| 34 | password: Option<&[u8]>, | ||
| 35 | ) -> ZipResult<Self> { | ||
| 30 | Ok(match info.encryption_method { | 36 | Ok(match info.encryption_method { |
| 31 | EncryptionMethod::None => Self::None(io), | 37 | EncryptionMethod::None => Self::None(IoCursor::new(io, cursor, end)), |
| 32 | EncryptionMethod::Weak => { | 38 | EncryptionMethod::Weak => { |
| 33 | let mut keys = Keys::new(); | 39 | let mut keys = Keys::new(); |
| 34 | keys.set_password(password.ok_or(ZipError::PasswordIsNotSpecified)?); | ||
| 35 | 40 | ||
| 36 | let check = keys.set_header(io.read_arr()?); | 41 | for b in password.ok_or(ZipError::PasswordIsNotSpecified)? { |
| 37 | if check != info.password_check() { | 42 | keys.update(*b) |
| 38 | return Err(ZipError::IncorrectPassword); | 43 | } |
| 44 | |||
| 45 | let header = io.read_arr::<12>()?; | ||
| 46 | for b in &header[..11] { | ||
| 47 | keys.decode_byte(*b); | ||
| 39 | } | 48 | } |
| 40 | 49 | ||
| 41 | Self::Weak(WeakDecoder::new(io, keys)) | 50 | if keys.decode_byte(header[11]) != info.password_check() { |
| 51 | return Err(ZipError::WrongPassword); | ||
| 52 | } | ||
| 53 | |||
| 54 | Self::Weak(WeakDecoder::new(IoCursor::new(io, cursor + 12, end), keys)) | ||
| 42 | } | 55 | } |
| 43 | EncryptionMethod::Aes128 => { | 56 | EncryptionMethod::Aes128 => { |
| 44 | let header = io.read_arr::<10>()?; | 57 | let header = io.read_arr::<10>()?; |
| @@ -53,10 +66,13 @@ impl<Io: Read> Encryption<Io> { | |||
| 53 | let key = &hash[..16]; | 66 | let key = &hash[..16]; |
| 54 | 67 | ||
| 55 | if check != &hash[32..] { | 68 | if check != &hash[32..] { |
| 56 | return Err(ZipError::IncorrectPassword); | 69 | return Err(ZipError::WrongPassword); |
| 57 | } | 70 | } |
| 58 | 71 | ||
| 59 | Self::Aes128(AesDecoder::new(io, Aes128::new(key.into()))?) | 72 | Self::Aes128(AesDecoder::new( |
| 73 | IoCursor::new(io, cursor + 10, end - 10), | ||
| 74 | Aes128::new(key.into()), | ||
| 75 | )?) | ||
| 60 | } | 76 | } |
| 61 | EncryptionMethod::Aes192 => { | 77 | EncryptionMethod::Aes192 => { |
| 62 | let header = io.read_arr::<14>()?; | 78 | let header = io.read_arr::<14>()?; |
| @@ -71,10 +87,13 @@ impl<Io: Read> Encryption<Io> { | |||
| 71 | let key = &hash[..24]; | 87 | let key = &hash[..24]; |
| 72 | 88 | ||
| 73 | if check != &hash[48..] { | 89 | if check != &hash[48..] { |
| 74 | return Err(ZipError::IncorrectPassword); | 90 | return Err(ZipError::WrongPassword); |
| 75 | } | 91 | } |
| 76 | 92 | ||
| 77 | Self::Aes192(AesDecoder::new(io, Aes192::new(key.into()))?) | 93 | Self::Aes192(AesDecoder::new( |
| 94 | IoCursor::new(io, cursor + 14, end - 10), | ||
| 95 | Aes192::new(key.into()), | ||
| 96 | )?) | ||
| 78 | } | 97 | } |
| 79 | EncryptionMethod::Aes256 => { | 98 | EncryptionMethod::Aes256 => { |
| 80 | let header = io.read_arr::<18>()?; | 99 | let header = io.read_arr::<18>()?; |
| @@ -89,10 +108,13 @@ impl<Io: Read> Encryption<Io> { | |||
| 89 | let key = &hash[..32]; | 108 | let key = &hash[..32]; |
| 90 | 109 | ||
| 91 | if check != &hash[64..] { | 110 | if check != &hash[64..] { |
| 92 | return Err(ZipError::IncorrectPassword); | 111 | return Err(ZipError::WrongPassword); |
| 93 | } | 112 | } |
| 94 | 113 | ||
| 95 | Self::Aes256(AesDecoder::new(io, Aes256::new(key.into()))?) | 114 | Self::Aes256(AesDecoder::new( |
| 115 | IoCursor::new(io, cursor + 18, end - 10), | ||
| 116 | Aes256::new(key.into()), | ||
| 117 | )?) | ||
| 96 | } | 118 | } |
| 97 | EncryptionMethod::Unsupported => return Err(ZipError::UnsupportedEncryptionMethod), | 119 | EncryptionMethod::Unsupported => return Err(ZipError::UnsupportedEncryptionMethod), |
| 98 | }) | 120 | }) |
| @@ -215,20 +237,17 @@ impl<'d, Io: Read + Seek> ZipFileReader<'d, Io> { | |||
| 215 | if buf[..4] != FILE_HEADER_SIGNATURE { | 237 | if buf[..4] != FILE_HEADER_SIGNATURE { |
| 216 | return Err(ZipError::InvalidFileHeaderSignature); | 238 | return Err(ZipError::InvalidFileHeaderSignature); |
| 217 | } | 239 | } |
| 218 | let data_pointer = info.header_pointer | 240 | |
| 219 | + 30 | 241 | let cursor = io.seek(SeekFrom::Start( |
| 220 | + u16::from_le_bytes(buf[26..28].try_into().unwrap()) as u64 | 242 | info.header_pointer |
| 221 | + u16::from_le_bytes(buf[28..30].try_into().unwrap()) as u64; | 243 | + 30 |
| 244 | + u16::from_le_bytes(buf[26..28].try_into().unwrap()) as u64 | ||
| 245 | + u16::from_le_bytes(buf[28..30].try_into().unwrap()) as u64, | ||
| 246 | ))?; | ||
| 247 | let end = cursor + info.compressed_size; | ||
| 222 | 248 | ||
| 223 | Ok(Self { | 249 | Ok(Self { |
| 224 | io: Compression::new( | 250 | io: Compression::new(Encryption::new(io, cursor, end, info, password)?, info)?, |
| 225 | Encryption::new( | ||
| 226 | IoCursor::new(io, data_pointer, data_pointer + info.compressed_size)?, | ||
| 227 | info, | ||
| 228 | password, | ||
| 229 | )?, | ||
| 230 | info, | ||
| 231 | )?, | ||
| 232 | info, | 251 | info, |
| 233 | }) | 252 | }) |
| 234 | } | 253 | } |
