Commit 0575d77d77b0308535422ad2d3a1bf7c94baabb0

Authored by Jay Berkenbilt
1 parent ee3682f1

Add public QPDFWriter::copyEncryptionParameters

Method to copy encryption parameters from another file.  Adapted from
existing code to copy encryption parameters from the original file.
ChangeLog
1 1 2012-07-14 Jay Berkenbilt <ejb@ql.org>
2 2  
  3 + * QPDFWriter: add public copyEncryptionParameters to allow copying
  4 + encryption parameters from another file.
  5 +
3 6 * QPDFWriter: detect if the user has inserted an indirect object
4 7 from another QPDF object and throw an exception directing the user
5 8 to copyForeignObject.
... ...
... ... @@ -64,10 +64,9 @@ Next
64 64 - Tests through qpdf command line: copy pages from multiple PDFs
65 65 starting with one PDF and also starting with empty.
66 66  
67   - * (Hopefully) Provide an option to copy encryption parameters from
68   - another file. This would make it possible to decrypt a file,
69   - manually work with it, and then re-encrypt it using the original
70   - encryption parameters including a possibly unknown owner password.
  67 + * qpdf commandline: provide an option to copy encryption parameters
  68 + from another file, specifying file and password. Search for "Copy
  69 + encryption parameters" in qpdf.test.
71 70  
72 71  
73 72 Soon
... ...
include/qpdf/QPDFWriter.hh
... ... @@ -188,6 +188,11 @@ class QPDFWriter
188 188 QPDF_DLL
189 189 void setPreserveEncryption(bool);
190 190  
  191 + // Copy encryption parameters from another QPDF object. If you
  192 + // want to copy encryption from the object you are writing, call
  193 + // setPreserveEncryption(true) instead.
  194 + void copyEncryptionParameters(QPDF&);
  195 +
191 196 // Set up for encrypted output. Disables stream prefiltering and
192 197 // content normalization. Note that setting R2 encryption
193 198 // parameters sets the PDF version to at least 1.3, setting R3
... ... @@ -269,7 +274,6 @@ class QPDFWriter
269 274 int V, int R, int key_len, long P,
270 275 std::string const& O, std::string const& U,
271 276 std::string const& id1, std::string const& user_password);
272   - void copyEncryptionParameters();
273 277 void setDataKey(int objid);
274 278 int openObject(int objid = 0);
275 279 void closeObject(int objid);
... ...
libqpdf/QPDFWriter.cc
... ... @@ -389,10 +389,11 @@ QPDFWriter::setEncryptionParameters(
389 389 }
390 390  
391 391 void
392   -QPDFWriter::copyEncryptionParameters()
  392 +QPDFWriter::copyEncryptionParameters(QPDF& qpdf)
393 393 {
  394 + this->preserve_encryption = false;
394 395 generateID();
395   - QPDFObjectHandle trailer = this->pdf.getTrailer();
  396 + QPDFObjectHandle trailer = qpdf.getTrailer();
396 397 if (trailer.hasKey("/Encrypt"))
397 398 {
398 399 QPDFObjectHandle encrypt = trailer.getKey("/Encrypt");
... ... @@ -410,6 +411,8 @@ QPDFWriter::copyEncryptionParameters()
410 411 }
411 412 QTC::TC("qpdf", "QPDFWriter copy encrypt metadata",
412 413 this->encrypt_metadata ? 0 : 1);
  414 + this->id1 =
  415 + trailer.getKey("/ID").getArrayItem(0).getStringValue();
413 416 setEncryptionParametersInternal(
414 417 V,
415 418 encrypt.getKey("/R").getIntValue(),
... ... @@ -1625,7 +1628,7 @@ QPDFWriter::write()
1625 1628  
1626 1629 if (preserve_encryption)
1627 1630 {
1628   - copyEncryptionParameters();
  1631 + copyEncryptionParameters(this->pdf);
1629 1632 }
1630 1633  
1631 1634 if (! this->forced_pdf_version.empty())
... ...
qpdf/qtest/qpdf.test
... ... @@ -1369,6 +1369,23 @@ $td-&gt;runtest(&quot;check output&quot;,
1369 1369 {$td->FILE => 'a.pdf'},
1370 1370 {$td->FILE => 'decrypted-crypt-filter.pdf'});
1371 1371  
  1372 +# Copy encryption parameters
  1373 +$n_tests += 3;
  1374 +$td->runtest("create encrypted file",
  1375 + {$td->COMMAND =>
  1376 + "qpdf --encrypt user owner 128 --use-aes=y --extract=n --" .
  1377 + " minimal.pdf a.pdf"},
  1378 + {$td->STRING => "", $td->EXIT_STATUS => 0});
  1379 +$td->runtest("copy encryption parameters",
  1380 + {$td->COMMAND => "test_driver 30 minimal.pdf a.pdf"},
  1381 + {$td->STRING => "test 30 done\n", $td->EXIT_STATUS => 0},
  1382 + $td->NORMALIZE_NEWLINES);
  1383 +$td->runtest("checkout encryption",
  1384 + {$td->COMMAND => "qpdf --show-encryption b.pdf --password=owner"},
  1385 + {$td->FILE => "copied-encryption.out",
  1386 + $td->EXIT_STATUS => 0},
  1387 + $td->NORMALIZE_NEWLINES);
  1388 +
1372 1389 show_ntests();
1373 1390 # ----------
1374 1391 $td->notify("--- Content Preservation Tests ---");
... ...
qpdf/qtest/qpdf/copied-encryption.out 0 → 100644
  1 +R = 4
  2 +P = -20
  3 +User password = user
  4 +extract for accessibility: allowed
  5 +extract for any purpose: not allowed
  6 +print low resolution: allowed
  7 +print high resolution: allowed
  8 +modify document assembly: allowed
  9 +modify forms: allowed
  10 +modify annotations: allowed
  11 +modify other: allowed
  12 +modify anything: allowed
... ...
qpdf/test_driver.cc
... ... @@ -1024,6 +1024,17 @@ void runtest(int n, char const* filename1, char const* filename2)
1024 1024 std::cout << "logic error: " << e.what() << std::endl;
1025 1025 }
1026 1026 }
  1027 + else if (n == 30)
  1028 + {
  1029 + assert(filename2 != 0);
  1030 + QPDF encrypted;
  1031 + encrypted.processFile(filename2, "user");
  1032 + QPDFWriter w(pdf, "b.pdf");
  1033 + w.setStaticID(true);
  1034 + w.setStreamDataMode(qpdf_s_preserve);
  1035 + w.copyEncryptionParameters(encrypted);
  1036 + w.write();
  1037 + }
1027 1038 else
1028 1039 {
1029 1040 throw std::runtime_error(std::string("invalid test ") +
... ...