From 750aca5b94351f730fa768b07caa3fc26c8d27c0 Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Wed, 10 Nov 2021 17:57:12 -0500 Subject: [PATCH] First increment of improving handling of weak crypto (fixes #358) --- ChangeLog | 6 +++ README.md | 4 ++ TODO | 17 ++++++++ fuzz/qpdf_fuzzer.cc | 2 +- include/qpdf/QPDFCryptoImpl.hh | 3 ++ include/qpdf/QPDFWriter.hh | 21 +++++++--- lgtm.yml | 11 ++++++ libqpdf/Pl_RC4.cc | 1 + libqpdf/qpdf-c.cc | 40 +++++++++++++++++++ manual/qpdf-manual.xml | 71 +++++++++++++++++++++++++++++++++ qpdf/qpdf.cc | 37 +++++++++++++++++ qpdf/qpdf.testcov | 1 + qpdf/qtest/qpdf.test | 72 ++++++++++++++++++++++++++++------ 13 files changed, 267 insertions(+), 19 deletions(-) create mode 100644 lgtm.yml diff --git a/ChangeLog b/ChangeLog index 4f15b9aa..8a5d285c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2021-11-10 Jay Berkenbilt + + * Add --allow-weak-crypto option to suppress warnings about use of + weak cryptographic algorithms. Update documentation around this + issue. Fixes #358. + 2021-11-07 Jay Berkenbilt * Relax xref recovery logic a bit so that files whose objects are diff --git a/README.md b/README.md index ceec231d..ff968dcb 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,10 @@ For example, if you want to guarantee that the GnuTLS crypto provider is used, y Please see the section on crypto providers in the manual for more details. +## Note about weak cryptographic algorithms + +The PDF file format used to rely on RC4 for encryption. Using 256-bit keys always uses AES instead, and with 128-bit keys, you can elect to use AES. qpdf does its best to warn when someone is writing a file with weak cryptographic algorithms, but qpdf must always retain support for being able to read and even write files with weak encryption to be able to fully support older PDF files and older PDF readers. + # Building from a pristine checkout When building qpdf from a pristine checkout from version control, generated documentation files are not present. You may either generate them (by passing `--enable-doc-maintenance` to `./configure` and satisfying the extra build-time dependencies) or obtain them from a released source package, which includes them. If you want to grab just the files that are in the source distribution but not in the repository, extract a source distribution in a temporary directory, and run `make CLEAN=1 distfiles.zip`. This will create a file called `distfiles.zip`, which can you can extract in a checkout of the source repository. This step is optional unless you are running make install and want the html and PDF versions of the documentation to be installed. diff --git a/TODO b/TODO index c98179c3..39631885 100644 --- a/TODO +++ b/TODO @@ -187,6 +187,23 @@ Comments appear in the code prefixed by "ABI" before copying, though maybe we don't because it could cause multiple copies to be made...usually it's better to handle that explicitly. +* Deal with weak cryptographic algorithms: + * Github issue #576 + * Add something to QPDFWriter that you must call in order to allow + creation of files with insecure crypto. Maybe + QPDFWriter::allowWeakCrypto. Call this when --allow-weak-crypto is + passed and probably also when copying encryption by default from + an input file. + * Change deterministic id to use something other than MD5 but allow + the old way for compatibility -- maybe rename the method to force + the developer to make a choice + * Find other uses of MD5 and find the ones that are discretionary, + if any + * Have QPDFWriter raise an exception if it's about to write using + weak crypto and hasn't been given permission + * Search for --allow-weak-crypto in the manual and in qpdf.cc's help + information + * Update the ref.weak-crypto section of the manual Page splitting/merging ====================== diff --git a/fuzz/qpdf_fuzzer.cc b/fuzz/qpdf_fuzzer.cc index 070817c6..eccab375 100644 --- a/fuzz/qpdf_fuzzer.cc +++ b/fuzz/qpdf_fuzzer.cc @@ -107,7 +107,7 @@ FuzzHelper::testWrite() w->setStaticID(true); w->setObjectStreamMode(qpdf_o_disable); w->setR3EncryptionParameters( - "u", "o", true, true, qpdf_r3p_full, qpdf_r3m_all); + "u", "o", true, true, true, true, true, true, qpdf_r3p_full); doWrite(w); q = getQpdf(); diff --git a/include/qpdf/QPDFCryptoImpl.hh b/include/qpdf/QPDFCryptoImpl.hh index ff25d594..ee37b233 100644 --- a/include/qpdf/QPDFCryptoImpl.hh +++ b/include/qpdf/QPDFCryptoImpl.hh @@ -69,6 +69,9 @@ class QPDF_DLL_CLASS QPDFCryptoImpl // Encryption/Decryption + // QPDF must support RC4 to be able to work with older PDF files + // and readers. Search for RC4 in README.md + // key_len of -1 means treat key_data as a null-terminated string QPDF_DLL virtual void RC4_init(unsigned char const* key_data, int key_len = -1) = 0; diff --git a/include/qpdf/QPDFWriter.hh b/include/qpdf/QPDFWriter.hh index 819198cc..8044d054 100644 --- a/include/qpdf/QPDFWriter.hh +++ b/include/qpdf/QPDFWriter.hh @@ -359,6 +359,16 @@ class QPDFWriter // this from your own application, QUtil contains many transcoding // functions that could be useful to you, most notably // utf8_to_pdf_doc. + + // R3 uses RC4, which is a weak cryptographic algorithm. Don't use + // it unless you have to. + QPDF_DLL + void setR2EncryptionParameters( + char const* user_password, char const* owner_password, + bool allow_print, bool allow_modify, + bool allow_extract, bool allow_annotate); + // R3 uses RC4, which is a weak cryptographic algorithm. Don't use + // it unless you have to. QPDF_DLL void setR3EncryptionParameters( char const* user_password, char const* owner_password, @@ -366,6 +376,8 @@ class QPDFWriter bool allow_assemble, bool allow_annotate_and_form, bool allow_form_filling, bool allow_modify_other, qpdf_r3_print_e print); + // R4 uses RC4, which is a weak cryptographic algorithm, when + // use_aes=false. Don't use it unless you have to. QPDF_DLL void setR4EncryptionParameters( char const* user_password, char const* owner_password, @@ -392,28 +404,27 @@ class QPDFWriter qpdf_r3_print_e print, bool encrypt_metadata_aes); // Pre qpdf 8.4.0 API - QPDF_DLL - void setR2EncryptionParameters( - char const* user_password, char const* owner_password, - bool allow_print, bool allow_modify, - bool allow_extract, bool allow_annotate); + [[deprecated("see newer API above")]] QPDF_DLL void setR3EncryptionParameters( char const* user_password, char const* owner_password, bool allow_accessibility, bool allow_extract, qpdf_r3_print_e print, qpdf_r3_modify_e modify); + [[deprecated("see newer API above")]] QPDF_DLL void setR4EncryptionParameters( char const* user_password, char const* owner_password, bool allow_accessibility, bool allow_extract, qpdf_r3_print_e print, qpdf_r3_modify_e modify, bool encrypt_metadata, bool use_aes); + [[deprecated("see newer API above")]] QPDF_DLL void setR5EncryptionParameters( char const* user_password, char const* owner_password, bool allow_accessibility, bool allow_extract, qpdf_r3_print_e print, qpdf_r3_modify_e modify, bool encrypt_metadata); + [[deprecated("see newer API above")]] QPDF_DLL void setR6EncryptionParameters( char const* user_password, char const* owner_password, diff --git a/lgtm.yml b/lgtm.yml new file mode 100644 index 00000000..73ccfd6c --- /dev/null +++ b/lgtm.yml @@ -0,0 +1,11 @@ +# See https://lgtm.com/help/lgtm/lgtm.yml-configuration-file + +# Suppress alerts for weak cryptographic algorithms. The PDF file +# format used to rely on various weak algorithms. It is no longer +# necessary to use them when creating encrypted PDF files, but qpdf +# must always retain support for those algorithms in order to be able +# to read older files. qpdf issues warnings to try to prevent users +# from creating new files with weak encryption algorithms. + +queries: +- exclude: cpp/weak-cryptographic-algorithm diff --git a/libqpdf/Pl_RC4.cc b/libqpdf/Pl_RC4.cc index 6c8fd3c6..e29551fa 100644 --- a/libqpdf/Pl_RC4.cc +++ b/libqpdf/Pl_RC4.cc @@ -34,6 +34,7 @@ Pl_RC4::write(unsigned char* data, size_t len) size_t bytes = (bytes_left < this->out_bufsize ? bytes_left : out_bufsize); bytes_left -= bytes; + // lgtm[cpp/weak-cryptographic-algorithm] rc4.process(p, bytes, outbuf.getPointer()); p += bytes; getNext()->write(outbuf.getPointer(), bytes); diff --git a/libqpdf/qpdf-c.cc b/libqpdf/qpdf-c.cc index 0d37f732..ea3782ce 100644 --- a/libqpdf/qpdf-c.cc +++ b/libqpdf/qpdf-c.cc @@ -702,10 +702,20 @@ void qpdf_set_r3_encryption_parameters( QPDF_BOOL allow_accessibility, QPDF_BOOL allow_extract, qpdf_r3_print_e print, qpdf_r3_modify_e modify) { +#ifdef _MSC_VER +# pragma warning (disable: 4996) +#endif +#if (defined(__GNUC__) || defined(__clang__)) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif qpdf->qpdf_writer->setR3EncryptionParameters( user_password, owner_password, allow_accessibility != QPDF_FALSE, allow_extract != QPDF_FALSE, print, modify); +#if (defined(__GNUC__) || defined(__clang__)) +# pragma GCC diagnostic pop +#endif } void qpdf_set_r4_encryption_parameters( @@ -714,11 +724,21 @@ void qpdf_set_r4_encryption_parameters( qpdf_r3_print_e print, qpdf_r3_modify_e modify, QPDF_BOOL encrypt_metadata, QPDF_BOOL use_aes) { +#ifdef _MSC_VER +# pragma warning (disable: 4996) +#endif +#if (defined(__GNUC__) || defined(__clang__)) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif qpdf->qpdf_writer->setR4EncryptionParameters( user_password, owner_password, allow_accessibility != QPDF_FALSE, allow_extract != QPDF_FALSE, print, modify, encrypt_metadata != QPDF_FALSE, use_aes != QPDF_FALSE); +#if (defined(__GNUC__) || defined(__clang__)) +# pragma GCC diagnostic pop +#endif } void qpdf_set_r5_encryption_parameters( @@ -727,11 +747,21 @@ void qpdf_set_r5_encryption_parameters( qpdf_r3_print_e print, qpdf_r3_modify_e modify, QPDF_BOOL encrypt_metadata) { +#ifdef _MSC_VER +# pragma warning (disable: 4996) +#endif +#if (defined(__GNUC__) || defined(__clang__)) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif qpdf->qpdf_writer->setR5EncryptionParameters( user_password, owner_password, allow_accessibility != QPDF_FALSE, allow_extract != QPDF_FALSE, print, modify, encrypt_metadata != QPDF_FALSE); +#if (defined(__GNUC__) || defined(__clang__)) +# pragma GCC diagnostic pop +#endif } void qpdf_set_r6_encryption_parameters( @@ -740,10 +770,20 @@ void qpdf_set_r6_encryption_parameters( qpdf_r3_print_e print, qpdf_r3_modify_e modify, QPDF_BOOL encrypt_metadata) { +#ifdef _MSC_VER +# pragma warning (disable: 4996) +#endif +#if (defined(__GNUC__) || defined(__clang__)) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif qpdf->qpdf_writer->setR6EncryptionParameters( user_password, owner_password, allow_accessibility != QPDF_FALSE, allow_extract != QPDF_FALSE, print, modify, encrypt_metadata != QPDF_FALSE); +#if (defined(__GNUC__) || defined(__clang__)) +# pragma GCC diagnostic pop +#endif } void qpdf_set_linearization(qpdf_data qpdf, QPDF_BOOL value) diff --git a/manual/qpdf-manual.xml b/manual/qpdf-manual.xml index 13008ef9..98ce8afa 100644 --- a/manual/qpdf-manual.xml +++ b/manual/qpdf-manual.xml @@ -873,6 +873,19 @@ make + + + + + Starting with version 10.4, qpdf issues warnings when + requested to create files using RC4 encryption. This option + suppresses those warnings. In future versions of qpdf, qpdf + will refuse to create files with weak cryptography when this + flag is not given. See for + additional details. + + + @@ -3355,6 +3368,43 @@ outfile.pdf + + Weak Cryptography + + Start with version 10.4, qpdf is taking steps to reduce the + likelihood of a user accidentally creating PDF + files with insecure cryptography but will continue to allow + creation of such files indefinitely with explicit acknowledgment. + + + The PDF file format makes use of RC4, which is known to be a weak + cryptography algorithm, and MD5, which is a weak hashing algorithm. + In version 10.4, qpdf generates warnings for some (but not all) + cases of writing files with weak cryptography when invoked from the + command-line. These warnings can be suppressed using the + option. + + + It is planned for qpdf version 11 to be stricter, making it an + error to write files with insecure cryptography from the + command-line tool in most cases without specifying the + flag and also to require + explicit steps when using the C++ library to enable use of insecure + cryptography. + + + Note that qpdf must always retain support for weak cryptographic + algorithms since this is required for reading older PDF files that + use it. Additionally, qpdf will always retain the ability to create + files using weak cryptographic algorithms since, as a development + tool, qpdf explicitly supports creating older or deprecated types + of PDF files since these are sometimes needed to test or work with + older versions of software. Even if other cryptography libraries + drop support for RC4 or MD5, qpdf can always fall back to its + internal implementations of those algorithms, so they are not going + to disappear from qpdf. + + QPDF JSON @@ -5070,6 +5120,27 @@ print "\n"; 10.4.0: Month dd, YYYY + + + Handling of Weak Cryptography Algorithms + + + + + From the qpdf CLI, the + is now required to suppress a warning when explicitly + creating PDF files using RC4 encryption. While qpdf will + always retain the ability to read and write such files, + doing so will require explicit acknowledgment moving + forward. For qpdf 10.4, this change only affects the + command-line tool. Starting in qpdf 11, there will be small + API changes to require explicit acknowledgment in those + cases as well. For additional information, see . + + + + Bug Fixes diff --git a/qpdf/qpdf.cc b/qpdf/qpdf.cc index 9438886e..f3fdfbc4 100644 --- a/qpdf/qpdf.cc +++ b/qpdf/qpdf.cc @@ -141,6 +141,7 @@ struct Options suppress_password_recovery(false), password_mode(pm_auto), allow_insecure(false), + allow_weak_crypto(false), keylen(0), r2_print(true), r2_modify(true), @@ -242,6 +243,7 @@ struct Options bool suppress_password_recovery; password_mode_e password_mode; bool allow_insecure; + bool allow_weak_crypto; std::string user_password; std::string owner_password; int keylen; @@ -811,6 +813,7 @@ class ArgParser void argDecrypt(); void argPasswordIsHexKey(); void argAllowInsecure(); + void argAllowWeakCrypto(); void argPasswordMode(char* parameter); void argSuppressPasswordRecovery(); void argCopyEncryption(char* parameter); @@ -1169,6 +1172,7 @@ ArgParser::initOptionTable() (*t)["replace-input"] = oe_bare(&ArgParser::argReplaceInput); (*t)["is-encrypted"] = oe_bare(&ArgParser::argIsEncrypted); (*t)["requires-password"] = oe_bare(&ArgParser::argRequiresPassword); + (*t)["allow-weak-crypto"] = oe_bare(&ArgParser::argAllowWeakCrypto); t = &this->encrypt40_option_table; (*t)["--"] = oe_bare(&ArgParser::argEndEncrypt); @@ -1376,6 +1380,8 @@ ArgParser::argHelp() << "--encryption-file-password=password\n" << " password used to open the file from which encryption\n" << " parameters are being copied\n" + << "--allow-weak-crypto allow creation of files using weak cryptographic\n" + << " algorithms\n" << "--encrypt options -- generate an encrypted file\n" << "--decrypt remove any encryption on the file\n" << "--password-is-hex-key treat primary password option as a hex-encoded key\n" @@ -1502,6 +1508,11 @@ ArgParser::argHelp() << "to be used even if not otherwise needed. This option is primarily useful\n" << "for testing qpdf and has no other practical use.\n" << "\n" + << "A warning will be issued if you attempt to encrypt a file with a format that\n" + << "uses a weak cryptographic algorithm such as RC4. To suppress the warning,\n" + << "specify the option --allow-weak-crypto. This option is outside of encryption\n" + << "options (e.g. --allow-week-crypto --encrypt u o 128 --)\n" + << "\n" << "\n" << "Password Modes\n" << "--------------\n" @@ -2068,6 +2079,12 @@ ArgParser::argAllowInsecure() o.allow_insecure = true; } +void +ArgParser::argAllowWeakCrypto() +{ + o.allow_weak_crypto = true; +} + void ArgParser::argCopyEncryption(char* parameter) { @@ -6253,6 +6270,26 @@ static void set_encryption_options(QPDF& pdf, Options& o, QPDFWriter& w) } maybe_fix_write_password(R, o, o.user_password); maybe_fix_write_password(R, o, o.owner_password); + if ((R < 4) || ((R == 4) && (! o.use_aes))) + { + if (! o.allow_weak_crypto) + { + // Do not set exit code to EXIT_WARNING for this case as + // this does not reflect a potential problem with the + // input file. + QTC::TC("qpdf", "qpdf weak crypto warning"); + std::cerr + << whoami + << ": writing a file with RC4, a weak cryptographic algorithm" + << std::endl + << "Please use 256-bit keys for better security." + << std::endl + << "Pass --allow-weak-crypto to suppress this warning." + << std::endl + << "This will become an error in a future version of qpdf." + << std::endl; + } + } switch (R) { case 2: diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov index 8f888209..8b04c04f 100644 --- a/qpdf/qpdf.testcov +++ b/qpdf/qpdf.testcov @@ -598,3 +598,4 @@ check unclosed --pages 1 QPDF_pages findPage not found 0 qpdf overlay page with no resources 0 QPDFObjectHandle check ownership 0 +qpdf weak crypto warning 0 diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test index 3c3283e9..5129025f 100644 --- a/qpdf/qtest/qpdf.test +++ b/qpdf/qtest/qpdf.test @@ -1358,7 +1358,8 @@ foreach my $file (qw(short-id long-id)) { $td->runtest("encrypt $file.pdf", {$td->COMMAND => - "qpdf --encrypt '' pass 40 -- $file.pdf a.pdf"}, + "qpdf --allow-weak-crypto". + " --encrypt '' pass 40 -- $file.pdf a.pdf"}, {$td->STRING => "", $td->EXIT_STATUS => 0}, $td->NORMALIZE_NEWLINES); @@ -2057,7 +2058,8 @@ $td->notify("--- Split Pages ---"); my @sp_cases = ( [11, '%d at beginning', '', '%d_split-out.zdf'], [11, '%d at end', '--qdf', 'split-out.zdf_%d'], - [11, '%d in middle', '--encrypt u o 128 --', 'a-%d-split-out.zdf'], + [11, '%d in middle', '--allow-weak-crypto --encrypt u o 128 --', + 'a-%d-split-out.zdf'], [11, 'pdf extension', '', 'split-out.Pdf'], [4, 'fallback', '--pages 11-pages.pdf 1-3 minimal.pdf --', 'split-out'], [1, 'broken data', '--pages broken-lzw.pdf --', 'split-out.pdf', @@ -2718,6 +2720,7 @@ $td->runtest("check output", $td->runtest("avoid respecification of password", {$td->COMMAND => "qpdf --empty a.pdf --copy-encryption=20-pages.pdf" . + " --allow-weak-crypto" . " --encryption-file-password=user" . " --pages 20-pages.pdf 1,z -- --static-id"}, {$td->STRING => "", $td->EXIT_STATUS => 0}); @@ -3483,7 +3486,7 @@ for (my $n = 16; $n <= 19; ++$n) '-object-streams=preserve', '-object-streams=generate') { - foreach my $qdf ('-qdf', '', '-encrypt "" x 128 --') + foreach my $qdf ('-qdf', '', '-allow-weak-crypto -encrypt "" x 128 --') { # 4 tests + 1 compare_pdfs * 36 cases # 2 additional tests * 12 cases @@ -3716,19 +3719,22 @@ foreach my $f (qw(compressed-metadata.pdf enc-base.pdf)) check_metadata("a.pdf", 0, 1); $td->runtest("encrypt normally", {$td->COMMAND => - "qpdf --encrypt '' o 128 -- a.pdf b.pdf"}, + "qpdf --allow-weak-crypto" . + " --encrypt '' o 128 -- a.pdf b.pdf"}, {$td->STRING => "", $td->EXIT_STATUS => 0}); check_metadata("b.pdf", 1, 0); unlink "b.pdf"; $td->runtest("encrypt V4", {$td->COMMAND => - "qpdf --encrypt '' o 128 --force-V4 -- a.pdf b.pdf"}, + "qpdf --allow-weak-crypto" . + " --encrypt '' o 128 --force-V4 -- a.pdf b.pdf"}, {$td->STRING => "", $td->EXIT_STATUS => 0}); check_metadata("b.pdf", 1, 0); unlink "b.pdf"; $td->runtest("encrypt with cleartext metadata", {$td->COMMAND => - "qpdf --encrypt '' o 128 --cleartext-metadata --" . + "qpdf --allow-weak-crypto" . + " --encrypt '' o 128 --cleartext-metadata --" . " a.pdf b.pdf"}, {$td->STRING => "", $td->EXIT_STATUS => 0}); check_metadata("b.pdf", 1, 1); @@ -3751,6 +3757,31 @@ foreach my $f (qw(compressed-metadata.pdf enc-base.pdf)) } } +show_ntests(); +# ---------- +$td->notify("--- Weak Cryptography ---"); +$n_tests += 4; +$td->runtest("256-bit: no warning", + {$td->COMMAND => 'qpdf --encrypt "" "" 256 -- minimal.pdf a.pdf'}, + {$td->STRING => "", $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); +$td->runtest("128-bit with AES: no warning", + {$td->COMMAND => 'qpdf --encrypt "" "" 128 --use-aes=y --' . + ' minimal.pdf a.pdf'}, + {$td->STRING => "", $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); +# Note: we intentionally have exit status 0 for this warning. +$td->runtest("128-bit without AES: warning", + {$td->COMMAND => 'qpdf --encrypt "" "" 128 -- minimal.pdf a.pdf'}, + {$td->REGEXP => "Pass --allow-weak-crypto to suppress", + $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); +$td->runtest("40-bit: warning", + {$td->COMMAND => 'qpdf --encrypt "" "" 40 -- minimal.pdf a.pdf'}, + {$td->REGEXP => "Pass --allow-weak-crypto to suppress", + $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); + show_ntests(); # ---------- $td->notify("--- Linearization Tests ---"); @@ -4128,7 +4159,8 @@ foreach my $d (@encrypted_files) $enc_json =~ s/---opm---/$opm/; $enc_json =~ s/---upm---/$upm/; - my $eflags = "-encrypt \"$upass\" \"$opass\" $bits $xeflags --"; + my $eflags = "--allow-weak-crypto" . + " -encrypt \"$upass\" \"$opass\" $bits $xeflags --"; if (($opass eq "") && ($bits == 256)) { $eflags =~ s/--$/--allow-insecure --/; @@ -4391,7 +4423,7 @@ foreach my $d (['--force-V4', 'V4'], my ($args, $out) = @$d; $td->runtest("encrypt $args", {$td->COMMAND => "qpdf --static-aes-iv --static-id" . - " --encrypt '' '' 128 $args --" . + " --allow-weak-crypto --encrypt '' '' 128 $args --" . " enc-base.pdf a.pdf"}, {$td->STRING => "", $td->EXIT_STATUS => 0}); $td->runtest("check output", @@ -4677,6 +4709,7 @@ foreach my $d (@unicode_pw_cases) $td->runtest("encode $bits, $pw, $w_encoding", {$td->COMMAND => "qpdf $xargs --static-id --static-aes-iv" . + " --allow-weak-crypto" . " --encrypt $upass o $bits -- minimal.pdf a.pdf"}, {$td->STRING => $exp, $td->EXIT_STATUS => ($exp ? 2 : 0)}, $td->NORMALIZE_NEWLINES); @@ -4718,7 +4751,8 @@ $n_tests += 5; $td->runtest("bytes fallback warning", {$td->COMMAND => - "qpdf --encrypt \@password-bare-complex-utf8 o 128 --" . + "qpdf --allow-weak-crypto" . + " --encrypt \@password-bare-complex-utf8 o 128 --" . " minimal.pdf a.pdf"}, {$td->FILE => "bytes-fallback.out", $td->EXIT_STATUS => 0}, $td->NORMALIZE_NEWLINES); @@ -4814,9 +4848,9 @@ my @flags = (["-qdf", # 1 "decrypted"], ["-linearize", # 9 "linearized"], - ["-encrypt \"\" owner 128 --", # 10 + ["-allow-weak-crypto -encrypt \"\" owner 128 --", # 10 "encrypted"], - ["-linearize -encrypt \"\" o 128 --", # 11 + ["-linearize -allow-weak-crypto -encrypt \"\" o 128 --", # 11 "linearized and encrypted"], ["", # 12 "no arguments"], @@ -4985,9 +5019,15 @@ $n_tests += 2; $n_tests += 12; foreach my $i (qw(40 128 256)) { + my $x = ""; + if ($i < 256) + { + $x = "--allow-weak-crypto"; + } $td->runtest("encrypt $i", {$td->COMMAND => - "qpdf --encrypt '' o $i -- digitally-signed.pdf a.pdf"}, + "qpdf $x --encrypt '' o $i --" . + " digitally-signed.pdf a.pdf"}, {$td->STRING => "", $td->EXIT_STATUS => 0}); $td->runtest("find desired contents (encrypt $i)", @@ -5010,9 +5050,15 @@ foreach my $i (qw(40 128 256)) $n_tests += 15; foreach my $i (qw(40 128 256)) { + my $x = ""; + if ($i < 256) + { + $x = "--allow-weak-crypto"; + } $td->runtest("non sig dict encrypt $i", {$td->COMMAND => - "qpdf --encrypt '' o $i -- comment-annotation.pdf a.pdf"}, + "qpdf $x --encrypt '' o $i --" . + " comment-annotation.pdf a.pdf"}, {$td->STRING => "", $td->EXIT_STATUS => 0}); $td->runtest("plain text not found due to encryption (non sig dict encrypt $i)",