aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2019-06-23 02:45:10 +0200
committerJay Berkenbilt <ejb@ql.org>2019-06-23 02:57:33 +0200
commitc5ed1b8075f412b2e9cfd9cf01f41ba04d3af2bc (patch)
tree0e6346b7109b3e133a7796cb3f7c8b4fb212798a
parent551dfbf697736b8cae677d87b7931b5f23f830b8 (diff)
downloadqpdf-c5ed1b8075f412b2e9cfd9cf01f41ba04d3af2bc.tar.zst
Handle invalid encryption Length (fixes #333)
-rw-r--r--ChangeLog3
-rw-r--r--libqpdf/QPDF_encryption.cc42
-rw-r--r--manual/qpdf-manual.xml8
-rw-r--r--qpdf/qtest/qpdf.test7
-rw-r--r--qpdf/qtest/qpdf/bad-encryption-length.out17
-rw-r--r--qpdf/qtest/qpdf/bad-encryption-length.pdf39
6 files changed, 102 insertions, 14 deletions
diff --git a/ChangeLog b/ChangeLog
index efb1d789..63f0233a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,8 @@
2019-06-22 Jay Berkenbilt <ejb@ql.org>
+ * Handle encrypted files with missing or invalid /Length entries
+ in the encryption dictionary.
+
* QPDFWriter: allow calling set*EncryptionParameters before
calling setFilename. Fixes #336.
diff --git a/libqpdf/QPDF_encryption.cc b/libqpdf/QPDF_encryption.cc
index b5f16e0c..b15cb29d 100644
--- a/libqpdf/QPDF_encryption.cc
+++ b/libqpdf/QPDF_encryption.cc
@@ -935,22 +935,38 @@ QPDF::initializeEncryption()
pad_short_parameter(Perms, Perms_key_bytes_V5);
}
- int Length = 40;
- if (encryption_dict.getKey("/Length").isInteger())
+ int Length = 0;
+ if (V <= 1)
{
- Length = encryption_dict.getKey("/Length").getIntValueAsInt();
- if (R < 3)
+ Length = 40;
+ }
+ else if (V == 4)
+ {
+ Length = 128;
+ }
+ else if (V == 5)
+ {
+ Length = 256;
+ }
+ else
+ {
+ if (encryption_dict.getKey("/Length").isInteger())
+ {
+ Length = encryption_dict.getKey("/Length").getIntValueAsInt();
+ if ((Length % 8) || (Length < 40) || (Length > 128))
+ {
+ Length = 0;
+ }
+ }
+ if (Length == 0)
{
- // Force Length to 40 regardless of what the file says.
- Length = 40;
+ Length = 128;
}
- if ((Length % 8) || (Length < 40) || (Length > 256))
- {
- throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(),
- "encryption dictionary",
- this->m->file->getLastOffset(),
- "invalid /Length value in encryption dictionary");
- }
+ }
+ if (Length == 0)
+ {
+ // Still no Length? Just take a guess.
+ Length = 128;
}
this->m->encp->encrypt_metadata = true;
diff --git a/manual/qpdf-manual.xml b/manual/qpdf-manual.xml
index 3bd1f259..956f4d19 100644
--- a/manual/qpdf-manual.xml
+++ b/manual/qpdf-manual.xml
@@ -4353,6 +4353,14 @@ print "\n";
segmentation fault.
</para>
</listitem>
+ <listitem>
+ <para>
+ When reading encrypted files, follow the spec more closely
+ regarding encryption key length. This allows qpdf to open
+ encrypted files in most cases when they have invalid or
+ missing /Length keys in the encryption dictionary.
+ </para>
+ </listitem>
</itemizedlist>
</listitem>
<listitem>
diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test
index 0274f604..0329d35a 100644
--- a/qpdf/qtest/qpdf.test
+++ b/qpdf/qtest/qpdf.test
@@ -3523,7 +3523,7 @@ foreach my $d (@enc_key)
}
# Miscellaneous encryption tests
-$n_tests += 2;
+$n_tests += 3;
$td->runtest("set encryption before set filename",
{$td->COMMAND => "test_driver 63 minimal.pdf"},
@@ -3534,6 +3534,11 @@ $td->runtest("check file's validity",
{$td->FILE => "encrypt-before-filename.out",
$td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
+$td->runtest("handle missing/invalid Length",
+ {$td->COMMAND => "qpdf --check bad-encryption-length.pdf"},
+ {$td->FILE => "bad-encryption-length.out",
+ $td->EXIT_STATUS => 0},
+ $td->NORMALIZE_NEWLINES);
show_ntests();
# ----------
diff --git a/qpdf/qtest/qpdf/bad-encryption-length.out b/qpdf/qtest/qpdf/bad-encryption-length.out
new file mode 100644
index 00000000..c59b750e
--- /dev/null
+++ b/qpdf/qtest/qpdf/bad-encryption-length.out
@@ -0,0 +1,17 @@
+checking bad-encryption-length.pdf
+PDF Version: 1.4
+R = 3
+P = -4
+User password =
+extract for accessibility: allowed
+extract for any purpose: allowed
+print low resolution: allowed
+print high resolution: allowed
+modify document assembly: allowed
+modify forms: allowed
+modify annotations: allowed
+modify other: allowed
+modify anything: allowed
+File is not linearized
+No syntax or stream encoding errors found; the file may still contain
+errors that qpdf cannot detect
diff --git a/qpdf/qtest/qpdf/bad-encryption-length.pdf b/qpdf/qtest/qpdf/bad-encryption-length.pdf
new file mode 100644
index 00000000..46fac865
--- /dev/null
+++ b/qpdf/qtest/qpdf/bad-encryption-length.pdf
@@ -0,0 +1,39 @@
+%PDF-1.4
+%¿÷¢þ
+1 0 obj
+<< /Pages 2 0 R /Type /Catalog >>
+endobj
+2 0 obj
+<< /Count 1 /Kids [ 3 0 R ] /Type /Pages >>
+endobj
+3 0 obj
+<< /Contents 4 0 R /MediaBox [ 0 0 612 792 ] /Parent 2 0 R /Resources << /Font << /F1 5 0 R >> /ProcSet 6 0 R >> /Type /Page >>
+endobj
+4 0 obj
+<< /Length 48 /Filter /FlateDecode >>
+stream
+u|+»[ –ØÄksBþSXŒA*–¥Oš<®" J(V¡¢zÉüL[}-šendstream
+endobj
+5 0 obj
+<< /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font >>
+endobj
+6 0 obj
+[ /PDF /Text ]
+endobj
+7 0 obj
+<< /Filter /Standard /Wength 128 /O <77b8fb098022d3ab34237ea5643c08710ea5123fc5f88bf993a68cca5f12b40f> /P -4 /R 3 /U <72ba254904669105f93c01524fceaa320122456a91bae5134273a6db134c87c4> /V 2 >>
+endobj
+xref
+0 8
+0000000000 65535 f
+0000000015 00000 n
+0000000064 00000 n
+0000000123 00000 n
+0000000266 00000 n
+0000000384 00000 n
+0000000491 00000 n
+0000000521 00000 n
+trailer << /Root 1 0 R /Size 8 /ID [<2dc7d3d0f5f5b44e5b39ff85e8a4f70c><2dc7d3d0f5f5b44e5b39ff85e8a4f70c>] /Encrypt 7 0 R >>
+startxref
+728
+%%EOF