Author: tilman
Date: Thu Feb 27 05:31:05 2025
New Revision: 1924073
URL: http://svn.apache.org/viewvc?rev=1924073&view=rev
Log:
PDFBOX-5955: pad encryption key as suggested by Ross Johnson; add test
Modified:
pdfbox/branches/3.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardSecurityHandler.java
pdfbox/branches/3.0/pdfbox/src/test/java/org/apache/pdfbox/encryption/TestSymmetricKeyEncryption.java
Modified:
pdfbox/branches/3.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardSecurityHandler.java
URL:
http://svn.apache.org/viewvc/pdfbox/branches/3.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardSecurityHandler.java?rev=1924073&r1=1924072&r2=1924073&view=diff
==============================================================================
---
pdfbox/branches/3.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardSecurityHandler.java
(original)
+++
pdfbox/branches/3.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardSecurityHandler.java
Thu Feb 27 05:31:05 2025
@@ -238,6 +238,9 @@ public final class StandardSecurityHandl
AccessPermission currentAccessPermission;
+ byte[] encryptedKey;
+ byte[] passwordBytes;
+ boolean isOwnerPassword;
if( isOwnerPassword(password.getBytes(passwordCharset), userKey,
ownerKey,
dicPermissions, documentIDBytes, dicRevision,
dicLength, encryptMetadata) )
@@ -245,26 +248,16 @@ public final class StandardSecurityHandl
currentAccessPermission =
AccessPermission.getOwnerAccessPermission();
setCurrentAccessPermission(currentAccessPermission);
- byte[] computedPassword;
if (dicRevision == REVISION_5 || dicRevision == REVISION_6)
{
- computedPassword = password.getBytes(passwordCharset);
+ passwordBytes = password.getBytes(passwordCharset);
}
else
{
- computedPassword =
getUserPassword234(password.getBytes(passwordCharset),
+ passwordBytes =
getUserPassword234(password.getBytes(passwordCharset),
ownerKey, dicRevision, dicLength );
}
-
- setEncryptionKey(
- computeEncryptedKey(
- computedPassword,
- ownerKey, userKey, oe, ue,
- dicPermissions,
- documentIDBytes,
- dicRevision,
- dicLength,
- encryptMetadata, true));
+ isOwnerPassword = true;
}
else if( isUserPassword(password.getBytes(passwordCharset), userKey,
ownerKey,
dicPermissions, documentIDBytes, dicRevision,
@@ -273,21 +266,27 @@ public final class StandardSecurityHandl
currentAccessPermission = new AccessPermission(dicPermissions);
currentAccessPermission.setReadOnly();
setCurrentAccessPermission(currentAccessPermission);
-
- setEncryptionKey(
- computeEncryptedKey(
- password.getBytes(passwordCharset),
- ownerKey, userKey, oe, ue,
- dicPermissions,
- documentIDBytes,
- dicRevision,
- dicLength,
- encryptMetadata, false));
+ passwordBytes = password.getBytes(passwordCharset);
+ isOwnerPassword = false;
}
else
{
throw new InvalidPasswordException("Cannot decrypt PDF, the
password is incorrect");
}
+ encryptedKey = computeEncryptedKey(
+ passwordBytes,
+ ownerKey, userKey, oe, ue,
+ dicPermissions,
+ documentIDBytes,
+ dicRevision,
+ dicLength,
+ encryptMetadata, isOwnerPassword);
+ if (dicRevision == REVISION_4 && encryptedKey.length < 16)
+ {
+ LOG.info("PDFBOX-5955: padding RC4 key to length 16");
+ encryptedKey = Arrays.copyOf(encryptedKey, 16);
+ }
+ setEncryptionKey(encryptedKey);
if (dicRevision == REVISION_5 || dicRevision == REVISION_6)
{
Modified:
pdfbox/branches/3.0/pdfbox/src/test/java/org/apache/pdfbox/encryption/TestSymmetricKeyEncryption.java
URL:
http://svn.apache.org/viewvc/pdfbox/branches/3.0/pdfbox/src/test/java/org/apache/pdfbox/encryption/TestSymmetricKeyEncryption.java?rev=1924073&r1=1924072&r2=1924073&view=diff
==============================================================================
---
pdfbox/branches/3.0/pdfbox/src/test/java/org/apache/pdfbox/encryption/TestSymmetricKeyEncryption.java
(original)
+++
pdfbox/branches/3.0/pdfbox/src/test/java/org/apache/pdfbox/encryption/TestSymmetricKeyEncryption.java
Thu Feb 27 05:31:05 2025
@@ -20,7 +20,6 @@ import static org.junit.jupiter.api.Asse
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import java.awt.image.BufferedImage;
@@ -58,6 +57,8 @@ import org.apache.pdfbox.pdmodel.encrypt
import org.apache.pdfbox.pdmodel.encryption.StandardSecurityHandler;
import org.apache.pdfbox.pdmodel.graphics.image.ValidateXImage;
import org.apache.pdfbox.rendering.PDFRenderer;
+import org.apache.pdfbox.text.PDFTextStripper;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
@@ -249,6 +250,42 @@ class TestSymmetricKeyEncryption
}
/**
+ * PDFBOX-5955: test unusual RC4 encryption that has 40 or 48 bits instead
of 128.
+ *
+ * @throws IOException
+ */
+ @Test
+ void testPDFBox5955() throws IOException
+ {
+ File file40bit = new File("target/pdfs", "PDFBOX-5955-40bit.pdf");
+ File file48bit = new File("target/pdfs", "PDFBOX-5955-48bit.pdf");
+ try (PDDocument doc = Loader.loadPDF(file40bit))
+ {
+ PDFTextStripper stripper = new PDFTextStripper();
+ String text = stripper.getText(doc);
+ assertTrue(text.contains("0x0446615747"));
+ }
+ try (PDDocument doc = Loader.loadPDF(file40bit, "ownerpass"))
+ {
+ PDFTextStripper stripper = new PDFTextStripper();
+ String text = stripper.getText(doc);
+ assertTrue(text.contains("0x0446615747"));
+ }
+ try (PDDocument doc = Loader.loadPDF(file48bit))
+ {
+ PDFTextStripper stripper = new PDFTextStripper();
+ String text = stripper.getText(doc);
+ assertTrue(text.contains("0x02988E82AFF8"));
+ }
+ try (PDDocument doc = Loader.loadPDF(file48bit, "ownerpass"))
+ {
+ PDFTextStripper stripper = new PDFTextStripper();
+ String text = stripper.getText(doc);
+ assertTrue(text.contains("0x02988E82AFF8"));
+ }
+ }
+
+ /**
* Protect a document with an embedded PDF with a key and try to reopen it
* with that key and compare.
*