Handle invalid encryption Length (fixes #333)

This commit is contained in:
Jay Berkenbilt 2019-06-22 20:45:10 -04:00
parent 551dfbf697
commit c5ed1b8075
6 changed files with 102 additions and 14 deletions

View File

@ -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.

View File

@ -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())
{
// Force Length to 40 regardless of what the file says.
Length = 40;
Length = encryption_dict.getKey("/Length").getIntValueAsInt();
if ((Length % 8) || (Length < 40) || (Length > 128))
{
Length = 0;
}
}
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)
{
Length = 128;
}
}
if (Length == 0)
{
// Still no Length? Just take a guess.
Length = 128;
}
this->m->encp->encrypt_metadata = true;

View File

@ -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>

View File

@ -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();
# ----------

View File

@ -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

View File

@ -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¨<<3C>®"<22> J(<28>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