aboutsummaryrefslogtreecommitdiff
path: root/src/zip
diff options
context:
space:
mode:
authorIgor Tolmachev <me@igorek.dev>2024-07-21 16:59:14 +0900
committerIgor Tolmachev <me@igorek.dev>2024-07-21 16:59:14 +0900
commit4c411b76cad9cc735687dc739d2e2db5d00e5eac (patch)
tree818168ca5726ad3f9d24089dba31a24ff6b1b1f4 /src/zip
parent7bcdc3b4ca460aec2b98fb2dca6165788c562b05 (diff)
downloadarchivator-4c411b76cad9cc735687dc739d2e2db5d00e5eac.tar.gz
archivator-4c411b76cad9cc735687dc739d2e2db5d00e5eac.zip
Add AES encryption
Diffstat (limited to 'src/zip')
-rw-r--r--src/zip/encryption/aes.rs49
-rw-r--r--src/zip/encryption/weak.rs15
-rw-r--r--src/zip/error.rs4
-rw-r--r--src/zip/file/read.rs71
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 @@
1use crate::utils::ReadUtils;
2use aes::cipher::generic_array::GenericArray; 1use aes::cipher::generic_array::GenericArray;
3use aes::cipher::BlockEncrypt; 2use aes::cipher::BlockEncrypt;
4use std::io::{Read, Result as IoResult}; 3use 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
16impl<Io: Read, Aes: BlockEncrypt> AesDecoder<Io, Aes> { 16impl<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
42impl<Io: Read, Aes: BlockEncrypt> Read for AesDecoder<Io, Aes> { 52impl<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
27impl<Io: Read> Encryption<Io> { 27impl<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 }