diff --git a/Cargo.toml b/Cargo.toml index f0829d91..95c4e7a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,15 +11,15 @@ Library to support the reading and writing of zip files. edition = "2018" [dependencies] -aes = { version = "0.6.0", optional = true } +aes = { version = "0.7.5", optional = true } byteorder = "1.3" bzip2 = { version = "0.4", optional = true } constant_time_eq = { version = "0.1.5", optional = true } crc32fast = "1.1.1" flate2 = { version = "1.0.0", default-features = false, optional = true } -hmac = {version = "0.10.1", optional = true } -pbkdf2 = {version = "0.6.0", optional = true } -sha-1 = {version = "0.9.2", optional = true } +hmac = {version = "0.12.0", optional = true} +pbkdf2 = {version = "0.10.0", optional = true } +sha-1 = {version = "0.10.0", optional = true } time = { version = "0.3", features = ["formatting", "macros" ], optional = true } zstd = { version = "0.10", optional = true } diff --git a/src/aes.rs b/src/aes.rs index 4aabccd0..fc65577a 100644 --- a/src/aes.rs +++ b/src/aes.rs @@ -6,8 +6,9 @@ use crate::aes_ctr; use crate::types::AesMode; +use aes::cipher::generic_array::{typenum::Unsigned, GenericArray}; use constant_time_eq::constant_time_eq; -use hmac::{Hmac, Mac, NewMac}; +use hmac::{digest::crypto_common::KeySizeUser, Hmac, Mac}; use sha1::Sha1; use std::io::{self, Read}; @@ -96,13 +97,14 @@ impl AesReader { } let cipher = cipher_from_mode(self.aes_mode, decrypt_key); - let hmac = Hmac::::new_varkey(hmac_key).unwrap(); + let hmac = Hmac::::new_from_slice(hmac_key).unwrap(); Ok(Some(AesReaderValid { reader: self.reader, data_remaining: self.data_length, cipher, hmac, + finalized: false, })) } } @@ -117,6 +119,7 @@ pub struct AesReaderValid { data_remaining: u64, cipher: Box, hmac: Hmac, + finalized: bool, } impl Read for AesReaderValid { @@ -148,11 +151,27 @@ impl Read for AesReaderValid { // if there is no data left to read, check the integrity of the data if self.data_remaining == 0 { + assert!( + !self.finalized, + "Tried to use an already finalized HMAC. This is a bug!" + ); + self.finalized = true; + // Zip uses HMAC-Sha1-80, which only uses the first half of the hash // see https://www.winzip.com/win/en/aes_info.html#auth-faq let mut read_auth_code = [0; AUTH_CODE_LENGTH]; self.reader.read_exact(&mut read_auth_code)?; - let computed_auth_code = &self.hmac.finalize_reset().into_bytes()[0..AUTH_CODE_LENGTH]; + + // The following call to `finalize` consumes `hmac` so we replace `self.hmac` with a + // dummy that uses a `Key` made up of only zeroes. `self.hmac` should not be used after + // this. + let hmac = std::mem::replace( + &mut self.hmac, + Hmac::new(&GenericArray::from_slice( + &vec![0; as KeySizeUser>::KeySize::to_usize()], + )), + ); + let computed_auth_code = &hmac.finalize().into_bytes()[0..AUTH_CODE_LENGTH]; // use constant time comparison to mitigate timing attacks if !constant_time_eq(computed_auth_code, &read_auth_code) { diff --git a/src/aes_ctr.rs b/src/aes_ctr.rs index db8957ee..25cd09ac 100644 --- a/src/aes_ctr.rs +++ b/src/aes_ctr.rs @@ -5,7 +5,7 @@ //! See [AesCtrZipKeyStream](./struct.AesCtrZipKeyStream.html) for more information. use aes::cipher::generic_array::GenericArray; -use aes::{BlockCipher, NewBlockCipher}; +use aes::{BlockEncrypt, NewBlockCipher}; use byteorder::WriteBytesExt; use std::{any, fmt}; @@ -102,7 +102,7 @@ where impl AesCipher for AesCtrZipKeyStream where C: AesKind, - C::Cipher: BlockCipher, + C::Cipher: BlockEncrypt, { /// Decrypt or encrypt `target`. #[inline]