diff --git a/src/libraries/System.IO.Compression/ref/System.IO.Compression.cs b/src/libraries/System.IO.Compression/ref/System.IO.Compression.cs index 3090d4aaba384c..b2037fd74e3408 100644 --- a/src/libraries/System.IO.Compression/ref/System.IO.Compression.cs +++ b/src/libraries/System.IO.Compression/ref/System.IO.Compression.cs @@ -49,9 +49,9 @@ public override void Flush() { } public override void SetLength(long value) { } public override void Write(byte[] buffer, int offset, int count) { } public override void Write(System.ReadOnlySpan buffer) { } - public override void WriteByte(byte value) { } public override System.Threading.Tasks.Task WriteAsync(byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) { throw null; } public override System.Threading.Tasks.ValueTask WriteAsync(System.ReadOnlyMemory buffer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public override void WriteByte(byte value) { } } public partial class GZipStream : System.IO.Stream { @@ -84,9 +84,9 @@ public override void Flush() { } public override void SetLength(long value) { } public override void Write(byte[] buffer, int offset, int count) { } public override void Write(System.ReadOnlySpan buffer) { } - public override void WriteByte(byte value) { } public override System.Threading.Tasks.Task WriteAsync(byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) { throw null; } public override System.Threading.Tasks.ValueTask WriteAsync(System.ReadOnlyMemory buffer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public override void WriteByte(byte value) { } } public partial class ZipArchive : System.IDisposable { @@ -94,7 +94,7 @@ public ZipArchive(System.IO.Stream stream) { } public ZipArchive(System.IO.Stream stream, System.IO.Compression.ZipArchiveMode mode) { } public ZipArchive(System.IO.Stream stream, System.IO.Compression.ZipArchiveMode mode, bool leaveOpen) { } public ZipArchive(System.IO.Stream stream, System.IO.Compression.ZipArchiveMode mode, bool leaveOpen, System.Text.Encoding? entryNameEncoding) { } - [System.Diagnostics.CodeAnalysis.AllowNull] + [System.Diagnostics.CodeAnalysis.AllowNullAttribute] public string Comment { get { throw null; } set { } } public System.Collections.ObjectModel.ReadOnlyCollection Entries { get { throw null; } } public System.IO.Compression.ZipArchiveMode Mode { get { throw null; } } @@ -108,13 +108,14 @@ public partial class ZipArchiveEntry { internal ZipArchiveEntry() { } public System.IO.Compression.ZipArchive Archive { get { throw null; } } - [System.Diagnostics.CodeAnalysis.AllowNull] + [System.Diagnostics.CodeAnalysis.AllowNullAttribute] public string Comment { get { throw null; } set { } } public long CompressedLength { get { throw null; } } [System.CLSCompliantAttribute(false)] public uint Crc32 { get { throw null; } } public int ExternalAttributes { get { throw null; } set { } } public string FullName { get { throw null; } } + public bool IsEncrypted { get { throw null; } } public System.DateTimeOffset LastWriteTime { get { throw null; } set { } } public long Length { get { throw null; } } public string Name { get { throw null; } } @@ -159,8 +160,8 @@ public override void Flush() { } public override void SetLength(long value) { } public override void Write(byte[] buffer, int offset, int count) { } public override void Write(System.ReadOnlySpan buffer) { } - public override void WriteByte(byte value) { } public override System.Threading.Tasks.Task WriteAsync(byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) { throw null; } public override System.Threading.Tasks.ValueTask WriteAsync(System.ReadOnlyMemory buffer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public override void WriteByte(byte value) { } } } diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs index f11986d2029757..d8b97fc66074ab 100644 --- a/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs +++ b/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs @@ -21,6 +21,7 @@ public partial class ZipArchiveEntry private ZipVersionNeededValues _versionMadeBySpecification; internal ZipVersionNeededValues _versionToExtract; private BitFlagValues _generalPurposeBitFlag; + private bool _isEncrypted; private CompressionMethodValues _storedCompressionMethod; private DateTimeOffset _lastModified; private long _compressedSize; @@ -55,6 +56,7 @@ internal ZipArchiveEntry(ZipArchive archive, ZipCentralDirectoryFileHeader cd) _versionMadeBySpecification = (ZipVersionNeededValues)cd.VersionMadeBySpecification; _versionToExtract = (ZipVersionNeededValues)cd.VersionNeededToExtract; _generalPurposeBitFlag = (BitFlagValues)cd.GeneralPurposeBitFlag; + _isEncrypted = (_generalPurposeBitFlag & BitFlagValues.IsEncrypted) != 0; CompressionMethod = (CompressionMethodValues)cd.CompressionMethod; _lastModified = new DateTimeOffset(ZipHelper.DosTimeToDateTime(cd.LastModified)); _compressedSize = cd.CompressedSize; @@ -151,6 +153,11 @@ internal ZipArchiveEntry(ZipArchive archive, string entryName) [CLSCompliant(false)] public uint Crc32 => _crc32; + /// + /// Gets a value that indicates whether the entry is encrypted. + /// + public bool IsEncrypted => _isEncrypted; + /// /// The compressed size of the entry. If the archive that the entry belongs to is in Create mode, attempts to get this property will always throw an exception. If the archive that the entry belongs to is in update mode, this property will only be valid if the entry has not been opened. /// @@ -1305,7 +1312,7 @@ protected override void Dispose(bool disposing) } [Flags] - internal enum BitFlagValues : ushort { DataDescriptor = 0x8, UnicodeFileNameAndComment = 0x800 } + internal enum BitFlagValues : ushort { IsEncrypted = 0x1, DataDescriptor = 0x8, UnicodeFileNameAndComment = 0x800 } internal enum CompressionMethodValues : ushort { Stored = 0x0, Deflate = 0x8, Deflate64 = 0x9, BZip2 = 0xC, LZMA = 0xE } } diff --git a/src/libraries/System.IO.Compression/tests/ZipArchive/zip_ReadTests.cs b/src/libraries/System.IO.Compression/tests/ZipArchive/zip_ReadTests.cs index 577c60ad087e9a..93418b7af2ac40 100644 --- a/src/libraries/System.IO.Compression/tests/ZipArchive/zip_ReadTests.cs +++ b/src/libraries/System.IO.Compression/tests/ZipArchive/zip_ReadTests.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Generic; using System.Threading.Tasks; using Xunit; @@ -207,5 +208,46 @@ public static void TestEmptyLastModifiedEntryValueNotThrowingInternalException() using var archive = new ZipArchive(memoryStream, ZipArchiveMode.Read, true); Assert.Equal(archive.Entries[0].LastWriteTime, emptyDateIndicator); } + + [Theory] + [InlineData("normal.zip")] + [InlineData("small.zip")] + public static async Task EntriesNotEncryptedByDefault(string zipFile) + { + using (ZipArchive archive = new ZipArchive(await StreamHelpers.CreateTempCopyStream(zfile(zipFile)), ZipArchiveMode.Read)) + { + foreach (ZipArchiveEntry entry in archive.Entries) + { + Assert.False(entry.IsEncrypted); + } + } + } + + [Theory] + [InlineData("encrypted_entries_weak.zip")] + [InlineData("encrypted_entries_aes256.zip")] + [InlineData("encrypted_entries_mixed.zip")] + public static async Task IdentifyEncryptedEntries(string zipFile) + { + var entriesEncrypted = new Dictionary(); + + using (ZipArchive archive = new ZipArchive(await StreamHelpers.CreateTempCopyStream(zfile(zipFile)), ZipArchiveMode.Read)) + { + foreach (ZipArchiveEntry entry in archive.Entries) + { + entriesEncrypted.Add(entry.Name, entry.IsEncrypted); + } + } + + var expectedEntries = new Dictionary() + { + { "file1-encrypted.txt", true }, + { "file2-unencrypted.txt", false }, + { "file3-encrypted.txt", true }, + { "file4-unencrypted.txt", false }, + }; + + Assert.Equal(expectedEntries, entriesEncrypted); + } } }