@@ -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 ( )
@@ -2618,13 +2645,20 @@ private Stream GetOutputStream(ZipEntry entry)
26182645 switch ( entry . CompressionMethod )
26192646 {
26202647 case CompressionMethod . Stored :
2621- result = new UncompressedStream ( result ) ;
2648+ if ( ! entry . IsCrypted )
2649+ {
2650+ // If there is an encryption stream in use, that can be written to directly
2651+ // otherwise, wrap it in an UncompressedStream instead of returning the base stream directly
2652+ result = new UncompressedStream ( result ) ;
2653+ }
26222654 break ;
26232655
26242656 case CompressionMethod . Deflated :
26252657 var dos = new DeflaterOutputStream ( result , new Deflater ( 9 , true ) )
26262658 {
2627- IsStreamOwner = false
2659+ // If there is an encryption stream in use, then we want that to be disposed when the deflator stream is disposed
2660+ // If not, then we don't want it to dispose the base stream
2661+ IsStreamOwner = entry . IsCrypted
26282662 } ;
26292663 result = dos ;
26302664 break ;
@@ -3664,9 +3698,16 @@ private Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)
36643698
36653699 private Stream CreateAndInitEncryptionStream ( Stream baseStream , ZipEntry entry )
36663700 {
3667- CryptoStream result = null ;
3668- if ( ( entry . Version < ZipConstants . VersionStrongEncryption )
3669- || ( entry . Flags & ( int ) GeneralBitFlags . StrongEncryption ) == 0 )
3701+ if ( entry . CompressionMethodForHeader == CompressionMethod . WinZipAES )
3702+ {
3703+ int blockSize = entry . AESKeySize / 8 ; // bits to bytes
3704+
3705+ var aesStream =
3706+ new ZipAESEncryptionStream ( baseStream , rawPassword_ , entry . AESSaltLen , blockSize ) ;
3707+
3708+ return aesStream ;
3709+ }
3710+ else
36703711 {
36713712 var classicManaged = new PkzipClassicManaged ( ) ;
36723713
@@ -3678,7 +3719,7 @@ private Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)
36783719
36793720 // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream
36803721 // which doesnt do this.
3681- result = new CryptoStream ( new UncompressedStream ( baseStream ) ,
3722+ CryptoStream result = new CryptoStream ( new UncompressedStream ( baseStream ) ,
36823723 classicManaged . CreateEncryptor ( key , null ) , CryptoStreamMode . Write ) ;
36833724
36843725 if ( ( entry . Crc < 0 ) || ( entry . Flags & 8 ) != 0 )
@@ -3689,8 +3730,9 @@ private Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)
36893730 {
36903731 WriteEncryptionHeader ( result , entry . Crc ) ;
36913732 }
3733+
3734+ return result ;
36923735 }
3693- return result ;
36943736 }
36953737
36963738 private static void CheckClassicPassword ( CryptoStream classicCryptoStream , ZipEntry entry )
0 commit comments