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

This commit is contained in:
Jay Berkenbilt 2019-08-24 09:34:48 -04:00
parent 5a0aef55a0
commit 5da146c8b5
6 changed files with 78 additions and 14 deletions

View File

@ -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

View File

@ -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

View File

@ -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)
{
}

View File

@ -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)
{

View File

@ -4579,6 +4579,17 @@ print "\n";
bytes of the combined contents.
</para>
</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

View File

@ -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