From bad57763a1210d39909a5a937c3386ac6dcdc18c Mon Sep 17 00:00:00 2001 From: Eliot Jones Date: Mon, 6 May 2019 15:41:29 +0100 Subject: [PATCH] finish initial support for rc4 encryption with blank user password --- .../Integration/LocalTests.cs | 12 +- .../AcroForms/AcroFormFactory.cs | 7 +- .../Encryption/EncryptionHandler.cs | 181 ++++++++++++------ .../Encryption/IEncryptionHandler.cs | 6 +- .../Encryption/NoOpEncryptionHandler.cs | 5 +- .../Parser/Handlers/TrueTypeFontHandler.cs | 10 +- .../Fonts/Parser/Handlers/Type0FontHandler.cs | 8 +- .../Fonts/Parser/Handlers/Type1FontHandler.cs | 9 +- .../Fonts/Parser/Handlers/Type3FontHandler.cs | 6 +- .../Fonts/Parser/Parts/CidFontFactory.cs | 12 +- src/UglyToad.PdfPig/Parser/PageFactory.cs | 7 +- .../CrossReferenceStreamParser.cs | 3 +- .../Parser/PdfDocumentFactory.cs | 16 +- .../Tokenization/Scanner/PdfTokenScanner.cs | 4 +- src/UglyToad.PdfPig/Tokens/StreamToken.cs | 5 +- 15 files changed, 166 insertions(+), 125 deletions(-) diff --git a/src/UglyToad.PdfPig.Tests/Integration/LocalTests.cs b/src/UglyToad.PdfPig.Tests/Integration/LocalTests.cs index 8a6b15c6..39a61e21 100644 --- a/src/UglyToad.PdfPig.Tests/Integration/LocalTests.cs +++ b/src/UglyToad.PdfPig.Tests/Integration/LocalTests.cs @@ -3,17 +3,17 @@ //using System; //using System.Diagnostics; //using System.IO; - using Xunit; + //using Xunit; /// /// A class for testing files which are not checked in to source control. /// public class LocalTests { - [Fact] - public void Tests() - { - // var files = new[]{ @"C:\Users\eliot\Downloads\Encrypted1.pdf" }; + //[Fact] + //public void Tests() + //{ + // var files = new[] { @"C:\Users\eliot\Downloads\Encrypted1.pdf" }; // foreach (var file in files) // { @@ -34,6 +34,6 @@ // throw new InvalidOperationException($"Error parsing: {Path.GetFileName(file)}.", ex); // } // } - } + //} } } diff --git a/src/UglyToad.PdfPig/AcroForms/AcroFormFactory.cs b/src/UglyToad.PdfPig/AcroForms/AcroFormFactory.cs index 1ec71f5f..a88b5841 100644 --- a/src/UglyToad.PdfPig/AcroForms/AcroFormFactory.cs +++ b/src/UglyToad.PdfPig/AcroForms/AcroFormFactory.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Linq; using Content; - using Encryption; using Exceptions; using Fields; using Filters; @@ -21,13 +20,11 @@ { private readonly IPdfTokenScanner tokenScanner; private readonly IFilterProvider filterProvider; - private readonly IEncryptionHandler encryptionHandler; - public AcroFormFactory(IPdfTokenScanner tokenScanner, IFilterProvider filterProvider, IEncryptionHandler encryptionHandler) + public AcroFormFactory(IPdfTokenScanner tokenScanner, IFilterProvider filterProvider) { this.tokenScanner = tokenScanner ?? throw new ArgumentNullException(nameof(tokenScanner)); this.filterProvider = filterProvider ?? throw new ArgumentNullException(nameof(filterProvider)); - this.encryptionHandler = encryptionHandler ?? throw new ArgumentNullException(nameof(encryptionHandler)); } /// @@ -215,7 +212,7 @@ } else if (DirectObjectFinder.TryGet(textValueToken, tokenScanner, out StreamToken valueStreamToken)) { - textValue = OtherEncodings.BytesAsLatin1String(valueStreamToken.Decode(filterProvider, encryptionHandler).ToArray()); + textValue = OtherEncodings.BytesAsLatin1String(valueStreamToken.Decode(filterProvider).ToArray()); } } diff --git a/src/UglyToad.PdfPig/Encryption/EncryptionHandler.cs b/src/UglyToad.PdfPig/Encryption/EncryptionHandler.cs index ad9dda11..d34e5dda 100644 --- a/src/UglyToad.PdfPig/Encryption/EncryptionHandler.cs +++ b/src/UglyToad.PdfPig/Encryption/EncryptionHandler.cs @@ -2,6 +2,7 @@ { using System; using System.Collections.Generic; + using System.Linq; using System.Security.Cryptography; using System.Text; using CrossReference; @@ -11,7 +12,7 @@ internal class EncryptionHandler : IEncryptionHandler { - private static readonly byte[] PaddingBytes = + private static readonly byte[] PaddingBytes = { 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, @@ -23,6 +24,8 @@ 0x64, 0x53, 0x69, 0x7A }; + private readonly HashSet previouslyDecrypted = new HashSet(); + [CanBeNull] private readonly EncryptionDictionary encryptionDictionary; @@ -40,7 +43,7 @@ { this.encryptionDictionary = encryptionDictionary; - documentIdBytes = trailerDictionary.Identifier != null && trailerDictionary.Identifier.Count == 2 ? + documentIdBytes = trailerDictionary.Identifier != null && trailerDictionary.Identifier.Count == 2 ? OtherEncodings.StringAsLatin1Bytes(trailerDictionary.Identifier[0]) : EmptyArray.Instance; this.password = password ?? string.Empty; @@ -63,47 +66,114 @@ var passwordBytes = charset.GetBytes(this.password); - var length = encryptionDictionary.EncryptionAlgorithmCode == EncryptionAlgorithmCode.Rc4OrAes40BitKey - ? 5 + var length = encryptionDictionary.EncryptionAlgorithmCode == EncryptionAlgorithmCode.Rc4OrAes40BitKey + ? 5 : encryptionDictionary.KeyLength.GetValueOrDefault() / 8; - encryptionKey = CalculateKeyRevisions2To4(passwordBytes, ownerKey, (int) encryptionDictionary.UserAccessPermissions, encryptionDictionary.StandardSecurityHandlerRevision, + encryptionKey = CalculateKeyRevisions2To4(passwordBytes, ownerKey, (int)encryptionDictionary.UserAccessPermissions, encryptionDictionary.StandardSecurityHandlerRevision, length, documentIdBytes, encryptionDictionary.EncryptMetadata); - } - - public IReadOnlyList Decrypt(StreamToken stream) - { - if (encryptionDictionary == null) - { - return stream?.Data; - } - if (stream == null) - { - throw new ArgumentNullException(nameof(stream)); - } - - throw new NotImplementedException($"Encryption is not supported yet. Encryption used in document was: {encryptionDictionary.Dictionary}."); + useAes = false; } - public void Decrypt(IndirectReference reference, IToken token) + public IToken Decrypt(IndirectReference reference, IToken token) { - if (token is StreamToken stream) + if (token == null) { - + throw new ArgumentNullException(nameof(token)); } - else if (token is StringToken stringToken) - { - - } - else if (token is DictionaryToken dictionary) - { - - } - else if (token is ArrayToken array) - { + + token = DecryptInternal(reference, token); + previouslyDecrypted.Add(reference); + + return token; + } + + private IToken DecryptInternal(IndirectReference reference, IToken token) + { + switch (token) + { + case StreamToken stream: + { + if (stream.StreamDictionary.TryGet(NameToken.Type, out NameToken typeName)) + { + if (NameToken.Xref.Equals(typeName)) + { + return token; + } + + if (!encryptionDictionary.EncryptMetadata && NameToken.Metadata.Equals(typeName)) + { + return token; + } + + // TODO: check unencrypted metadata + } + + var streamDictionary = (DictionaryToken)DecryptInternal(reference, stream.StreamDictionary); + + var decrypted = DecryptData(stream.Data.ToArray(), reference); + + token = new StreamToken(streamDictionary, decrypted); + + break; + } + case StringToken stringToken: + { + var data = OtherEncodings.StringAsLatin1Bytes(stringToken.Data); + + var decrypted = DecryptData(data, reference); + + token = new StringToken(OtherEncodings.BytesAsLatin1String(decrypted)); + + break; + } + case DictionaryToken dictionary: + { + // PDFBOX-2936: avoid orphan /CF dictionaries found in US govt "I-" files + if (dictionary.TryGet(NameToken.Cf, out _)) + { + return token; + } + + var isSignatureDictionary = dictionary.TryGet(NameToken.Type, out NameToken typeName) + && (typeName.Equals(NameToken.Sig) || typeName.Equals(NameToken.DocTimeStamp)); + + foreach (var keyValuePair in dictionary.Data) + { + if (isSignatureDictionary && keyValuePair.Key == NameToken.Contents.Data) + { + continue; + } + + if (keyValuePair.Value is StringToken || keyValuePair.Value is ArrayToken || keyValuePair.Value is DictionaryToken) + { + var inner = DecryptInternal(reference, keyValuePair.Value); + dictionary = dictionary.With(keyValuePair.Key, inner); + } + } + + token = dictionary; + + break; + } + case ArrayToken array: + { + var result = new IToken[array.Length]; + + for (var i = 0; i < array.Length; i++) + { + result[i] = DecryptInternal(reference, array.Data[i]); + } + + token = new ArrayToken(result); + + break; + } } + + return token; } private byte[] DecryptData(byte[] data, IndirectReference reference) @@ -119,12 +189,12 @@ { throw new NotImplementedException("Decryption for AES-128 not currently supported."); } - + return RC4.Encrypt(finalKey, data); } private byte[] GetObjectKey(IndirectReference reference) - { + { // 1. Get the object and generation number from the object // 2. Treating the object and generation number as binary integers extend the @@ -134,13 +204,13 @@ var finalKey = new byte[encryptionKey.Length + 5 + (useAes ? 4 : 0)]; Array.Copy(encryptionKey, finalKey, encryptionKey.Length); - finalKey[encryptionKey.Length] = (byte) reference.ObjectNumber; - finalKey[encryptionKey.Length + 1] = (byte) (reference.ObjectNumber >> 1); - finalKey[encryptionKey.Length + 2] = (byte) (reference.ObjectNumber >> 2); + finalKey[encryptionKey.Length] = (byte)reference.ObjectNumber; + finalKey[encryptionKey.Length + 1] = (byte)(reference.ObjectNumber >> 8); + finalKey[encryptionKey.Length + 2] = (byte)(reference.ObjectNumber >> 16); + + finalKey[encryptionKey.Length + 3] = (byte)reference.Generation; + finalKey[encryptionKey.Length + 4] = (byte)(reference.Generation >> 8); - finalKey[encryptionKey.Length + 3] = (byte) reference.Generation; - finalKey[encryptionKey.Length + 4] = (byte) (reference.Generation >> 1); - // 2. If using the AES algorithm extend the encryption key by 4 bytes by adding the value "sAlT". if (useAes) { @@ -195,32 +265,28 @@ using (var md5 = MD5.Create()) { // 2. Initialize the MD5 hash function and pass the result of step 1 as input to this function. - var has = md5.ComputeHash(passwordFull); + UpdateMd5(md5, passwordFull); // 3. Pass the value of the encryption dictionary's owner key entry to the MD5 hash function. - var has1 = md5.ComputeHash(ownerKey); + UpdateMd5(md5, ownerKey); // 4. Treat the value of the P entry as an unsigned 4-byte integer. - var unsigned = (uint) permissions; - var permissionsBytes = new [] - { - (byte) (unsigned), - (byte) (unsigned >> 8), - (byte) (unsigned >> 16), - (byte) (unsigned >> 24) - }; + var unsigned = (uint)permissions; // 4. Pass these bytes to the MD5 hash function, low-order byte first. - var has2 = md5.ComputeHash(permissionsBytes); + UpdateMd5(md5, new[] { (byte)(unsigned) }); + UpdateMd5(md5, new[] { (byte)(unsigned >> 8) }); + UpdateMd5(md5, new[] { (byte)(unsigned >> 16) }); + UpdateMd5(md5, new[] { (byte)(unsigned >> 24) }); // 5. Pass the first element of the file's file identifier array to the hash. - var has3 = md5.ComputeHash(documentId); + UpdateMd5(md5, documentId); // 6. (Revision 4 or greater) If document metadata is not being encrypted, pass 4 bytes // with the value 0xFFFFFFFF to the MD5 hash function. if (revision >= 4) { - md5.ComputeHash(new byte[] {0xFF, 0xFF, 0xFF, 0xFF}); + UpdateMd5(md5, new byte[] { 0xFF, 0xFF, 0xFF, 0xFF }); } // 7. Do the following 50 times: Take the output from the previous MD5 hash and @@ -235,11 +301,13 @@ for (var i = 0; i < 50; i++) { - md5.ComputeHash(input, 0, n); + UpdateMd5(md5, input.Take(n).ToArray()); input = md5.Hash; } } + md5.TransformFinalBlock(EmptyArray.Instance, 0, 0); + var result = new byte[length]; Array.Copy(md5.Hash, result, length); @@ -248,6 +316,11 @@ } } + private static void UpdateMd5(MD5 md5, byte[] data) + { + md5.TransformBlock(data, 0, data.Length, null, 0); + } + private static byte[] GetPaddedPassword(byte[] password) { if (password == null || password.Length == 0) diff --git a/src/UglyToad.PdfPig/Encryption/IEncryptionHandler.cs b/src/UglyToad.PdfPig/Encryption/IEncryptionHandler.cs index 84090a2b..70140628 100644 --- a/src/UglyToad.PdfPig/Encryption/IEncryptionHandler.cs +++ b/src/UglyToad.PdfPig/Encryption/IEncryptionHandler.cs @@ -1,6 +1,5 @@ namespace UglyToad.PdfPig.Encryption { - using System.Collections.Generic; using Tokens; /// @@ -8,9 +7,6 @@ /// internal interface IEncryptionHandler { - /// - /// Decrypt the contents of the stream if encryption is applied. - /// - IReadOnlyList Decrypt(StreamToken stream); + IToken Decrypt(IndirectReference reference, IToken token); } } diff --git a/src/UglyToad.PdfPig/Encryption/NoOpEncryptionHandler.cs b/src/UglyToad.PdfPig/Encryption/NoOpEncryptionHandler.cs index 092edd36..7befe211 100644 --- a/src/UglyToad.PdfPig/Encryption/NoOpEncryptionHandler.cs +++ b/src/UglyToad.PdfPig/Encryption/NoOpEncryptionHandler.cs @@ -1,6 +1,5 @@ namespace UglyToad.PdfPig.Encryption { - using System.Collections.Generic; using Tokens; internal class NoOpEncryptionHandler : IEncryptionHandler @@ -11,9 +10,9 @@ { } - public IReadOnlyList Decrypt(StreamToken stream) + public IToken Decrypt(IndirectReference reference, IToken token) { - return stream.Data; + return token; } } } \ No newline at end of file diff --git a/src/UglyToad.PdfPig/Fonts/Parser/Handlers/TrueTypeFontHandler.cs b/src/UglyToad.PdfPig/Fonts/Parser/Handlers/TrueTypeFontHandler.cs index d7867712..12776b7b 100644 --- a/src/UglyToad.PdfPig/Fonts/Parser/Handlers/TrueTypeFontHandler.cs +++ b/src/UglyToad.PdfPig/Fonts/Parser/Handlers/TrueTypeFontHandler.cs @@ -4,7 +4,6 @@ using SystemFonts; using Cmap; using Encodings; - using Encryption; using Exceptions; using Filters; using IO; @@ -23,15 +22,13 @@ private readonly ILog log; private readonly IPdfTokenScanner pdfScanner; private readonly IFilterProvider filterProvider; - private readonly IEncryptionHandler encryptionHandler; private readonly CMapCache cMapCache; private readonly FontDescriptorFactory fontDescriptorFactory; private readonly TrueTypeFontParser trueTypeFontParser; private readonly IEncodingReader encodingReader; private readonly ISystemFontFinder systemFontFinder; - public TrueTypeFontHandler(ILog log, IPdfTokenScanner pdfScanner, IFilterProvider filterProvider, - IEncryptionHandler encryptionHandler, + public TrueTypeFontHandler(ILog log, IPdfTokenScanner pdfScanner, IFilterProvider filterProvider, CMapCache cMapCache, FontDescriptorFactory fontDescriptorFactory, TrueTypeFontParser trueTypeFontParser, @@ -40,7 +37,6 @@ { this.log = log; this.filterProvider = filterProvider; - this.encryptionHandler = encryptionHandler; this.cMapCache = cMapCache; this.fontDescriptorFactory = fontDescriptorFactory; this.trueTypeFontParser = trueTypeFontParser; @@ -89,7 +85,7 @@ { var toUnicode = DirectObjectFinder.Get(toUnicodeObj, pdfScanner); - var decodedUnicodeCMap = toUnicode.Decode(filterProvider, encryptionHandler); + var decodedUnicodeCMap = toUnicode.Decode(filterProvider); if (decodedUnicodeCMap != null) { @@ -129,7 +125,7 @@ var fontFileStream = DirectObjectFinder.Get(descriptor.FontFile.ObjectKey, pdfScanner); - var fontFile = fontFileStream.Decode(filterProvider, encryptionHandler); + var fontFile = fontFileStream.Decode(filterProvider); var font = trueTypeFontParser.Parse(new TrueTypeDataBytes(new ByteArrayInputBytes(fontFile))); diff --git a/src/UglyToad.PdfPig/Fonts/Parser/Handlers/Type0FontHandler.cs b/src/UglyToad.PdfPig/Fonts/Parser/Handlers/Type0FontHandler.cs index 329efe73..89c27fec 100644 --- a/src/UglyToad.PdfPig/Fonts/Parser/Handlers/Type0FontHandler.cs +++ b/src/UglyToad.PdfPig/Fonts/Parser/Handlers/Type0FontHandler.cs @@ -4,7 +4,6 @@ using CidFonts; using Cmap; using Composite; - using Encryption; using Exceptions; using Filters; using IO; @@ -19,17 +18,14 @@ private readonly CidFontFactory cidFontFactory; private readonly CMapCache cMapCache; private readonly IFilterProvider filterProvider; - private readonly IEncryptionHandler encryptionHandler; private readonly IPdfTokenScanner scanner; public Type0FontHandler(CidFontFactory cidFontFactory, CMapCache cMapCache, IFilterProvider filterProvider, - IEncryptionHandler encryptionHandler, IPdfTokenScanner scanner) { this.cidFontFactory = cidFontFactory; this.cMapCache = cMapCache; this.filterProvider = filterProvider; - this.encryptionHandler = encryptionHandler; this.scanner = scanner; } @@ -72,7 +68,7 @@ var toUnicode = DirectObjectFinder.Get(toUnicodeValue, scanner); - var decodedUnicodeCMap = toUnicode?.Decode(filterProvider, encryptionHandler); + var decodedUnicodeCMap = toUnicode?.Decode(filterProvider); if (decodedUnicodeCMap != null) { @@ -151,7 +147,7 @@ } else if (value is StreamToken stream) { - var decoded = stream.Decode(filterProvider, encryptionHandler); + var decoded = stream.Decode(filterProvider); var cmap = cMapCache.Parse(new ByteArrayInputBytes(decoded), false); diff --git a/src/UglyToad.PdfPig/Fonts/Parser/Handlers/Type1FontHandler.cs b/src/UglyToad.PdfPig/Fonts/Parser/Handlers/Type1FontHandler.cs index 16b6352f..7904b24d 100644 --- a/src/UglyToad.PdfPig/Fonts/Parser/Handlers/Type1FontHandler.cs +++ b/src/UglyToad.PdfPig/Fonts/Parser/Handlers/Type1FontHandler.cs @@ -1,10 +1,8 @@ namespace UglyToad.PdfPig.Fonts.Parser.Handlers { - using System.Linq; using Cmap; using CompactFontFormat; using Encodings; - using Encryption; using Exceptions; using Filters; using IO; @@ -22,14 +20,12 @@ private readonly IPdfTokenScanner pdfScanner; private readonly CMapCache cMapCache; private readonly IFilterProvider filterProvider; - private readonly IEncryptionHandler encryptionHandler; private readonly FontDescriptorFactory fontDescriptorFactory; private readonly IEncodingReader encodingReader; private readonly Type1FontParser type1FontParser; private readonly CompactFontFormatParser compactFontFormatParser; public Type1FontHandler(IPdfTokenScanner pdfScanner, CMapCache cMapCache, IFilterProvider filterProvider, - IEncryptionHandler encryptionHandler, FontDescriptorFactory fontDescriptorFactory, IEncodingReader encodingReader, Type1FontParser type1FontParser, @@ -38,7 +34,6 @@ this.pdfScanner = pdfScanner; this.cMapCache = cMapCache; this.filterProvider = filterProvider; - this.encryptionHandler = encryptionHandler; this.fontDescriptorFactory = fontDescriptorFactory; this.encodingReader = encodingReader; this.type1FontParser = type1FontParser; @@ -93,7 +88,7 @@ { var toUnicode = DirectObjectFinder.Get(toUnicodeObj, pdfScanner); - var decodedUnicodeCMap = toUnicode?.Decode(filterProvider, encryptionHandler); + var decodedUnicodeCMap = toUnicode?.Decode(filterProvider); if (decodedUnicodeCMap != null) { @@ -130,7 +125,7 @@ return null; } - var bytes = stream.Decode(filterProvider, encryptionHandler); + var bytes = stream.Decode(filterProvider); // We have a Compact Font Format font rather than an Adobe Type 1 Font. if (stream.StreamDictionary.TryGet(NameToken.Subtype, out NameToken subTypeName) diff --git a/src/UglyToad.PdfPig/Fonts/Parser/Handlers/Type3FontHandler.cs b/src/UglyToad.PdfPig/Fonts/Parser/Handlers/Type3FontHandler.cs index d52f8d7e..a0cffbd3 100644 --- a/src/UglyToad.PdfPig/Fonts/Parser/Handlers/Type3FontHandler.cs +++ b/src/UglyToad.PdfPig/Fonts/Parser/Handlers/Type3FontHandler.cs @@ -3,7 +3,6 @@ using Cmap; using Core; using Encodings; - using Encryption; using Exceptions; using Filters; using Geometry; @@ -18,17 +17,14 @@ { private readonly CMapCache cMapCache; private readonly IFilterProvider filterProvider; - private readonly IEncryptionHandler encryptionHandler; private readonly IEncodingReader encodingReader; private readonly IPdfTokenScanner scanner; public Type3FontHandler(IPdfTokenScanner scanner, CMapCache cMapCache, IFilterProvider filterProvider, - IEncryptionHandler encryptionHandler, IEncodingReader encodingReader) { this.cMapCache = cMapCache; this.filterProvider = filterProvider; - this.encryptionHandler = encryptionHandler; this.encodingReader = encodingReader; this.scanner = scanner; } @@ -50,7 +46,7 @@ { var toUnicode = DirectObjectFinder.Get(toUnicodeObj, scanner); - var decodedUnicodeCMap = toUnicode?.Decode(filterProvider, encryptionHandler); + var decodedUnicodeCMap = toUnicode?.Decode(filterProvider); if (decodedUnicodeCMap != null) { diff --git a/src/UglyToad.PdfPig/Fonts/Parser/Parts/CidFontFactory.cs b/src/UglyToad.PdfPig/Fonts/Parser/Parts/CidFontFactory.cs index eca91c3e..e05fda32 100644 --- a/src/UglyToad.PdfPig/Fonts/Parser/Parts/CidFontFactory.cs +++ b/src/UglyToad.PdfPig/Fonts/Parser/Parts/CidFontFactory.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using CidFonts; using CompactFontFormat; - using Encryption; using Exceptions; using Filters; using Geometry; @@ -23,21 +22,18 @@ private readonly TrueTypeFontParser trueTypeFontParser; private readonly CompactFontFormatParser compactFontFormatParser; private readonly IFilterProvider filterProvider; - private readonly IEncryptionHandler encryptionHandler; private readonly IPdfTokenScanner pdfScanner; public CidFontFactory(IPdfTokenScanner pdfScanner, FontDescriptorFactory descriptorFactory, TrueTypeFontParser trueTypeFontParser, CompactFontFormatParser compactFontFormatParser, - IFilterProvider filterProvider, - IEncryptionHandler encryptionHandler) + IFilterProvider filterProvider) { this.pdfScanner = pdfScanner; this.descriptorFactory = descriptorFactory; this.trueTypeFontParser = trueTypeFontParser; this.compactFontFormatParser = compactFontFormatParser; this.filterProvider = filterProvider; - this.encryptionHandler = encryptionHandler; } public ICidFont Generate(DictionaryToken dictionary, bool isLenientParsing) @@ -109,7 +105,7 @@ return null; } - var fontFile = fontFileStream.Decode(filterProvider, encryptionHandler); + var fontFile = fontFileStream.Decode(filterProvider); switch (descriptor.FontFile.FileType) { @@ -130,7 +126,7 @@ if (subtypeName == NameToken.CidFontType0C) { - var bytes = str.Decode(filterProvider, encryptionHandler); + var bytes = str.Decode(filterProvider); var font = compactFontFormatParser.Parse(new CompactFontFormatData(bytes)); return font; } @@ -302,7 +298,7 @@ var stream = DirectObjectFinder.Get(entry, pdfScanner); - var bytes = stream.Decode(filterProvider, encryptionHandler); + var bytes = stream.Decode(filterProvider); return new CharacterIdentifierToGlyphIndexMap(bytes); } diff --git a/src/UglyToad.PdfPig/Parser/PageFactory.cs b/src/UglyToad.PdfPig/Parser/PageFactory.cs index d51969d2..7bebcc75 100644 --- a/src/UglyToad.PdfPig/Parser/PageFactory.cs +++ b/src/UglyToad.PdfPig/Parser/PageFactory.cs @@ -22,20 +22,17 @@ private readonly IPdfTokenScanner pdfScanner; private readonly IResourceStore resourceStore; private readonly IFilterProvider filterProvider; - private readonly IEncryptionHandler encryptionHandler; private readonly IPageContentParser pageContentParser; private readonly XObjectFactory xObjectFactory; private readonly ILog log; public PageFactory(IPdfTokenScanner pdfScanner, IResourceStore resourceStore, IFilterProvider filterProvider, - IEncryptionHandler encryptionHandler, IPageContentParser pageContentParser, XObjectFactory xObjectFactory, ILog log) { this.resourceStore = resourceStore; this.filterProvider = filterProvider; - this.encryptionHandler = encryptionHandler; this.pageContentParser = pageContentParser; this.xObjectFactory = xObjectFactory; this.log = log; @@ -88,7 +85,7 @@ throw new InvalidOperationException($"Could not find the contents for object {obj}."); } - bytes.AddRange(contentStream.Decode(filterProvider, encryptionHandler)); + bytes.AddRange(contentStream.Decode(filterProvider)); } content = GetContent(bytes, cropBox, userSpaceUnit, isLenientParsing); @@ -102,7 +99,7 @@ throw new InvalidOperationException("Failed to parse the content for the page: " + number); } - var bytes = contentStream.Decode(filterProvider, encryptionHandler); + var bytes = contentStream.Decode(filterProvider); content = GetContent(bytes, cropBox, userSpaceUnit, isLenientParsing); } diff --git a/src/UglyToad.PdfPig/Parser/Parts/CrossReference/CrossReferenceStreamParser.cs b/src/UglyToad.PdfPig/Parser/Parts/CrossReference/CrossReferenceStreamParser.cs index 9a18689a..c00b94aa 100644 --- a/src/UglyToad.PdfPig/Parser/Parts/CrossReference/CrossReferenceStreamParser.cs +++ b/src/UglyToad.PdfPig/Parser/Parts/CrossReference/CrossReferenceStreamParser.cs @@ -1,7 +1,6 @@ namespace UglyToad.PdfPig.Parser.Parts.CrossReference { using System.Collections.Generic; - using Encryption; using Exceptions; using Filters; using PdfPig.CrossReference; @@ -22,7 +21,7 @@ /// public CrossReferenceTablePart Parse(long streamOffset, StreamToken stream) { - var decoded = stream.Decode(filterProvider, NoOpEncryptionHandler.Instance); + var decoded = stream.Decode(filterProvider); var fieldSizes = new CrossReferenceStreamFieldSize(stream.StreamDictionary); diff --git a/src/UglyToad.PdfPig/Parser/PdfDocumentFactory.cs b/src/UglyToad.PdfPig/Parser/PdfDocumentFactory.cs index d44d3e51..72dae092 100644 --- a/src/UglyToad.PdfPig/Parser/PdfDocumentFactory.cs +++ b/src/UglyToad.PdfPig/Parser/PdfDocumentFactory.cs @@ -107,25 +107,25 @@ var rootDictionary = ParseTrailer(crossReferenceTable, isLenientParsing, pdfScanner, out var encryptionDictionary); - var encryptionHandler = new EncryptionHandler(encryptionDictionary, crossReferenceTable.Trailer, string.Empty); + var encryptionHandler = encryptionDictionary != null ? (IEncryptionHandler)new EncryptionHandler(encryptionDictionary, crossReferenceTable.Trailer, string.Empty) + : NoOpEncryptionHandler.Instance; pdfScanner.UpdateEncryptionHandler(encryptionHandler); - var cidFontFactory = new CidFontFactory(pdfScanner, fontDescriptorFactory, trueTypeFontParser, compactFontFormatParser, filterProvider, encryptionHandler); + var cidFontFactory = new CidFontFactory(pdfScanner, fontDescriptorFactory, trueTypeFontParser, compactFontFormatParser, filterProvider); var encodingReader = new EncodingReader(pdfScanner); var fontFactory = new FontFactory(log, new Type0FontHandler(cidFontFactory, cMapCache, - filterProvider, encryptionHandler, pdfScanner), - new TrueTypeFontHandler(log, pdfScanner, filterProvider, encryptionHandler, cMapCache, fontDescriptorFactory, trueTypeFontParser, encodingReader, new SystemFontFinder(new TrueTypeFontParser())), - new Type1FontHandler(pdfScanner, cMapCache, filterProvider, encryptionHandler, fontDescriptorFactory, encodingReader, + filterProvider, pdfScanner), + new TrueTypeFontHandler(log, pdfScanner, filterProvider, cMapCache, fontDescriptorFactory, trueTypeFontParser, encodingReader, new SystemFontFinder(new TrueTypeFontParser())), + new Type1FontHandler(pdfScanner, cMapCache, filterProvider, fontDescriptorFactory, encodingReader, new Type1FontParser(new Type1EncryptedPortionParser()), compactFontFormatParser), - new Type3FontHandler(pdfScanner, cMapCache, filterProvider, encryptionHandler, encodingReader)); + new Type3FontHandler(pdfScanner, cMapCache, filterProvider, encodingReader)); var resourceContainer = new ResourceContainer(pdfScanner, fontFactory); var pageFactory = new PageFactory(pdfScanner, resourceContainer, filterProvider, - encryptionHandler, new PageContentParser(new ReflectionGraphicsStateOperationFactory()), new XObjectFactory(), log); var informationFactory = new DocumentInformationFactory(); @@ -136,7 +136,7 @@ var caching = new ParsingCachingProviders(bruteForceSearcher, resourceContainer); - var acroFormFactory = new AcroFormFactory(pdfScanner, filterProvider, encryptionHandler); + var acroFormFactory = new AcroFormFactory(pdfScanner, filterProvider); return new PdfDocument(log, inputBytes, version, crossReferenceTable, isLenientParsing, caching, pageFactory, catalog, information, encryptionDictionary, diff --git a/src/UglyToad.PdfPig/Tokenization/Scanner/PdfTokenScanner.cs b/src/UglyToad.PdfPig/Tokenization/Scanner/PdfTokenScanner.cs index 27ef20eb..c0fcfb19 100644 --- a/src/UglyToad.PdfPig/Tokenization/Scanner/PdfTokenScanner.cs +++ b/src/UglyToad.PdfPig/Tokenization/Scanner/PdfTokenScanner.cs @@ -158,6 +158,8 @@ token = readTokens[readTokens.Count - 1]; } + token = encryptionHandler.Decrypt(reference, token); + CurrentToken = new ObjectToken(startPosition, reference, token); objectLocationProvider.UpdateOffset(reference, startPosition); @@ -537,7 +539,7 @@ } // Read the N integers - var bytes = new ByteArrayInputBytes(stream.Decode(filterProvider, encryptionHandler)); + var bytes = new ByteArrayInputBytes(stream.Decode(filterProvider)); var scanner = new CoreTokenScanner(bytes); diff --git a/src/UglyToad.PdfPig/Tokens/StreamToken.cs b/src/UglyToad.PdfPig/Tokens/StreamToken.cs index 40f98ebc..8a9ad5d9 100644 --- a/src/UglyToad.PdfPig/Tokens/StreamToken.cs +++ b/src/UglyToad.PdfPig/Tokens/StreamToken.cs @@ -2,7 +2,6 @@ { using System; using System.Collections.Generic; - using Encryption; using Filters; using Util.JetBrains.Annotations; @@ -39,7 +38,7 @@ Data = data ?? throw new ArgumentNullException(nameof(data)); } - internal IReadOnlyList Decode(IFilterProvider filterProvider, IEncryptionHandler encryptionHandler) + internal IReadOnlyList Decode(IFilterProvider filterProvider) { lock (lockObject) { @@ -50,7 +49,7 @@ var filters = filterProvider.GetFilters(StreamDictionary); - var transform = encryptionHandler.Decrypt(this); + var transform = Data; for (var i = 0; i < filters.Count; i++) { transform = filters[i].Decode(transform, StreamDictionary, i);