You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ti...@apache.org on 2014/11/14 20:13:08 UTC
svn commit: r1639740 -
/pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/encryption/TestSymmetricKeyEncryption.java
Author: tilman
Date: Fri Nov 14 19:13:08 2014
New Revision: 1639740
URL: http://svn.apache.org/r1639740
Log:
PDFBOX-2456: add the check of permissions for three files created by Maruan Sahyoun with Adobe Reader; expand existing tests for seq and nonseq parser and open with owner and user password
Modified:
pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/encryption/TestSymmetricKeyEncryption.java
Modified: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/encryption/TestSymmetricKeyEncryption.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/encryption/TestSymmetricKeyEncryption.java?rev=1639740&r1=1639739&r2=1639740&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/encryption/TestSymmetricKeyEncryption.java (original)
+++ pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/encryption/TestSymmetricKeyEncryption.java Fri Nov 14 19:13:08 2014
@@ -51,9 +51,16 @@ import org.apache.pdfbox.rendering.PDFRe
import org.junit.Assert;
/**
- * Tests for public key encryption.
+ * Tests for symmetric key encryption.
+ *
+ * IMPORTANT! When making changes in the encryption / decryption methods, do
+ * also check whether the six generated encrypted files (to be found in
+ * pdfbox/target/test-output/crypto and named *encrypted.pdf) can be opened with
+ * Adobe Reader by providing the owner password and the user password.
*
* @author Ralf Hauser
+ * @author Tilman Hausherr
+ *
*/
public class TestSymmetricKeyEncryption extends TestCase
{
@@ -64,10 +71,10 @@ public class TestSymmetricKeyEncryption
private final File testResultsDir = new File("target/test-output/crypto");
- private AccessPermission permission1;
- private AccessPermission permission2;
+ private AccessPermission permission;
- static final String PASSWORD = "1234567890abcdefghijk1234567890abcdefghijk";
+ static final String USERPASSWORD = "1234567890abcdefghijk1234567890abcdefghijk";
+ static final String OWNERPASSWORD = "abcdefghijk1234567890abcdefghijk1234567890";
/**
* {@inheritDoc}
@@ -83,26 +90,142 @@ public class TestSymmetricKeyEncryption
fail("JCE unlimited strength jurisdiction policy files are not installed");
}
- permission1 = new AccessPermission();
- permission1.setCanAssembleDocument(false);
- permission1.setCanExtractContent(false);
- permission1.setCanExtractForAccessibility(true);
- permission1.setCanFillInForm(false);
- permission1.setCanModify(false);
- permission1.setCanModifyAnnotations(false);
- permission1.setCanPrint(false);
- permission1.setCanPrintDegraded(false);
- permission1.setReadOnly();
-
- permission2 = new AccessPermission();
- permission2.setCanAssembleDocument(false);
- permission2.setCanExtractContent(false);
- permission2.setCanExtractForAccessibility(true);
- permission2.setCanFillInForm(false);
- permission2.setCanModify(false);
- permission2.setCanModifyAnnotations(false);
- permission2.setCanPrint(true); // it is true now !
- permission2.setCanPrintDegraded(false);
+ permission = new AccessPermission();
+ permission.setCanAssembleDocument(false);
+ permission.setCanExtractContent(false);
+ permission.setCanExtractForAccessibility(true);
+ permission.setCanFillInForm(false);
+ permission.setCanModify(false);
+ permission.setCanModifyAnnotations(false);
+ permission.setCanPrint(true);
+ permission.setCanPrintDegraded(false);
+ permission.setReadOnly();
+ }
+
+ /**
+ * Test that permissions work as intended: the user psw ("user") is enough
+ * to open the PDF with possibly restricted rights, the owner psw ("owner")
+ * gives full permissions. The 3 files of this test were created by Maruan
+ * Sayhoun, NOT with PDFBox, but with Adobe Acrobat to ensure "the gold
+ * standard". The restricted permissions prevent printing and text
+ * extraction. In the 128 and 256 bit encrypted files, AssembleDocument,
+ * ExtractForAccessibility and PrintDegraded are also disabled.
+ */
+ public void testPermissions() throws Exception
+ {
+ AccessPermission fullAP = new AccessPermission();
+ AccessPermission restrAP = new AccessPermission();
+ restrAP.setCanPrint(false);
+ restrAP.setCanExtractContent(false);
+ restrAP.setCanModify(false);
+
+ byte[] inputFileAsByteArray = getFileResourceAsByteArray("PasswordSample-40bit.pdf");
+ checkPerms(inputFileAsByteArray, "owner", false, fullAP);
+ checkPerms(inputFileAsByteArray, "owner", true, fullAP);
+ checkPerms(inputFileAsByteArray, "user", false, restrAP);
+ checkPerms(inputFileAsByteArray, "user", true, restrAP);
+ try
+ {
+ checkPerms(inputFileAsByteArray, "", false, null);
+ fail("wrong password not detected");
+ }
+ catch (IOException ex)
+ {
+ assertEquals("Cannot decrypt PDF, the password is incorrect", ex.getMessage());
+ }
+ try
+ {
+ checkPerms(inputFileAsByteArray, "", true, null);
+ fail("wrong password not detected");
+ }
+ catch (IOException ex)
+ {
+ assertEquals("Cannot decrypt PDF, the password is incorrect", ex.getMessage());
+ }
+
+ restrAP.setCanAssembleDocument(false);
+ restrAP.setCanExtractForAccessibility(false);
+ restrAP.setCanPrintDegraded(false);
+
+ inputFileAsByteArray = getFileResourceAsByteArray("PasswordSample-128bit.pdf");
+ checkPerms(inputFileAsByteArray, "owner", false, fullAP);
+ checkPerms(inputFileAsByteArray, "owner", true, fullAP);
+ checkPerms(inputFileAsByteArray, "user", false, restrAP);
+ checkPerms(inputFileAsByteArray, "user", true, restrAP);
+ try
+ {
+ checkPerms(inputFileAsByteArray, "", false, null);
+ fail("wrong password not detected");
+ }
+ catch (IOException ex)
+ {
+ }
+ try
+ {
+ checkPerms(inputFileAsByteArray, "", true, null);
+ fail("wrong password not detected");
+ }
+ catch (IOException ex)
+ {
+ }
+
+ inputFileAsByteArray = getFileResourceAsByteArray("PasswordSample-256bit.pdf");
+ checkPerms(inputFileAsByteArray, "owner", false, fullAP);
+ checkPerms(inputFileAsByteArray, "owner", true, fullAP);
+ checkPerms(inputFileAsByteArray, "user", false, restrAP);
+ checkPerms(inputFileAsByteArray, "user", true, restrAP);
+ try
+ {
+ checkPerms(inputFileAsByteArray, "", false, null);
+ fail("wrong password not detected");
+ }
+ catch (IOException ex)
+ {
+ }
+ try
+ {
+ checkPerms(inputFileAsByteArray, "", true, null);
+ fail("wrong password not detected");
+ }
+ catch (IOException ex)
+ {
+ }
+ }
+
+ private void checkPerms(byte[] inputFileAsByteArray, String password, boolean nonSeq,
+ AccessPermission expectedPermissions) throws IOException
+ {
+ PDDocument doc;
+ if (nonSeq)
+ {
+ doc = PDDocument.loadNonSeq(
+ new ByteArrayInputStream(inputFileAsByteArray),
+ password);
+ }
+ else
+ {
+ doc = PDDocument.load(new ByteArrayInputStream(inputFileAsByteArray));
+ Assert.assertTrue(doc.isEncrypted());
+ DecryptionMaterial decryptionMaterial = new StandardDecryptionMaterial(password);
+ doc.openProtection(decryptionMaterial);
+ }
+ AccessPermission currentAccessPermission = doc.getCurrentAccessPermission();
+
+ // check permissions
+ assertEquals(expectedPermissions.isOwnerPermission(), currentAccessPermission.isOwnerPermission());
+ assertEquals(expectedPermissions.isReadOnly(), currentAccessPermission.isReadOnly());
+ assertEquals(expectedPermissions.canAssembleDocument(), currentAccessPermission.canAssembleDocument());
+ assertEquals(expectedPermissions.canExtractContent(), currentAccessPermission.canExtractContent());
+ assertEquals(expectedPermissions.canExtractForAccessibility(), currentAccessPermission.canExtractForAccessibility());
+ assertEquals(expectedPermissions.canFillInForm(), currentAccessPermission.canFillInForm());
+ assertEquals(expectedPermissions.canModify(), currentAccessPermission.canModify());
+ assertEquals(expectedPermissions.canModifyAnnotations(), currentAccessPermission.canModifyAnnotations());
+ assertEquals(expectedPermissions.canPrint(), currentAccessPermission.canPrint());
+ assertEquals(expectedPermissions.canPrintDegraded(), currentAccessPermission.canPrintDegraded());
+
+ new PDFRenderer(doc).renderImage(0);
+
+ doc.close();
}
/**
@@ -116,15 +239,20 @@ public class TestSymmetricKeyEncryption
byte[] inputFileAsByteArray = getFileResourceAsByteArray("Acroform-PDFBOX-2333.pdf");
int sizePriorToEncryption = inputFileAsByteArray.length;
- testSymmEncrForKeySize(40, sizePriorToEncryption, inputFileAsByteArray, PASSWORD, permission1, false);
- testSymmEncrForKeySize(40, sizePriorToEncryption, inputFileAsByteArray, PASSWORD, permission1, true);
-
- testSymmEncrForKeySize(128, sizePriorToEncryption, inputFileAsByteArray, PASSWORD, permission1, false);
- testSymmEncrForKeySize(128, sizePriorToEncryption, inputFileAsByteArray, PASSWORD, permission1, true);
-
- testSymmEncrForKeySize(256, sizePriorToEncryption, inputFileAsByteArray, PASSWORD, permission1, false);
- testSymmEncrForKeySize(256, sizePriorToEncryption, inputFileAsByteArray, PASSWORD, permission1, true);
- //TODO check permissions
+ testSymmEncrForKeySize(40, sizePriorToEncryption, inputFileAsByteArray,
+ USERPASSWORD, OWNERPASSWORD, permission, false);
+ testSymmEncrForKeySize(40, sizePriorToEncryption, inputFileAsByteArray,
+ USERPASSWORD, OWNERPASSWORD, permission, true);
+
+ testSymmEncrForKeySize(128, sizePriorToEncryption, inputFileAsByteArray,
+ USERPASSWORD, OWNERPASSWORD, permission, false);
+ testSymmEncrForKeySize(128, sizePriorToEncryption, inputFileAsByteArray,
+ USERPASSWORD, OWNERPASSWORD, permission, true);
+
+ testSymmEncrForKeySize(256, sizePriorToEncryption, inputFileAsByteArray,
+ USERPASSWORD, OWNERPASSWORD, permission, false);
+ testSymmEncrForKeySize(256, sizePriorToEncryption, inputFileAsByteArray,
+ USERPASSWORD, OWNERPASSWORD, permission, true);
}
/**
@@ -143,18 +271,25 @@ public class TestSymmetricKeyEncryption
File extractedEmbeddedFile
= extractEmbeddedFile(new ByteArrayInputStream(inputFileWithEmbeddedFileAsByteArray), "innerFile.pdf");
- testSymmEncrForKeySizeInner(40, sizeOfFileWithEmbeddedFile, inputFileWithEmbeddedFileAsByteArray, extractedEmbeddedFile, false);
- testSymmEncrForKeySizeInner(40, sizeOfFileWithEmbeddedFile, inputFileWithEmbeddedFileAsByteArray, extractedEmbeddedFile, true);
-
- testSymmEncrForKeySizeInner(128, sizeOfFileWithEmbeddedFile, inputFileWithEmbeddedFileAsByteArray, extractedEmbeddedFile, false);
- testSymmEncrForKeySizeInner(128, sizeOfFileWithEmbeddedFile, inputFileWithEmbeddedFileAsByteArray, extractedEmbeddedFile, true);
-
- testSymmEncrForKeySizeInner(256, sizeOfFileWithEmbeddedFile, inputFileWithEmbeddedFileAsByteArray, extractedEmbeddedFile, false);
- testSymmEncrForKeySizeInner(256, sizeOfFileWithEmbeddedFile, inputFileWithEmbeddedFileAsByteArray, extractedEmbeddedFile, true);
+ testSymmEncrForKeySizeInner(40, sizeOfFileWithEmbeddedFile,
+ inputFileWithEmbeddedFileAsByteArray, extractedEmbeddedFile, false, USERPASSWORD, OWNERPASSWORD);
+ testSymmEncrForKeySizeInner(40, sizeOfFileWithEmbeddedFile,
+ inputFileWithEmbeddedFileAsByteArray, extractedEmbeddedFile, true, USERPASSWORD, OWNERPASSWORD);
+
+ testSymmEncrForKeySizeInner(128, sizeOfFileWithEmbeddedFile,
+ inputFileWithEmbeddedFileAsByteArray, extractedEmbeddedFile, false, USERPASSWORD, OWNERPASSWORD);
+ testSymmEncrForKeySizeInner(128, sizeOfFileWithEmbeddedFile,
+ inputFileWithEmbeddedFileAsByteArray, extractedEmbeddedFile, true, USERPASSWORD, OWNERPASSWORD);
+
+ testSymmEncrForKeySizeInner(256, sizeOfFileWithEmbeddedFile,
+ inputFileWithEmbeddedFileAsByteArray, extractedEmbeddedFile, false, USERPASSWORD, OWNERPASSWORD);
+ testSymmEncrForKeySizeInner(256, sizeOfFileWithEmbeddedFile,
+ inputFileWithEmbeddedFileAsByteArray, extractedEmbeddedFile, true, USERPASSWORD, OWNERPASSWORD);
}
private void testSymmEncrForKeySize(int keyLength,
- int sizePriorToEncr, byte [] inputFileAsByteArray, String password,
+ int sizePriorToEncr, byte[] inputFileAsByteArray,
+ String userpassword, String ownerpassword,
AccessPermission permission, boolean nonSeq) throws IOException
{
PDDocument document = PDDocument.load(new ByteArrayInputStream(inputFileAsByteArray));
@@ -174,68 +309,42 @@ public class TestSymmetricKeyEncryption
srcContentStreamTab.add(baos);
}
- PDDocument encryptedDoc = encrypt(keyLength, sizePriorToEncr, document, prefix, permission, nonSeq);
-
- try
- {
- AccessPermission newPermission = encryptedDoc.getCurrentAccessPermission();
+ PDDocument encryptedDoc = encrypt(keyLength, sizePriorToEncr, document,
+ prefix, permission, nonSeq, userpassword, ownerpassword);
- Assert.assertEquals(numSrcPages, encryptedDoc.getNumberOfPages());
- pdfRenderer = new PDFRenderer(encryptedDoc);
- for (int i = 0; i < encryptedDoc.getNumberOfPages(); ++i)
- {
- // compare content stream
- BufferedImage bim = pdfRenderer.renderImage(i);
- ValidateXImage.checkIdent(bim, srcImgTab.get(i));
-
- // compare content streams
- COSStream contentStreamDecr = encryptedDoc.getPage(i).getContentStream();
- InputStream unfilteredStream = contentStreamDecr.getUnfilteredStream();
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- IOUtils.copy(unfilteredStream, baos);
- unfilteredStream.close();
- Assert.assertArrayEquals("content stream of page " + i + " not identical",
- srcContentStreamTab.get(i).toByteArray(),
- baos.toByteArray());
- }
-
- File pdfFile = new File(testResultsDir, prefix + keyLength + "-bit-decrypted.pdf");
- encryptedDoc.setAllSecurityToBeRemoved(true);
- encryptedDoc.save(pdfFile);
-
- boolean canAssembleDocument = newPermission.canAssembleDocument();
- boolean canExtractContent = newPermission.canExtractContent();
- boolean canExtractForAccessibility = newPermission
- .canExtractForAccessibility();
- boolean canFillInForm = newPermission.canFillInForm();
- boolean canModify = newPermission.canModify();
- boolean canModifyAnnotations = newPermission.canModifyAnnotations();
- boolean canPrint = newPermission.canPrint();
- boolean canPrintDegraded = newPermission.canPrintDegraded();
- encryptedDoc.close();
-// Assert.assertFalse(canAssembleDocument);
-// Assert.assertFalse(canExtractContent);
-// Assert.assertTrue(canExtractForAccessibility);
-// Assert.assertFalse(canFillInForm);
-// Assert.assertFalse(canModify);
-// Assert.assertFalse(canModifyAnnotations);
-// Assert.assertFalse(canPrint);
-// Assert.assertFalse(canPrintDegraded);
- }
- finally
+ Assert.assertEquals(numSrcPages, encryptedDoc.getNumberOfPages());
+ pdfRenderer = new PDFRenderer(encryptedDoc);
+ for (int i = 0; i < encryptedDoc.getNumberOfPages(); ++i)
{
- encryptedDoc.close();
+ // compare rendering
+ BufferedImage bim = pdfRenderer.renderImage(i);
+ ValidateXImage.checkIdent(bim, srcImgTab.get(i));
+
+ // compare content streams
+ COSStream contentStreamDecr = encryptedDoc.getPage(i).getContentStream();
+ InputStream unfilteredStream = contentStreamDecr.getUnfilteredStream();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ IOUtils.copy(unfilteredStream, baos);
+ unfilteredStream.close();
+ Assert.assertArrayEquals("content stream of page " + i + " not identical",
+ srcContentStreamTab.get(i).toByteArray(),
+ baos.toByteArray());
}
+
+ File pdfFile = new File(testResultsDir, prefix + keyLength + "-bit-decrypted.pdf");
+ encryptedDoc.setAllSecurityToBeRemoved(true);
+ encryptedDoc.save(pdfFile);
+ encryptedDoc.close();
}
// encrypt with keylength and permission, save, check sizes before and after encryption
// reopen, decrypt and return document
private PDDocument encrypt(int keyLength, int sizePriorToEncr,
PDDocument doc, String prefix, AccessPermission permission,
- boolean nonSeq) throws IOException
+ boolean nonSeq, String userpassword, String ownerpassword) throws IOException
{
AccessPermission ap = new AccessPermission();
- StandardProtectionPolicy spp = new StandardProtectionPolicy(PASSWORD, PASSWORD, ap);
+ StandardProtectionPolicy spp = new StandardProtectionPolicy(ownerpassword, userpassword, ap);
spp.setEncryptionKeyLength(keyLength);
spp.setPermissions(permission);
doc.protect(spp);
@@ -250,17 +359,37 @@ public class TestSymmetricKeyEncryption
sizeEncrypted != sizePriorToEncr);
PDDocument encryptedDoc;
+
+ // test with owner password => full permissions
+ if (nonSeq)
+ {
+ encryptedDoc = PDDocument.loadNonSeq(pdfFile, ownerpassword);
+ }
+ else
+ {
+ encryptedDoc = PDDocument.load(pdfFile);
+ Assert.assertTrue(encryptedDoc.isEncrypted());
+ DecryptionMaterial decryptionMaterial = new StandardDecryptionMaterial(ownerpassword);
+ encryptedDoc.openProtection(decryptionMaterial);
+ }
+ Assert.assertTrue(encryptedDoc.getCurrentAccessPermission().isOwnerPermission());
+ encryptedDoc.close();
+
+ // test with owner password => restricted permissions
if (nonSeq)
{
- encryptedDoc = PDDocument.loadNonSeq(pdfFile, PASSWORD);
+ encryptedDoc = PDDocument.loadNonSeq(pdfFile, userpassword);
}
else
{
encryptedDoc = PDDocument.load(pdfFile);
Assert.assertTrue(encryptedDoc.isEncrypted());
- DecryptionMaterial decryptionMaterial = new StandardDecryptionMaterial(PASSWORD);
+ DecryptionMaterial decryptionMaterial = new StandardDecryptionMaterial(userpassword);
encryptedDoc.openProtection(decryptionMaterial);
}
+ Assert.assertFalse(encryptedDoc.getCurrentAccessPermission().isOwnerPermission());
+
+ assertEquals(permission.getPermissionBytes(), encryptedDoc.getCurrentAccessPermission().getPermissionBytes());
return encryptedDoc;
}
@@ -295,52 +424,26 @@ public class TestSymmetricKeyEncryption
private void testSymmEncrForKeySizeInner(int keyLength,
int sizePriorToEncr, byte[] inputFileWithEmbeddedFileAsByteArray,
- File embeddedFilePriorToEncryption, boolean nonSeq) throws IOException
+ File embeddedFilePriorToEncryption, boolean nonSeq,
+ String userpassword, String ownerpassword) throws IOException
{
PDDocument document = PDDocument.load(new ByteArrayInputStream(inputFileWithEmbeddedFileAsByteArray));
- PDDocument encryptedDoc = encrypt(keyLength, sizePriorToEncr, document, "ContainsEmbedded-", permission1, nonSeq);
-
- try
- {
- AccessPermission permission = encryptedDoc.getCurrentAccessPermission();
+ PDDocument encryptedDoc = encrypt(keyLength, sizePriorToEncr, document, "ContainsEmbedded-", permission, nonSeq, userpassword, ownerpassword);
- File decryptedFile = new File(testResultsDir, "DecryptedContainsEmbedded-" + keyLength + "-bit.pdf");
- encryptedDoc.setAllSecurityToBeRemoved(true);
- encryptedDoc.save(decryptedFile);
-
- File extractedEmbeddedFile = extractEmbeddedFile(new FileInputStream(decryptedFile), "decryptedInnerFile-" + keyLength + "-bit.pdf");
-
- Assert.assertEquals(keyLength + "-bit decrypted inner attachment pdf should have same size as plain one",
- embeddedFilePriorToEncryption.length(), extractedEmbeddedFile.length());
-
- // compare the two embedded files
- Assert.assertArrayEquals(
- getFileAsByteArray(embeddedFilePriorToEncryption),
- getFileAsByteArray(extractedEmbeddedFile));
-
- boolean canAssembleDocument = permission.canAssembleDocument();
- boolean canExtractContent = permission.canExtractContent();
- boolean canExtractForAccessibility = permission
- .canExtractForAccessibility();
- boolean canFillInForm = permission.canFillInForm();
- boolean canModify = permission.canModify();
- boolean canModifyAnnotations = permission.canModifyAnnotations();
- boolean canPrint = permission.canPrint();
- boolean canPrintDegraded = permission.canPrintDegraded();
- encryptedDoc.close();
- // Assert.assertFalse(canAssembleDocument);
- // Assert.assertFalse(canExtractContent);
- // Assert.assertTrue(canExtractForAccessibility);
- // Assert.assertFalse(canFillInForm);
- // Assert.assertFalse(canModify);
- // Assert.assertFalse(canModifyAnnotations);
- // Assert.assertFalse(canPrint);
- // Assert.assertFalse(canPrintDegraded);
- }
- finally
- {
- encryptedDoc.close();
- }
+ File decryptedFile = new File(testResultsDir, "DecryptedContainsEmbedded-" + keyLength + "-bit.pdf");
+ encryptedDoc.setAllSecurityToBeRemoved(true);
+ encryptedDoc.save(decryptedFile);
+
+ File extractedEmbeddedFile = extractEmbeddedFile(new FileInputStream(decryptedFile), "decryptedInnerFile-" + keyLength + "-bit.pdf");
+
+ Assert.assertEquals(keyLength + "-bit decrypted inner attachment pdf should have same size as plain one",
+ embeddedFilePriorToEncryption.length(), extractedEmbeddedFile.length());
+
+ // compare the two embedded files
+ Assert.assertArrayEquals(
+ getFileAsByteArray(embeddedFilePriorToEncryption),
+ getFileAsByteArray(extractedEmbeddedFile));
+ encryptedDoc.close();
}
private byte[] getStreamAsByteArray(InputStream is) throws IOException