Commit 46cb7392732451e7ba12a8e1a7d30c4cb1014ac0

Authored by m-holger
1 parent a78d18f7

Refactor `QPDFWriter` encryption logic to simplify pipeline writes and consolida…

…te encryption handling
include/qpdf/QPDFWriter.hh
@@ -466,6 +466,7 @@ class QPDFWriter @@ -466,6 +466,7 @@ class QPDFWriter
466 QPDFWriter& write(std::integral auto val); 466 QPDFWriter& write(std::integral auto val);
467 QPDFWriter& write_name(std::string const& str); 467 QPDFWriter& write_name(std::string const& str);
468 QPDFWriter& write_string(std::string const& str, bool force_binary = false); 468 QPDFWriter& write_string(std::string const& str, bool force_binary = false);
  469 + QPDFWriter& write_encrypted(std::string_view str);
469 470
470 template <typename... Args> 471 template <typename... Args>
471 QPDFWriter& write_qdf(Args&&... args); 472 QPDFWriter& write_qdf(Args&&... args);
@@ -569,7 +570,6 @@ class QPDFWriter @@ -569,7 +570,6 @@ class QPDFWriter
569 // is popped. 570 // is popped.
570 571
571 void adjustAESStreamLength(size_t& length); 572 void adjustAESStreamLength(size_t& length);
572 - PipelinePopper pushEncryptionFilter();  
573 void pushMD5Pipeline(PipelinePopper&); 573 void pushMD5Pipeline(PipelinePopper&);
574 void computeDeterministicIDData(); 574 void computeDeterministicIDData();
575 575
libqpdf/QPDFWriter.cc
@@ -1098,32 +1098,27 @@ QPDFWriter::adjustAESStreamLength(size_t&amp; length) @@ -1098,32 +1098,27 @@ QPDFWriter::adjustAESStreamLength(size_t&amp; length)
1098 } 1098 }
1099 } 1099 }
1100 1100
1101 -QPDFWriter::PipelinePopper  
1102 -QPDFWriter::pushEncryptionFilter()  
1103 -{  
1104 - auto pp = m->pipeline_stack.popper();  
1105 - if (m->encryption && !m->cur_data_key.empty()) {  
1106 - Pipeline* p = nullptr;  
1107 - if (m->encrypt_use_aes) {  
1108 - p = new Pl_AES_PDF(  
1109 - "aes stream encryption",  
1110 - m->pipeline, 1101 +QPDFWriter&
  1102 +QPDFWriter::write_encrypted(std::string_view str)
  1103 +{
  1104 + if (!(m->encryption && !m->cur_data_key.empty())) {
  1105 + write(str);
  1106 + } else if (m->encrypt_use_aes) {
  1107 + write(
  1108 + pl::pipe<Pl_AES_PDF>(
  1109 + str,
1111 true, 1110 true,
1112 QUtil::unsigned_char_pointer(m->cur_data_key), 1111 QUtil::unsigned_char_pointer(m->cur_data_key),
1113 - m->cur_data_key.length());  
1114 - } else {  
1115 - p = new Pl_RC4(  
1116 - "rc4 stream encryption",  
1117 - m->pipeline, 1112 + m->cur_data_key.length()));
  1113 + } else {
  1114 + write(
  1115 + pl::pipe<Pl_RC4>(
  1116 + str,
1118 QUtil::unsigned_char_pointer(m->cur_data_key), 1117 QUtil::unsigned_char_pointer(m->cur_data_key),
1119 - QIntC::to_int(m->cur_data_key.length()));  
1120 - }  
1121 - m->pipeline_stack.push(p); 1118 + QIntC::to_int(m->cur_data_key.length())));
1122 } 1119 }
1123 - // Must call this unconditionally so we can call popPipelineStack to balance  
1124 - // pushEncryptionFilter().  
1125 - m->pipeline_stack.activate(pp);  
1126 - return pp; 1120 +
  1121 + return *this;
1127 } 1122 }
1128 1123
1129 void 1124 void
@@ -1659,18 +1654,9 @@ QPDFWriter::unparseObject( @@ -1659,18 +1654,9 @@ QPDFWriter::unparseObject(
1659 adjustAESStreamLength(m->cur_stream_length); 1654 adjustAESStreamLength(m->cur_stream_length);
1660 unparseObject(stream_dict, 0, flags, m->cur_stream_length, compress_stream); 1655 unparseObject(stream_dict, 0, flags, m->cur_stream_length, compress_stream);
1661 char last_char = stream_data.empty() ? '\0' : stream_data.back(); 1656 char last_char = stream_data.empty() ? '\0' : stream_data.back();
1662 - write("\nstream\n");  
1663 - {  
1664 - auto pp_enc = pushEncryptionFilter();  
1665 - write(stream_data);  
1666 - }  
1667 -  
1668 - if ((m->added_newline =  
1669 - m->newline_before_endstream || (m->qdf_mode && last_char != '\n'))) {  
1670 - write("\nendstream");  
1671 - } else {  
1672 - write("endstream");  
1673 - } 1657 + write("\nstream\n").write_encrypted(stream_data);
  1658 + m->added_newline = m->newline_before_endstream || (m->qdf_mode && last_char != '\n');
  1659 + write(m->added_newline ? "\nendstream" : "endstream");
1674 } else if (tc == ::ot_string) { 1660 } else if (tc == ::ot_string) {
1675 std::string val; 1661 std::string val;
1676 if (m->encryption && !(flags & f_in_ostream) && !(flags & f_no_encryption) && 1662 if (m->encryption && !(flags & f_in_ostream) && !(flags & f_no_encryption) &&
@@ -1842,18 +1828,11 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) @@ -1842,18 +1828,11 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object)
1842 unparseChild(extends, 1, f_in_ostream); 1828 unparseChild(extends, 1, f_in_ostream);
1843 } 1829 }
1844 } 1830 }
1845 - write_qdf("\n").write_no_qdf(" ").write(">>\nstream\n"); 1831 + write_qdf("\n").write_no_qdf(" ").write(">>\nstream\n").write_encrypted(stream_buffer_pass2);
1846 if (m->encryption) { 1832 if (m->encryption) {
1847 QTC::TC("qpdf", "QPDFWriter encrypt object stream"); 1833 QTC::TC("qpdf", "QPDFWriter encrypt object stream");
1848 } 1834 }
1849 - {  
1850 - auto pp_enc = pushEncryptionFilter();  
1851 - write(stream_buffer_pass2);  
1852 - }  
1853 - if (m->newline_before_endstream) {  
1854 - write("\n");  
1855 - }  
1856 - write("endstream"); 1835 + write(m->newline_before_endstream ? "\nendstream" : "endstream");
1857 m->cur_data_key.clear(); 1836 m->cur_data_key.clear();
1858 closeObject(new_stream_id); 1837 closeObject(new_stream_id);
1859 } 1838 }
@@ -2462,21 +2441,13 @@ QPDFWriter::writeHintStream(int hint_id) @@ -2462,21 +2441,13 @@ QPDFWriter::writeHintStream(int hint_id)
2462 } 2441 }
2463 adjustAESStreamLength(hlen); 2442 adjustAESStreamLength(hlen);
2464 write(" /Length ").write(hlen); 2443 write(" /Length ").write(hlen);
2465 - write(" >>\nstream\n"); 2444 + write(" >>\nstream\n").write_encrypted(hint_buffer);
2466 2445
2467 if (m->encryption) { 2446 if (m->encryption) {
2468 QTC::TC("qpdf", "QPDFWriter encrypted hint stream"); 2447 QTC::TC("qpdf", "QPDFWriter encrypted hint stream");
2469 } 2448 }
2470 - char last_char = hint_buffer.empty() ? '\0' : hint_buffer.back();  
2471 - {  
2472 - auto pp_enc = pushEncryptionFilter();  
2473 - write(hint_buffer);  
2474 - }  
2475 2449
2476 - if (last_char != '\n') {  
2477 - write("\n");  
2478 - }  
2479 - write("endstream"); 2450 + write(hint_buffer.empty() || hint_buffer.back() != '\n' ? "\nendstream" : "endstream");
2480 closeObject(hint_id); 2451 closeObject(hint_id);
2481 } 2452 }
2482 2453
libqpdf/qpdf/Pipeline_private.hh
@@ -173,6 +173,18 @@ namespace qpdf::pl @@ -173,6 +173,18 @@ namespace qpdf::pl
173 unsigned long id_{0}; 173 unsigned long id_{0};
174 bool pass_immediately_to_next{false}; 174 bool pass_immediately_to_next{false};
175 }; 175 };
  176 +
  177 + template <typename P, typename... Args>
  178 + std::string
  179 + pipe(std::string_view data, Args&&... args)
  180 + {
  181 + std::string result;
  182 + String s("", nullptr, result);
  183 + P pl("", &s, std::forward<Args>(args)...);
  184 + pl.write(reinterpret_cast<unsigned char const*>(data.data()), data.size());
  185 + pl.finish();
  186 + return result;
  187 + }
176 } // namespace qpdf::pl 188 } // namespace qpdf::pl
177 189
178 #endif // PIPELINE_PRIVATE_HH 190 #endif // PIPELINE_PRIVATE_HH