@@ -204,6 +204,167 @@ public void ZipFileStoreAesPartialRead()
204
204
}
205
205
}
206
206
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
+
207
368
private static readonly string [ ] possible7zPaths = new [ ] {
208
369
// Check in PATH
209
370
"7z" , "7za" ,
@@ -259,65 +420,96 @@ public void WriteEncryptedZipToStream(Stream stream, string password, int keySiz
259
420
zs . SetLevel ( 9 ) ; // 0-9, 9 being the highest level of compression
260
421
zs . Password = password ; // optional. Null is the same as not setting. Required if using AES.
261
422
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
+ }
268
426
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.
270
434
271
- using ( var dummyStream = new MemoryStream ( dummyData ) )
435
+ for ( int i = 0 ; i < entryCount ; i ++ )
272
436
{
273
- dummyStream . CopyTo ( zs ) ;
437
+ AddEncrypedEntryToStream ( zs , $ "test- { i } " , keySize , compressionMethod ) ;
274
438
}
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 ) ;
275
452
276
- zs . CloseEntry ( ) ;
453
+ byte [ ] dummyData = Encoding . UTF8 . GetBytes ( DummyDataString ) ;
454
+
455
+ using ( var dummyStream = new MemoryStream ( dummyData ) )
456
+ {
457
+ dummyStream . CopyTo ( zipOutputStream ) ;
277
458
}
459
+
460
+ zipOutputStream . CloseEntry ( ) ;
278
461
}
279
462
280
463
public void CreateZipWithEncryptedEntries ( string password , int keySize , CompressionMethod compressionMethod = CompressionMethod . Deflated )
281
464
{
282
465
using ( var ms = new MemoryStream ( ) )
283
466
{
284
467
WriteEncryptedZipToStream ( ms , password , keySize , compressionMethod ) ;
468
+ VerifyZipWith7Zip ( ms , password ) ;
469
+ }
470
+ }
285
471
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 } \" ") ;
291
482
292
- var fileName = Path . GetTempFileName ( ) ;
483
+ var fileName = Path . GetTempFileName ( ) ;
293
484
294
- try
485
+ try
486
+ {
487
+ using ( var fs = File . OpenWrite ( fileName ) )
295
488
{
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 ) ;
308
491
}
309
- finally
492
+
493
+ var p = Process . Start ( path7z , $ "t -p{ password } \" { fileName } \" ") ;
494
+ if ( ! p . WaitForExit ( 2000 ) )
310
495
{
311
- File . Delete ( fileName ) ;
496
+ Assert . Warn ( "Timed out verifying zip file!" ) ;
312
497
}
498
+
499
+ Assert . AreEqual ( 0 , p . ExitCode , "Archive verification failed" ) ;
313
500
}
314
- else
501
+ finally
315
502
{
316
- Assert . Warn ( "Skipping file verification since 7za is not in path" ) ;
503
+ File . Delete ( fileName ) ;
317
504
}
318
505
}
506
+ else
507
+ {
508
+ Assert . Warn ( "Skipping file verification since 7za is not in path" ) ;
509
+ }
319
510
}
320
511
512
+
321
513
private const string DummyDataString = @"Lorem ipsum dolor sit amet, consectetur adipiscing elit.
322
514
Fusce bibendum diam ac nunc rutrum ornare. Maecenas blandit elit ligula, eget suscipit lectus rutrum eu.
323
515
Maecenas aliquam, purus mattis pulvinar pharetra, nunc orci maximus justo, sed facilisis massa dui sed lorem.
0 commit comments