Commit 232c037a7e95ffd8ce98bb5eccc004ed0b578731
1 parent
c8fd2f9b
Refactor and centralize encryption-related logic in `QPDFWriter::Members` to red…
…uce redundancy, improve maintainability, and streamline parameter handling.
Showing
3 changed files
with
120 additions
and
148 deletions
include/qpdf/QPDFWriter.hh
| @@ -532,18 +532,7 @@ class QPDFWriter | @@ -532,18 +532,7 @@ class QPDFWriter | ||
| 532 | int key_len, | 532 | int key_len, |
| 533 | std::set<int>& bits_to_clear); | 533 | std::set<int>& bits_to_clear); |
| 534 | void setEncryptionParametersInternal( | 534 | void setEncryptionParametersInternal( |
| 535 | - int V, | ||
| 536 | - int R, | ||
| 537 | - int key_len, | ||
| 538 | - int P, | ||
| 539 | - std::string const& O, | ||
| 540 | - std::string const& U, | ||
| 541 | - std::string const& OE, | ||
| 542 | - std::string const& UE, | ||
| 543 | - std::string const& Perms, | ||
| 544 | - std::string const& id1, | ||
| 545 | - std::string const& user_password, | ||
| 546 | - std::string const& encryption_key); | 535 | + std::string const& user_password, std::string const& encryption_key); |
| 547 | void setDataKey(int objid); | 536 | void setDataKey(int objid); |
| 548 | int openObject(int objid = 0); | 537 | int openObject(int objid = 0); |
| 549 | void closeObject(int objid); | 538 | void closeObject(int objid); |
libqpdf/QPDFWriter.cc
| @@ -50,6 +50,93 @@ QPDFWriter::FunctionProgressReporter::reportProgress(int progress) | @@ -50,6 +50,93 @@ QPDFWriter::FunctionProgressReporter::reportProgress(int progress) | ||
| 50 | this->handler(progress); | 50 | this->handler(progress); |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | +class QPDFWriter::Members | ||
| 54 | +{ | ||
| 55 | + friend class QPDFWriter; | ||
| 56 | + | ||
| 57 | + public: | ||
| 58 | + ~Members(); | ||
| 59 | + | ||
| 60 | + private: | ||
| 61 | + Members(QPDF& pdf); | ||
| 62 | + Members(Members const&) = delete; | ||
| 63 | + | ||
| 64 | + QPDF& pdf; | ||
| 65 | + QPDFObjGen root_og{-1, 0}; | ||
| 66 | + char const* filename{"unspecified"}; | ||
| 67 | + FILE* file{nullptr}; | ||
| 68 | + bool close_file{false}; | ||
| 69 | + Pl_Buffer* buffer_pipeline{nullptr}; | ||
| 70 | + Buffer* output_buffer{nullptr}; | ||
| 71 | + bool normalize_content_set{false}; | ||
| 72 | + bool normalize_content{false}; | ||
| 73 | + bool compress_streams{true}; | ||
| 74 | + bool compress_streams_set{false}; | ||
| 75 | + qpdf_stream_decode_level_e stream_decode_level{qpdf_dl_generalized}; | ||
| 76 | + bool stream_decode_level_set{false}; | ||
| 77 | + bool recompress_flate{false}; | ||
| 78 | + bool qdf_mode{false}; | ||
| 79 | + bool preserve_unreferenced_objects{false}; | ||
| 80 | + bool newline_before_endstream{false}; | ||
| 81 | + bool static_id{false}; | ||
| 82 | + bool suppress_original_object_ids{false}; | ||
| 83 | + bool direct_stream_lengths{true}; | ||
| 84 | + bool encrypted{false}; | ||
| 85 | + bool preserve_encryption{true}; | ||
| 86 | + bool linearized{false}; | ||
| 87 | + bool pclm{false}; | ||
| 88 | + qpdf_object_stream_e object_stream_mode{qpdf_o_preserve}; | ||
| 89 | + | ||
| 90 | + std::unique_ptr<QPDF::EncryptionData> encryption; | ||
| 91 | + std::string encryption_key; | ||
| 92 | + bool encrypt_metadata{true}; | ||
| 93 | + bool encrypt_use_aes{false}; | ||
| 94 | + std::map<std::string, std::string> encryption_dictionary; | ||
| 95 | + | ||
| 96 | + std::string id1; // for /ID key of | ||
| 97 | + std::string id2; // trailer dictionary | ||
| 98 | + std::string final_pdf_version; | ||
| 99 | + int final_extension_level{0}; | ||
| 100 | + std::string min_pdf_version; | ||
| 101 | + int min_extension_level{0}; | ||
| 102 | + std::string forced_pdf_version; | ||
| 103 | + int forced_extension_level{0}; | ||
| 104 | + std::string extra_header_text; | ||
| 105 | + int encryption_dict_objid{0}; | ||
| 106 | + std::string cur_data_key; | ||
| 107 | + std::list<std::shared_ptr<Pipeline>> to_delete; | ||
| 108 | + qpdf::pl::Count* pipeline{nullptr}; | ||
| 109 | + std::vector<QPDFObjectHandle> object_queue; | ||
| 110 | + size_t object_queue_front{0}; | ||
| 111 | + QPDFWriter::ObjTable obj; | ||
| 112 | + QPDFWriter::NewObjTable new_obj; | ||
| 113 | + int next_objid{1}; | ||
| 114 | + int cur_stream_length_id{0}; | ||
| 115 | + size_t cur_stream_length{0}; | ||
| 116 | + bool added_newline{false}; | ||
| 117 | + size_t max_ostream_index{0}; | ||
| 118 | + std::set<QPDFObjGen> normalized_streams; | ||
| 119 | + std::map<QPDFObjGen, int> page_object_to_seq; | ||
| 120 | + std::map<QPDFObjGen, int> contents_to_page_seq; | ||
| 121 | + std::map<int, std::vector<QPDFObjGen>> object_stream_to_objects; | ||
| 122 | + std::vector<Pipeline*> pipeline_stack; | ||
| 123 | + unsigned long next_stack_id{2}; | ||
| 124 | + std::string count_buffer; | ||
| 125 | + bool deterministic_id{false}; | ||
| 126 | + Pl_MD5* md5_pipeline{nullptr}; | ||
| 127 | + std::string deterministic_id_data; | ||
| 128 | + bool did_write_setup{false}; | ||
| 129 | + | ||
| 130 | + // For linearization only | ||
| 131 | + std::string lin_pass1_filename; | ||
| 132 | + | ||
| 133 | + // For progress reporting | ||
| 134 | + std::shared_ptr<QPDFWriter::ProgressReporter> progress_reporter; | ||
| 135 | + int events_expected{0}; | ||
| 136 | + int events_seen{0}; | ||
| 137 | + int next_progress_report{0}; | ||
| 138 | +}; | ||
| 139 | + | ||
| 53 | QPDFWriter::Members::Members(QPDF& pdf) : | 140 | QPDFWriter::Members::Members(QPDF& pdf) : |
| 54 | pdf(pdf), | 141 | pdf(pdf), |
| 55 | root_og(pdf.getRoot().getObjGen().isIndirect() ? pdf.getRoot().getObjGen() : QPDFObjGen(-1, 0)) | 142 | root_og(pdf.getRoot().getObjGen().isIndirect() ? pdf.getRoot().getObjGen() : QPDFObjGen(-1, 0)) |
| @@ -619,22 +706,10 @@ QPDFWriter::setEncryptionParameters( | @@ -619,22 +706,10 @@ QPDFWriter::setEncryptionParameters( | ||
| 619 | P = ~P; | 706 | P = ~P; |
| 620 | 707 | ||
| 621 | generateID(); | 708 | generateID(); |
| 622 | - QPDF::EncryptionData encryption_data( | 709 | + m->encryption = std::make_unique<QPDF::EncryptionData>( |
| 623 | V, R, key_len, P, "", "", "", "", "", m->id1, m->encrypt_metadata); | 710 | V, R, key_len, P, "", "", "", "", "", m->id1, m->encrypt_metadata); |
| 624 | - auto encryption_key = encryption_data.compute_parameters(user_password, owner_password); | ||
| 625 | - setEncryptionParametersInternal( | ||
| 626 | - V, | ||
| 627 | - R, | ||
| 628 | - key_len, | ||
| 629 | - P, | ||
| 630 | - encryption_data.getO(), | ||
| 631 | - encryption_data.getU(), | ||
| 632 | - encryption_data.getOE(), | ||
| 633 | - encryption_data.getUE(), | ||
| 634 | - encryption_data.getPerms(), | ||
| 635 | - m->id1, | ||
| 636 | - user_password, | ||
| 637 | - encryption_key); | 711 | + auto encryption_key = m->encryption->compute_parameters(user_password, owner_password); |
| 712 | + setEncryptionParametersInternal(user_password, encryption_key); | ||
| 638 | } | 713 | } |
| 639 | 714 | ||
| 640 | void | 715 | void |
| @@ -675,7 +750,7 @@ QPDFWriter::copyEncryptionParameters(QPDF& qpdf) | @@ -675,7 +750,7 @@ QPDFWriter::copyEncryptionParameters(QPDF& qpdf) | ||
| 675 | encryption_key = qpdf.getEncryptionKey(); | 750 | encryption_key = qpdf.getEncryptionKey(); |
| 676 | } | 751 | } |
| 677 | 752 | ||
| 678 | - setEncryptionParametersInternal( | 753 | + m->encryption = std::make_unique<QPDF::EncryptionData>( |
| 679 | V, | 754 | V, |
| 680 | encrypt.getKey("/R").getIntValueAsInt(), | 755 | encrypt.getKey("/R").getIntValueAsInt(), |
| 681 | key_len, | 756 | key_len, |
| @@ -686,8 +761,9 @@ QPDFWriter::copyEncryptionParameters(QPDF& qpdf) | @@ -686,8 +761,9 @@ QPDFWriter::copyEncryptionParameters(QPDF& qpdf) | ||
| 686 | UE, | 761 | UE, |
| 687 | Perms, | 762 | Perms, |
| 688 | m->id1, // m->id1 == the other file's id1 | 763 | m->id1, // m->id1 == the other file's id1 |
| 689 | - qpdf.getPaddedUserPassword(), | ||
| 690 | - encryption_key); | 764 | + m->encrypt_metadata); |
| 765 | + | ||
| 766 | + setEncryptionParametersInternal(qpdf.getPaddedUserPassword(), encryption_key); | ||
| 691 | } | 767 | } |
| 692 | } | 768 | } |
| 693 | 769 | ||
| @@ -765,32 +841,22 @@ QPDFWriter::compareVersions(int major1, int minor1, int major2, int minor2) cons | @@ -765,32 +841,22 @@ QPDFWriter::compareVersions(int major1, int minor1, int major2, int minor2) cons | ||
| 765 | 841 | ||
| 766 | void | 842 | void |
| 767 | QPDFWriter::setEncryptionParametersInternal( | 843 | QPDFWriter::setEncryptionParametersInternal( |
| 768 | - int V, | ||
| 769 | - int R, | ||
| 770 | - int key_len, | ||
| 771 | - int P, | ||
| 772 | - std::string const& O, | ||
| 773 | - std::string const& U, | ||
| 774 | - std::string const& OE, | ||
| 775 | - std::string const& UE, | ||
| 776 | - std::string const& Perms, | ||
| 777 | - std::string const& id1, | ||
| 778 | - std::string const& user_password, | ||
| 779 | - std::string const& encryption_key) | ||
| 780 | -{ | ||
| 781 | - m->encryption_V = V; | ||
| 782 | - m->encryption_R = R; | 844 | + std::string const& user_password, std::string const& encryption_key) |
| 845 | +{ | ||
| 846 | + auto& enc = *m->encryption; | ||
| 847 | + auto const V = enc.getV(); | ||
| 848 | + auto const R = enc.getR(); | ||
| 783 | m->encryption_dictionary["/Filter"] = "/Standard"; | 849 | m->encryption_dictionary["/Filter"] = "/Standard"; |
| 784 | - m->encryption_dictionary["/V"] = std::to_string(V); | ||
| 785 | - m->encryption_dictionary["/Length"] = std::to_string(key_len * 8); | ||
| 786 | - m->encryption_dictionary["/R"] = std::to_string(R); | ||
| 787 | - m->encryption_dictionary["/P"] = std::to_string(P); | ||
| 788 | - m->encryption_dictionary["/O"] = QPDF_String(O).unparse(true); | ||
| 789 | - m->encryption_dictionary["/U"] = QPDF_String(U).unparse(true); | 850 | + m->encryption_dictionary["/V"] = std::to_string(enc.getV()); |
| 851 | + m->encryption_dictionary["/Length"] = std::to_string(enc.getLengthBytes() * 8); | ||
| 852 | + m->encryption_dictionary["/R"] = std::to_string(enc.getR()); | ||
| 853 | + m->encryption_dictionary["/P"] = std::to_string(enc.getP()); | ||
| 854 | + m->encryption_dictionary["/O"] = QPDF_String(enc.getO()).unparse(true); | ||
| 855 | + m->encryption_dictionary["/U"] = QPDF_String(enc.getU()).unparse(true); | ||
| 790 | if (V >= 5) { | 856 | if (V >= 5) { |
| 791 | - m->encryption_dictionary["/OE"] = QPDF_String(OE).unparse(true); | ||
| 792 | - m->encryption_dictionary["/UE"] = QPDF_String(UE).unparse(true); | ||
| 793 | - m->encryption_dictionary["/Perms"] = QPDF_String(Perms).unparse(true); | 857 | + m->encryption_dictionary["/OE"] = QPDF_String(enc.getOE()).unparse(true); |
| 858 | + m->encryption_dictionary["/UE"] = QPDF_String(enc.getUE()).unparse(true); | ||
| 859 | + m->encryption_dictionary["/Perms"] = QPDF_String(enc.getPerms()).unparse(true); | ||
| 794 | } | 860 | } |
| 795 | if (R >= 6) { | 861 | if (R >= 6) { |
| 796 | setMinimumPDFVersion("1.7", 8); | 862 | setMinimumPDFVersion("1.7", 8); |
| @@ -804,7 +870,7 @@ QPDFWriter::setEncryptionParametersInternal( | @@ -804,7 +870,7 @@ QPDFWriter::setEncryptionParametersInternal( | ||
| 804 | setMinimumPDFVersion("1.3"); | 870 | setMinimumPDFVersion("1.3"); |
| 805 | } | 871 | } |
| 806 | 872 | ||
| 807 | - if ((R >= 4) && (!m->encrypt_metadata)) { | 873 | + if (R >= 4 && !m->encrypt_metadata) { |
| 808 | m->encryption_dictionary["/EncryptMetadata"] = "false"; | 874 | m->encryption_dictionary["/EncryptMetadata"] = "false"; |
| 809 | } | 875 | } |
| 810 | if ((V == 4) || (V == 5)) { | 876 | if ((V == 4) || (V == 5)) { |
| @@ -820,10 +886,8 @@ QPDFWriter::setEncryptionParametersInternal( | @@ -820,10 +886,8 @@ QPDFWriter::setEncryptionParametersInternal( | ||
| 820 | } | 886 | } |
| 821 | 887 | ||
| 822 | m->encrypted = true; | 888 | m->encrypted = true; |
| 823 | - QPDF::EncryptionData encryption_data( | ||
| 824 | - V, R, key_len, P, O, U, OE, UE, Perms, id1, m->encrypt_metadata); | ||
| 825 | if (V < 5) { | 889 | if (V < 5) { |
| 826 | - m->encryption_key = QPDF::compute_encryption_key(user_password, encryption_data); | 890 | + m->encryption_key = enc.compute_encryption_key(user_password); |
| 827 | } else { | 891 | } else { |
| 828 | m->encryption_key = encryption_key; | 892 | m->encryption_key = encryption_key; |
| 829 | } | 893 | } |
| @@ -832,8 +896,15 @@ QPDFWriter::setEncryptionParametersInternal( | @@ -832,8 +896,15 @@ QPDFWriter::setEncryptionParametersInternal( | ||
| 832 | void | 896 | void |
| 833 | QPDFWriter::setDataKey(int objid) | 897 | QPDFWriter::setDataKey(int objid) |
| 834 | { | 898 | { |
| 835 | - m->cur_data_key = QPDF::compute_data_key( | ||
| 836 | - m->encryption_key, objid, 0, m->encrypt_use_aes, m->encryption_V, m->encryption_R); | 899 | + if (m->encrypted) { |
| 900 | + m->cur_data_key = QPDF::compute_data_key( | ||
| 901 | + m->encryption_key, | ||
| 902 | + objid, | ||
| 903 | + 0, | ||
| 904 | + m->encrypt_use_aes, | ||
| 905 | + m->encryption->getV(), | ||
| 906 | + m->encryption->getR()); | ||
| 907 | + } | ||
| 837 | } | 908 | } |
| 838 | 909 | ||
| 839 | unsigned int | 910 | unsigned int |
libqpdf/qpdf/QPDFWriter_private.hh
| @@ -43,92 +43,4 @@ class QPDFWriter::NewObjTable: public ::ObjTable<QPDFWriter::NewObject> | @@ -43,92 +43,4 @@ class QPDFWriter::NewObjTable: public ::ObjTable<QPDFWriter::NewObject> | ||
| 43 | friend class QPDFWriter; | 43 | friend class QPDFWriter; |
| 44 | }; | 44 | }; |
| 45 | 45 | ||
| 46 | -class QPDFWriter::Members | ||
| 47 | -{ | ||
| 48 | - friend class QPDFWriter; | ||
| 49 | - | ||
| 50 | - public: | ||
| 51 | - QPDF_DLL | ||
| 52 | - ~Members(); | ||
| 53 | - | ||
| 54 | - private: | ||
| 55 | - Members(QPDF& pdf); | ||
| 56 | - Members(Members const&) = delete; | ||
| 57 | - | ||
| 58 | - QPDF& pdf; | ||
| 59 | - QPDFObjGen root_og{-1, 0}; | ||
| 60 | - char const* filename{"unspecified"}; | ||
| 61 | - FILE* file{nullptr}; | ||
| 62 | - bool close_file{false}; | ||
| 63 | - Pl_Buffer* buffer_pipeline{nullptr}; | ||
| 64 | - Buffer* output_buffer{nullptr}; | ||
| 65 | - bool normalize_content_set{false}; | ||
| 66 | - bool normalize_content{false}; | ||
| 67 | - bool compress_streams{true}; | ||
| 68 | - bool compress_streams_set{false}; | ||
| 69 | - qpdf_stream_decode_level_e stream_decode_level{qpdf_dl_generalized}; | ||
| 70 | - bool stream_decode_level_set{false}; | ||
| 71 | - bool recompress_flate{false}; | ||
| 72 | - bool qdf_mode{false}; | ||
| 73 | - bool preserve_unreferenced_objects{false}; | ||
| 74 | - bool newline_before_endstream{false}; | ||
| 75 | - bool static_id{false}; | ||
| 76 | - bool suppress_original_object_ids{false}; | ||
| 77 | - bool direct_stream_lengths{true}; | ||
| 78 | - bool encrypted{false}; | ||
| 79 | - bool preserve_encryption{true}; | ||
| 80 | - bool linearized{false}; | ||
| 81 | - bool pclm{false}; | ||
| 82 | - qpdf_object_stream_e object_stream_mode{qpdf_o_preserve}; | ||
| 83 | - std::string encryption_key; | ||
| 84 | - bool encrypt_metadata{true}; | ||
| 85 | - bool encrypt_use_aes{false}; | ||
| 86 | - std::map<std::string, std::string> encryption_dictionary; | ||
| 87 | - int encryption_V{0}; | ||
| 88 | - int encryption_R{0}; | ||
| 89 | - | ||
| 90 | - std::string id1; // for /ID key of | ||
| 91 | - std::string id2; // trailer dictionary | ||
| 92 | - std::string final_pdf_version; | ||
| 93 | - int final_extension_level{0}; | ||
| 94 | - std::string min_pdf_version; | ||
| 95 | - int min_extension_level{0}; | ||
| 96 | - std::string forced_pdf_version; | ||
| 97 | - int forced_extension_level{0}; | ||
| 98 | - std::string extra_header_text; | ||
| 99 | - int encryption_dict_objid{0}; | ||
| 100 | - std::string cur_data_key; | ||
| 101 | - std::list<std::shared_ptr<Pipeline>> to_delete; | ||
| 102 | - qpdf::pl::Count* pipeline{nullptr}; | ||
| 103 | - std::vector<QPDFObjectHandle> object_queue; | ||
| 104 | - size_t object_queue_front{0}; | ||
| 105 | - QPDFWriter::ObjTable obj; | ||
| 106 | - QPDFWriter::NewObjTable new_obj; | ||
| 107 | - int next_objid{1}; | ||
| 108 | - int cur_stream_length_id{0}; | ||
| 109 | - size_t cur_stream_length{0}; | ||
| 110 | - bool added_newline{false}; | ||
| 111 | - size_t max_ostream_index{0}; | ||
| 112 | - std::set<QPDFObjGen> normalized_streams; | ||
| 113 | - std::map<QPDFObjGen, int> page_object_to_seq; | ||
| 114 | - std::map<QPDFObjGen, int> contents_to_page_seq; | ||
| 115 | - std::map<int, std::vector<QPDFObjGen>> object_stream_to_objects; | ||
| 116 | - std::vector<Pipeline*> pipeline_stack; | ||
| 117 | - unsigned long next_stack_id{2}; | ||
| 118 | - std::string count_buffer; | ||
| 119 | - bool deterministic_id{false}; | ||
| 120 | - Pl_MD5* md5_pipeline{nullptr}; | ||
| 121 | - std::string deterministic_id_data; | ||
| 122 | - bool did_write_setup{false}; | ||
| 123 | - | ||
| 124 | - // For linearization only | ||
| 125 | - std::string lin_pass1_filename; | ||
| 126 | - | ||
| 127 | - // For progress reporting | ||
| 128 | - std::shared_ptr<QPDFWriter::ProgressReporter> progress_reporter; | ||
| 129 | - int events_expected{0}; | ||
| 130 | - int events_seen{0}; | ||
| 131 | - int next_progress_report{0}; | ||
| 132 | -}; | ||
| 133 | - | ||
| 134 | #endif // QPDFWRITER_PRIVATE_HH | 46 | #endif // QPDFWRITER_PRIVATE_HH |