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 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&amp; 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&amp; 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&lt;QPDFWriter::NewObject&gt;
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
... ...