Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 32 additions & 30 deletions src/extra_fields/aex_encryption.rs
Original file line number Diff line number Diff line change
@@ -1,39 +1,33 @@
//! AE-x encryption structure extra field

use std::io::{ErrorKind, Read};
use std::io::{ErrorKind, Read, Write};
Comment thread
Its-Just-Nans marked this conversation as resolved.

use crate::AesMode;
use crate::CompressionMethod;
use crate::extra_fields::UsedExtraField;
use crate::result::{ZipError, ZipResult, invalid, invalid_archive_const};
use crate::spec::Pod;
use crate::types::AesVendorVersion;
use crate::unstable::LittleEndianReadExt;

#[derive(Copy, Clone)]
#[repr(packed, C)]
pub(crate) struct AexEncryption {
header_id: u16,
data_size: u16,
pub(crate) version: u16,
vendor_id: u16,
aes_mode: u8,
compression_method: u16,
}

unsafe impl Pod for AexEncryption {}

impl AexEncryption {
#[inline(always)]
pub(crate) fn to_le(mut self) -> Self {
self.header_id = u16::to_le(self.header_id);
self.data_size = u16::to_le(self.data_size);
self.version = u16::to_le(self.version);
self.vendor_id = u16::to_le(self.vendor_id);
self.aes_mode = u8::to_le(self.aes_mode);
self.compression_method = u16::to_le(self.compression_method);
self
}
/// Field Header ID
pub(crate) const EXTRA_FIELD_ID: u16 = UsedExtraField::AeXEncryption.as_u16();
/// Field size
pub(crate) const EXTRA_FIELD_SIZE: u16 =
(size_of::<u16>() + size_of::<u16>() + size_of::<u8>() + size_of::<u16>()) as u16;
/// 0x4541
pub(crate) const VENDOR_ID: u16 = u16::from_le_bytes(*b"AE");
/// Full size of the extra field
pub(crate) const FULL_SIZE: usize =
size_of::<u16>() + size_of::<u16>() + Self::EXTRA_FIELD_SIZE as usize;

#[inline]
pub(crate) fn new(
Expand All @@ -42,15 +36,25 @@ impl AexEncryption {
compression_method: CompressionMethod,
) -> Self {
Self {
header_id: UsedExtraField::AeXEncryption.as_u16(),
data_size: (size_of::<u16>() + size_of::<u16>() + size_of::<u8>() + size_of::<u16>())
as u16,
version: version.as_u16(),
vendor_id: u16::from_le_bytes(*b"AE"),
aes_mode: aes_mode.as_u8(),
compression_method: compression_method.serialize_to_u16(),
}
.to_le()
}

pub fn write<T: Write>(self, writer: &mut T) -> ZipResult<()> {
writer.write_all(&u16::to_le_bytes(Self::EXTRA_FIELD_ID))?;
writer.write_all(&u16::to_le_bytes(Self::EXTRA_FIELD_SIZE))?;
self.write_data(writer)?;
Ok(())
}

pub fn write_data<T: Write>(self, writer: &mut T) -> ZipResult<()> {
writer.write_all(&u16::to_le_bytes(self.version))?;
writer.write_all(&u16::to_le_bytes(Self::VENDOR_ID))?;
writer.write_all(&u8::to_le_bytes(self.aes_mode))?;
writer.write_all(&u16::to_le_bytes(self.compression_method))?;
Ok(())
}

#[inline]
Expand All @@ -72,7 +76,7 @@ impl AexEncryption {
}
return Err(e.into());
}
if vendor_id != 0x4541 {
if vendor_id != Self::VENDOR_ID {
return Err(invalid!("Invalid AES vendor"));
}
let vendor_version = vendor_version.try_into().map_err(invalid_archive_const)?;
Expand All @@ -89,26 +93,23 @@ mod tests {
use super::AexEncryption;
use crate::AesMode;
use crate::CompressionMethod;
use crate::spec::Pod;
use crate::types::AesVendorVersion;

let aex_encryption = AexEncryption::new(
AesVendorVersion::Ae2,
AesMode::Aes256,
CompressionMethod::Stored,
);
let mut buf = Vec::new();
aex_encryption.write(&mut buf).unwrap();

let buf = aex_encryption.as_bytes();
assert_eq!(buf.len(), 11);
assert_eq!(buf[0..2], [1, 153]);
assert_eq!(buf[2..4], [7, 0]);
assert_eq!(buf[4..6], [2, 0]);
assert_eq!(buf[6..8], [65, 69]);
assert_eq!(buf[8], 0x03);
assert_eq!(buf[9..], [0, 0]);

// test length used in write.rs
assert_eq!(buf[std::mem::offset_of!(AexEncryption, version)..].len(), 7);
}

#[test]
Expand All @@ -129,7 +130,6 @@ mod tests {
use super::AexEncryption;
use crate::AesMode;
use crate::CompressionMethod;
use crate::spec::Pod;
use crate::types::AesVendorVersion;
use std::io::Cursor;

Expand All @@ -139,7 +139,9 @@ mod tests {
CompressionMethod::Stored,
);

let data = aex_encryption.as_bytes();
let mut data = Vec::new();
aex_encryption.write(&mut data).unwrap();

let len_data = u16::from_le_bytes([data[2], data[3]]);
let data = &data[4..]; // remove the signature
let len = data.len() as u16;
Expand Down
53 changes: 16 additions & 37 deletions src/extra_fields/zip64_extended_information.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//!

use core::mem;
use std::io::{ErrorKind, Read, copy, sink};
use std::io::{ErrorKind, Read, Write, copy, sink};

use crate::unstable::LittleEndianReadExt;
use crate::{
Expand All @@ -25,7 +25,6 @@ use crate::{
pub(crate) struct Zip64ExtendedInformation {
/// The local header does not contains any `header_start`
is_local_header: bool,
magic: UsedExtraField,
size: u16,
uncompressed_size: Option<u64>,
compressed_size: Option<u64>,
Expand Down Expand Up @@ -68,7 +67,6 @@ impl Zip64ExtendedInformation {

Some(Self {
is_local_header: true,
magic: Self::MAGIC,
size,
uncompressed_size,
compressed_size,
Expand Down Expand Up @@ -111,7 +109,6 @@ impl Zip64ExtendedInformation {

Some(Self {
is_local_header: false,
magic: Self::MAGIC,
size,
uncompressed_size,
compressed_size,
Expand All @@ -125,49 +122,31 @@ impl Zip64ExtendedInformation {
}

/// Serialize the block
pub fn serialize(self) -> Box<[u8]> {
let Self {
is_local_header,
magic,
size,
uncompressed_size,
compressed_size,
header_start,
} = self;
pub fn write<T: Write>(self, writer: &mut T) -> ZipResult<()> {
writer.write_all(&Self::MAGIC.to_le_bytes())?;
writer.write_all(&self.size.to_le_bytes())?;

let full_size = self.full_size();
if is_local_header {
if self.is_local_header {
// the local header does not contains the header start
if let (Some(uncompressed_size), Some(compressed_size)) =
(uncompressed_size, compressed_size)
(self.uncompressed_size, self.compressed_size)
{
let mut ret = Vec::with_capacity(full_size);
ret.extend(magic.to_le_bytes());
ret.extend(size.to_le_bytes());
ret.extend(u64::to_le_bytes(uncompressed_size));
ret.extend(u64::to_le_bytes(compressed_size));
return ret.into_boxed_slice();
writer.write_all(&u64::to_le_bytes(uncompressed_size))?;
writer.write_all(&u64::to_le_bytes(compressed_size))?;
}
// this should be unreachable
Box::new([])
// the else should be unreachable
} else {
let mut ret = Vec::with_capacity(full_size);
ret.extend(magic.to_le_bytes());
ret.extend(u16::to_le_bytes(size));

if let Some(uncompressed_size) = uncompressed_size {
ret.extend(u64::to_le_bytes(uncompressed_size));
if let Some(uncompressed_size) = self.uncompressed_size {
writer.write_all(&u64::to_le_bytes(uncompressed_size))?;
}
if let Some(compressed_size) = compressed_size {
ret.extend(u64::to_le_bytes(compressed_size));
if let Some(compressed_size) = self.compressed_size {
writer.write_all(&u64::to_le_bytes(compressed_size))?;
}
if let Some(header_start) = header_start {
ret.extend(u64::to_le_bytes(header_start));
if let Some(header_start) = self.header_start {
writer.write_all(&u64::to_le_bytes(header_start))?;
}
debug_assert_eq!(ret.len(), full_size);

ret.into_boxed_slice()
}
Ok(())
}

#[inline]
Expand Down
27 changes: 15 additions & 12 deletions src/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::extra_fields::Zip64ExtendedInformation;
use crate::read::{Config, ZipArchive, ZipFile, parse_single_extra_field};
use crate::result::{ZipError, ZipResult, invalid};
use crate::spec::ZipFlags;
use crate::spec::{self, FixedSizeBlock, Magic, Pod, Zip32CDEBlock, ZipLocalEntryBlock};
use crate::spec::{self, FixedSizeBlock, Magic, Zip32CDEBlock, ZipLocalEntryBlock};
use crate::types::EncryptWith;
use crate::types::{AesVendorVersion, MIN_VERSION, System, ZipFileData, ZipRawValues, ffi};
use core::default::Default;
Expand Down Expand Up @@ -1166,8 +1166,9 @@ impl<W: Write + Seek> ZipWriter<W> {
};
let central_extra_data = options.extended_options.central_extra_data();
if let Some(zip64_block) = Zip64ExtendedInformation::new_local(options.large_file) {
let mut new_extra_data = zip64_block.serialize().into_vec();
new_extra_data.append(&mut extra_data);
let mut new_extra_data = Vec::with_capacity(zip64_block.full_size() + extra_data.len());
zip64_block.write(&mut new_extra_data)?;
new_extra_data.extend_from_slice(&extra_data);
extra_data = new_extra_data;
}

Expand All @@ -1187,12 +1188,14 @@ impl<W: Write + Seek> ZipWriter<W> {
// Write AES encryption extra data.
// For raw copies of AES entries, write the correct AES extra data immediately
let aex_extra_field = AexEncryption::new(vendor_version, mode, compression_method);
let buf = &aex_extra_field.as_bytes()[offset_of!(AexEncryption, version)..];
let mut buf = [0u8; AexEncryption::EXTRA_FIELD_SIZE as usize];
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
aex_extra_field.write_data(&mut buf.as_mut_slice())?;

aes_extra_data_start = extra_data.len() as u64;
ExtendedFileOptions::add_extra_data_unchecked(
&mut extra_data,
UsedExtraField::AeXEncryption.as_u16(),
buf,
&buf,
)?;
Some((mode, vendor_version))
}
Expand Down Expand Up @@ -2393,8 +2396,9 @@ fn update_aes_extra_data<W: Write + Seek>(
))?;

let aes_extra_field = AexEncryption::new(*version, *aes_mode, inner_compression_method);
let buf = aes_extra_field.as_bytes();
writer.write_all(buf)?;
let mut buf = [0u8; AexEncryption::FULL_SIZE];
aes_extra_field.write(&mut buf.as_mut_slice())?;
writer.write_all(&buf)?;

let aes_extra_data_start = file.aes_extra_data_start as usize;
let Some(ref mut extra_field) = file.extra_field else {
Expand All @@ -2403,8 +2407,8 @@ fn update_aes_extra_data<W: Write + Seek>(
));
};
let mut vec = extra_field.to_vec();
vec[aes_extra_data_start..aes_extra_data_start + size_of::<AexEncryption>()]
.copy_from_slice(buf);
vec[aes_extra_data_start..aes_extra_data_start + AexEncryption::FULL_SIZE]
.copy_from_slice(&buf);
*extra_field = Arc::from(vec.into_boxed_slice());

Ok(())
Expand Down Expand Up @@ -2461,8 +2465,7 @@ impl ZipFileData {
+ file_name_raw.len() as u64;

writer.seek(SeekFrom::Start(zip64_extra_field_start))?;
let zip64_block = zip64_block.serialize();
writer.write_all(&zip64_block)?;
zip64_block.write(writer)?;
Ok(())
}

Expand Down Expand Up @@ -2498,7 +2501,7 @@ impl ZipFileData {
writer.write_all(file_name_raw)?;
// extra field
if let Some(zip64_extra_field) = zip64_extra_field_block {
writer.write_all(&zip64_extra_field.serialize())?;
zip64_extra_field.write(writer)?;
}
if !stripped_extra.is_empty() {
writer.write_all(&stripped_extra)?;
Expand Down
Loading
Loading