mirror of
https://github.com/qpdf/qpdf.git
synced 2024-12-22 10:58:58 +00:00
Try passwords with different string encodings
This commit is contained in:
parent
e4fa5a3c2a
commit
392f2ece51
@ -1,5 +1,12 @@
|
|||||||
2019-01-17 Jay Berkenbilt <ejb@ql.org>
|
2019-01-17 Jay Berkenbilt <ejb@ql.org>
|
||||||
|
|
||||||
|
* When attempting to open an encrypted file with a password, if
|
||||||
|
the password doesn't work, try alternative passwords created by
|
||||||
|
re-interpreting the supplied password with different string
|
||||||
|
encodings. This makes qpdf able to recover passwords with
|
||||||
|
non-ASCII characters when either the decryption or encryption
|
||||||
|
operation was performed with an incorrectly encoded password.
|
||||||
|
|
||||||
* Fix data loss bug: qpdf was discarding referenced resources in
|
* Fix data loss bug: qpdf was discarding referenced resources in
|
||||||
the case in which a page's resource dictionary contained an
|
the case in which a page's resource dictionary contained an
|
||||||
indirect reference for either /Font or /XObject that contained
|
indirect reference for either /Font or /XObject that contained
|
||||||
|
79
qpdf/qpdf.cc
79
qpdf/qpdf.cc
@ -3671,7 +3671,7 @@ ImageOptimizer::provideStreamData(int, int, Pipeline* pipeline)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static PointerHolder<QPDF> do_process(
|
static PointerHolder<QPDF> do_process_once(
|
||||||
void (QPDF::*fn)(T, char const*),
|
void (QPDF::*fn)(T, char const*),
|
||||||
T item, char const* password,
|
T item, char const* password,
|
||||||
Options& o, bool empty)
|
Options& o, bool empty)
|
||||||
@ -3689,6 +3689,83 @@ static PointerHolder<QPDF> do_process(
|
|||||||
return pdf;
|
return pdf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static PointerHolder<QPDF> do_process(
|
||||||
|
void (QPDF::*fn)(T, char const*),
|
||||||
|
T item, char const* password,
|
||||||
|
Options& o, bool empty)
|
||||||
|
{
|
||||||
|
// If a password has been specified but doesn't work, try other
|
||||||
|
// passwords that are equivalent in different character encodings.
|
||||||
|
// This makes it possible to open PDF files that were encrypted
|
||||||
|
// using incorrect string encodings. For example, if someone used
|
||||||
|
// a password encoded in PDF Doc encoding or Windows code page
|
||||||
|
// 1252 for an AES-encrypted file or a UTF-8-encoded password on
|
||||||
|
// an RC4-encrypted file, or if the password was properly encoded
|
||||||
|
// by the password given here was incorrectly encoded, there's a
|
||||||
|
// good chance we'd succeed here.
|
||||||
|
|
||||||
|
if ((password == 0) || empty || o.password_is_hex_key)
|
||||||
|
{
|
||||||
|
// There is no password, so just do the normal processing.
|
||||||
|
return do_process_once(fn, item, password, o, empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a list of otherwise encoded strings. Keep in scope for this
|
||||||
|
// method.
|
||||||
|
std::vector<std::string> passwords_str =
|
||||||
|
QUtil::possible_repaired_encodings(password);
|
||||||
|
// Represent to char const*, as required by the QPDF class.
|
||||||
|
std::vector<char const*> passwords;
|
||||||
|
for (std::vector<std::string>::iterator iter = passwords_str.begin();
|
||||||
|
iter != passwords_str.end(); ++iter)
|
||||||
|
{
|
||||||
|
passwords.push_back((*iter).c_str());
|
||||||
|
}
|
||||||
|
// We always try the supplied password first because it is the
|
||||||
|
// first string returned by possible_repaired_encodings. If there
|
||||||
|
// is more than one option, go ahead and put the supplied password
|
||||||
|
// at the end so that it's that decoding attempt whose exception
|
||||||
|
// is thrown.
|
||||||
|
if (passwords.size() > 1)
|
||||||
|
{
|
||||||
|
passwords.push_back(password);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try each password. If one works, return the resulting object.
|
||||||
|
// If they all fail, throw the exception thrown by the final
|
||||||
|
// attempt, which, like the first attempt, will be with the
|
||||||
|
// supplied password.
|
||||||
|
bool warned = false;
|
||||||
|
for (std::vector<char const*>::iterator iter = passwords.begin();
|
||||||
|
iter != passwords.end(); ++iter)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return do_process_once(fn, item, *iter, o, empty);
|
||||||
|
}
|
||||||
|
catch (QPDFExc& e)
|
||||||
|
{
|
||||||
|
std::vector<char const*>::iterator next = iter;
|
||||||
|
++next;
|
||||||
|
if (next == passwords.end())
|
||||||
|
{
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((! warned) && o.verbose)
|
||||||
|
{
|
||||||
|
warned = true;
|
||||||
|
std::cout << whoami << ": supplied password didn't work;"
|
||||||
|
<< " trying other passwords based on interpreting"
|
||||||
|
<< " password with different string encodings"
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Should not be reachable
|
||||||
|
throw std::logic_error("do_process returned");
|
||||||
|
}
|
||||||
|
|
||||||
static PointerHolder<QPDF> process_file(char const* filename,
|
static PointerHolder<QPDF> process_file(char const* filename,
|
||||||
char const* password,
|
char const* password,
|
||||||
Options& o)
|
Options& o)
|
||||||
|
Loading…
Reference in New Issue
Block a user