Skip to content

Commit a30527d

Browse files
IdamkinIitext-teamcity
authored andcommitted
Merge branch 'feature/DEVSIX-1213' into develop
Autoported commit. Original commit hash: [7cb1896c4]
2 parents 40a6c98 + 5ac1031 commit a30527d

File tree

15 files changed

+509
-3
lines changed

15 files changed

+509
-3
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
using System;
2+
using System.IO;
3+
using iText.IO.Source;
4+
using iText.Kernel.Font;
5+
using iText.Kernel.Pdf;
6+
using iText.Kernel.Pdf.Canvas;
7+
using iText.Kernel.Pdf.Filespec;
8+
using iText.Kernel.Utils;
9+
using iText.Test;
10+
11+
namespace iText.Kernel.Crypto {
12+
public class UnencryptedWrapperTest : ExtendedITextTest {
13+
public static readonly String destinationFolder = NUnit.Framework.TestContext.CurrentContext.TestDirectory
14+
+ "/test/itext/kernel/crypto/UnencryptedWrapperTest/";
15+
16+
public static readonly String sourceFolder = iText.Test.TestUtil.GetParentProjectDirectory(NUnit.Framework.TestContext
17+
.CurrentContext.TestDirectory) + "/resources/itext/kernel/crypto/UnencryptedWrapperTest/";
18+
19+
[NUnit.Framework.OneTimeSetUp]
20+
public static void BeforeClass() {
21+
CreateOrClearDestinationFolder(destinationFolder);
22+
}
23+
24+
/// <exception cref="System.IO.IOException"/>
25+
/// <exception cref="System.Exception"/>
26+
[NUnit.Framework.Test]
27+
public virtual void CreateSimpleWrapperDocumentTest() {
28+
CreateWrapper("customEncryptedDocument.pdf", "simpleUnencryptedWrapper.pdf", "iText");
29+
}
30+
31+
/// <exception cref="System.IO.IOException"/>
32+
/// <exception cref="System.Exception"/>
33+
[NUnit.Framework.Test]
34+
public virtual void ExtractCustomEncryptedDocumentTest() {
35+
ExtractEncrypted("customEncryptedDocument.pdf", "simpleUnencryptedWrapper.pdf", null);
36+
}
37+
38+
/// <exception cref="System.IO.IOException"/>
39+
/// <exception cref="System.Exception"/>
40+
[NUnit.Framework.Test]
41+
public virtual void CreateWrapperForStandardEncryptedTest() {
42+
CreateWrapper("standardEncryptedDocument.pdf", "standardUnencryptedWrapper.pdf", "Standard");
43+
}
44+
45+
/// <exception cref="System.IO.IOException"/>
46+
/// <exception cref="System.Exception"/>
47+
[NUnit.Framework.Test]
48+
public virtual void ExtractStandardEncryptedDocumentTest() {
49+
ExtractEncrypted("standardEncryptedDocument.pdf", "standardUnencryptedWrapper.pdf", "World".GetBytes(iText.IO.Util.EncodingUtil.ISO_8859_1
50+
));
51+
}
52+
53+
/// <exception cref="System.IO.IOException"/>
54+
/// <exception cref="System.Exception"/>
55+
private void CreateWrapper(String encryptedName, String wrapperName, String cryptoFilter) {
56+
String inPath = sourceFolder + "cmp_" + encryptedName;
57+
String cmpPath = sourceFolder + "cmp_" + wrapperName;
58+
String outPath = destinationFolder + wrapperName;
59+
String diff = "diff_" + wrapperName + "_";
60+
PdfDocument document = new PdfDocument(new PdfWriter(outPath, new WriterProperties().SetPdfVersion(PdfVersion
61+
.PDF_2_0)));
62+
PdfFileSpec fs = PdfEncryptedPayloadFileSpecFactory.Create(document, inPath, new PdfEncryptedPayload(cryptoFilter
63+
));
64+
document.SetEncryptedPayload(fs);
65+
PdfFont font = PdfFontFactory.CreateFont();
66+
PdfCanvas canvas = new PdfCanvas(document.AddNewPage());
67+
canvas.SaveState().BeginText().MoveText(36, 750).SetFontAndSize(font, 30).ShowText("Hi! I'm wrapper document."
68+
).EndText().RestoreState();
69+
canvas.Release();
70+
document.Close();
71+
NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(outPath, cmpPath, destinationFolder, diff
72+
));
73+
}
74+
75+
/// <exception cref="System.IO.IOException"/>
76+
/// <exception cref="System.Exception"/>
77+
private void ExtractEncrypted(String encryptedName, String wrapperName, byte[] password) {
78+
String inPath = sourceFolder + "cmp_" + wrapperName;
79+
String cmpPath = sourceFolder + "cmp_" + encryptedName;
80+
String outPath = destinationFolder + encryptedName;
81+
String diff = "diff_" + encryptedName + "_";
82+
PdfDocument document = new PdfDocument(new PdfReader(inPath));
83+
PdfEncryptedPayloadDocument encryptedDocument = document.GetEncryptedPayloadDocument();
84+
byte[] encryptedDocumentBytes = encryptedDocument.GetDocumentBytes();
85+
FileStream fos = new FileStream(outPath, FileMode.Create);
86+
fos.Write(encryptedDocumentBytes);
87+
fos.Dispose();
88+
document.Close();
89+
PdfEncryptedPayload ep = encryptedDocument.GetEncryptedPayload();
90+
NUnit.Framework.Assert.AreEqual(PdfEncryptedPayloadFileSpecFactory.GenerateFileDisplay(ep), encryptedDocument
91+
.GetName());
92+
if (password != null) {
93+
NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(outPath, cmpPath, destinationFolder, diff
94+
, password, password));
95+
}
96+
else {
97+
RandomAccessFileOrArray raf = new RandomAccessFileOrArray(new RandomAccessSourceFactory().CreateBestSource
98+
(cmpPath));
99+
byte[] cmpBytes = new byte[(int)raf.Length()];
100+
raf.ReadFully(cmpBytes);
101+
raf.Close();
102+
NUnit.Framework.Assert.AreEqual(cmpBytes, encryptedDocumentBytes);
103+
}
104+
}
105+
}
106+
}

itext/itext.io/itext/io/LogMessageConstant.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ public sealed class LogMessageConstant {
7878

7979
public const String CLIP_ELEMENT = "Element content was clipped because some height properties are set.";
8080

81+
public const String COLLECTION_DICTIONARY_ALREADY_EXISTS_IT_WILL_BE_MODIFIED = "Collection dictionary already exists. It will be modified.";
82+
8183
public const String COLORANT_INTENSITIES_INVALID = "Some of colorant intensities are invalid: they are bigger than 1 or less than 0. We will force them to become 1 or 0 respectively.";
8284

8385
public const String COLOR_ALPHA_CHANNEL_IS_IGNORED = "Alpha channel {0} was ignored during color creation. Note that opacity can be achieved in some places by using 'setOpacity' method or 'TransparentColor' class";
@@ -104,6 +106,9 @@ public sealed class LogMessageConstant {
104106

105107
public const String ENCOUNTERED_INVALID_MCR = "Corrupted tag structure: encountered invalid marked content reference - it doesn't refer to any page or any mcid. This content reference will be ignored.";
106108

109+
public const String ENCRYPTED_PAYLOAD_FILE_SPEC_SHALL_HAVE_AFRELATIONSHIP_FILED_EQUAL_TO_ENCRYPTED_PAYLOAD
110+
= "Encrypted payload file spec shall have 'AFRelationship' filed equal to 'EncryptedPayload'";
111+
107112
public const String ENCRYPTION_ENTRIES_P_AND_ENCRYPT_METADATA_NOT_CORRESPOND_PERMS_ENTRY = "Encryption dictionary entries P and EncryptMetadata have value that does not correspond to encrypted values in Perms key.";
108113

109114
public const String EXCEPTION_WHILE_CREATING_DEFAULT_FONT = "Exception while creating default font (Helvetica, WinAnsi)";

itext/itext.kernel/itext/kernel/PdfException.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,10 @@ public class PdfException : Exception {
164164

165165
public const String CannotSetDataToPdfstreamWhichWasCreatedByInputStream = "Cannot set data to PdfStream which was created by InputStream.";
166166

167+
public const String CannotSetEncryptedPayloadToDocumentOpenedInReadingMode = "Cannot set encrypted payload to a document opened in read only mode.";
168+
169+
public const String CannotSetEncryptedPayloadToEncryptedDocument = "Cannot set encrypted payload to an encrypted document.";
170+
167171
public const String CannotSplitDocumentThatIsBeingWritten = "Cannot split document that is being written.";
168172

169173
public const String CannotWriteToPdfStream = "Cannot write to PdfStream.";
@@ -216,6 +220,18 @@ public class PdfException : Exception {
216220

217221
public const String ErrorWhileReadingObjectStream = "Error while reading Object Stream.";
218222

223+
public const String EncryptedPayloadFileSpecDoesntHaveEncryptedPayloadDictionary = "Encrypted payload file spec shall have encrypted payload dictionary.";
224+
225+
public const String EncryptedPayloadFileSpecShallBeIndirect = "Encrypted payload file spec shall be indirect.";
226+
227+
public const String EncryptedPayloadFileSpecShallHaveEFDictionary = "Encrypted payload file spec shall have 'EF' key. The value of such key shall be a dictionary that contains embedded file stream.";
228+
229+
public const String EncryptedPayloadFileSpecShallHaveTypeEqualToFilespec = "Encrypted payload file spec shall have 'Type' key. The value of such key shall be 'Filespec'.";
230+
231+
public const String EncryptedPayloadShallHaveTypeEqualsToEncryptedPayloadIfPresent = "Encrypted payload dictionary shall have field 'Type' equal to 'EncryptedPayload' if present";
232+
233+
public const String EncryptedPayloadShallHaveSubtype = "Encrypted payload shall have 'Subtype' field specifying crypto filter";
234+
219235
public const String FailedToGetTsaResponseFrom1 = "Failed to get TSA response from {0}.";
220236

221237
public const String FieldFlatteningIsNotSupportedInAppendMode = "Field flattening is not supported in append mode.";

itext/itext.kernel/itext/kernel/pdf/PdfCatalog.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,23 @@ public virtual void AddDeveloperExtension(PdfDeveloperExtension extension) {
283283
extensions.Put(extension.GetPrefix(), extension.GetDeveloperExtensions());
284284
}
285285

286+
/// <summary>
287+
/// Gets collection dictionary that a conforming reader shall use to enhance the presentation of file attachments
288+
/// stored in the PDF document.
289+
/// </summary>
290+
/// <returns>
291+
///
292+
/// <see cref="iText.Kernel.Pdf.Collection.PdfCollection"/>
293+
/// wrapper of collection dictionary.
294+
/// </returns>
295+
public virtual PdfCollection GetCollection() {
296+
PdfDictionary collectionDictionary = GetPdfObject().GetAsDictionary(PdfName.Collection);
297+
if (collectionDictionary != null) {
298+
return new PdfCollection(collectionDictionary);
299+
}
300+
return null;
301+
}
302+
286303
/// <summary>
287304
/// Sets collection dictionary that a conforming reader shall use to enhance the presentation of file attachments
288305
/// stored in the PDF document.

itext/itext.kernel/itext/kernel/pdf/PdfDocument.cs

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ source product.
5656
using iText.Kernel.Numbering;
5757
using iText.Kernel.Pdf.Annot;
5858
using iText.Kernel.Pdf.Canvas;
59+
using iText.Kernel.Pdf.Collection;
5960
using iText.Kernel.Pdf.Filespec;
6061
using iText.Kernel.Pdf.Navigation;
6162
using iText.Kernel.Pdf.Tagging;
@@ -214,8 +215,7 @@ public PdfDocument(PdfReader reader, PdfWriter writer, StampingProperties proper
214215
this.reader = reader;
215216
this.writer = writer;
216217
this.properties = properties;
217-
bool writerHasEncryption = writer.properties.IsStandardEncryptionUsed() || writer.properties.IsPublicKeyEncryptionUsed
218-
();
218+
bool writerHasEncryption = WriterHasEncryption();
219219
if (properties.appendMode && writerHasEncryption) {
220220
ILog logger = LogManager.GetLogger(typeof(iText.Kernel.Pdf.PdfDocument));
221221
logger.Warn(iText.IO.LogMessageConstant.WRITER_ENCRYPTION_IS_IGNORED_APPEND);
@@ -1432,6 +1432,86 @@ public virtual PdfArray GetAssociatedFiles() {
14321432
return catalog.GetPdfObject().GetAsArray(PdfName.AF);
14331433
}
14341434

1435+
/// <summary>
1436+
/// Gets the encrypted payload of this document,
1437+
/// or returns
1438+
/// <see langword="null"/>
1439+
/// if this document isn't an unencrypted wrapper document.
1440+
/// </summary>
1441+
/// <returns>encrypted payload of this document.</returns>
1442+
public virtual PdfEncryptedPayloadDocument GetEncryptedPayloadDocument() {
1443+
if (GetReader() != null && GetReader().IsEncrypted()) {
1444+
return null;
1445+
}
1446+
PdfCollection collection = GetCatalog().GetCollection();
1447+
if (collection != null && collection.IsViewHidden()) {
1448+
PdfString documentName = collection.GetInitialDocument();
1449+
PdfNameTree embeddedFiles = GetCatalog().GetNameTree(PdfName.EmbeddedFiles);
1450+
String documentNameUnicode = documentName.ToUnicodeString();
1451+
PdfObject fileSpecObject = embeddedFiles.GetNames().Get(documentNameUnicode);
1452+
if (fileSpecObject != null && fileSpecObject.IsDictionary()) {
1453+
try {
1454+
PdfFileSpec fileSpec = PdfEncryptedPayloadFileSpecFactory.Wrap((PdfDictionary)fileSpecObject);
1455+
if (fileSpec != null) {
1456+
PdfDictionary embeddedDictionary = ((PdfDictionary)fileSpec.GetPdfObject()).GetAsDictionary(PdfName.EF);
1457+
PdfStream stream = embeddedDictionary.GetAsStream(PdfName.UF);
1458+
if (stream == null) {
1459+
stream = embeddedDictionary.GetAsStream(PdfName.F);
1460+
}
1461+
if (stream != null) {
1462+
return new PdfEncryptedPayloadDocument(stream, fileSpec, documentNameUnicode);
1463+
}
1464+
}
1465+
}
1466+
catch (PdfException e) {
1467+
LogManager.GetLogger(GetType()).Error(e.Message);
1468+
}
1469+
}
1470+
}
1471+
return null;
1472+
}
1473+
1474+
/// <summary>Sets an encrypted payload, making this document an unencrypted wrapper document.</summary>
1475+
/// <remarks>
1476+
/// Sets an encrypted payload, making this document an unencrypted wrapper document.
1477+
/// The file spec shall include the AFRelationship key with a value of EncryptedPayload,
1478+
/// and shall include an encrypted payload dictionary.
1479+
/// </remarks>
1480+
/// <param name="fs">
1481+
/// encrypted payload file spec.
1482+
/// <see cref="iText.Kernel.Pdf.Filespec.PdfEncryptedPayloadFileSpecFactory"/>
1483+
/// can produce one.
1484+
/// </param>
1485+
public virtual void SetEncryptedPayload(PdfFileSpec fs) {
1486+
if (GetWriter() == null) {
1487+
throw new PdfException(PdfException.CannotSetEncryptedPayloadToDocumentOpenedInReadingMode);
1488+
}
1489+
if (WriterHasEncryption()) {
1490+
throw new PdfException(PdfException.CannotSetEncryptedPayloadToEncryptedDocument);
1491+
}
1492+
if (!PdfName.EncryptedPayload.Equals(((PdfDictionary)fs.GetPdfObject()).Get(PdfName.AFRelationship))) {
1493+
LogManager.GetLogger(GetType()).Error(iText.IO.LogMessageConstant.ENCRYPTED_PAYLOAD_FILE_SPEC_SHALL_HAVE_AFRELATIONSHIP_FILED_EQUAL_TO_ENCRYPTED_PAYLOAD
1494+
);
1495+
}
1496+
PdfEncryptedPayload encryptedPayload = PdfEncryptedPayload.ExtractFrom(fs);
1497+
if (encryptedPayload == null) {
1498+
throw new PdfException(PdfException.EncryptedPayloadFileSpecDoesntHaveEncryptedPayloadDictionary);
1499+
}
1500+
PdfCollection collection = GetCatalog().GetCollection();
1501+
if (collection != null) {
1502+
LogManager.GetLogger(GetType()).Warn(iText.IO.LogMessageConstant.COLLECTION_DICTIONARY_ALREADY_EXISTS_IT_WILL_BE_MODIFIED
1503+
);
1504+
}
1505+
else {
1506+
collection = new PdfCollection();
1507+
GetCatalog().SetCollection(collection);
1508+
}
1509+
collection.SetView(PdfCollection.HIDDEN);
1510+
String displayName = PdfEncryptedPayloadFileSpecFactory.GenerateFileDisplay(encryptedPayload);
1511+
collection.SetInitialDocument(displayName);
1512+
AddAssociatedFile(displayName, fs);
1513+
}
1514+
14351515
/// <summary>This method retrieves the page labels from a document as an array of String objects.</summary>
14361516
/// <returns>
14371517
///
@@ -2148,6 +2228,10 @@ private long GetDocumentId() {
21482228
return documentId;
21492229
}
21502230

2231+
private bool WriterHasEncryption() {
2232+
return writer.properties.IsStandardEncryptionUsed() || writer.properties.IsPublicKeyEncryptionUsed();
2233+
}
2234+
21512235
/// <summary>A structure storing documentId, object number and generation number.</summary>
21522236
/// <remarks>
21532237
/// A structure storing documentId, object number and generation number. This structure is using to calculate
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
using System;
2+
using iText.Kernel;
3+
using iText.Kernel.Pdf.Filespec;
4+
5+
namespace iText.Kernel.Pdf {
6+
public class PdfEncryptedPayload : PdfObjectWrapper<PdfDictionary> {
7+
public PdfEncryptedPayload(String subtype)
8+
: this(new PdfDictionary()) {
9+
GetPdfObject().Put(PdfName.Type, PdfName.EncryptedPayload);
10+
SetSubtype(subtype);
11+
}
12+
13+
private PdfEncryptedPayload(PdfDictionary pdfObject)
14+
: base(pdfObject) {
15+
}
16+
17+
public static iText.Kernel.Pdf.PdfEncryptedPayload ExtractFrom(PdfFileSpec fileSpec) {
18+
if (fileSpec != null && fileSpec.GetPdfObject().IsDictionary()) {
19+
return iText.Kernel.Pdf.PdfEncryptedPayload.Wrap(((PdfDictionary)fileSpec.GetPdfObject()).GetAsDictionary(
20+
PdfName.EP));
21+
}
22+
return null;
23+
}
24+
25+
public static iText.Kernel.Pdf.PdfEncryptedPayload Wrap(PdfDictionary dictionary) {
26+
PdfName type = dictionary.GetAsName(PdfName.Type);
27+
if (type != null && !type.Equals(PdfName.EncryptedPayload)) {
28+
throw new PdfException(PdfException.EncryptedPayloadShallHaveTypeEqualsToEncryptedPayloadIfPresent);
29+
}
30+
if (dictionary.GetAsName(PdfName.Subtype) == null) {
31+
throw new PdfException(PdfException.EncryptedPayloadShallHaveSubtype);
32+
}
33+
return new iText.Kernel.Pdf.PdfEncryptedPayload(dictionary);
34+
}
35+
36+
public virtual PdfName GetSubtype() {
37+
return GetPdfObject().GetAsName(PdfName.Subtype);
38+
}
39+
40+
public virtual iText.Kernel.Pdf.PdfEncryptedPayload SetSubtype(String subtype) {
41+
return SetSubtype(new PdfName(subtype));
42+
}
43+
44+
public virtual iText.Kernel.Pdf.PdfEncryptedPayload SetSubtype(PdfName subtype) {
45+
SetModified();
46+
GetPdfObject().Put(PdfName.Subtype, subtype);
47+
return this;
48+
}
49+
50+
public virtual PdfName GetVersion() {
51+
return GetPdfObject().GetAsName(PdfName.Version);
52+
}
53+
54+
public virtual iText.Kernel.Pdf.PdfEncryptedPayload SetVersion(String version) {
55+
return SetVersion(new PdfName(version));
56+
}
57+
58+
public virtual iText.Kernel.Pdf.PdfEncryptedPayload SetVersion(PdfName version) {
59+
SetModified();
60+
GetPdfObject().Put(PdfName.Version, version);
61+
return this;
62+
}
63+
64+
protected internal override bool IsWrappedObjectMustBeIndirect() {
65+
return false;
66+
}
67+
}
68+
}

0 commit comments

Comments
 (0)