From 4078bd34cd5daf1baa6f5da60ba3538df6f7d04f Mon Sep 17 00:00:00 2001 From: awakening Date: Sat, 27 Apr 2024 23:41:32 +0700 Subject: [PATCH] fix: Decrypt the read bytes in ZipCrypto instead of entire buffer Fixes `corrupt deflate stream` panic when extracting a file from encrypted archive (zip-rs/zip#280). --- src/zipcrypto.rs | 6 +++--- tests/zip_crypto.rs | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/zipcrypto.rs b/src/zipcrypto.rs index 43ef1048b..995bf23f8 100644 --- a/src/zipcrypto.rs +++ b/src/zipcrypto.rs @@ -183,11 +183,11 @@ impl std::io::Read for ZipCryptoReaderValid { // Note: There might be potential for optimization. Inspiration can be found at: // https://github.com/kornelski/7z/blob/master/CPP/7zip/Crypto/ZipCrypto.cpp - let result = self.reader.file.read(buf); - for byte in buf.iter_mut() { + let n = self.reader.file.read(buf)?; + for byte in buf.iter_mut().take(n) { *byte = self.reader.keys.decrypt_byte(*byte); } - result + Ok(n) } } diff --git a/tests/zip_crypto.rs b/tests/zip_crypto.rs index 1b9f44d38..9e91e1bd3 100644 --- a/tests/zip_crypto.rs +++ b/tests/zip_crypto.rs @@ -102,3 +102,21 @@ fn encrypted_file() { assert_eq!(data, "abcdefghijklmnopqrstuvwxyz123456789".as_bytes()); } } + +#[test] +fn buffered_read() { + use std::io::{BufReader, Read}; + + // delibirately pick a buffer capacity in a way that when `ZipCryptoReaderValid` read happens, it's not going to take entire buffer, + // for this file it needs to be between 13..=46 bytes (with exception of 44 bytes) + let zip_file_bytes = &mut Cursor::new(ZIP_CRYPTO_FILE); + let buffered = BufReader::with_capacity(13, zip_file_bytes); + let mut archive = zip::ZipArchive::new(buffered).unwrap(); + + let mut file = archive.by_index_decrypt(0, b"test").unwrap(); + + // should not panic with `Custom { kind: Other, error: "Invalid checksum" }` + // or `Custom { kind: InvalidInput, error: "corrupt deflate stream" }` + let mut data = Vec::new(); + file.read_to_end(&mut data).unwrap(); +}