@@ -1864,10 +1864,10 @@ public void Add(IStaticDataSource dataSource, ZipEntry entry)
18641864
18651865 // We don't currently support adding entries with AES encryption, so throw
18661866 // up front instead of failing or falling back to ZipCrypto later on
1867- if ( entry . AESKeySize > 0 )
1868- {
1869- throw new NotSupportedException ( "Creation of AES encrypted entries is not supported" ) ;
1870- }
1867+ // if (entry.AESKeySize > 0)
1868+ // {
1869+ // throw new NotSupportedException("Creation of AES encrypted entries is not supported");
1870+ // }
18711871
18721872 CheckSupportedCompressionMethod ( entry . CompressionMethod ) ;
18731873 CheckUpdating ( ) ;
@@ -2158,6 +2158,12 @@ private void WriteLocalEntryHeader(ZipUpdate update)
21582158 ed . Delete ( 1 ) ;
21592159 }
21602160
2161+ // Write AES Data if needed
2162+ if ( entry . AESKeySize > 0 )
2163+ {
2164+ AddExtraDataAES ( entry , ed ) ;
2165+ }
2166+
21612167 entry . ExtraData = ed . GetEntryData ( ) ;
21622168
21632169 WriteLEShort ( name . Length ) ;
@@ -2281,6 +2287,11 @@ private int WriteCentralDirectoryHeader(ZipEntry entry)
22812287 ed . Delete ( 1 ) ;
22822288 }
22832289
2290+ if ( entry . AESKeySize > 0 )
2291+ {
2292+ AddExtraDataAES ( entry , ed ) ;
2293+ }
2294+
22842295 byte [ ] centralExtraData = ed . GetEntryData ( ) ;
22852296
22862297 WriteLEShort ( centralExtraData . Length ) ;
@@ -2335,6 +2346,22 @@ private int WriteCentralDirectoryHeader(ZipEntry entry)
23352346 return ZipConstants . CentralHeaderBaseSize + name . Length + centralExtraData . Length + rawComment . Length ;
23362347 }
23372348
2349+ private static void AddExtraDataAES ( ZipEntry entry , ZipExtraData extraData )
2350+ {
2351+ // Vendor Version: AE-1 IS 1. AE-2 is 2. With AE-2 no CRC is required and 0 is stored.
2352+ const int VENDOR_VERSION = 2 ;
2353+ // Vendor ID is the two ASCII characters "AE".
2354+ const int VENDOR_ID = 0x4541 ; //not 6965;
2355+ extraData . StartNewEntry ( ) ;
2356+ // Pack AES extra data field see http://www.winzip.com/aes_info.htm
2357+ //extraData.AddLeShort(7); // Data size (currently 7)
2358+ extraData . AddLeShort ( VENDOR_VERSION ) ; // 2 = AE-2
2359+ extraData . AddLeShort ( VENDOR_ID ) ; // "AE"
2360+ extraData . AddData ( entry . AESEncryptionStrength ) ; // 1 = 128, 2 = 192, 3 = 256
2361+ extraData . AddLeShort ( ( int ) entry . CompressionMethod ) ; // The actual compression method used to compress the file
2362+ extraData . AddNewEntry ( 0x9901 ) ;
2363+ }
2364+
23382365 #endregion Writing Values/Headers
23392366
23402367 private void PostUpdateCleanup ( )
@@ -2621,13 +2648,20 @@ private Stream GetOutputStream(ZipEntry entry)
26212648 switch ( entry . CompressionMethod )
26222649 {
26232650 case CompressionMethod . Stored :
2624- result = new UncompressedStream ( result ) ;
2651+ if ( ! entry . IsCrypted )
2652+ {
2653+ // If there is an encryption stream in use, that can be written to directly
2654+ // otherwise, wrap it in an UncompressedStream instead of returning the base stream directly
2655+ result = new UncompressedStream ( result ) ;
2656+ }
26252657 break ;
26262658
26272659 case CompressionMethod . Deflated :
26282660 var dos = new DeflaterOutputStream ( result , new Deflater ( 9 , true ) )
26292661 {
2630- IsStreamOwner = false
2662+ // If there is an encryption stream in use, then we want that to be disposed when the deflator stream is disposed
2663+ // If not, then we don't want it to dispose the base stream
2664+ IsStreamOwner = entry . IsCrypted
26312665 } ;
26322666 result = dos ;
26332667 break ;
@@ -3667,9 +3701,16 @@ private Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)
36673701
36683702 private Stream CreateAndInitEncryptionStream ( Stream baseStream , ZipEntry entry )
36693703 {
3670- CryptoStream result = null ;
3671- if ( ( entry . Version < ZipConstants . VersionStrongEncryption )
3672- || ( entry . Flags & ( int ) GeneralBitFlags . StrongEncryption ) == 0 )
3704+ if ( entry . CompressionMethodForHeader == CompressionMethod . WinZipAES )
3705+ {
3706+ int blockSize = entry . AESKeySize / 8 ; // bits to bytes
3707+
3708+ var aesStream =
3709+ new ZipAESEncryptionStream ( baseStream , rawPassword_ , entry . AESSaltLen , blockSize ) ;
3710+
3711+ return aesStream ;
3712+ }
3713+ else
36733714 {
36743715 var classicManaged = new PkzipClassicManaged ( ) ;
36753716
@@ -3681,7 +3722,7 @@ private Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)
36813722
36823723 // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream
36833724 // which doesnt do this.
3684- result = new CryptoStream ( new UncompressedStream ( baseStream ) ,
3725+ CryptoStream result = new CryptoStream ( new UncompressedStream ( baseStream ) ,
36853726 classicManaged . CreateEncryptor ( key , null ) , CryptoStreamMode . Write ) ;
36863727
36873728 if ( ( entry . Crc < 0 ) || ( entry . Flags & 8 ) != 0 )
@@ -3692,8 +3733,9 @@ private Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)
36923733 {
36933734 WriteEncryptionHeader ( result , entry . Crc ) ;
36943735 }
3736+
3737+ return result ;
36953738 }
3696- return result ;
36973739 }
36983740
36993741 private static void CheckClassicPassword ( CryptoStream classicCryptoStream , ZipEntry entry )
0 commit comments