aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog3
-rw-r--r--TODO7
-rw-r--r--include/qpdf/QPDFWriter.hh6
-rw-r--r--libqpdf/QPDFWriter.cc9
-rw-r--r--qpdf/qtest/qpdf.test17
-rw-r--r--qpdf/qtest/qpdf/copied-encryption.out12
-rw-r--r--qpdf/test_driver.cc11
7 files changed, 57 insertions, 8 deletions
diff --git a/ChangeLog b/ChangeLog
index 5b150c27..35b78e91 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
diff --git a/TODO b/TODO
index b29559ee..d38cb002 100644
--- a/TODO
+++ b/TODO
@@ -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
diff --git a/include/qpdf/QPDFWriter.hh b/include/qpdf/QPDFWriter.hh
index 2261e45b..a17b91f4 100644
--- a/include/qpdf/QPDFWriter.hh
+++ b/include/qpdf/QPDFWriter.hh
@@ -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);
diff --git a/libqpdf/QPDFWriter.cc b/libqpdf/QPDFWriter.cc
index ce5cb3e0..96f3ff21 100644
--- a/libqpdf/QPDFWriter.cc
+++ b/libqpdf/QPDFWriter.cc
@@ -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())
diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test
index 46a786cc..8687d713 100644
--- a/qpdf/qtest/qpdf.test
+++ b/qpdf/qtest/qpdf.test
@@ -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 ---");
diff --git a/qpdf/qtest/qpdf/copied-encryption.out b/qpdf/qtest/qpdf/copied-encryption.out
new file mode 100644
index 00000000..6db6fa63
--- /dev/null
+++ b/qpdf/qtest/qpdf/copied-encryption.out
@@ -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
diff --git a/qpdf/test_driver.cc b/qpdf/test_driver.cc
index 0d1ecbb2..518e5569 100644
--- a/qpdf/test_driver.cc
+++ b/qpdf/test_driver.cc
@@ -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 ") +