differentiate between ae1 and ae2
This commit is contained in:
parent
8ffc2d1545
commit
ff23539624
3 changed files with 44 additions and 23 deletions
11
src/crc32.rs
11
src/crc32.rs
|
@ -12,17 +12,18 @@ pub struct Crc32Reader<R> {
|
|||
check: u32,
|
||||
/// Signals if `inner` stores aes encrypted data.
|
||||
/// AE-2 encrypted data doesn't use crc and sets the value to 0.
|
||||
aes_encrypted: bool,
|
||||
ae2_encrypted: bool,
|
||||
}
|
||||
|
||||
impl<R> Crc32Reader<R> {
|
||||
/// Get a new Crc32Reader which check the inner reader against checksum.
|
||||
pub fn new(inner: R, checksum: u32, aes_encrypted: bool) -> Crc32Reader<R> {
|
||||
/// Get a new Crc32Reader which checks the inner reader against checksum.
|
||||
/// The check is disabled if `ae2_encrypted == true`.
|
||||
pub fn new(inner: R, checksum: u32, ae2_encrypted: bool) -> Crc32Reader<R> {
|
||||
Crc32Reader {
|
||||
inner,
|
||||
hasher: Hasher::new(),
|
||||
check: checksum,
|
||||
aes_encrypted,
|
||||
ae2_encrypted,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,7 +39,7 @@ impl<R> Crc32Reader<R> {
|
|||
impl<R: Read> Read for Crc32Reader<R> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
let count = match self.inner.read(buf) {
|
||||
Ok(0) if !buf.is_empty() && !self.check_matches() && !self.aes_encrypted => {
|
||||
Ok(0) if !buf.is_empty() && !self.check_matches() && !self.ae2_encrypted => {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "Invalid checksum"))
|
||||
}
|
||||
Ok(n) => n,
|
||||
|
|
46
src/read.rs
46
src/read.rs
|
@ -6,7 +6,7 @@ use crate::cp437::FromCp437;
|
|||
use crate::crc32::Crc32Reader;
|
||||
use crate::result::{InvalidPassword, ZipError, ZipResult};
|
||||
use crate::spec;
|
||||
use crate::types::{AesMode, DateTime, System, ZipFileData};
|
||||
use crate::types::{AesMode, AesVendorVersion, DateTime, System, ZipFileData};
|
||||
use crate::zipcrypto::{ZipCryptoReader, ZipCryptoReaderValid, ZipCryptoValidator};
|
||||
use byteorder::{LittleEndian, ReadBytesExt};
|
||||
use std::borrow::Cow;
|
||||
|
@ -58,7 +58,10 @@ pub struct ZipArchive<R> {
|
|||
enum CryptoReader<'a> {
|
||||
Plaintext(io::Take<&'a mut dyn Read>),
|
||||
ZipCrypto(ZipCryptoReaderValid<io::Take<&'a mut dyn Read>>),
|
||||
Aes(AesReaderValid<io::Take<&'a mut dyn Read>>),
|
||||
Aes {
|
||||
reader: AesReaderValid<io::Take<&'a mut dyn Read>>,
|
||||
vendor_version: AesVendorVersion,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'a> Read for CryptoReader<'a> {
|
||||
|
@ -66,7 +69,7 @@ impl<'a> Read for CryptoReader<'a> {
|
|||
match self {
|
||||
CryptoReader::Plaintext(r) => r.read(buf),
|
||||
CryptoReader::ZipCrypto(r) => r.read(buf),
|
||||
CryptoReader::Aes(r) => r.read(buf),
|
||||
CryptoReader::Aes { reader: r, .. } => r.read(buf),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -77,7 +80,7 @@ impl<'a> CryptoReader<'a> {
|
|||
match self {
|
||||
CryptoReader::Plaintext(r) => r,
|
||||
CryptoReader::ZipCrypto(r) => r.into_inner(),
|
||||
CryptoReader::Aes(r) => r.into_inner(),
|
||||
CryptoReader::Aes { reader: r, .. } => r.into_inner(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -168,7 +171,7 @@ fn make_crypto_reader<'a>(
|
|||
using_data_descriptor: bool,
|
||||
reader: io::Take<&'a mut dyn io::Read>,
|
||||
password: Option<&[u8]>,
|
||||
aes_mode: Option<AesMode>,
|
||||
aes_info: Option<(AesMode, AesVendorVersion)>,
|
||||
compressed_size: u64,
|
||||
) -> ZipResult<Result<CryptoReader<'a>, InvalidPassword>> {
|
||||
#[allow(deprecated)]
|
||||
|
@ -178,7 +181,7 @@ fn make_crypto_reader<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
let reader = match (password, aes_mode) {
|
||||
let reader = match (password, aes_info) {
|
||||
(None, _) => CryptoReader::Plaintext(reader),
|
||||
(Some(password), None) => {
|
||||
let validator = if using_data_descriptor {
|
||||
|
@ -191,10 +194,13 @@ fn make_crypto_reader<'a>(
|
|||
Some(r) => CryptoReader::ZipCrypto(r),
|
||||
}
|
||||
}
|
||||
(Some(password), Some(aes_mode)) => {
|
||||
(Some(password), Some((aes_mode, vendor_version))) => {
|
||||
match AesReader::new(reader, aes_mode, compressed_size).validate(&password)? {
|
||||
None => return Ok(Err(InvalidPassword)),
|
||||
Some(r) => CryptoReader::Aes(r),
|
||||
Some(r) => CryptoReader::Aes {
|
||||
reader: r,
|
||||
vendor_version,
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -206,10 +212,13 @@ fn make_reader<'a>(
|
|||
crc32: u32,
|
||||
reader: CryptoReader<'a>,
|
||||
) -> ZipFileReader<'a> {
|
||||
let aes_encrypted = matches!(reader, CryptoReader::Aes(_));
|
||||
let ae2_encrypted = matches!(reader, CryptoReader::Aes {
|
||||
vendor_version: AesVendorVersion::Ae2,
|
||||
..
|
||||
});
|
||||
match compression_method {
|
||||
CompressionMethod::Stored => {
|
||||
ZipFileReader::Stored(Crc32Reader::new(reader, crc32, aes_encrypted))
|
||||
ZipFileReader::Stored(Crc32Reader::new(reader, crc32, ae2_encrypted))
|
||||
}
|
||||
#[cfg(any(
|
||||
feature = "deflate",
|
||||
|
@ -218,12 +227,12 @@ fn make_reader<'a>(
|
|||
))]
|
||||
CompressionMethod::Deflated => {
|
||||
let deflate_reader = DeflateDecoder::new(reader);
|
||||
ZipFileReader::Deflated(Crc32Reader::new(deflate_reader, crc32, aes_encrypted))
|
||||
ZipFileReader::Deflated(Crc32Reader::new(deflate_reader, crc32, ae2_encrypted))
|
||||
}
|
||||
#[cfg(feature = "bzip2")]
|
||||
CompressionMethod::Bzip2 => {
|
||||
let bzip2_reader = BzDecoder::new(reader);
|
||||
ZipFileReader::Bzip2(Crc32Reader::new(bzip2_reader, crc32, aes_encrypted))
|
||||
ZipFileReader::Bzip2(Crc32Reader::new(bzip2_reader, crc32, ae2_encrypted))
|
||||
}
|
||||
_ => panic!("Compression method not supported"),
|
||||
}
|
||||
|
@ -665,7 +674,7 @@ fn parse_extra_field(file: &mut ZipFileData) -> ZipResult<()> {
|
|||
"AES extra data field has an unsupported length",
|
||||
));
|
||||
}
|
||||
let _vendor_version = reader.read_u16::<LittleEndian>()?; // TODO: CRC value handling changes
|
||||
let vendor_version = reader.read_u16::<LittleEndian>()?;
|
||||
let vendor_id = reader.read_u16::<LittleEndian>()?;
|
||||
let aes_mode = reader.read_u8()?;
|
||||
let compression_method = reader.read_u16::<LittleEndian>()?;
|
||||
|
@ -673,10 +682,15 @@ fn parse_extra_field(file: &mut ZipFileData) -> ZipResult<()> {
|
|||
if vendor_id != 0x4541 {
|
||||
return Err(ZipError::InvalidArchive("Invalid AES vendor"));
|
||||
}
|
||||
let vendor_version = match vendor_version {
|
||||
0x0001 => AesVendorVersion::Ae1,
|
||||
0x0002 => AesVendorVersion::Ae2,
|
||||
_ => return Err(ZipError::InvalidArchive("Invalid AES vendor version")),
|
||||
};
|
||||
match aes_mode {
|
||||
0x01 => file.aes_mode = Some(AesMode::Aes128),
|
||||
0x02 => file.aes_mode = Some(AesMode::Aes192),
|
||||
0x03 => file.aes_mode = Some(AesMode::Aes256),
|
||||
0x01 => file.aes_mode = Some((AesMode::Aes128, vendor_version)),
|
||||
0x02 => file.aes_mode = Some((AesMode::Aes192, vendor_version)),
|
||||
0x03 => file.aes_mode = Some((AesMode::Aes256, vendor_version)),
|
||||
_ => return Err(ZipError::InvalidArchive("Invalid AES encryption strength")),
|
||||
};
|
||||
file.compression_method = {
|
||||
|
|
10
src/types.rs
10
src/types.rs
|
@ -249,7 +249,7 @@ pub struct ZipFileData {
|
|||
/// Reserve local ZIP64 extra field
|
||||
pub large_file: bool,
|
||||
/// AES mode if applicable
|
||||
pub aes_mode: Option<AesMode>,
|
||||
pub aes_mode: Option<(AesMode, AesVendorVersion)>,
|
||||
}
|
||||
|
||||
impl ZipFileData {
|
||||
|
@ -300,8 +300,14 @@ impl ZipFileData {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum AesVendorVersion {
|
||||
Ae1,
|
||||
Ae2,
|
||||
}
|
||||
|
||||
/// AES variant used.
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum AesMode {
|
||||
Aes128,
|
||||
Aes192,
|
||||
|
|
Loading…
Add table
Reference in a new issue