• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Implementation of the AES decryption for zip files.
2 //!
3 //! This was implemented according to the [WinZip specification](https://www.winzip.com/win/en/aes_info.html).
4 //! Note that using CRC with AES depends on the used encryption specification, AE-1 or AE-2.
5 //! If the file is marked as encrypted with AE-2 the CRC field is ignored, even if it isn't set to 0.
6 
7 use crate::aes_ctr;
8 use crate::types::AesMode;
9 use constant_time_eq::constant_time_eq;
10 use hmac::{Hmac, Mac};
11 use sha1::Sha1;
12 use std::io::{self, Read};
13 
14 /// The length of the password verifcation value in bytes
15 const PWD_VERIFY_LENGTH: usize = 2;
16 /// The length of the authentication code in bytes
17 const AUTH_CODE_LENGTH: usize = 10;
18 /// The number of iterations used with PBKDF2
19 const ITERATION_COUNT: u32 = 1000;
20 
21 /// Create a AesCipher depending on the used `AesMode` and the given `key`.
22 ///
23 /// # Panics
24 ///
25 /// This panics if `key` doesn't have the correct size for the chosen aes mode.
cipher_from_mode(aes_mode: AesMode, key: &[u8]) -> Box<dyn aes_ctr::AesCipher>26 fn cipher_from_mode(aes_mode: AesMode, key: &[u8]) -> Box<dyn aes_ctr::AesCipher> {
27     match aes_mode {
28         AesMode::Aes128 => Box::new(aes_ctr::AesCtrZipKeyStream::<aes_ctr::Aes128>::new(key))
29             as Box<dyn aes_ctr::AesCipher>,
30         AesMode::Aes192 => Box::new(aes_ctr::AesCtrZipKeyStream::<aes_ctr::Aes192>::new(key))
31             as Box<dyn aes_ctr::AesCipher>,
32         AesMode::Aes256 => Box::new(aes_ctr::AesCtrZipKeyStream::<aes_ctr::Aes256>::new(key))
33             as Box<dyn aes_ctr::AesCipher>,
34     }
35 }
36 
37 // An aes encrypted file starts with a salt, whose length depends on the used aes mode
38 // followed by a 2 byte password verification value
39 // then the variable length encrypted data
40 // and lastly a 10 byte authentication code
41 pub struct AesReader<R> {
42     reader: R,
43     aes_mode: AesMode,
44     data_length: u64,
45 }
46 
47 impl<R: Read> AesReader<R> {
new(reader: R, aes_mode: AesMode, compressed_size: u64) -> AesReader<R>48     pub fn new(reader: R, aes_mode: AesMode, compressed_size: u64) -> AesReader<R> {
49         let data_length = compressed_size
50             - (PWD_VERIFY_LENGTH + AUTH_CODE_LENGTH + aes_mode.salt_length()) as u64;
51 
52         Self {
53             reader,
54             aes_mode,
55             data_length,
56         }
57     }
58 
59     /// Read the AES header bytes and validate the password.
60     ///
61     /// Even if the validation succeeds, there is still a 1 in 65536 chance that an incorrect
62     /// password was provided.
63     /// It isn't possible to check the authentication code in this step. This will be done after
64     /// reading and decrypting the file.
65     ///
66     /// # Returns
67     ///
68     /// If the password verification failed `Ok(None)` will be returned to match the validate
69     /// method of ZipCryptoReader.
validate(mut self, password: &[u8]) -> io::Result<Option<AesReaderValid<R>>>70     pub fn validate(mut self, password: &[u8]) -> io::Result<Option<AesReaderValid<R>>> {
71         let salt_length = self.aes_mode.salt_length();
72         let key_length = self.aes_mode.key_length();
73 
74         let mut salt = vec![0; salt_length];
75         self.reader.read_exact(&mut salt)?;
76 
77         // next are 2 bytes used for password verification
78         let mut pwd_verification_value = vec![0; PWD_VERIFY_LENGTH];
79         self.reader.read_exact(&mut pwd_verification_value)?;
80 
81         // derive a key from the password and salt
82         // the length depends on the aes key length
83         let derived_key_len = 2 * key_length + PWD_VERIFY_LENGTH;
84         let mut derived_key: Vec<u8> = vec![0; derived_key_len];
85 
86         // use PBKDF2 with HMAC-Sha1 to derive the key
87         pbkdf2::pbkdf2::<Hmac<Sha1>>(password, &salt, ITERATION_COUNT, &mut derived_key);
88         let decrypt_key = &derived_key[0..key_length];
89         let hmac_key = &derived_key[key_length..key_length * 2];
90         let pwd_verify = &derived_key[derived_key_len - 2..];
91 
92         // the last 2 bytes should equal the password verification value
93         if pwd_verification_value != pwd_verify {
94             // wrong password
95             return Ok(None);
96         }
97 
98         let cipher = cipher_from_mode(self.aes_mode, decrypt_key);
99         let hmac = Hmac::<Sha1>::new_from_slice(hmac_key).unwrap();
100 
101         Ok(Some(AesReaderValid {
102             reader: self.reader,
103             data_remaining: self.data_length,
104             cipher,
105             hmac,
106             finalized: false,
107         }))
108     }
109 }
110 
111 /// A reader for aes encrypted files, which has already passed the first password check.
112 ///
113 /// There is a 1 in 65536 chance that an invalid password passes that check.
114 /// After the data has been read and decrypted an HMAC will be checked and provide a final means
115 /// to check if either the password is invalid or if the data has been changed.
116 pub struct AesReaderValid<R: Read> {
117     reader: R,
118     data_remaining: u64,
119     cipher: Box<dyn aes_ctr::AesCipher>,
120     hmac: Hmac<Sha1>,
121     finalized: bool,
122 }
123 
124 impl<R: Read> Read for AesReaderValid<R> {
125     /// This implementation does not fulfill all requirements set in the trait documentation.
126     ///
127     /// ```txt
128     /// "If an error is returned then it must be guaranteed that no bytes were read."
129     /// ```
130     ///
131     /// Whether this applies to errors that occur while reading the encrypted data depends on the
132     /// underlying reader. If the error occurs while verifying the HMAC, the reader might become
133     /// practically unusable, since its position after the error is not known.
read(&mut self, buf: &mut [u8]) -> io::Result<usize>134     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
135         if self.data_remaining == 0 {
136             return Ok(0);
137         }
138 
139         // get the number of bytes to read, compare as u64 to make sure we can read more than
140         // 2^32 bytes even on 32 bit systems.
141         let bytes_to_read = self.data_remaining.min(buf.len() as u64) as usize;
142         let read = self.reader.read(&mut buf[0..bytes_to_read])?;
143         self.data_remaining -= read as u64;
144 
145         // Update the hmac with the encrypted data
146         self.hmac.update(&buf[0..read]);
147 
148         // decrypt the data
149         self.cipher.crypt_in_place(&mut buf[0..read]);
150 
151         // if there is no data left to read, check the integrity of the data
152         if self.data_remaining == 0 {
153             assert!(
154                 !self.finalized,
155                 "Tried to use an already finalized HMAC. This is a bug!"
156             );
157             self.finalized = true;
158 
159             // Zip uses HMAC-Sha1-80, which only uses the first half of the hash
160             // see https://www.winzip.com/win/en/aes_info.html#auth-faq
161             let mut read_auth_code = [0; AUTH_CODE_LENGTH];
162             self.reader.read_exact(&mut read_auth_code)?;
163             let computed_auth_code = &self.hmac.finalize_reset().into_bytes()[0..AUTH_CODE_LENGTH];
164 
165             // use constant time comparison to mitigate timing attacks
166             if !constant_time_eq(computed_auth_code, &read_auth_code) {
167                 return Err(
168                     io::Error::new(
169                         io::ErrorKind::InvalidData,
170                         "Invalid authentication code, this could be due to an invalid password or errors in the data"
171                     )
172                 );
173             }
174         }
175 
176         Ok(read)
177     }
178 }
179 
180 impl<R: Read> AesReaderValid<R> {
181     /// Consumes this decoder, returning the underlying reader.
into_inner(self) -> R182     pub fn into_inner(self) -> R {
183         self.reader
184     }
185 }
186