Commit 0575d77d77b0308535422ad2d3a1bf7c94baabb0
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.
Showing
7 changed files
with
57 additions
and
8 deletions
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. | ... | ... |
TODO
| ... | ... | @@ -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->runtest("check output", |
| 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 ") + | ... | ... |