Commit c5ed1b8075f412b2e9cfd9cf01f41ba04d3af2bc

Authored by Jay Berkenbilt
1 parent 551dfbf6

Handle invalid encryption Length (fixes #333)

ChangeLog
1 1 2019-06-22 Jay Berkenbilt <ejb@ql.org>
2 2  
  3 + * Handle encrypted files with missing or invalid /Length entries
  4 + in the encryption dictionary.
  5 +
3 6 * QPDFWriter: allow calling set*EncryptionParameters before
4 7 calling setFilename. Fixes #336.
5 8  
... ...
libqpdf/QPDF_encryption.cc
... ... @@ -935,22 +935,38 @@ QPDF::initializeEncryption()
935 935 pad_short_parameter(Perms, Perms_key_bytes_V5);
936 936 }
937 937  
938   - int Length = 40;
939   - if (encryption_dict.getKey("/Length").isInteger())
  938 + int Length = 0;
  939 + if (V <= 1)
940 940 {
941   - Length = encryption_dict.getKey("/Length").getIntValueAsInt();
942   - if (R < 3)
  941 + Length = 40;
  942 + }
  943 + else if (V == 4)
  944 + {
  945 + Length = 128;
  946 + }
  947 + else if (V == 5)
  948 + {
  949 + Length = 256;
  950 + }
  951 + else
  952 + {
  953 + if (encryption_dict.getKey("/Length").isInteger())
  954 + {
  955 + Length = encryption_dict.getKey("/Length").getIntValueAsInt();
  956 + if ((Length % 8) || (Length < 40) || (Length > 128))
  957 + {
  958 + Length = 0;
  959 + }
  960 + }
  961 + if (Length == 0)
943 962 {
944   - // Force Length to 40 regardless of what the file says.
945   - Length = 40;
  963 + Length = 128;
946 964 }
947   - if ((Length % 8) || (Length < 40) || (Length > 256))
948   - {
949   - throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(),
950   - "encryption dictionary",
951   - this->m->file->getLastOffset(),
952   - "invalid /Length value in encryption dictionary");
953   - }
  965 + }
  966 + if (Length == 0)
  967 + {
  968 + // Still no Length? Just take a guess.
  969 + Length = 128;
954 970 }
955 971  
956 972 this->m->encp->encrypt_metadata = true;
... ...
manual/qpdf-manual.xml
... ... @@ -4353,6 +4353,14 @@ print &quot;\n&quot;;
4353 4353 segmentation fault.
4354 4354 </para>
4355 4355 </listitem>
  4356 + <listitem>
  4357 + <para>
  4358 + When reading encrypted files, follow the spec more closely
  4359 + regarding encryption key length. This allows qpdf to open
  4360 + encrypted files in most cases when they have invalid or
  4361 + missing /Length keys in the encryption dictionary.
  4362 + </para>
  4363 + </listitem>
4356 4364 </itemizedlist>
4357 4365 </listitem>
4358 4366 <listitem>
... ...
qpdf/qtest/qpdf.test
... ... @@ -3523,7 +3523,7 @@ foreach my $d (@enc_key)
3523 3523 }
3524 3524  
3525 3525 # Miscellaneous encryption tests
3526   -$n_tests += 2;
  3526 +$n_tests += 3;
3527 3527  
3528 3528 $td->runtest("set encryption before set filename",
3529 3529 {$td->COMMAND => "test_driver 63 minimal.pdf"},
... ... @@ -3534,6 +3534,11 @@ $td-&gt;runtest(&quot;check file&#39;s validity&quot;,
3534 3534 {$td->FILE => "encrypt-before-filename.out",
3535 3535 $td->EXIT_STATUS => 0},
3536 3536 $td->NORMALIZE_NEWLINES);
  3537 +$td->runtest("handle missing/invalid Length",
  3538 + {$td->COMMAND => "qpdf --check bad-encryption-length.pdf"},
  3539 + {$td->FILE => "bad-encryption-length.out",
  3540 + $td->EXIT_STATUS => 0},
  3541 + $td->NORMALIZE_NEWLINES);
3537 3542  
3538 3543 show_ntests();
3539 3544 # ----------
... ...
qpdf/qtest/qpdf/bad-encryption-length.out 0 → 100644
  1 +checking bad-encryption-length.pdf
  2 +PDF Version: 1.4
  3 +R = 3
  4 +P = -4
  5 +User password =
  6 +extract for accessibility: allowed
  7 +extract for any purpose: allowed
  8 +print low resolution: allowed
  9 +print high resolution: allowed
  10 +modify document assembly: allowed
  11 +modify forms: allowed
  12 +modify annotations: allowed
  13 +modify other: allowed
  14 +modify anything: allowed
  15 +File is not linearized
  16 +No syntax or stream encoding errors found; the file may still contain
  17 +errors that qpdf cannot detect
... ...
qpdf/qtest/qpdf/bad-encryption-length.pdf 0 → 100644
No preview for this file type