Commit a8715c495b218c9b9388a2e20c8202a3fa73b2c1

Authored by Jay Berkenbilt
1 parent 09175e45

add C API for R4 encryption

git-svn-id: svn+q:///qpdf/trunk@825 71b93d88-0707-0410-a8cf-f5a4172ac649
include/qpdf/QPDFWriter.hh
... ... @@ -110,6 +110,11 @@ class DLL_EXPORT QPDFWriter
110 110 // suites.
111 111 void setStaticID(bool);
112 112  
  113 + // Use a fixed initialization vector for AES-CBC encryption. This
  114 + // is not secure. It should be used only in test suites for
  115 + // creating predictable encrypted output.
  116 + void setStaticAesIV(bool);
  117 +
113 118 // Suppress inclusion of comments indicating original object IDs
114 119 // when writing QDF files. This can also be useful for testing,
115 120 // particularly when using comparison of two qdf files to
... ...
include/qpdf/qpdf-c.h
... ... @@ -226,6 +226,12 @@ extern "C" {
226 226 DLL_EXPORT
227 227 void qpdf_set_static_ID(qpdf_data qpdf, QPDF_BOOL value);
228 228  
  229 + /* Never use qpdf_set_static_aes_IV except in test suites to
  230 + * create predictable AES encrypted output.
  231 + */
  232 + DLL_EXPORT
  233 + void qpdf_set_static_aes_IV(qpdf_data qpdf, QPDF_BOOL value);
  234 +
229 235 DLL_EXPORT
230 236 void qpdf_set_suppress_original_object_IDs(
231 237 qpdf_data qpdf, QPDF_BOOL value);
... ... @@ -259,6 +265,13 @@ extern "C" {
259 265 int print, int modify);
260 266  
261 267 DLL_EXPORT
  268 + void qpdf_set_r4_encryption_parameters(
  269 + qpdf_data qpdf, char const* user_password, char const* owner_password,
  270 + QPDF_BOOL allow_accessibility, QPDF_BOOL allow_extract,
  271 + int print, int modify,
  272 + QPDF_BOOL encrypt_metadata, QPDF_BOOL use_aes);
  273 +
  274 + DLL_EXPORT
262 275 void qpdf_set_linearization(qpdf_data qpdf, QPDF_BOOL value);
263 276  
264 277 DLL_EXPORT
... ...
libqpdf/Pl_AES_PDF.cc
... ... @@ -12,6 +12,8 @@
12 12 # define srandom srand
13 13 #endif
14 14  
  15 +bool Pl_AES_PDF::use_static_iv = false;
  16 +
15 17 Pl_AES_PDF::Pl_AES_PDF(char const* identifier, Pipeline* next,
16 18 bool encrypt, unsigned char const key[key_size]) :
17 19 Pipeline(identifier, next),
... ... @@ -52,6 +54,12 @@ Pl_AES_PDF::disableCBC()
52 54 }
53 55  
54 56 void
  57 +Pl_AES_PDF::useStaticIV()
  58 +{
  59 + use_static_iv = true;
  60 +}
  61 +
  62 +void
55 63 Pl_AES_PDF::write(unsigned char* data, int len)
56 64 {
57 65 unsigned int bytes_left = len;
... ... @@ -116,9 +124,19 @@ Pl_AES_PDF::initializeVector()
116 124 srandom((int)QUtil::get_current_time() ^ 0xcccc);
117 125 seeded_random = true;
118 126 }
119   - for (unsigned int i = 0; i < this->buf_size; ++i)
  127 + if (use_static_iv)
  128 + {
  129 + for (unsigned int i = 0; i < this->buf_size; ++i)
  130 + {
  131 + this->cbc_block[i] = 14 * (1 + i);
  132 + }
  133 + }
  134 + else
120 135 {
121   - this->cbc_block[i] = (unsigned char)((random() & 0xff0) >> 4);
  136 + for (unsigned int i = 0; i < this->buf_size; ++i)
  137 + {
  138 + this->cbc_block[i] = (unsigned char)((random() & 0xff0) >> 4);
  139 + }
122 140 }
123 141 }
124 142  
... ...
libqpdf/QPDFWriter.cc
... ... @@ -140,6 +140,15 @@ QPDFWriter::setStaticID(bool val)
140 140 }
141 141  
142 142 void
  143 +QPDFWriter::setStaticAesIV(bool val)
  144 +{
  145 + if (val)
  146 + {
  147 + Pl_AES_PDF::useStaticIV();
  148 + }
  149 +}
  150 +
  151 +void
143 152 QPDFWriter::setSuppressOriginalObjectIDs(bool val)
144 153 {
145 154 this->suppress_original_object_ids = val;
... ...
libqpdf/qpdf-c.cc
... ... @@ -313,6 +313,12 @@ void qpdf_set_static_ID(qpdf_data qpdf, QPDF_BOOL value)
313 313 qpdf->qpdf_writer->setStaticID(value);
314 314 }
315 315  
  316 +void qpdf_set_static_aes_IV(qpdf_data qpdf, QPDF_BOOL value)
  317 +{
  318 + QTC::TC("qpdf", "qpdf-c called qpdf_set_static_aes_IV");
  319 + qpdf->qpdf_writer->setStaticAesIV(value);
  320 +}
  321 +
316 322 void qpdf_set_suppress_original_object_IDs(
317 323 qpdf_data qpdf, QPDF_BOOL value)
318 324 {
... ... @@ -356,6 +362,26 @@ void qpdf_set_r3_encryption_parameters(
356 362 QPDFWriter::r3m_all));
357 363 }
358 364  
  365 +void qpdf_set_r4_encryption_parameters(
  366 + qpdf_data qpdf, char const* user_password, char const* owner_password,
  367 + QPDF_BOOL allow_accessibility, QPDF_BOOL allow_extract,
  368 + int print, int modify, QPDF_BOOL encrypt_metadata, QPDF_BOOL use_aes)
  369 +{
  370 + QTC::TC("qpdf", "qpdf-c called qpdf_set_r4_encryption_parameters");
  371 + qpdf->qpdf_writer->setR4EncryptionParameters(
  372 + user_password, owner_password,
  373 + allow_accessibility, allow_extract,
  374 + ((print == QPDF_R3_PRINT_LOW) ? QPDFWriter::r3p_low :
  375 + (print == QPDF_R3_PRINT_NONE) ? QPDFWriter::r3p_none :
  376 + QPDFWriter::r3p_full),
  377 + ((modify == QPDF_R3_MODIFY_ANNOTATE) ? QPDFWriter::r3m_annotate :
  378 + (modify == QPDF_R3_MODIFY_FORM) ? QPDFWriter::r3m_form :
  379 + (modify == QPDF_R3_MODIFY_ASSEMBLY) ? QPDFWriter::r3m_assembly :
  380 + (modify == QPDF_R3_MODIFY_NONE) ? QPDFWriter::r3m_none :
  381 + QPDFWriter::r3m_all),
  382 + encrypt_metadata, use_aes);
  383 +}
  384 +
359 385 void qpdf_set_linearization(qpdf_data qpdf, QPDF_BOOL value)
360 386 {
361 387 QTC::TC("qpdf", "qpdf-c called qpdf_set_linearization");
... ...
libqpdf/qpdf/Pl_AES_PDF.hh
... ... @@ -20,12 +20,15 @@ class DLL_EXPORT Pl_AES_PDF: public Pipeline
20 20  
21 21 // For testing only; PDF always uses CBC
22 22 void disableCBC();
  23 + // For testing only: use a fixed initialization vector for CBC
  24 + static void useStaticIV();
23 25  
24 26 private:
25 27 void flush(bool discard_padding);
26 28 void initializeVector();
27 29  
28 30 static unsigned int const buf_size = 16;
  31 + static bool use_static_iv;
29 32  
30 33 bool encrypt;
31 34 bool cbc_mode;
... ...
qpdf/qpdf-ctest.c
... ... @@ -229,6 +229,22 @@ static void test14(char const* infile,
229 229 report_errors();
230 230 }
231 231  
  232 +static void test15(char const* infile,
  233 + char const* password,
  234 + char const* outfile,
  235 + char const* outfile2)
  236 +{
  237 + qpdf_read(qpdf, infile, password);
  238 + qpdf_init_write(qpdf, outfile);
  239 + qpdf_set_static_ID(qpdf, QPDF_TRUE);
  240 + qpdf_set_static_aes_IV(qpdf, QPDF_TRUE);
  241 + qpdf_set_r4_encryption_parameters(
  242 + qpdf, "user2", "owner2", QPDF_TRUE, QPDF_TRUE,
  243 + QPDF_R3_PRINT_LOW, QPDF_R3_MODIFY_ALL, QPDF_TRUE, QPDF_TRUE);
  244 + qpdf_write(qpdf);
  245 + report_errors();
  246 +}
  247 +
232 248 int main(int argc, char* argv[])
233 249 {
234 250 char* whoami = 0;
... ... @@ -278,6 +294,7 @@ int main(int argc, char* argv[])
278 294 (n == 12) ? test12 :
279 295 (n == 13) ? test13 :
280 296 (n == 14) ? test14 :
  297 + (n == 15) ? test15 :
281 298 0);
282 299  
283 300 if (fn == 0)
... ...
qpdf/qpdf.cc
... ... @@ -146,6 +146,8 @@ These options can be useful for digging into PDF files or for use in\n\
146 146 automated test suites for software that uses the qpdf library.\n\
147 147 \n\
148 148 --static-id generate static /ID: FOR TESTING ONLY!\n\
  149 +--static-aes-iv use a static initialization vector for AES-CBC\n\
  150 + This is option is not secure! FOR TESTING ONLY!\n\
149 151 --no-original-object-ids suppress original object ID comments in qdf mode\n\
150 152 --show-encryption quickly show encryption parameters\n\
151 153 --check-linearization check file integrity and linearization status\n\
... ... @@ -604,6 +606,7 @@ int main(int argc, char* argv[])
604 606 std::string force_version;
605 607  
606 608 bool static_id = false;
  609 + bool static_aes_iv = false;
607 610 bool suppress_original_object_id = false;
608 611 bool show_encryption = false;
609 612 bool check_linearization = false;
... ... @@ -758,6 +761,10 @@ int main(int argc, char* argv[])
758 761 {
759 762 static_id = true;
760 763 }
  764 + else if (strcmp(arg, "static-aes-iv") == 0)
  765 + {
  766 + static_aes_iv = true;
  767 + }
761 768 else if (strcmp(arg, "no-original-object-ids") == 0)
762 769 {
763 770 suppress_original_object_id = true;
... ... @@ -1049,6 +1056,10 @@ int main(int argc, char* argv[])
1049 1056 {
1050 1057 w.setStaticID(true);
1051 1058 }
  1059 + if (static_aes_iv)
  1060 + {
  1061 + w.setStaticAesIV(true);
  1062 + }
1052 1063 if (suppress_original_object_id)
1053 1064 {
1054 1065 w.setSuppressOriginalObjectIDs(true);
... ...
qpdf/qpdf.testcov
... ... @@ -168,3 +168,5 @@ QPDF_encryption cleartext metadata 0
168 168 QPDF_encryption aes decode stream 0
169 169 QPDFWriter forcing object stream disable 0
170 170 QPDFWriter forced version disabled encryption 0
  171 +qpdf-c called qpdf_set_r4_encryption_parameters 0
  172 +qpdf-c called qpdf_set_static_aes_IV 0
... ...
qpdf/qtest/qpdf.test
... ... @@ -954,6 +954,7 @@ $td-&gt;runtest(&quot;invalid password&quot;,
954 954 my @cenc = (
955 955 [11, 'hybrid-xref.pdf', "''", 'r2', ""],
956 956 [12, 'hybrid-xref.pdf', "''", 'r3', ""],
  957 + [15, 'hybrid-xref.pdf', "''", 'r4', ""],
957 958 [13, 'c-r2.pdf', 'user1', 'decrypt with user',
958 959 "user password: user1\n"],
959 960 [13, 'c-r3.pdf', 'owner2', 'decrypt with owner',
... ...
qpdf/qtest/qpdf/c-r4.pdf 0 → 100644
No preview for this file type