@@ -204,6 +204,167 @@ public void ZipFileStoreAesPartialRead()
204204 }
205205 }
206206
207+ /// <summary>
208+ /// Test adding files to an encrypted zip
209+ /// </summary>
210+ [ Test ]
211+ [ Category ( "Encryption" ) ]
212+ [ Category ( "Zip" ) ]
213+ public void ZipFileAesAdd ( )
214+ {
215+ string password = "password" ;
216+ string testData = "AdditionalData" ;
217+ int keySize = 256 ;
218+
219+ using ( var memoryStream = new MemoryStream ( ) )
220+ {
221+ // Try to create a zip stream
222+ WriteEncryptedZipToStream ( memoryStream , password , keySize , CompressionMethod . Deflated ) ;
223+
224+ // reset
225+ memoryStream . Seek ( 0 , SeekOrigin . Begin ) ;
226+
227+ // Update the archive with ZipFile
228+ {
229+ using ( var zipFile = new ZipFile ( memoryStream , leaveOpen : true ) { Password = password } )
230+ {
231+ zipFile . BeginUpdate ( ) ;
232+ zipFile . Add ( new StringMemoryDataSource ( testData ) , "AdditionalEntry" , CompressionMethod . Deflated ) ;
233+ zipFile . CommitUpdate ( ) ;
234+ }
235+ }
236+
237+ // Test the updated archive
238+ {
239+ memoryStream . Seek ( 0 , SeekOrigin . Begin ) ;
240+
241+ using ( var zipFile = new ZipFile ( memoryStream , leaveOpen : true ) { Password = password } )
242+ {
243+ Assert . That ( zipFile . Count , Is . EqualTo ( 2 ) , "Incorrect entry count in updated archive" ) ;
244+
245+ // Disabled because of bug #317
246+ // Assert.That(zipFile.TestArchive(true), Is.True);
247+
248+ // Check the original entry
249+ {
250+ var originalEntry = zipFile . GetEntry ( "test" ) ;
251+ Assert . That ( originalEntry . IsCrypted , Is . True ) ;
252+ Assert . That ( originalEntry . AESKeySize , Is . EqualTo ( keySize ) ) ;
253+
254+
255+ using ( var zis = zipFile . GetInputStream ( originalEntry ) )
256+ using ( var sr = new StreamReader ( zis , Encoding . UTF8 ) )
257+ {
258+ var content = sr . ReadToEnd ( ) ;
259+ Assert . That ( content , Is . EqualTo ( DummyDataString ) , "Decompressed content does not match input data" ) ;
260+ }
261+ }
262+
263+ // Check the additional entry
264+ // This should be encrypted, though currently only with ZipCrypto
265+ {
266+ var additionalEntry = zipFile . GetEntry ( "AdditionalEntry" ) ;
267+ Assert . That ( additionalEntry . IsCrypted , Is . True ) ;
268+
269+ using ( var zis = zipFile . GetInputStream ( additionalEntry ) )
270+ using ( var sr = new StreamReader ( zis , Encoding . UTF8 ) )
271+ {
272+ var content = sr . ReadToEnd ( ) ;
273+ Assert . That ( content , Is . EqualTo ( testData ) , "Decompressed content does not match input data" ) ;
274+ }
275+ }
276+ }
277+ }
278+
279+ // As an extra test, verify the file with 7-zip
280+ VerifyZipWith7Zip ( memoryStream , password ) ;
281+ }
282+ }
283+
284+ /// <summary>
285+ /// Test deleting files from an encrypted zip
286+ /// </summary>
287+ [ Test ]
288+ [ Category ( "Encryption" ) ]
289+ [ Category ( "Zip" ) ]
290+ public void ZipFileAesDelete ( )
291+ {
292+ string password = "password" ;
293+ int keySize = 256 ;
294+
295+ using ( var memoryStream = new MemoryStream ( ) )
296+ {
297+ // Try to create a zip stream
298+ WriteEncryptedZipToStream ( memoryStream , 3 , password , keySize , CompressionMethod . Deflated ) ;
299+
300+ // reset
301+ memoryStream . Seek ( 0 , SeekOrigin . Begin ) ;
302+
303+ // delete one of the entries from the file
304+ {
305+ using ( var zipFile = new ZipFile ( memoryStream , leaveOpen : true ) { Password = password } )
306+ {
307+ // Must have 3 entries to start with
308+ Assert . That ( zipFile . Count , Is . EqualTo ( 3 ) , "Must have 3 entries to start with" ) ;
309+
310+ var entryToDelete = zipFile . GetEntry ( "test-1" ) ;
311+ Assert . That ( entryToDelete , Is . Not . Null , "the entry that we want to delete must exist" ) ;
312+
313+ zipFile . BeginUpdate ( ) ;
314+ zipFile . Delete ( entryToDelete ) ;
315+ zipFile . CommitUpdate ( ) ;
316+ }
317+ }
318+
319+ // Test the updated archive
320+ {
321+ memoryStream . Seek ( 0 , SeekOrigin . Begin ) ;
322+
323+ using ( var zipFile = new ZipFile ( memoryStream , leaveOpen : true ) { Password = password } )
324+ {
325+ // We should now only have 2 files
326+ Assert . That ( zipFile . Count , Is . EqualTo ( 2 ) , "Incorrect entry count in updated archive" ) ;
327+
328+ // Disabled because of bug #317
329+ // Assert.That(zipFile.TestArchive(true), Is.True);
330+
331+ // Check the first entry
332+ {
333+ var originalEntry = zipFile . GetEntry ( "test-0" ) ;
334+ Assert . That ( originalEntry . IsCrypted , Is . True ) ;
335+ Assert . That ( originalEntry . AESKeySize , Is . EqualTo ( keySize ) ) ;
336+
337+
338+ using ( var zis = zipFile . GetInputStream ( originalEntry ) )
339+ using ( var sr = new StreamReader ( zis , Encoding . UTF8 ) )
340+ {
341+ var content = sr . ReadToEnd ( ) ;
342+ Assert . That ( content , Is . EqualTo ( DummyDataString ) , "Decompressed content does not match input data" ) ;
343+ }
344+ }
345+
346+ // Check the second entry
347+ {
348+ var originalEntry = zipFile . GetEntry ( "test-2" ) ;
349+ Assert . That ( originalEntry . IsCrypted , Is . True ) ;
350+ Assert . That ( originalEntry . AESKeySize , Is . EqualTo ( keySize ) ) ;
351+
352+
353+ using ( var zis = zipFile . GetInputStream ( originalEntry ) )
354+ using ( var sr = new StreamReader ( zis , Encoding . UTF8 ) )
355+ {
356+ var content = sr . ReadToEnd ( ) ;
357+ Assert . That ( content , Is . EqualTo ( DummyDataString ) , "Decompressed content does not match input data" ) ;
358+ }
359+ }
360+ }
361+ }
362+
363+ // As an extra test, verify the file with 7-zip
364+ VerifyZipWith7Zip ( memoryStream , password ) ;
365+ }
366+ }
367+
207368 private static readonly string [ ] possible7zPaths = new [ ] {
208369 // Check in PATH
209370 "7z" , "7za" ,
@@ -259,65 +420,96 @@ public void WriteEncryptedZipToStream(Stream stream, string password, int keySiz
259420 zs . SetLevel ( 9 ) ; // 0-9, 9 being the highest level of compression
260421 zs . Password = password ; // optional. Null is the same as not setting. Required if using AES.
261422
262- ZipEntry zipEntry = new ZipEntry ( "test" ) ;
263- zipEntry . AESKeySize = keySize ;
264- zipEntry . DateTime = DateTime . Now ;
265- zipEntry . CompressionMethod = compressionMethod ;
266-
267- zs . PutNextEntry ( zipEntry ) ;
423+ AddEncrypedEntryToStream ( zs , $ "test", keySize , compressionMethod ) ;
424+ }
425+ }
268426
269- byte [ ] dummyData = Encoding . UTF8 . GetBytes ( DummyDataString ) ;
427+ public void WriteEncryptedZipToStream ( Stream stream , int entryCount , string password , int keySize , CompressionMethod compressionMethod )
428+ {
429+ using ( var zs = new ZipOutputStream ( stream ) )
430+ {
431+ zs . IsStreamOwner = false ;
432+ zs . SetLevel ( 9 ) ; // 0-9, 9 being the highest level of compression
433+ zs . Password = password ; // optional. Null is the same as not setting. Required if using AES.
270434
271- using ( var dummyStream = new MemoryStream ( dummyData ) )
435+ for ( int i = 0 ; i < entryCount ; i ++ )
272436 {
273- dummyStream . CopyTo ( zs ) ;
437+ AddEncrypedEntryToStream ( zs , $ "test- { i } " , keySize , compressionMethod ) ;
274438 }
439+ }
440+ }
441+
442+ private void AddEncrypedEntryToStream ( ZipOutputStream zipOutputStream , string entryName , int keySize , CompressionMethod compressionMethod )
443+ {
444+ ZipEntry zipEntry = new ZipEntry ( entryName )
445+ {
446+ AESKeySize = keySize ,
447+ DateTime = DateTime . Now ,
448+ CompressionMethod = compressionMethod
449+ } ;
450+
451+ zipOutputStream . PutNextEntry ( zipEntry ) ;
275452
276- zs . CloseEntry ( ) ;
453+ byte [ ] dummyData = Encoding . UTF8 . GetBytes ( DummyDataString ) ;
454+
455+ using ( var dummyStream = new MemoryStream ( dummyData ) )
456+ {
457+ dummyStream . CopyTo ( zipOutputStream ) ;
277458 }
459+
460+ zipOutputStream . CloseEntry ( ) ;
278461 }
279462
280463 public void CreateZipWithEncryptedEntries ( string password , int keySize , CompressionMethod compressionMethod = CompressionMethod . Deflated )
281464 {
282465 using ( var ms = new MemoryStream ( ) )
283466 {
284467 WriteEncryptedZipToStream ( ms , password , keySize , compressionMethod ) ;
468+ VerifyZipWith7Zip ( ms , password ) ;
469+ }
470+ }
285471
286- if ( TryGet7zBinPath ( out string path7z ) )
287- {
288- Console . WriteLine ( $ "Using 7z path: \" { path7z } \" ") ;
289-
290- ms . Seek ( 0 , SeekOrigin . Begin ) ;
472+ /// <summary>
473+ /// Helper function to verify the provided zip stream with 7Zip.
474+ /// </summary>
475+ /// <param name="zipStream">A stream containing the zip archive to test.</param>
476+ /// <param name="password">The password for the archive.</param>
477+ private void VerifyZipWith7Zip ( Stream zipStream , string password )
478+ {
479+ if ( TryGet7zBinPath ( out string path7z ) )
480+ {
481+ Console . WriteLine ( $ "Using 7z path: \" { path7z } \" ") ;
291482
292- var fileName = Path . GetTempFileName ( ) ;
483+ var fileName = Path . GetTempFileName ( ) ;
293484
294- try
485+ try
486+ {
487+ using ( var fs = File . OpenWrite ( fileName ) )
295488 {
296- using ( var fs = File . OpenWrite ( fileName ) )
297- {
298- ms . CopyTo ( fs ) ;
299- }
300-
301- var p = Process . Start ( path7z , $ "t -p{ password } \" { fileName } \" ") ;
302- if ( ! p . WaitForExit ( 2000 ) )
303- {
304- Assert . Warn ( "Timed out verifying zip file!" ) ;
305- }
306-
307- Assert . AreEqual ( 0 , p . ExitCode , "Archive verification failed" ) ;
489+ zipStream . Seek ( 0 , SeekOrigin . Begin ) ;
490+ zipStream . CopyTo ( fs ) ;
308491 }
309- finally
492+
493+ var p = Process . Start ( path7z , $ "t -p{ password } \" { fileName } \" ") ;
494+ if ( ! p . WaitForExit ( 2000 ) )
310495 {
311- File . Delete ( fileName ) ;
496+ Assert . Warn ( "Timed out verifying zip file!" ) ;
312497 }
498+
499+ Assert . AreEqual ( 0 , p . ExitCode , "Archive verification failed" ) ;
313500 }
314- else
501+ finally
315502 {
316- Assert . Warn ( "Skipping file verification since 7za is not in path" ) ;
503+ File . Delete ( fileName ) ;
317504 }
318505 }
506+ else
507+ {
508+ Assert . Warn ( "Skipping file verification since 7za is not in path" ) ;
509+ }
319510 }
320511
512+
321513 private const string DummyDataString = @"Lorem ipsum dolor sit amet, consectetur adipiscing elit.
322514Fusce bibendum diam ac nunc rutrum ornare. Maecenas blandit elit ligula, eget suscipit lectus rutrum eu.
323515Maecenas aliquam, purus mattis pulvinar pharetra, nunc orci maximus justo, sed facilisis massa dui sed lorem.
0 commit comments