diff --git a/ChangeLog b/ChangeLog index 915d73f8..7e5962fd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2019-08-24 Jay Berkenbilt + + * Add QPDF::userPasswordMatched() and QPDF::ownerPasswordMatched() + methods so it can be deterined separately whether the supplied + password matched the user password, the owner password, or both. + Fixes #159. + 2019-08-23 Jay Berkenbilt * Add --recompress-streams option to qpdf and diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index 5fae5a57..c488e0b1 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -406,6 +406,12 @@ class QPDF encryption_method_e& string_method, encryption_method_e& file_method); + QPDF_DLL + bool ownerPasswordMatched() const; + + QPDF_DLL + bool userPasswordMatched() const; + // Encryption permissions -- not enforced by QPDF QPDF_DLL bool allowAccessibility(); @@ -756,6 +762,8 @@ class QPDF std::string cached_object_encryption_key; int cached_key_objid; int cached_key_generation; + bool user_password_matched; + bool owner_password_matched; }; class ForeignStreamData diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 1d54ef44..fd661ba0 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -132,7 +132,9 @@ QPDF::EncryptionParameters::EncryptionParameters() : cf_string(e_none), cf_file(e_none), cached_key_objid(0), - cached_key_generation(0) + cached_key_generation(0), + user_password_matched(false), + owner_password_matched(false) { } diff --git a/libqpdf/QPDF_encryption.cc b/libqpdf/QPDF_encryption.cc index 3b1bb619..5a6735ee 100644 --- a/libqpdf/QPDF_encryption.cc +++ b/libqpdf/QPDF_encryption.cc @@ -1041,21 +1041,43 @@ QPDF::initializeEncryption() { // ignore passwords in file } - else if (check_owner_password( - this->m->encp->user_password, - this->m->encp->provided_password, data)) - { - // password supplied was owner password; user_password has - // been initialized for V < 5 - } - else if (check_user_password(this->m->encp->provided_password, data)) - { - this->m->encp->user_password = this->m->encp->provided_password; - } else { - throw QPDFExc(qpdf_e_password, this->m->file->getName(), - "", 0, "invalid password"); + this->m->encp->owner_password_matched = check_owner_password( + this->m->encp->user_password, + this->m->encp->provided_password, data); + if (this->m->encp->owner_password_matched && (V < 5)) + { + // password supplied was owner password; user_password has + // been initialized for V < 5 + if (getTrimmedUserPassword() == this->m->encp->provided_password) + { + this->m->encp->user_password_matched = true; + QTC::TC("qpdf", "QPDF_encryption user matches owner V < 5"); + } + } + else + { + this->m->encp->user_password_matched = check_user_password( + this->m->encp->provided_password, data); + if (this->m->encp->user_password_matched) + { + this->m->encp->user_password = + this->m->encp->provided_password; + } + } + if (this->m->encp->user_password_matched && + this->m->encp->owner_password_matched) + { + QTC::TC("qpdf", "QPDF_encryption same password", + (V < 5) ? 0 : 1); + } + if (! (this->m->encp->owner_password_matched || + this->m->encp->user_password_matched)) + { + throw QPDFExc(qpdf_e_password, this->m->file->getName(), + "", 0, "invalid password"); + } } if (this->m->provided_password_is_hex_key) @@ -1440,6 +1462,18 @@ QPDF::isEncrypted(int& R, int& P, int& V, } } +bool +QPDF::ownerPasswordMatched() const +{ + return this->m->encp->owner_password_matched; +} + +bool +QPDF::userPasswordMatched() const +{ + return this->m->encp->user_password_matched; +} + static bool is_bit_set(int P, int bit) { diff --git a/manual/qpdf-manual.xml b/manual/qpdf-manual.xml index bd861efe..c1ac5e15 100644 --- a/manual/qpdf-manual.xml +++ b/manual/qpdf-manual.xml @@ -4579,6 +4579,17 @@ print "\n"; bytes of the combined contents. + + + New methods QPDF::userPasswordMatched + and QPDF::ownerPasswordMatched have + been added to enable a caller to determine whether the + supplied password was the user password, the owner password, + or both. This information is also displayed by qpdf + --show-encryption and qpdf + --check. + + Static method diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov index e8e5bf3e..c8ad0bdd 100644 --- a/qpdf/qpdf.testcov +++ b/qpdf/qpdf.testcov @@ -442,3 +442,5 @@ QPDFObjectHandle uint returning UINT_MAX 0 QPDFObjectHandle uint uint returning 0 0 QPDF xref skipped space 0 QPDF eof skipping spaces before xref 1 +QPDF_encryption user matches owner V < 5 0 +QPDF_encryption same password 1