Commit 5da146c8b53bb5a12c514f83fb52265e4922b5e1
1 parent
5a0aef55
Track separately whether password was user/owner (fixes #159)
Showing
6 changed files
with
78 additions
and
14 deletions
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 | 2019-08-23 Jay Berkenbilt <ejb@ql.org> | 8 | 2019-08-23 Jay Berkenbilt <ejb@ql.org> |
| 2 | 9 | ||
| 3 | * Add --recompress-streams option to qpdf and | 10 | * Add --recompress-streams option to qpdf and |
include/qpdf/QPDF.hh
| @@ -406,6 +406,12 @@ class QPDF | @@ -406,6 +406,12 @@ class QPDF | ||
| 406 | encryption_method_e& string_method, | 406 | encryption_method_e& string_method, |
| 407 | encryption_method_e& file_method); | 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 | // Encryption permissions -- not enforced by QPDF | 415 | // Encryption permissions -- not enforced by QPDF |
| 410 | QPDF_DLL | 416 | QPDF_DLL |
| 411 | bool allowAccessibility(); | 417 | bool allowAccessibility(); |
| @@ -756,6 +762,8 @@ class QPDF | @@ -756,6 +762,8 @@ class QPDF | ||
| 756 | std::string cached_object_encryption_key; | 762 | std::string cached_object_encryption_key; |
| 757 | int cached_key_objid; | 763 | int cached_key_objid; |
| 758 | int cached_key_generation; | 764 | int cached_key_generation; |
| 765 | + bool user_password_matched; | ||
| 766 | + bool owner_password_matched; | ||
| 759 | }; | 767 | }; |
| 760 | 768 | ||
| 761 | class ForeignStreamData | 769 | class ForeignStreamData |
libqpdf/QPDF.cc
| @@ -132,7 +132,9 @@ QPDF::EncryptionParameters::EncryptionParameters() : | @@ -132,7 +132,9 @@ QPDF::EncryptionParameters::EncryptionParameters() : | ||
| 132 | cf_string(e_none), | 132 | cf_string(e_none), |
| 133 | cf_file(e_none), | 133 | cf_file(e_none), |
| 134 | cached_key_objid(0), | 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,21 +1041,43 @@ QPDF::initializeEncryption() | ||
| 1041 | { | 1041 | { |
| 1042 | // ignore passwords in file | 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 | else | 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 | if (this->m->provided_password_is_hex_key) | 1083 | if (this->m->provided_password_is_hex_key) |
| @@ -1440,6 +1462,18 @@ QPDF::isEncrypted(int& R, int& P, int& V, | @@ -1440,6 +1462,18 @@ QPDF::isEncrypted(int& R, int& P, int& 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 | static bool | 1477 | static bool |
| 1444 | is_bit_set(int P, int bit) | 1478 | is_bit_set(int P, int bit) |
| 1445 | { | 1479 | { |
manual/qpdf-manual.xml
| @@ -4581,6 +4581,17 @@ print "\n"; | @@ -4581,6 +4581,17 @@ print "\n"; | ||
| 4581 | </listitem> | 4581 | </listitem> |
| 4582 | <listitem> | 4582 | <listitem> |
| 4583 | <para> | 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 | Static method | 4595 | Static method |
| 4585 | <function>Pl_Flate::setCompressionLevel</function> can be | 4596 | <function>Pl_Flate::setCompressionLevel</function> can be |
| 4586 | called to set the zlib compression level globally used by | 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,3 +442,5 @@ QPDFObjectHandle uint returning UINT_MAX 0 | ||
| 442 | QPDFObjectHandle uint uint returning 0 0 | 442 | QPDFObjectHandle uint uint returning 0 0 |
| 443 | QPDF xref skipped space 0 | 443 | QPDF xref skipped space 0 |
| 444 | QPDF eof skipping spaces before xref 1 | 444 | QPDF eof skipping spaces before xref 1 |
| 445 | +QPDF_encryption user matches owner V < 5 0 | ||
| 446 | +QPDF_encryption same password 1 |