@@ -1865,10 +1865,10 @@ public void Add(IStaticDataSource dataSource, ZipEntry entry)
1865
1865
1866
1866
// We don't currently support adding entries with AES encryption, so throw
1867
1867
// 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
+ // }
1872
1872
1873
1873
CheckSupportedCompressionMethod ( entry . CompressionMethod ) ;
1874
1874
CheckUpdating ( ) ;
@@ -2159,6 +2159,12 @@ private void WriteLocalEntryHeader(ZipUpdate update)
2159
2159
ed . Delete ( 1 ) ;
2160
2160
}
2161
2161
2162
+ // Write AES Data if needed
2163
+ if ( entry . AESKeySize > 0 )
2164
+ {
2165
+ AddExtraDataAES ( entry , ed ) ;
2166
+ }
2167
+
2162
2168
entry . ExtraData = ed . GetEntryData ( ) ;
2163
2169
2164
2170
WriteLEShort ( name . Length ) ;
@@ -2282,6 +2288,11 @@ private int WriteCentralDirectoryHeader(ZipEntry entry)
2282
2288
ed . Delete ( 1 ) ;
2283
2289
}
2284
2290
2291
+ if ( entry . AESKeySize > 0 )
2292
+ {
2293
+ AddExtraDataAES ( entry , ed ) ;
2294
+ }
2295
+
2285
2296
byte [ ] centralExtraData = ed . GetEntryData ( ) ;
2286
2297
2287
2298
WriteLEShort ( centralExtraData . Length ) ;
@@ -2336,6 +2347,22 @@ private int WriteCentralDirectoryHeader(ZipEntry entry)
2336
2347
return ZipConstants . CentralHeaderBaseSize + name . Length + centralExtraData . Length + rawComment . Length ;
2337
2348
}
2338
2349
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
+
2339
2366
#endregion Writing Values/Headers
2340
2367
2341
2368
private void PostUpdateCleanup ( )
@@ -2622,13 +2649,20 @@ private Stream GetOutputStream(ZipEntry entry)
2622
2649
switch ( entry . CompressionMethod )
2623
2650
{
2624
2651
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
+ }
2626
2658
break ;
2627
2659
2628
2660
case CompressionMethod . Deflated :
2629
2661
var dos = new DeflaterOutputStream ( result , new Deflater ( 9 , true ) )
2630
2662
{
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
2632
2666
} ;
2633
2667
result = dos ;
2634
2668
break ;
@@ -3668,9 +3702,16 @@ private Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)
3668
3702
3669
3703
private Stream CreateAndInitEncryptionStream ( Stream baseStream , ZipEntry entry )
3670
3704
{
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
3674
3715
{
3675
3716
var classicManaged = new PkzipClassicManaged ( ) ;
3676
3717
@@ -3682,7 +3723,7 @@ private Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)
3682
3723
3683
3724
// Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream
3684
3725
// which doesnt do this.
3685
- result = new CryptoStream ( new UncompressedStream ( baseStream ) ,
3726
+ CryptoStream result = new CryptoStream ( new UncompressedStream ( baseStream ) ,
3686
3727
classicManaged . CreateEncryptor ( key , null ) , CryptoStreamMode . Write ) ;
3687
3728
3688
3729
if ( ( entry . Crc < 0 ) || ( entry . Flags & 8 ) != 0 )
@@ -3693,8 +3734,9 @@ private Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)
3693
3734
{
3694
3735
WriteEncryptionHeader ( result , entry . Crc ) ;
3695
3736
}
3737
+
3738
+ return result ;
3696
3739
}
3697
- return result ;
3698
3740
}
3699
3741
3700
3742
private static void CheckClassicPassword ( CryptoStream classicCryptoStream , ZipEntry entry )
0 commit comments