mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-11-15 17:02:03 +00:00
Fix 7z encryption detection for streamless files
This commit is contained in:
@@ -831,3 +831,7 @@ using (var reader = ReaderFactory.OpenReader(stream))
|
||||
- [USAGE.md](USAGE.md) - Complete code examples
|
||||
- [FORMATS.md](FORMATS.md) - Supported formats
|
||||
- [PERFORMANCE.md](PERFORMANCE.md) - API selection guide
|
||||
## 7z Encryption Detection
|
||||
|
||||
For 7z archives, `IsEncrypted` is true when any entry has an AES-encrypted data stream.
|
||||
Streamless empty files and directories are not encrypted. Archives without files return false.
|
||||
|
||||
@@ -98,7 +98,7 @@ public partial class SevenZipArchive : AbstractArchive<SevenZipArchiveEntry, Sev
|
||||
.GroupBy(x => x.FilePart.Folder)
|
||||
.Any(folder => folder.Skip(1).Any());
|
||||
|
||||
public override bool IsEncrypted => Entries.First(x => !x.IsDirectory).IsEncrypted;
|
||||
public override bool IsEncrypted => Entries.Any(x => x.IsEncrypted);
|
||||
|
||||
public override long TotalSize =>
|
||||
_database?._packSizes.Aggregate(0L, (total, packSize) => total + packSize) ?? 0;
|
||||
|
||||
@@ -119,7 +119,5 @@ internal class SevenZipFilePart : FilePart
|
||||
};
|
||||
}
|
||||
|
||||
internal bool IsEncrypted =>
|
||||
!Header.IsDir
|
||||
&& Folder?._coders.FindIndex(c => c._methodId._id == CMethodId.K_AES_ID) != -1;
|
||||
internal bool IsEncrypted => !Header.IsDir && Folder?.IsEncrypted() == true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Archives.SevenZip;
|
||||
using SharpCompress.Common.SevenZip;
|
||||
using SharpCompress.Crypto;
|
||||
using SharpCompress.Writers.SevenZip;
|
||||
using Xunit;
|
||||
|
||||
namespace SharpCompress.Test.SevenZip;
|
||||
|
||||
public class SevenZipEncryptionDetectionTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public async Task SevenZipArchive_EmptyFirstFile_EncryptionDetection(bool encrypted)
|
||||
{
|
||||
using var output = new MemoryStream();
|
||||
using (var writer = new SevenZipWriter(output, new SevenZipWriterOptions()))
|
||||
{
|
||||
using var empty = new MemoryStream();
|
||||
using var data = new MemoryStream(new byte[] { 1, 2, 3 });
|
||||
writer.Write("empty.txt", empty, null);
|
||||
writer.Write("data.txt", data, null);
|
||||
}
|
||||
output.Position = 0;
|
||||
using var archive = (SevenZipArchive)SevenZipArchive.OpenArchive(output);
|
||||
var entries = archive.Entries.Cast<SevenZipArchiveEntry>().ToList();
|
||||
if (encrypted)
|
||||
{
|
||||
// Only metadata is under test; do not decode after adding the AES marker.
|
||||
entries[1]
|
||||
.FilePart.Folder!._coders.Add(new CCoderInfo { _methodId = CMethodId.K_AES });
|
||||
}
|
||||
Assert.False(entries[0].IsEncrypted);
|
||||
Assert.Same(Stream.Null, entries[0].OpenEntryStream());
|
||||
Assert.Equal(encrypted, entries[1].IsEncrypted);
|
||||
Assert.Equal(encrypted, archive.IsEncrypted);
|
||||
Assert.Equal(encrypted, await archive.IsEncryptedAsync());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public void SevenZipArchive_NoFiles_IsNotEncrypted(bool directory)
|
||||
{
|
||||
using var stream = new MemoryStream();
|
||||
// Build reader fixtures directly so this PR does not depend on the writer fix in #1440.
|
||||
using var header = new MemoryStream();
|
||||
ArchiveHeaderWriter.WriteRawHeader(
|
||||
header,
|
||||
null,
|
||||
new SevenZipFilesInfoWriter
|
||||
{
|
||||
Entries = directory
|
||||
? new[]
|
||||
{
|
||||
new SevenZipWriteEntry
|
||||
{
|
||||
Name = "dir",
|
||||
IsDirectory = true,
|
||||
IsEmpty = true,
|
||||
Attributes = 0x10,
|
||||
},
|
||||
}
|
||||
: System.Array.Empty<SevenZipWriteEntry>(),
|
||||
}
|
||||
);
|
||||
var bytes = header.ToArray();
|
||||
var crc = Crc32Stream.Compute(
|
||||
Crc32Stream.DEFAULT_POLYNOMIAL,
|
||||
Crc32Stream.DEFAULT_SEED,
|
||||
bytes
|
||||
);
|
||||
SevenZipSignatureHeaderWriter.WriteFinal(stream, 0, (ulong)bytes.Length, crc);
|
||||
stream.Write(bytes, 0, bytes.Length);
|
||||
stream.Position = 0;
|
||||
using var archive = SevenZipArchive.OpenArchive(stream);
|
||||
Assert.False(archive.IsEncrypted);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user