29

I'm working on a project that I need to create zip with password protected from file content in c#.

Before I've use System.IO.Compression.GZipStream for creating gzip content. Does .net have any functionality for create zip or rar password protected file?

McMillan Cheng
  • 382
  • 1
  • 6
  • 20
Reza Akraminejad
  • 1,412
  • 3
  • 24
  • 38
  • 1
    In general if the functionality of System.IO.Compression.GZipStream is not enough for you - there is https://sevenzipsharp.codeplex.com framework which is much more complex. Inside the .net framework GZipStream is the only way to create archives. – VitaliyK May 04 '16 at 06:56
  • @VitaliyK I too would recommend 7Zip#, but there are a couple of other compression mechanisms in the framework besides `GZipStream`(e.g. `DeflateStream`, `ZipPackage`, `ZipFile` (since 4.5) etc.) – Manfred Radlwimmer May 04 '16 at 07:02
  • @VitaliyK does gzipstream has password functionality? I did not find any kind of password functionality – Reza Akraminejad May 04 '16 at 07:06
  • @Hamed_gibago No you cannot password protect the arcive using GZipStream. You need to use another zip frameworks(7Zip, DotNetZip etc). – VitaliyK May 04 '16 at 07:12

5 Answers5

14

Take a look at DotNetZip (@AFract supplied a new link to GitHub in the comments)

It has got pretty geat documentation and it also allow you to load the dll at runtime as an embeded file.

Jan Wiesemann
  • 455
  • 2
  • 16
  • I have downloaded this one but can't find a DLL in the download to use in my project. – Paul Jul 10 '18 at 13:36
  • Is this still being maintained? There is a github fork of the original project but I'm often unsure of the status of projects like that since CodePlex closed – StayOnTarget Aug 08 '18 at 14:47
  • 2
    https://www.nuget.org/packages/DotNetZip 'Last Update 3 months ago' I think it ts still maintained. – Jan Wiesemann Aug 09 '18 at 05:36
  • github repository bound to nuget package : https://github.com/haf/DotNetZip.Semverd Do not look at codeplex, it's (obviously) obsolete as Codeplex is dead. – AFract Jan 27 '20 at 09:20
  • Please provide example – Demodave Apr 30 '20 at 16:28
  • @Demodave take a look at the examples on the DotNetZip repo.https://github.com/haf/DotNetZip.Semverd/tree/master/src/Examples/C%23 – Jan Wiesemann May 10 '20 at 16:01
  • It creates a zip where you can see the files inside; to open any of them you will be requested for a password. What is very funny though is, that you can extract the zip and will get all the files inside... without having to type in any password! So... what is really the use case of this "password" functionality? – Paul Efford Mar 14 '23 at 19:39
  • @PaulEfford welcome to ZIP…. Only the actual content is encrypted but the index table isn’t. This is why you’re able to see, what files exist. Never versions are supposed to support it but I’m not sure if it’s used anywhere. A workaround is to Nest two zip files. The outer one will set a password and the inner one can be stored without encryption. But, please don’t… there are other tools and formats… – Jan Wiesemann Mar 16 '23 at 02:50
8

Unfortunately there is no such functionality in the framework. There is a way to make ZIP files, but without password. If you want to create password protected ZIP files in C#, I'd recommend SevenZipSharp. It's basically a managed wrapper for 7-Zip.

SevenZipBase.SetLibraryPath(Path.Combine(
        Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? Environment.CurrentDirectory,
        "7za.dll"));

SevenZipCompressor compressor = new SevenZipCompressor();

compressor.Compressing += Compressor_Compressing;
compressor.FileCompressionStarted += Compressor_FileCompressionStarted;
compressor.CompressionFinished += Compressor_CompressionFinished;

string password = @"whatever";
string destinationFile = @"C:\Temp\whatever.zip";
string[] sourceFiles = Directory.GetFiles(@"C:\Temp\YourFiles\");

if (String.IsNullOrWhiteSpace(password))
{
    compressor.CompressFiles(destinationFile, sourceFiles);
}
else
{
    //optional
    compressor.EncryptHeaders = true;
    compressor.CompressFilesEncrypted(destinationFile, password, sourceFiles);
}
Manfred Radlwimmer
  • 13,257
  • 13
  • 53
  • 62
6

DotNetZip worked great in a clean way.

DotNetZip is a FAST, FREE class library and toolset for manipulating zip files.

Code

static void Main(string[] args)
{
        using (ZipFile zip = new ZipFile())
        {

            zip.Password = "mypassword";

            zip.AddDirectory(@"C:\Test\Report_CCLF5\");
            zip.Save(@"C:\Test\Report_CCLF5_PartB.zip");
        }
 }
LCJ
  • 22,196
  • 67
  • 260
  • 418
  • It creates a zip where you can see the files inside; to open any of them you will be requested for a password. What is very funny though is, that you can extract the zip and will get all the files inside... without having to type in any password! So... what is really the use case of this "password" functionality? – Paul Efford Mar 14 '23 at 19:34
5

I want to add some more alternatives.

For .NET one can use SharpZipLib, for Xamarin use SharpZipLib.Portable.

Example for .NET:

using ICSharpCode.SharpZipLib.Zip;

// Compresses the supplied memory stream, naming it as zipEntryName, into a zip,
// which is returned as a memory stream or a byte array.
//
public MemoryStream CreateToMemoryStream(MemoryStream memStreamIn, string zipEntryName) {

    MemoryStream outputMemStream = new MemoryStream();
    ZipOutputStream zipStream = new ZipOutputStream(outputMemStream);

    zipStream.SetLevel(3); //0-9, 9 being the highest level of compression
    zipStream.Password = "Your password";

    ZipEntry newEntry = new ZipEntry(zipEntryName);
    newEntry.DateTime = DateTime.Now;

    zipStream.PutNextEntry(newEntry);

    StreamUtils.Copy(memStreamIn, zipStream, new byte[4096]);
    zipStream.CloseEntry();

    zipStream.IsStreamOwner = false;    // False stops the Close also Closing the underlying stream.
    zipStream.Close();          // Must finish the ZipOutputStream before using outputMemStream.

    outputMemStream.Position = 0;
    return outputMemStream;

    // Alternative outputs:
    // ToArray is the cleaner and easiest to use correctly with the penalty of duplicating allocated memory.
    byte[] byteArrayOut = outputMemStream.ToArray();

    // GetBuffer returns a raw buffer raw and so you need to account for the true length yourself.
    byte[] byteArrayOut = outputMemStream.GetBuffer();
    long len = outputMemStream.Length;
}

More samples can be found here.

If you can live without password functionality, one can mention ZipStorer or the built in .NET function in System.IO.Compression.

testing
  • 19,681
  • 50
  • 236
  • 417
0

There are two options I found to be reliable and easy enough to be used, depending on the license type you are allowed to use in your project.

The first one is:

using ICSharpCode.SharpZipLib.Core;
using ICSharpCode.SharpZipLib.Zip;

namespace DataReader.zip
{
internal static class Zip1 // SharpZipLib nuget lib, MIT free license
{
    public static bool Create(string destZipPath, string folderToCompress, string? password = null, int compressionLevel = 3)
    {
        bool res;

        try
        {
            var fsOut = File.Create($"{destZipPath}.zip"); // ending '.zip' is a must!
            var zipStream = new ZipOutputStream(fsOut);

            zipStream.SetLevel(compressionLevel); // 0-9, 9 being the highest level of compression

            zipStream.Password = password; // optional. Null is the same as not setting. Required if using AES.

            // This setting will strip the leading part of the folder path in the entries, to
            // make the entries relative to the starting folder.
            // To include the full path for each entry up to the drive root, assign folderOffset = 0.
            var folderOffset = folderToCompress.Length + (folderToCompress.EndsWith("\\") ? 0 : 1);

            res = CompressFolder(folderToCompress, zipStream, folderOffset);

            zipStream.IsStreamOwner = true; // Makes the Close also Close the underlying stream
            zipStream.Close();
            return res;
        }
        catch (Exception e)
        {
            return Console.WriteLine($"{e.Message}: {destZipPath}");
        }
    }

    private static bool CompressFolder(string path, ZipOutputStream zipStream, int folderOffset)
    {
        try
        {
            var files = Directory.GetFiles(path);

            if (files.Length == 0)
            {
                Message.Show($"Warning: no files to compress found in folder '{path}'");
                return false;
            }

            foreach (var filename in files)
            {
                var fi = new FileInfo(filename);
                var entryName = filename.Substring(folderOffset); // Makes the name in zip based on the folder
                entryName = ZipEntry.CleanName(entryName); // Removes drive from name and fixes slash direction
                var newEntry = new ZipEntry(entryName);
                newEntry.DateTime = fi.LastWriteTime; // Note the zip format stores 2 second granularity

                // Specifying the AESKeySize triggers AES encryption. Allowable values are 0 (off), 128 or 256.
                // A password on the ZipOutputStream is required if using AES.
                //  newEntry.AESKeySize = 256;

                // To permit the zip to be unpacked by built-in extractor in WinXP and Server2003, WinZip 8, Java, and other older code,
                // you need to do one of the following: Specify UseZip64.Off, or set the Size.
                // If the file may be bigger than 4GB, or you do not need WinXP built-in compatibility, you do not need either,
                // but the zip will be in Zip64 format which not all utilities can understand.
                   zipStream.UseZip64 = UseZip64.On;
                newEntry.Size = fi.Length;

                zipStream.PutNextEntry(newEntry);

                // Zip the file in buffered chunks
                // the "using" will close the stream even if an exception occurs
                var buffer = new byte[4096];
                using (var streamReader = File.OpenRead(filename))
                {
                    StreamUtils.Copy(streamReader, zipStream, buffer);
                }
                zipStream.CloseEntry();
            }
            return true;
        }
        catch (Exception e)
        {
            return Console.WriteLine($"{e.Message}: {destZipPath}");
        }
    }
}
}

And the second one:

using Ionic.Zip;

namespace DataReader.zip
{
    internal class Zip2 // DotNetZip nuget lib
    {
        public static bool Create(string destZipPath, string folderToCompress, string? password = null, int compressionLevel = 3)
        {
            try
            {
                using ZipFile zip = new();

                if (password != null)
                    zip.Password = password;

                zip.CompressionLevel = (Ionic.Zlib.CompressionLevel)compressionLevel;
                zip.AddDirectory(folderToCompress);
                zip.Save($"{destZipPath}.zip");

                return true;
            }
            catch (Exception e)
            {
                return Console.WriteLine($"{e.Message}: {destZipPath}");
            }
        }
    }
}

With both options you will create a zip folder where a password will be reqzired to extract the files (if you have set it when calling the method).

Paul Efford
  • 261
  • 4
  • 12