Commit a8715c495b218c9b9388a2e20c8202a3fa73b2c1
1 parent
09175e45
add C API for R4 encryption
git-svn-id: svn+q:///qpdf/trunk@825 71b93d88-0707-0410-a8cf-f5a4172ac649
Showing
11 changed files
with
107 additions
and
2 deletions
include/qpdf/QPDFWriter.hh
| @@ -110,6 +110,11 @@ class DLL_EXPORT QPDFWriter | @@ -110,6 +110,11 @@ class DLL_EXPORT QPDFWriter | ||
| 110 | // suites. | 110 | // suites. |
| 111 | void setStaticID(bool); | 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 | // Suppress inclusion of comments indicating original object IDs | 118 | // Suppress inclusion of comments indicating original object IDs |
| 114 | // when writing QDF files. This can also be useful for testing, | 119 | // when writing QDF files. This can also be useful for testing, |
| 115 | // particularly when using comparison of two qdf files to | 120 | // particularly when using comparison of two qdf files to |
include/qpdf/qpdf-c.h
| @@ -226,6 +226,12 @@ extern "C" { | @@ -226,6 +226,12 @@ extern "C" { | ||
| 226 | DLL_EXPORT | 226 | DLL_EXPORT |
| 227 | void qpdf_set_static_ID(qpdf_data qpdf, QPDF_BOOL value); | 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 | DLL_EXPORT | 235 | DLL_EXPORT |
| 230 | void qpdf_set_suppress_original_object_IDs( | 236 | void qpdf_set_suppress_original_object_IDs( |
| 231 | qpdf_data qpdf, QPDF_BOOL value); | 237 | qpdf_data qpdf, QPDF_BOOL value); |
| @@ -259,6 +265,13 @@ extern "C" { | @@ -259,6 +265,13 @@ extern "C" { | ||
| 259 | int print, int modify); | 265 | int print, int modify); |
| 260 | 266 | ||
| 261 | DLL_EXPORT | 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 | void qpdf_set_linearization(qpdf_data qpdf, QPDF_BOOL value); | 275 | void qpdf_set_linearization(qpdf_data qpdf, QPDF_BOOL value); |
| 263 | 276 | ||
| 264 | DLL_EXPORT | 277 | DLL_EXPORT |
libqpdf/Pl_AES_PDF.cc
| @@ -12,6 +12,8 @@ | @@ -12,6 +12,8 @@ | ||
| 12 | # define srandom srand | 12 | # define srandom srand |
| 13 | #endif | 13 | #endif |
| 14 | 14 | ||
| 15 | +bool Pl_AES_PDF::use_static_iv = false; | ||
| 16 | + | ||
| 15 | Pl_AES_PDF::Pl_AES_PDF(char const* identifier, Pipeline* next, | 17 | Pl_AES_PDF::Pl_AES_PDF(char const* identifier, Pipeline* next, |
| 16 | bool encrypt, unsigned char const key[key_size]) : | 18 | bool encrypt, unsigned char const key[key_size]) : |
| 17 | Pipeline(identifier, next), | 19 | Pipeline(identifier, next), |
| @@ -52,6 +54,12 @@ Pl_AES_PDF::disableCBC() | @@ -52,6 +54,12 @@ Pl_AES_PDF::disableCBC() | ||
| 52 | } | 54 | } |
| 53 | 55 | ||
| 54 | void | 56 | void |
| 57 | +Pl_AES_PDF::useStaticIV() | ||
| 58 | +{ | ||
| 59 | + use_static_iv = true; | ||
| 60 | +} | ||
| 61 | + | ||
| 62 | +void | ||
| 55 | Pl_AES_PDF::write(unsigned char* data, int len) | 63 | Pl_AES_PDF::write(unsigned char* data, int len) |
| 56 | { | 64 | { |
| 57 | unsigned int bytes_left = len; | 65 | unsigned int bytes_left = len; |
| @@ -116,9 +124,19 @@ Pl_AES_PDF::initializeVector() | @@ -116,9 +124,19 @@ Pl_AES_PDF::initializeVector() | ||
| 116 | srandom((int)QUtil::get_current_time() ^ 0xcccc); | 124 | srandom((int)QUtil::get_current_time() ^ 0xcccc); |
| 117 | seeded_random = true; | 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,6 +140,15 @@ QPDFWriter::setStaticID(bool val) | ||
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | void | 142 | void |
| 143 | +QPDFWriter::setStaticAesIV(bool val) | ||
| 144 | +{ | ||
| 145 | + if (val) | ||
| 146 | + { | ||
| 147 | + Pl_AES_PDF::useStaticIV(); | ||
| 148 | + } | ||
| 149 | +} | ||
| 150 | + | ||
| 151 | +void | ||
| 143 | QPDFWriter::setSuppressOriginalObjectIDs(bool val) | 152 | QPDFWriter::setSuppressOriginalObjectIDs(bool val) |
| 144 | { | 153 | { |
| 145 | this->suppress_original_object_ids = val; | 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,6 +313,12 @@ void qpdf_set_static_ID(qpdf_data qpdf, QPDF_BOOL value) | ||
| 313 | qpdf->qpdf_writer->setStaticID(value); | 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 | void qpdf_set_suppress_original_object_IDs( | 322 | void qpdf_set_suppress_original_object_IDs( |
| 317 | qpdf_data qpdf, QPDF_BOOL value) | 323 | qpdf_data qpdf, QPDF_BOOL value) |
| 318 | { | 324 | { |
| @@ -356,6 +362,26 @@ void qpdf_set_r3_encryption_parameters( | @@ -356,6 +362,26 @@ void qpdf_set_r3_encryption_parameters( | ||
| 356 | QPDFWriter::r3m_all)); | 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 | void qpdf_set_linearization(qpdf_data qpdf, QPDF_BOOL value) | 385 | void qpdf_set_linearization(qpdf_data qpdf, QPDF_BOOL value) |
| 360 | { | 386 | { |
| 361 | QTC::TC("qpdf", "qpdf-c called qpdf_set_linearization"); | 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,12 +20,15 @@ class DLL_EXPORT Pl_AES_PDF: public Pipeline | ||
| 20 | 20 | ||
| 21 | // For testing only; PDF always uses CBC | 21 | // For testing only; PDF always uses CBC |
| 22 | void disableCBC(); | 22 | void disableCBC(); |
| 23 | + // For testing only: use a fixed initialization vector for CBC | ||
| 24 | + static void useStaticIV(); | ||
| 23 | 25 | ||
| 24 | private: | 26 | private: |
| 25 | void flush(bool discard_padding); | 27 | void flush(bool discard_padding); |
| 26 | void initializeVector(); | 28 | void initializeVector(); |
| 27 | 29 | ||
| 28 | static unsigned int const buf_size = 16; | 30 | static unsigned int const buf_size = 16; |
| 31 | + static bool use_static_iv; | ||
| 29 | 32 | ||
| 30 | bool encrypt; | 33 | bool encrypt; |
| 31 | bool cbc_mode; | 34 | bool cbc_mode; |
qpdf/qpdf-ctest.c
| @@ -229,6 +229,22 @@ static void test14(char const* infile, | @@ -229,6 +229,22 @@ static void test14(char const* infile, | ||
| 229 | report_errors(); | 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 | int main(int argc, char* argv[]) | 248 | int main(int argc, char* argv[]) |
| 233 | { | 249 | { |
| 234 | char* whoami = 0; | 250 | char* whoami = 0; |
| @@ -278,6 +294,7 @@ int main(int argc, char* argv[]) | @@ -278,6 +294,7 @@ int main(int argc, char* argv[]) | ||
| 278 | (n == 12) ? test12 : | 294 | (n == 12) ? test12 : |
| 279 | (n == 13) ? test13 : | 295 | (n == 13) ? test13 : |
| 280 | (n == 14) ? test14 : | 296 | (n == 14) ? test14 : |
| 297 | + (n == 15) ? test15 : | ||
| 281 | 0); | 298 | 0); |
| 282 | 299 | ||
| 283 | if (fn == 0) | 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,6 +146,8 @@ These options can be useful for digging into PDF files or for use in\n\ | ||
| 146 | automated test suites for software that uses the qpdf library.\n\ | 146 | automated test suites for software that uses the qpdf library.\n\ |
| 147 | \n\ | 147 | \n\ |
| 148 | --static-id generate static /ID: FOR TESTING ONLY!\n\ | 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 | --no-original-object-ids suppress original object ID comments in qdf mode\n\ | 151 | --no-original-object-ids suppress original object ID comments in qdf mode\n\ |
| 150 | --show-encryption quickly show encryption parameters\n\ | 152 | --show-encryption quickly show encryption parameters\n\ |
| 151 | --check-linearization check file integrity and linearization status\n\ | 153 | --check-linearization check file integrity and linearization status\n\ |
| @@ -604,6 +606,7 @@ int main(int argc, char* argv[]) | @@ -604,6 +606,7 @@ int main(int argc, char* argv[]) | ||
| 604 | std::string force_version; | 606 | std::string force_version; |
| 605 | 607 | ||
| 606 | bool static_id = false; | 608 | bool static_id = false; |
| 609 | + bool static_aes_iv = false; | ||
| 607 | bool suppress_original_object_id = false; | 610 | bool suppress_original_object_id = false; |
| 608 | bool show_encryption = false; | 611 | bool show_encryption = false; |
| 609 | bool check_linearization = false; | 612 | bool check_linearization = false; |
| @@ -758,6 +761,10 @@ int main(int argc, char* argv[]) | @@ -758,6 +761,10 @@ int main(int argc, char* argv[]) | ||
| 758 | { | 761 | { |
| 759 | static_id = true; | 762 | static_id = true; |
| 760 | } | 763 | } |
| 764 | + else if (strcmp(arg, "static-aes-iv") == 0) | ||
| 765 | + { | ||
| 766 | + static_aes_iv = true; | ||
| 767 | + } | ||
| 761 | else if (strcmp(arg, "no-original-object-ids") == 0) | 768 | else if (strcmp(arg, "no-original-object-ids") == 0) |
| 762 | { | 769 | { |
| 763 | suppress_original_object_id = true; | 770 | suppress_original_object_id = true; |
| @@ -1049,6 +1056,10 @@ int main(int argc, char* argv[]) | @@ -1049,6 +1056,10 @@ int main(int argc, char* argv[]) | ||
| 1049 | { | 1056 | { |
| 1050 | w.setStaticID(true); | 1057 | w.setStaticID(true); |
| 1051 | } | 1058 | } |
| 1059 | + if (static_aes_iv) | ||
| 1060 | + { | ||
| 1061 | + w.setStaticAesIV(true); | ||
| 1062 | + } | ||
| 1052 | if (suppress_original_object_id) | 1063 | if (suppress_original_object_id) |
| 1053 | { | 1064 | { |
| 1054 | w.setSuppressOriginalObjectIDs(true); | 1065 | w.setSuppressOriginalObjectIDs(true); |
qpdf/qpdf.testcov
| @@ -168,3 +168,5 @@ QPDF_encryption cleartext metadata 0 | @@ -168,3 +168,5 @@ QPDF_encryption cleartext metadata 0 | ||
| 168 | QPDF_encryption aes decode stream 0 | 168 | QPDF_encryption aes decode stream 0 |
| 169 | QPDFWriter forcing object stream disable 0 | 169 | QPDFWriter forcing object stream disable 0 |
| 170 | QPDFWriter forced version disabled encryption 0 | 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->runtest("invalid password", | @@ -954,6 +954,7 @@ $td->runtest("invalid password", | ||
| 954 | my @cenc = ( | 954 | my @cenc = ( |
| 955 | [11, 'hybrid-xref.pdf', "''", 'r2', ""], | 955 | [11, 'hybrid-xref.pdf', "''", 'r2', ""], |
| 956 | [12, 'hybrid-xref.pdf', "''", 'r3', ""], | 956 | [12, 'hybrid-xref.pdf', "''", 'r3', ""], |
| 957 | + [15, 'hybrid-xref.pdf', "''", 'r4', ""], | ||
| 957 | [13, 'c-r2.pdf', 'user1', 'decrypt with user', | 958 | [13, 'c-r2.pdf', 'user1', 'decrypt with user', |
| 958 | "user password: user1\n"], | 959 | "user password: user1\n"], |
| 959 | [13, 'c-r3.pdf', 'owner2', 'decrypt with owner', | 960 | [13, 'c-r3.pdf', 'owner2', 'decrypt with owner', |
qpdf/qtest/qpdf/c-r4.pdf
0 → 100644
No preview for this file type