@@ -927,19 +927,26 @@ impl<W: Write + Seek> ZipWriter<W> {
927927 new_extra_data. append ( & mut extra_data) ;
928928 extra_data = new_extra_data;
929929 }
930+
931+ // Figure out the underlying compression_method and aes mode when using
932+ // AES encryption.
933+ let ( compression_method, aes_mode) = match options. encrypt_with {
934+ // Preserve AES method for raw copies without needing a password
935+ #[ cfg( feature = "aes-crypto" ) ]
936+ None if options. aes_mode . is_some ( ) => ( CompressionMethod :: Aes , options. aes_mode ) ,
937+ #[ cfg( feature = "aes-crypto" ) ]
938+ Some ( EncryptWith :: Aes { mode, .. } ) => (
939+ CompressionMethod :: Aes ,
940+ Some ( ( mode, AesVendorVersion :: Ae2 , options. compression_method ) ) ,
941+ ) ,
942+ _ => ( options. compression_method , None ) ,
943+ } ;
944+
930945 // Write AES encryption extra data.
931946 #[ allow( unused_mut) ]
932947 let mut aes_extra_data_start = 0 ;
933948 #[ cfg( feature = "aes-crypto" ) ]
934- if let Some ( EncryptWith :: Aes { mode, .. } ) = options. encrypt_with {
935- let aes_dummy_extra_data = [ 0x02 , 0x00 , 0x41 , 0x45 , mode as u8 , 0x00 , 0x00 ] ;
936- aes_extra_data_start = extra_data. len ( ) as u64 ;
937- ExtendedFileOptions :: add_extra_data_unchecked (
938- & mut extra_data,
939- 0x9901 ,
940- & aes_dummy_extra_data,
941- ) ?;
942- } else if let Some ( ( mode, vendor, underlying) ) = options. aes_mode {
949+ if let Some ( ( mode, vendor, underlying) ) = aes_mode {
943950 // For raw copies of AES entries, write the correct AES extra data immediately
944951 let mut body = [ 0 ; 7 ] ;
945952 [ body[ 0 ] , body[ 1 ] ] = ( vendor as u16 ) . to_le_bytes ( ) ; // vendor version (1 or 2)
@@ -949,18 +956,6 @@ impl<W: Write + Seek> ZipWriter<W> {
949956 aes_extra_data_start = extra_data. len ( ) as u64 ;
950957 ExtendedFileOptions :: add_extra_data_unchecked ( & mut extra_data, 0x9901 , & body) ?;
951958 }
952-
953- let ( compression_method, aes_mode) = match options. encrypt_with {
954- // Preserve AES method for raw copies without needing a password
955- #[ cfg( feature = "aes-crypto" ) ]
956- None if options. aes_mode . is_some ( ) => ( CompressionMethod :: Aes , options. aes_mode ) ,
957- #[ cfg( feature = "aes-crypto" ) ]
958- Some ( EncryptWith :: Aes { mode, .. } ) => (
959- CompressionMethod :: Aes ,
960- Some ( ( mode, AesVendorVersion :: Ae2 , options. compression_method ) ) ,
961- ) ,
962- _ => ( options. compression_method , None ) ,
963- } ;
964959 let header_end =
965960 header_start + size_of :: < ZipLocalEntryBlock > ( ) as u64 + name. to_string ( ) . len ( ) as u64 ;
966961
@@ -1090,29 +1085,40 @@ impl<W: Write + Seek> ZipWriter<W> {
10901085 let file_end = writer. stream_position ( ) ?;
10911086 debug_assert ! ( file_end >= self . stats. start) ;
10921087 file. compressed_size = file_end - self . stats . start ;
1093- let mut crc = true ;
1094- if let Some ( aes_mode) = & mut file. aes_mode {
1095- // We prefer using AE-1 which provides an extra CRC check, but for small files we
1096- // switch to AE-2 to prevent being able to use the CRC value to to reconstruct the
1097- // unencrypted contents.
1098- //
1099- // C.f. https://www.winzip.com/en/support/aes-encryption/#crc-faq
1100- aes_mode. 1 = if self . stats . bytes_written < 20 {
1101- crc = false ;
1102- AesVendorVersion :: Ae2
1103- } else {
1104- AesVendorVersion :: Ae1
1105- } ;
1088+
1089+ if !file. using_data_descriptor {
1090+ if let Some ( aes_mode) = & mut file. aes_mode {
1091+ // We prefer using AE-1 which provides an extra CRC check, but for small files we
1092+ // switch to AE-2 to prevent being able to use the CRC value to to reconstruct the
1093+ // unencrypted contents.
1094+ //
1095+ // We can only do this when the underlying writer supports
1096+ // seek operations, so we gate this behind using_data_descriptor.
1097+ //
1098+ // C.f. https://www.winzip.com/en/support/aes-encryption/#crc-faq
1099+ aes_mode. 1 = if self . stats . bytes_written < 20 {
1100+ AesVendorVersion :: Ae2
1101+ } else {
1102+ AesVendorVersion :: Ae1
1103+ } ;
1104+ }
11061105 }
1106+
1107+ let crc = !matches ! ( file. aes_mode, Some ( ( _, AesVendorVersion :: Ae2 , _) ) ) ;
1108+
11071109 file. crc32 = if crc {
11081110 self . stats . hasher . clone ( ) . finalize ( )
11091111 } else {
11101112 0
11111113 } ;
1112- update_aes_extra_data ( writer , file ) ? ;
1114+
11131115 if file. using_data_descriptor {
11141116 write_data_descriptor ( writer, file) ?;
11151117 } else {
1118+ // If using a data descriptor, it's because the underlying
1119+ // Write implementation doesn't support seek. In this case, we
1120+ // shouldn't update the AES Extra Data.
1121+ update_aes_extra_data ( writer, file) ?;
11161122 update_local_file_header ( writer, file) ?;
11171123 writer. seek ( SeekFrom :: Start ( file_end) ) ?;
11181124 }
0 commit comments