aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2019-08-24 15:34:48 +0200
committerJay Berkenbilt <ejb@ql.org>2019-08-24 17:01:19 +0200
commit5da146c8b53bb5a12c514f83fb52265e4922b5e1 (patch)
tree2de81282a32a66c86abf2aa0bf4cd191a2974b94
parent5a0aef55a094da6ef3b2e8b0409830db60d58c5f (diff)
downloadqpdf-5da146c8b53bb5a12c514f83fb52265e4922b5e1.tar.zst
Track separately whether password was user/owner (fixes #159)
-rw-r--r--ChangeLog7
-rw-r--r--include/qpdf/QPDF.hh8
-rw-r--r--libqpdf/QPDF.cc4
-rw-r--r--libqpdf/QPDF_encryption.cc60
-rw-r--r--manual/qpdf-manual.xml11
-rw-r--r--qpdf/qpdf.testcov2
6 files changed, 78 insertions, 14 deletions
diff --git a/ChangeLog b/ChangeLog
index 915d73f8..7e5962fd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2019-08-24 Jay Berkenbilt <ejb@ql.org>
+
+ * 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 <ejb@ql.org>
* 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
@@ -4581,6 +4581,17 @@ print "\n";
</listitem>
<listitem>
<para>
+ New methods <function>QPDF::userPasswordMatched</function>
+ and <function>QPDF::ownerPasswordMatched</function> 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 <command>qpdf
+ --show-encryption</command> and <command>qpdf
+ --check</command>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
Static method
<function>Pl_Flate::setCompressionLevel</function> can be
called to set the zlib compression level globally used by
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