Runtime: Add password to ZipArchive

Created on 26 Sep 2016  路  11Comments  路  Source: dotnet/runtime

can we make that happen?

api-suggestion area-System.IO.Compression needs more info

Most helpful comment

I'm not quite sure what's being asked of me here. So here are words.

All further comments relate to the WinZIp version:

  • Technically speaking, I think each entry could be encrypted with a different password. In practice, it seems unlikely; so asking for a single _decryption_ password seems reasonable.
  • Key generation uses PBKDF2, which is the algorithm used by System.Security.Cryptography.Rfc2898DeriveBytes.
  • Encryption is done using AES-CTR. We currently don't expose AES-CTR as public API.

    • There are ways to cheat and get it... and people have asked for it... so we might just add it this release with some of the new API.

  • For _creating_ new encrypted ZIP files you probably want to accept an encryption algorithm/mode value. This allows for callers to change from Aes256 to whatever algorithm replaces Aes256 in the future without creating compatibility/tool-interop concerns.

The preference in cryptography API is to never have a default algorithm choice, so creating new encrypted ZIP files would require using a method that took that as an input. That might mean that instead of

```C#
public static ZipArchive Open(String archiveFileName, ZipArchiveMode mode, Encoding entryNameEncoding, string password);

You want

```C#
public enum ZipEncryptionMode
{
    Unknown,
    Aes128,
    Aes192,
    Aes256,
}

public static ZipArchive OpenRead(string archiveFileName, Encoding entryNameEncoding, string password);

public static ZipArchive OpenCreate(string archiveFileName, Encoding entryNameEncoding, string password, ZipEncryptionMode encryptionMode);

public static ZipArchive OpenUpdate(string archiveFileName, Encoding entryNameEncoding, string password, ZipEncryptionMode encryptionMode);

Or, you could combine them:

```C#
public enum ZipEncryptionMode
{
Unknown,
Aes128,
Aes192,
Aes256,
}

// Update/Create modes will throw if newFileEncryptionMode is default
public static ZipArchive Open(string archiveFileName, Encoding entryNameEncoding, string password, ZipEncryptionMode newFileEncryptionMode = default);
```

This is all unfortunate that you're holding the password string in memory. Being able to take it as a ReadOnlySpan would be nicer, but requires moving the encrypt/decrypt to verbs on ZipFileEntry (which may be useful anyways, for degenerate files that use multiple different passwords).

So, short form:

  • Prefer a mode where you don't persist the password to a field.

    • If you feel you need it for high-level usability, well, I guess. So try for "in addition"

  • The encryption mode must be an input for new content. Prefer a parameter input (explicitly specified) over a property (with a default value)... because we're almost never willing to change defaults for choices that apply to persisted files.

All 11 comments

It's certainly possible to add encryption support to ZipArchives. There are a few competing standards for which encryption and accompanying header definitions, but I think the AES one used by 7-zip is one of the more popular ones. There's also basic passwords included in the zip format but iirc those are easily crackable.

The format also has some strong encryption support but it's copyrighted so out of bounds for us.

We need API proposal to move it further.

Speaks something against?

namespace System.IO.Compression
{
    public static class ZipFile 
    {
        public static ZipArchive Open(String archiveFileName, ZipArchiveMode mode, Encoding entryNameEncoding, string password)
    }
}

@ianhays can you please comment if that is sufficient?

@lburkovsky take a look at this issue for a good example of the kind of API proposal that we're looking for. In general, the more implementation details, the better. You can also look at our API Review process doc for more info on the process.

For Zip password support specifically, an API proposal should include analysis on the different methods of password support in Zip, the pros and cons of each, and which you think should be officially supported in .NET.

@neridonk perhaps you would like to make the proposal for us to formally review? as above.

Any news or plans about this feature? Would be very useful!

@mfjerome we are open to API proposal and contribution. Are you interested?

What do we need this feature for? Is it for reading password-protected files or producing or something else?
@bartonjs can you please chime in?

I'm not quite sure what's being asked of me here. So here are words.

All further comments relate to the WinZIp version:

  • Technically speaking, I think each entry could be encrypted with a different password. In practice, it seems unlikely; so asking for a single _decryption_ password seems reasonable.
  • Key generation uses PBKDF2, which is the algorithm used by System.Security.Cryptography.Rfc2898DeriveBytes.
  • Encryption is done using AES-CTR. We currently don't expose AES-CTR as public API.

    • There are ways to cheat and get it... and people have asked for it... so we might just add it this release with some of the new API.

  • For _creating_ new encrypted ZIP files you probably want to accept an encryption algorithm/mode value. This allows for callers to change from Aes256 to whatever algorithm replaces Aes256 in the future without creating compatibility/tool-interop concerns.

The preference in cryptography API is to never have a default algorithm choice, so creating new encrypted ZIP files would require using a method that took that as an input. That might mean that instead of

```C#
public static ZipArchive Open(String archiveFileName, ZipArchiveMode mode, Encoding entryNameEncoding, string password);

You want

```C#
public enum ZipEncryptionMode
{
    Unknown,
    Aes128,
    Aes192,
    Aes256,
}

public static ZipArchive OpenRead(string archiveFileName, Encoding entryNameEncoding, string password);

public static ZipArchive OpenCreate(string archiveFileName, Encoding entryNameEncoding, string password, ZipEncryptionMode encryptionMode);

public static ZipArchive OpenUpdate(string archiveFileName, Encoding entryNameEncoding, string password, ZipEncryptionMode encryptionMode);

Or, you could combine them:

```C#
public enum ZipEncryptionMode
{
Unknown,
Aes128,
Aes192,
Aes256,
}

// Update/Create modes will throw if newFileEncryptionMode is default
public static ZipArchive Open(string archiveFileName, Encoding entryNameEncoding, string password, ZipEncryptionMode newFileEncryptionMode = default);
```

This is all unfortunate that you're holding the password string in memory. Being able to take it as a ReadOnlySpan would be nicer, but requires moving the encrypt/decrypt to verbs on ZipFileEntry (which may be useful anyways, for degenerate files that use multiple different passwords).

So, short form:

  • Prefer a mode where you don't persist the password to a field.

    • If you feel you need it for high-level usability, well, I guess. So try for "in addition"

  • The encryption mode must be an input for new content. Prefer a parameter input (explicitly specified) over a property (with a default value)... because we're almost never willing to change defaults for choices that apply to persisted files.
Was this page helpful?
0 / 5 - 0 ratings

Related issues

EgorBo picture EgorBo  路  3Comments

jamesqo picture jamesqo  路  3Comments

yahorsi picture yahorsi  路  3Comments

bencz picture bencz  路  3Comments

noahfalk picture noahfalk  路  3Comments