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 | 532 | int key_len, |
| 533 | 533 | std::set<int>& bits_to_clear); |
| 534 | 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 | 536 | void setDataKey(int objid); |
| 548 | 537 | int openObject(int objid = 0); |
| 549 | 538 | void closeObject(int objid); | ... | ... |
libqpdf/QPDFWriter.cc
| ... | ... | @@ -50,6 +50,93 @@ QPDFWriter::FunctionProgressReporter::reportProgress(int progress) |
| 50 | 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 | 140 | QPDFWriter::Members::Members(QPDF& pdf) : |
| 54 | 141 | pdf(pdf), |
| 55 | 142 | root_og(pdf.getRoot().getObjGen().isIndirect() ? pdf.getRoot().getObjGen() : QPDFObjGen(-1, 0)) |
| ... | ... | @@ -619,22 +706,10 @@ QPDFWriter::setEncryptionParameters( |
| 619 | 706 | P = ~P; |
| 620 | 707 | |
| 621 | 708 | generateID(); |
| 622 | - QPDF::EncryptionData encryption_data( | |
| 709 | + m->encryption = std::make_unique<QPDF::EncryptionData>( | |
| 623 | 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 | 715 | void |
| ... | ... | @@ -675,7 +750,7 @@ QPDFWriter::copyEncryptionParameters(QPDF& qpdf) |
| 675 | 750 | encryption_key = qpdf.getEncryptionKey(); |
| 676 | 751 | } |
| 677 | 752 | |
| 678 | - setEncryptionParametersInternal( | |
| 753 | + m->encryption = std::make_unique<QPDF::EncryptionData>( | |
| 679 | 754 | V, |
| 680 | 755 | encrypt.getKey("/R").getIntValueAsInt(), |
| 681 | 756 | key_len, |
| ... | ... | @@ -686,8 +761,9 @@ QPDFWriter::copyEncryptionParameters(QPDF& qpdf) |
| 686 | 761 | UE, |
| 687 | 762 | Perms, |
| 688 | 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 | 841 | |
| 766 | 842 | void |
| 767 | 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 | 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 | 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 | 861 | if (R >= 6) { |
| 796 | 862 | setMinimumPDFVersion("1.7", 8); |
| ... | ... | @@ -804,7 +870,7 @@ QPDFWriter::setEncryptionParametersInternal( |
| 804 | 870 | setMinimumPDFVersion("1.3"); |
| 805 | 871 | } |
| 806 | 872 | |
| 807 | - if ((R >= 4) && (!m->encrypt_metadata)) { | |
| 873 | + if (R >= 4 && !m->encrypt_metadata) { | |
| 808 | 874 | m->encryption_dictionary["/EncryptMetadata"] = "false"; |
| 809 | 875 | } |
| 810 | 876 | if ((V == 4) || (V == 5)) { |
| ... | ... | @@ -820,10 +886,8 @@ QPDFWriter::setEncryptionParametersInternal( |
| 820 | 886 | } |
| 821 | 887 | |
| 822 | 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 | 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 | 891 | } else { |
| 828 | 892 | m->encryption_key = encryption_key; |
| 829 | 893 | } |
| ... | ... | @@ -832,8 +896,15 @@ QPDFWriter::setEncryptionParametersInternal( |
| 832 | 896 | void |
| 833 | 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 | 910 | unsigned int | ... | ... |
libqpdf/qpdf/QPDFWriter_private.hh
| ... | ... | @@ -43,92 +43,4 @@ class QPDFWriter::NewObjTable: public ::ObjTable<QPDFWriter::NewObject> |
| 43 | 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 | 46 | #endif // QPDFWRITER_PRIVATE_HH | ... | ... |