Recursive AI

Zip files with AES encryption

All onearchive recipes

Write zip files with OneArchive that every zip tool opens, encrypt one with WinZip AES-256, and handle a missing or wrong password.

C#
using System.IO.Compression;
using RecursiveAI.OneArchive;
 
Directory.CreateDirectory("report");
File.WriteAllText("report/summary.txt", "Q3: 444 orders shipped.\n");
File.WriteAllText("report/data.csv", string.Concat(Enumerable.Range(1, 500).Select(i => $"{i},order-{i},shipped\n")));
 
// A plain zip opens with System.IO.Compression and every other zip tool.
Archive.Create("report.zip").Add("report/").Save();
using (var zip = ZipFile.OpenRead("report.zip"))
    foreach (var e in zip.Entries) Console.WriteLine($"System.IO.Compression reads {e.FullName} ({e.Length:N0} bytes)");
 
// WinZip AES-256: every file entry is encrypted with the password.
Archive.Create("secret.zip", new ArchiveCreateOptions { Password = "correct horse" }).Add("report/").Save();
 
try { Archive.Extract("secret.zip", "nopass"); }
catch (ArchivePasswordException e) { Console.WriteLine($"no password: {e.Problem}, {e.EntryName}"); }
 
try
{
    using var wrong = Archive.Open("secret.zip", new ArchiveOpenOptions { Password = "battery staple" });
    wrong.Extract("wrong");
}
catch (ArchivePasswordException e) { Console.WriteLine($"wrong password: {e.Problem}, {e.EntryName}"); }
 
using (var right = Archive.Open("secret.zip", new ArchiveOpenOptions { Password = "correct horse" }))
    right.Extract("opened");
Console.WriteLine($"right password: {File.ReadAllText("opened/report/summary.txt").Trim()}");
Text
System.IO.Compression reads report/ (0 bytes)
System.IO.Compression reads report/data.csv (10,784 bytes)
System.IO.Compression reads report/summary.txt (24 bytes)
no password: Required, report/data.csv
wrong password: Incorrect, report/data.csv
right password: Q3: 444 orders shipped.

Good to know

  • ArchiveCreateOptions.Password encrypts every file entry, empty files included, with WinZip AES-256; listing needs no password. 7-Zip opens these archives.
  • A missing password is an ArchivePasswordException with Problem Required; a wrong one is Incorrect, found from the entry’s 2-byte password verifier. The 1 in 65,536 wrong passwords that pass the verifier then fail the authentication code, a CompressionFormatException.
  • Traditional zip encryption (ZipCrypto) is read, never written: it is broken.
  • Passwords never appear in exception messages, logs or ToString.
  • Zip entries are stored or compressed with Deflate, Deflate64, bzip2, PPMd or Zstandard; zip64 and data descriptors are handled. 7z archives can be encrypted too, with AES-256 and encrypted headers.
  • AES needs System.Security.Cryptography.Aes, which the browser doesn’t provide, so encryption is not available in WebAssembly.

The encryption formats are in zip encryption.