Commit 232c037a7e95ffd8ce98bb5eccc004ed0b578731

Authored by m-holger
1 parent c8fd2f9b

Refactor and centralize encryption-related logic in `QPDFWriter::Members` to red…

…uce redundancy, improve maintainability, and streamline parameter handling.
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&amp; qpdf) @@ -675,7 +750,7 @@ QPDFWriter::copyEncryptionParameters(QPDF&amp; 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&amp; qpdf) @@ -686,8 +761,9 @@ QPDFWriter::copyEncryptionParameters(QPDF&amp; 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&lt;QPDFWriter::NewObject&gt; @@ -43,92 +43,4 @@ class QPDFWriter::NewObjTable: public ::ObjTable&lt;QPDFWriter::NewObject&gt;
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