@@ -1865,10 +1865,10 @@ public void Add(IStaticDataSource dataSource, ZipEntry entry)
18651865
18661866 // We don't currently support adding entries with AES encryption, so throw
18671867 // up front instead of failing or falling back to ZipCrypto later on
1868- if ( entry . AESKeySize > 0 )
1869- {
1870- throw new NotSupportedException ( "Creation of AES encrypted entries is not supported" ) ;
1871- }
1868+ // if (entry.AESKeySize > 0)
1869+ // {
1870+ // throw new NotSupportedException("Creation of AES encrypted entries is not supported");
1871+ // }
18721872
18731873 CheckSupportedCompressionMethod ( entry . CompressionMethod ) ;
18741874 CheckUpdating ( ) ;
@@ -2159,6 +2159,12 @@ private void WriteLocalEntryHeader(ZipUpdate update)
21592159 ed . Delete ( 1 ) ;
21602160 }
21612161
2162+ // Write AES Data if needed
2163+ if ( entry . AESKeySize > 0 )
2164+ {
2165+ AddExtraDataAES ( entry , ed ) ;
2166+ }
2167+
21622168 entry . ExtraData = ed . GetEntryData ( ) ;
21632169
21642170 WriteLEShort ( name . Length ) ;
@@ -2282,6 +2288,11 @@ private int WriteCentralDirectoryHeader(ZipEntry entry)
22822288 ed . Delete ( 1 ) ;
22832289 }
22842290
2291+ if ( entry . AESKeySize > 0 )
2292+ {
2293+ AddExtraDataAES ( entry , ed ) ;
2294+ }
2295+
22852296 byte [ ] centralExtraData = ed . GetEntryData ( ) ;
22862297
22872298 WriteLEShort ( centralExtraData . Length ) ;
@@ -2336,6 +2347,22 @@ private int WriteCentralDirectoryHeader(ZipEntry entry)
23362347 return ZipConstants . CentralHeaderBaseSize + name . Length + centralExtraData . Length + rawComment . Length ;
23372348 }
23382349
2350+ private static void AddExtraDataAES ( ZipEntry entry , ZipExtraData extraData )
2351+ {
2352+ // Vendor Version: AE-1 IS 1. AE-2 is 2. With AE-2 no CRC is required and 0 is stored.
2353+ const int VENDOR_VERSION = 2 ;
2354+ // Vendor ID is the two ASCII characters "AE".
2355+ const int VENDOR_ID = 0x4541 ; //not 6965;
2356+ extraData . StartNewEntry ( ) ;
2357+ // Pack AES extra data field see http://www.winzip.com/aes_info.htm
2358+ //extraData.AddLeShort(7); // Data size (currently 7)
2359+ extraData . AddLeShort ( VENDOR_VERSION ) ; // 2 = AE-2
2360+ extraData . AddLeShort ( VENDOR_ID ) ; // "AE"
2361+ extraData . AddData ( entry . AESEncryptionStrength ) ; // 1 = 128, 2 = 192, 3 = 256
2362+ extraData . AddLeShort ( ( int ) entry . CompressionMethod ) ; // The actual compression method used to compress the file
2363+ extraData . AddNewEntry ( 0x9901 ) ;
2364+ }
2365+
23392366 #endregion Writing Values/Headers
23402367
23412368 private void PostUpdateCleanup ( )
@@ -2622,13 +2649,20 @@ private Stream GetOutputStream(ZipEntry entry)
26222649 switch ( entry . CompressionMethod )
26232650 {
26242651 case CompressionMethod . Stored :
2625- result = new UncompressedStream ( result ) ;
2652+ if ( ! entry . IsCrypted )
2653+ {
2654+ // If there is an encryption stream in use, that can be written to directly
2655+ // otherwise, wrap it in an UncompressedStream instead of returning the base stream directly
2656+ result = new UncompressedStream ( result ) ;
2657+ }
26262658 break ;
26272659
26282660 case CompressionMethod . Deflated :
26292661 var dos = new DeflaterOutputStream ( result , new Deflater ( 9 , true ) )
26302662 {
2631- IsStreamOwner = false
2663+ // If there is an encryption stream in use, then we want that to be disposed when the deflator stream is disposed
2664+ // If not, then we don't want it to dispose the base stream
2665+ IsStreamOwner = entry . IsCrypted
26322666 } ;
26332667 result = dos ;
26342668 break ;
@@ -3668,9 +3702,16 @@ private Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)
36683702
36693703 private Stream CreateAndInitEncryptionStream ( Stream baseStream , ZipEntry entry )
36703704 {
3671- CryptoStream result = null ;
3672- if ( ( entry . Version < ZipConstants . VersionStrongEncryption )
3673- || ( entry . Flags & ( int ) GeneralBitFlags . StrongEncryption ) == 0 )
3705+ if ( entry . CompressionMethodForHeader == CompressionMethod . WinZipAES )
3706+ {
3707+ int blockSize = entry . AESKeySize / 8 ; // bits to bytes
3708+
3709+ var aesStream =
3710+ new ZipAESEncryptionStream ( baseStream , rawPassword_ , entry . AESSaltLen , blockSize ) ;
3711+
3712+ return aesStream ;
3713+ }
3714+ else
36743715 {
36753716 var classicManaged = new PkzipClassicManaged ( ) ;
36763717
@@ -3682,7 +3723,7 @@ private Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)
36823723
36833724 // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream
36843725 // which doesnt do this.
3685- result = new CryptoStream ( new UncompressedStream ( baseStream ) ,
3726+ CryptoStream result = new CryptoStream ( new UncompressedStream ( baseStream ) ,
36863727 classicManaged . CreateEncryptor ( key , null ) , CryptoStreamMode . Write ) ;
36873728
36883729 if ( ( entry . Crc < 0 ) || ( entry . Flags & 8 ) != 0 )
@@ -3693,8 +3734,9 @@ private Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)
36933734 {
36943735 WriteEncryptionHeader ( result , entry . Crc ) ;
36953736 }
3737+
3738+ return result ;
36963739 }
3697- return result ;
36983740 }
36993741
37003742 private static void CheckClassicPassword ( CryptoStream classicCryptoStream , ZipEntry entry )
0 commit comments