Skip to content

Commit 4c53d42

Browse files
committed
add error for encrypted files
1 parent eb21f62 commit 4c53d42

File tree

6 files changed

+85
-2
lines changed

6 files changed

+85
-2
lines changed

src/DocumentFormat.OpenXml.Framework/Features/StreamPackageFeature.cs

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.Diagnostics.CodeAnalysis;
99
using System.IO;
1010
using System.IO.Packaging;
11+
using System.Linq;
1112

1213
namespace DocumentFormat.OpenXml.Features;
1314

@@ -56,7 +57,12 @@ public StreamPackageFeature(Stream stream, PackageOpenMode openMode, bool isOwne
5657
}
5758
catch when (isOwned)
5859
{
59-
// Ensure that the stream if created is disposed before leaving the constructor so we don't hold onto it
60+
if (_stream is not null && IsEncryptedOfficeFile(_stream))
61+
{
62+
_stream.Dispose();
63+
throw new OpenXmlPackageException(ExceptionMessages.EncryptedPackageNotSupported);
64+
}
65+
6066
_stream?.Dispose();
6167
throw;
6268
}
@@ -172,4 +178,54 @@ protected override void Register(IFeatureCollection features)
172178
features.Set<IPackageStreamFeature>(this);
173179
features.GetRequired<IDisposableFeature>().Register(this);
174180
}
181+
182+
private static bool IsEncryptedOfficeFile(Stream inputStream)
183+
{
184+
if (!inputStream.CanSeek)
185+
{
186+
throw new ArgumentException("Stream must be seekable.");
187+
}
188+
189+
long originalPosition = inputStream.Position;
190+
191+
try
192+
{
193+
byte[] header = new byte[8];
194+
inputStream.Seek(0, SeekOrigin.Begin);
195+
int read = inputStream.Read(header, 0, header.Length);
196+
inputStream.Seek(originalPosition, SeekOrigin.Begin);
197+
198+
// OLE Compound File signature for encrypted Office files
199+
byte[] oleSignature = { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 };
200+
if (read == 8 && header.SequenceEqual(oleSignature))
201+
{
202+
return true;
203+
}
204+
205+
// If not OLE, try to open as package and check for encrypted part
206+
try
207+
{
208+
using (var package = System.IO.Packaging.Package.Open(inputStream, FileMode.Open, FileAccess.Read))
209+
{
210+
foreach (var part in package.GetParts())
211+
{
212+
if (part.ContentType.Equals("application/vnd.openxmlformats-officedocument.encrypted-package", StringComparison.OrdinalIgnoreCase))
213+
{
214+
return true;
215+
}
216+
}
217+
}
218+
}
219+
catch
220+
{
221+
return false;
222+
}
223+
224+
return false;
225+
}
226+
finally
227+
{
228+
inputStream.Seek(originalPosition, SeekOrigin.Begin);
229+
}
230+
}
175231
}

src/DocumentFormat.OpenXml.Framework/Resources/ExceptionMessages.Designer.cs

Lines changed: 10 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/DocumentFormat.OpenXml.Framework/Resources/ExceptionMessages.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,4 +414,7 @@
414414
<data name="FirstOrDefaultMaxOne" xml:space="preserve">
415415
<value>The enumerable contained more than a single element when only zero or one are allowed.</value>
416416
</data>
417+
<data name="EncryptedPackageNotSupported" xml:space="preserve">
418+
<value>Encrypted packages are not supported.</value>
419+
</data>
417420
</root>

test/DocumentFormat.OpenXml.Framework.Tests/Features/StreamPackageFeatureTests.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using System.IO.Packaging;
1111
using System.Linq;
1212
using Xunit;
13+
using static DocumentFormat.OpenXml.Tests.TestAssets;
1314

1415
namespace DocumentFormat.OpenXml.Features.Tests;
1516

@@ -431,6 +432,18 @@ protected override void Dispose(bool disposing)
431432
}
432433
}
433434

435+
[Fact]
436+
public void ThrowsForEncryptedOfficeFile()
437+
{
438+
using (Stream stream = GetStream(TestFiles.Encrypted_pptx, false))
439+
{
440+
// Act & Assert
441+
var ex = Assert.Throws<OpenXmlPackageException>(() => new StreamPackageFeature(stream, PackageOpenMode.Read, isOwned: true));
442+
Assert.Equal(ExceptionMessages.EncryptedPackageNotSupported, ex.Message);
443+
}
444+
445+
}
446+
434447
private static readonly PartInfo Part1 = new(new("/part1", UriKind.Relative), "type1/content");
435448
private static readonly PartInfo Part2 = new(new("/part2", UriKind.Relative), "type2/content");
436449
private static readonly PartInfo PartRels = new(new("/_rels/.rels", UriKind.Relative), "application/vnd.openxmlformats-package.relationships+xml");

test/DocumentFormat.OpenXml.Tests.Assets/TestAssets.TestFiles.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ public static class Templates
127127
public const string Of16_09_unknownelement_docx = "TestFiles.Of16-09-UnknownElement.docx";
128128

129129
public const string Of16_10_symex_docx = "TestFiles.Of16-10-SymEx.docx";
130+
131+
public const string Encrypted_pptx = "TestFiles.encrypted_pptx.pptx";
130132
}
131133
}
132134
}
Binary file not shown.

0 commit comments

Comments
 (0)