Commit 5da146c8b53bb5a12c514f83fb52265e4922b5e1

Authored by Jay Berkenbilt
1 parent 5a0aef55

Track separately whether password was user/owner (fixes #159)

ChangeLog
  1 +2019-08-24 Jay Berkenbilt <ejb@ql.org>
  2 +
  3 + * Add QPDF::userPasswordMatched() and QPDF::ownerPasswordMatched()
  4 + methods so it can be deterined separately whether the supplied
  5 + password matched the user password, the owner password, or both.
  6 + Fixes #159.
  7 +
1 8 2019-08-23 Jay Berkenbilt <ejb@ql.org>
2 9  
3 10 * Add --recompress-streams option to qpdf and
... ...
include/qpdf/QPDF.hh
... ... @@ -406,6 +406,12 @@ class QPDF
406 406 encryption_method_e& string_method,
407 407 encryption_method_e& file_method);
408 408  
  409 + QPDF_DLL
  410 + bool ownerPasswordMatched() const;
  411 +
  412 + QPDF_DLL
  413 + bool userPasswordMatched() const;
  414 +
409 415 // Encryption permissions -- not enforced by QPDF
410 416 QPDF_DLL
411 417 bool allowAccessibility();
... ... @@ -756,6 +762,8 @@ class QPDF
756 762 std::string cached_object_encryption_key;
757 763 int cached_key_objid;
758 764 int cached_key_generation;
  765 + bool user_password_matched;
  766 + bool owner_password_matched;
759 767 };
760 768  
761 769 class ForeignStreamData
... ...
libqpdf/QPDF.cc
... ... @@ -132,7 +132,9 @@ QPDF::EncryptionParameters::EncryptionParameters() :
132 132 cf_string(e_none),
133 133 cf_file(e_none),
134 134 cached_key_objid(0),
135   - cached_key_generation(0)
  135 + cached_key_generation(0),
  136 + user_password_matched(false),
  137 + owner_password_matched(false)
136 138 {
137 139 }
138 140  
... ...
libqpdf/QPDF_encryption.cc
... ... @@ -1041,21 +1041,43 @@ QPDF::initializeEncryption()
1041 1041 {
1042 1042 // ignore passwords in file
1043 1043 }
1044   - else if (check_owner_password(
1045   - this->m->encp->user_password,
1046   - this->m->encp->provided_password, data))
1047   - {
1048   - // password supplied was owner password; user_password has
1049   - // been initialized for V < 5
1050   - }
1051   - else if (check_user_password(this->m->encp->provided_password, data))
1052   - {
1053   - this->m->encp->user_password = this->m->encp->provided_password;
1054   - }
1055 1044 else
1056 1045 {
1057   - throw QPDFExc(qpdf_e_password, this->m->file->getName(),
1058   - "", 0, "invalid password");
  1046 + this->m->encp->owner_password_matched = check_owner_password(
  1047 + this->m->encp->user_password,
  1048 + this->m->encp->provided_password, data);
  1049 + if (this->m->encp->owner_password_matched && (V < 5))
  1050 + {
  1051 + // password supplied was owner password; user_password has
  1052 + // been initialized for V < 5
  1053 + if (getTrimmedUserPassword() == this->m->encp->provided_password)
  1054 + {
  1055 + this->m->encp->user_password_matched = true;
  1056 + QTC::TC("qpdf", "QPDF_encryption user matches owner V < 5");
  1057 + }
  1058 + }
  1059 + else
  1060 + {
  1061 + this->m->encp->user_password_matched = check_user_password(
  1062 + this->m->encp->provided_password, data);
  1063 + if (this->m->encp->user_password_matched)
  1064 + {
  1065 + this->m->encp->user_password =
  1066 + this->m->encp->provided_password;
  1067 + }
  1068 + }
  1069 + if (this->m->encp->user_password_matched &&
  1070 + this->m->encp->owner_password_matched)
  1071 + {
  1072 + QTC::TC("qpdf", "QPDF_encryption same password",
  1073 + (V < 5) ? 0 : 1);
  1074 + }
  1075 + if (! (this->m->encp->owner_password_matched ||
  1076 + this->m->encp->user_password_matched))
  1077 + {
  1078 + throw QPDFExc(qpdf_e_password, this->m->file->getName(),
  1079 + "", 0, "invalid password");
  1080 + }
1059 1081 }
1060 1082  
1061 1083 if (this->m->provided_password_is_hex_key)
... ... @@ -1440,6 +1462,18 @@ QPDF::isEncrypted(int&amp; R, int&amp; P, int&amp; V,
1440 1462 }
1441 1463 }
1442 1464  
  1465 +bool
  1466 +QPDF::ownerPasswordMatched() const
  1467 +{
  1468 + return this->m->encp->owner_password_matched;
  1469 +}
  1470 +
  1471 +bool
  1472 +QPDF::userPasswordMatched() const
  1473 +{
  1474 + return this->m->encp->user_password_matched;
  1475 +}
  1476 +
1443 1477 static bool
1444 1478 is_bit_set(int P, int bit)
1445 1479 {
... ...
manual/qpdf-manual.xml
... ... @@ -4581,6 +4581,17 @@ print &quot;\n&quot;;
4581 4581 </listitem>
4582 4582 <listitem>
4583 4583 <para>
  4584 + New methods <function>QPDF::userPasswordMatched</function>
  4585 + and <function>QPDF::ownerPasswordMatched</function> have
  4586 + been added to enable a caller to determine whether the
  4587 + supplied password was the user password, the owner password,
  4588 + or both. This information is also displayed by <command>qpdf
  4589 + --show-encryption</command> and <command>qpdf
  4590 + --check</command>.
  4591 + </para>
  4592 + </listitem>
  4593 + <listitem>
  4594 + <para>
4584 4595 Static method
4585 4596 <function>Pl_Flate::setCompressionLevel</function> can be
4586 4597 called to set the zlib compression level globally used by
... ...
qpdf/qpdf.testcov
... ... @@ -442,3 +442,5 @@ QPDFObjectHandle uint returning UINT_MAX 0
442 442 QPDFObjectHandle uint uint returning 0 0
443 443 QPDF xref skipped space 0
444 444 QPDF eof skipping spaces before xref 1
  445 +QPDF_encryption user matches owner V < 5 0
  446 +QPDF_encryption same password 1
... ...