Add public QPDFWriter::copyEncryptionParameters

Method to copy encryption parameters from another file.  Adapted from
existing code to copy encryption parameters from the original file.
This commit is contained in:
Jay Berkenbilt 2012-07-14 09:13:49 -04:00
parent ee3682f106
commit 0575d77d77
7 changed files with 57 additions and 8 deletions

View File

@ -1,5 +1,8 @@
2012-07-14 Jay Berkenbilt <ejb@ql.org>
* QPDFWriter: add public copyEncryptionParameters to allow copying
encryption parameters from another file.
* QPDFWriter: detect if the user has inserted an indirect object
from another QPDF object and throw an exception directing the user
to copyForeignObject.

7
TODO
View File

@ -64,10 +64,9 @@ Next
- Tests through qpdf command line: copy pages from multiple PDFs
starting with one PDF and also starting with empty.
* (Hopefully) Provide an option to copy encryption parameters from
another file. This would make it possible to decrypt a file,
manually work with it, and then re-encrypt it using the original
encryption parameters including a possibly unknown owner password.
* qpdf commandline: provide an option to copy encryption parameters
from another file, specifying file and password. Search for "Copy
encryption parameters" in qpdf.test.
Soon

View File

@ -188,6 +188,11 @@ class QPDFWriter
QPDF_DLL
void setPreserveEncryption(bool);
// Copy encryption parameters from another QPDF object. If you
// want to copy encryption from the object you are writing, call
// setPreserveEncryption(true) instead.
void copyEncryptionParameters(QPDF&);
// Set up for encrypted output. Disables stream prefiltering and
// content normalization. Note that setting R2 encryption
// parameters sets the PDF version to at least 1.3, setting R3
@ -269,7 +274,6 @@ class QPDFWriter
int V, int R, int key_len, long P,
std::string const& O, std::string const& U,
std::string const& id1, std::string const& user_password);
void copyEncryptionParameters();
void setDataKey(int objid);
int openObject(int objid = 0);
void closeObject(int objid);

View File

@ -389,10 +389,11 @@ QPDFWriter::setEncryptionParameters(
}
void
QPDFWriter::copyEncryptionParameters()
QPDFWriter::copyEncryptionParameters(QPDF& qpdf)
{
this->preserve_encryption = false;
generateID();
QPDFObjectHandle trailer = this->pdf.getTrailer();
QPDFObjectHandle trailer = qpdf.getTrailer();
if (trailer.hasKey("/Encrypt"))
{
QPDFObjectHandle encrypt = trailer.getKey("/Encrypt");
@ -410,6 +411,8 @@ QPDFWriter::copyEncryptionParameters()
}
QTC::TC("qpdf", "QPDFWriter copy encrypt metadata",
this->encrypt_metadata ? 0 : 1);
this->id1 =
trailer.getKey("/ID").getArrayItem(0).getStringValue();
setEncryptionParametersInternal(
V,
encrypt.getKey("/R").getIntValue(),
@ -1625,7 +1628,7 @@ QPDFWriter::write()
if (preserve_encryption)
{
copyEncryptionParameters();
copyEncryptionParameters(this->pdf);
}
if (! this->forced_pdf_version.empty())

View File

@ -1369,6 +1369,23 @@ $td->runtest("check output",
{$td->FILE => 'a.pdf'},
{$td->FILE => 'decrypted-crypt-filter.pdf'});
# Copy encryption parameters
$n_tests += 3;
$td->runtest("create encrypted file",
{$td->COMMAND =>
"qpdf --encrypt user owner 128 --use-aes=y --extract=n --" .
" minimal.pdf a.pdf"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
$td->runtest("copy encryption parameters",
{$td->COMMAND => "test_driver 30 minimal.pdf a.pdf"},
{$td->STRING => "test 30 done\n", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("checkout encryption",
{$td->COMMAND => "qpdf --show-encryption b.pdf --password=owner"},
{$td->FILE => "copied-encryption.out",
$td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
show_ntests();
# ----------
$td->notify("--- Content Preservation Tests ---");

View File

@ -0,0 +1,12 @@
R = 4
P = -20
User password = user
extract for accessibility: allowed
extract for any purpose: not allowed
print low resolution: allowed
print high resolution: allowed
modify document assembly: allowed
modify forms: allowed
modify annotations: allowed
modify other: allowed
modify anything: allowed

View File

@ -1024,6 +1024,17 @@ void runtest(int n, char const* filename1, char const* filename2)
std::cout << "logic error: " << e.what() << std::endl;
}
}
else if (n == 30)
{
assert(filename2 != 0);
QPDF encrypted;
encrypted.processFile(filename2, "user");
QPDFWriter w(pdf, "b.pdf");
w.setStaticID(true);
w.setStreamDataMode(qpdf_s_preserve);
w.copyEncryptionParameters(encrypted);
w.write();
}
else
{
throw std::runtime_error(std::string("invalid test ") +