Commit 8ccd3a8a89d95ae0613679ba7b394a4f87699e12

Authored by Jay Berkenbilt
1 parent 2213ed0c

Mark weak encryption with API changes (fixes #576)

ChangeLog
1 1 2022-04-30 Jay Berkenbilt <ejb@ql.org>
2 2  
  3 + * QPDFWriter: change encryption API calls
  4 + - Remove deprecated versions of setR*EncryptionParameters
  5 + methods from before qpdf 8.4.0
  6 + - Replace setR2EncryptionParameters with
  7 + setR2EncryptionParametersInsecure
  8 + - Replace setR3EncryptionParameters with
  9 + setR3EncryptionParametersInsecure
  10 + - Replace setR4EncryptionParameters with
  11 + setR4EncryptionParametersInsecure
  12 +
  13 + * C API: change encryption API calls to match C++ interface
  14 + - Remove pre-8.4.0 functions:
  15 + - qpdf_set_r3_encryption_parameters
  16 + - qpdf_set_r4_encryption_parameters
  17 + - qpdf_set_r5_encryption_parameters
  18 + - qpdf_set_r6_encryption_parameters
  19 + - Add "_insecure" to insecure encryption triggers:
  20 + - Replace void qpdf_set_r2_encryption_parameters
  21 + with qpdf_set_r2_encryption_parameters_insecure
  22 + - Replace void qpdf_set_r3_encryption_parameters2
  23 + with qpdf_set_r3_encryption_parameters_insecure
  24 + - Replace void qpdf_set_r4_encryption_parameters2
  25 + with qpdf_set_r4_encryption_parameters_insecure
  26 +
3 27 * Make attempting to write encrypted files that use RC4 (40-bit or
4 28 128-bit without AES) an error rather than a warning when
5   - --allow-weak-crypto is not specified.
  29 + --allow-weak-crypto is not specified. Fixes #576.
6 30  
7 31 2022-04-29 Jay Berkenbilt <ejb@ql.org>
8 32  
... ...
... ... @@ -475,18 +475,6 @@ Comments appear in the code prefixed by &quot;ABI&quot;. Always Search for ABI
475 475 in source and header files to find items not listed here. Also search
476 476 for "[[deprecated" to find deprecated APIs that can be removed.
477 477  
478   -* Deal with weak cryptographic algorithms:
479   - * Github issue #576
480   - * Add something to QPDFWriter that you must call in order to allow
481   - creation of files with insecure crypto. Maybe
482   - QPDFWriter::allowWeakCrypto. Call this when --allow-weak-crypto is
483   - passed and probably also when copying encryption by default from
484   - an input file. There should be some API change so that, when
485   - people recompile with qpdf 11, their code won't suddenly stop
486   - working. Getting this right will take careful consideration of the
487   - developer and user experience. We don't want to create a situation
488   - where exactly the same code fails to work in 11 but worked on 10.
489   - See #576 for latest notes.
490 478  
491 479 Page splitting/merging
492 480 ======================
... ...
fuzz/qpdf_fuzzer.cc
... ... @@ -107,7 +107,7 @@ FuzzHelper::testWrite()
107 107 w = getWriter(q);
108 108 w->setStaticID(true);
109 109 w->setObjectStreamMode(qpdf_o_disable);
110   - w->setR3EncryptionParameters(
  110 + w->setR3EncryptionParametersInsecure(
111 111 "u", "o", true, true, true, true, true, true, qpdf_r3p_full);
112 112 doWrite(w);
113 113  
... ...
include/qpdf/QPDFWriter.hh
... ... @@ -366,10 +366,12 @@ class QPDFWriter
366 366 // functions that could be useful to you, most notably
367 367 // utf8_to_pdf_doc.
368 368  
369   - // R3 uses RC4, which is a weak cryptographic algorithm. Don't use
370   - // it unless you have to.
  369 + // R2 uses RC4, which is a weak cryptographic algorithm. Don't use
  370 + // it unless you have to. See "Weak Cryptography" in the manual.
  371 + // This encryption format is deprecated in the PDF 2.0
  372 + // specification.
371 373 QPDF_DLL
372   - void setR2EncryptionParameters(
  374 + void setR2EncryptionParametersInsecure(
373 375 char const* user_password,
374 376 char const* owner_password,
375 377 bool allow_print,
... ... @@ -377,9 +379,11 @@ class QPDFWriter
377 379 bool allow_extract,
378 380 bool allow_annotate);
379 381 // R3 uses RC4, which is a weak cryptographic algorithm. Don't use
380   - // it unless you have to.
  382 + // it unless you have to. See "Weak Cryptography" in the manual.
  383 + // This encryption format is deprecated in the PDF 2.0
  384 + // specification.
381 385 QPDF_DLL
382   - void setR3EncryptionParameters(
  386 + void setR3EncryptionParametersInsecure(
383 387 char const* user_password,
384 388 char const* owner_password,
385 389 bool allow_accessibility,
... ... @@ -389,10 +393,13 @@ class QPDFWriter
389 393 bool allow_form_filling,
390 394 bool allow_modify_other,
391 395 qpdf_r3_print_e print);
392   - // R4 uses RC4, which is a weak cryptographic algorithm, when
393   - // use_aes=false. Don't use it unless you have to.
  396 + // When use_aes=false, this call enables R4 with RC4, which is a
  397 + // weak cryptographic algorithm. Even with use_aes=true, the
  398 + // overall encryption scheme is weak. Don't use it unless you have
  399 + // to. See "Weak Cryptography" in the manual. This encryption
  400 + // format is deprecated in the PDF 2.0 specification.
394 401 QPDF_DLL
395   - void setR4EncryptionParameters(
  402 + void setR4EncryptionParametersInsecure(
396 403 char const* user_password,
397 404 char const* owner_password,
398 405 bool allow_accessibility,
... ... @@ -419,6 +426,8 @@ class QPDFWriter
419 426 bool allow_modify_other,
420 427 qpdf_r3_print_e print,
421 428 bool encrypt_metadata);
  429 + // This is the only password-based encryption format supported by
  430 + // the PDF specification.
422 431 QPDF_DLL
423 432 void setR6EncryptionParameters(
424 433 char const* user_password,
... ...
include/qpdf/qpdf-c.h
... ... @@ -458,8 +458,13 @@ extern &quot;C&quot; {
458 458 QPDF_DLL
459 459 void qpdf_set_preserve_encryption(qpdf_data qpdf, QPDF_BOOL value);
460 460  
  461 + /* The *_insecure functions are identical to the old versions but
  462 + * have been renamed as a an alert to the caller that they are
  463 + * insecure. See "Weak Cryptographic" in the manual for
  464 + * details.
  465 + */
461 466 QPDF_DLL
462   - void qpdf_set_r2_encryption_parameters(
  467 + void qpdf_set_r2_encryption_parameters_insecure(
463 468 qpdf_data qpdf,
464 469 char const* user_password,
465 470 char const* owner_password,
... ... @@ -469,7 +474,7 @@ extern &quot;C&quot; {
469 474 QPDF_BOOL allow_annotate);
470 475  
471 476 QPDF_DLL
472   - void qpdf_set_r3_encryption_parameters2(
  477 + void qpdf_set_r3_encryption_parameters_insecure(
473 478 qpdf_data qpdf,
474 479 char const* user_password,
475 480 char const* owner_password,
... ... @@ -482,7 +487,7 @@ extern &quot;C&quot; {
482 487 enum qpdf_r3_print_e print);
483 488  
484 489 QPDF_DLL
485   - void qpdf_set_r4_encryption_parameters2(
  490 + void qpdf_set_r4_encryption_parameters_insecure(
486 491 qpdf_data qpdf,
487 492 char const* user_password,
488 493 char const* owner_password,
... ...
job.sums
... ... @@ -14,4 +14,4 @@ libqpdf/qpdf/auto_job_json_decl.hh 06caa46eaf71db8a50c046f91866baa8087745a947431
14 14 libqpdf/qpdf/auto_job_json_init.hh 06d51f11c117011256e175386eee9946441f3c22b49dd91fc591bbc1fa3bbeec
15 15 libqpdf/qpdf/auto_job_schema.hh 43273b9edfc48b1f4cccbff1d2b31916a9057c474ef97d2936b2f1f14170885b
16 16 manual/_ext/qpdf.py e9ac9d6c70642a3d29281ee5ad92ae2422dee8be9306fb8a0bc9dba0ed5e28f3
17   -manual/cli.rst 6a2d99acedbd207370a8dc2807f6657323c42bccbe51ebdc6bc2d00f6851219c
  17 +manual/cli.rst 70258db13d89b0476248e9703bf5f50ffe28fce2a179dfeca241582dd28b455c
... ...
libqpdf/QPDFJob.cc
... ... @@ -2815,19 +2815,22 @@ QPDFJob::setEncryptionOptions(QPDF&amp; pdf, QPDFWriter&amp; w)
2815 2815 QTC::TC("qpdf", "QPDFJob weak crypto error");
2816 2816 *(this->m->cerr)
2817 2817 << this->m->message_prefix
2818   - << ": refusing to write a file with RC4, a weak cryptographic algorithm"
  2818 + << ": refusing to write a file with RC4, a weak cryptographic "
  2819 + "algorithm"
2819 2820 << std::endl
2820 2821 << "Please use 256-bit keys for better security." << std::endl
2821 2822 << "Pass --allow-weak-crypto to enable writing insecure files."
2822 2823 << std::endl
2823   - << "See also https://qpdf.readthedocs.io/en/stable/weak-crypto.html"
  2824 + << "See also "
  2825 + "https://qpdf.readthedocs.io/en/stable/weak-crypto.html"
2824 2826 << std::endl;
2825   - throw std::runtime_error("refusing to write a file with weak crypto");
  2827 + throw std::runtime_error(
  2828 + "refusing to write a file with weak crypto");
2826 2829 }
2827 2830 }
2828 2831 switch (R) {
2829 2832 case 2:
2830   - w.setR2EncryptionParameters(
  2833 + w.setR2EncryptionParametersInsecure(
2831 2834 m->user_password.c_str(),
2832 2835 m->owner_password.c_str(),
2833 2836 m->r2_print,
... ... @@ -2836,7 +2839,7 @@ QPDFJob::setEncryptionOptions(QPDF&amp; pdf, QPDFWriter&amp; w)
2836 2839 m->r2_annotate);
2837 2840 break;
2838 2841 case 3:
2839   - w.setR3EncryptionParameters(
  2842 + w.setR3EncryptionParametersInsecure(
2840 2843 m->user_password.c_str(),
2841 2844 m->owner_password.c_str(),
2842 2845 m->r3_accessibility,
... ... @@ -2848,7 +2851,7 @@ QPDFJob::setEncryptionOptions(QPDF&amp; pdf, QPDFWriter&amp; w)
2848 2851 m->r3_print);
2849 2852 break;
2850 2853 case 4:
2851   - w.setR4EncryptionParameters(
  2854 + w.setR4EncryptionParametersInsecure(
2852 2855 m->user_password.c_str(),
2853 2856 m->owner_password.c_str(),
2854 2857 m->r3_accessibility,
... ...
libqpdf/QPDFWriter.cc
... ... @@ -365,7 +365,7 @@ QPDFWriter::setPCLm(bool val)
365 365 }
366 366  
367 367 void
368   -QPDFWriter::setR2EncryptionParameters(
  368 +QPDFWriter::setR2EncryptionParametersInsecure(
369 369 char const* user_password,
370 370 char const* owner_password,
371 371 bool allow_print,
... ... @@ -391,7 +391,7 @@ QPDFWriter::setR2EncryptionParameters(
391 391 }
392 392  
393 393 void
394   -QPDFWriter::setR3EncryptionParameters(
  394 +QPDFWriter::setR3EncryptionParametersInsecure(
395 395 char const* user_password,
396 396 char const* owner_password,
397 397 bool allow_accessibility,
... ... @@ -419,7 +419,7 @@ QPDFWriter::setR3EncryptionParameters(
419 419 }
420 420  
421 421 void
422   -QPDFWriter::setR4EncryptionParameters(
  422 +QPDFWriter::setR4EncryptionParametersInsecure(
423 423 char const* user_password,
424 424 char const* owner_password,
425 425 bool allow_accessibility,
... ...
libqpdf/qpdf-c.cc
... ... @@ -674,7 +674,7 @@ qpdf_set_preserve_encryption(qpdf_data qpdf, QPDF_BOOL value)
674 674 }
675 675  
676 676 void
677   -qpdf_set_r2_encryption_parameters(
  677 +qpdf_set_r2_encryption_parameters_insecure(
678 678 qpdf_data qpdf,
679 679 char const* user_password,
680 680 char const* owner_password,
... ... @@ -683,8 +683,8 @@ qpdf_set_r2_encryption_parameters(
683 683 QPDF_BOOL allow_extract,
684 684 QPDF_BOOL allow_annotate)
685 685 {
686   - QTC::TC("qpdf", "qpdf-c called qpdf_set_r2_encryption_parameters");
687   - qpdf->qpdf_writer->setR2EncryptionParameters(
  686 + QTC::TC("qpdf", "qpdf-c called qpdf_set_r2_encryption_parameters_insecure");
  687 + qpdf->qpdf_writer->setR2EncryptionParametersInsecure(
688 688 user_password,
689 689 owner_password,
690 690 allow_print != QPDF_FALSE,
... ... @@ -694,7 +694,7 @@ qpdf_set_r2_encryption_parameters(
694 694 }
695 695  
696 696 void
697   -qpdf_set_r3_encryption_parameters2(
  697 +qpdf_set_r3_encryption_parameters_insecure(
698 698 qpdf_data qpdf,
699 699 char const* user_password,
700 700 char const* owner_password,
... ... @@ -706,8 +706,8 @@ qpdf_set_r3_encryption_parameters2(
706 706 QPDF_BOOL allow_modify_other,
707 707 enum qpdf_r3_print_e print)
708 708 {
709   - QTC::TC("qpdf", "qpdf-c called qpdf_set_r3_encryption_parameters");
710   - qpdf->qpdf_writer->setR3EncryptionParameters(
  709 + QTC::TC("qpdf", "qpdf-c called qpdf_set_r3_encryption_parameters_insecure");
  710 + qpdf->qpdf_writer->setR3EncryptionParametersInsecure(
711 711 user_password,
712 712 owner_password,
713 713 allow_accessibility != QPDF_FALSE,
... ... @@ -720,7 +720,7 @@ qpdf_set_r3_encryption_parameters2(
720 720 }
721 721  
722 722 void
723   -qpdf_set_r4_encryption_parameters2(
  723 +qpdf_set_r4_encryption_parameters_insecure(
724 724 qpdf_data qpdf,
725 725 char const* user_password,
726 726 char const* owner_password,
... ... @@ -734,8 +734,8 @@ qpdf_set_r4_encryption_parameters2(
734 734 QPDF_BOOL encrypt_metadata,
735 735 QPDF_BOOL use_aes)
736 736 {
737   - QTC::TC("qpdf", "qpdf-c called qpdf_set_r4_encryption_parameters");
738   - qpdf->qpdf_writer->setR4EncryptionParameters(
  737 + QTC::TC("qpdf", "qpdf-c called qpdf_set_r4_encryption_parameters_insecure");
  738 + qpdf->qpdf_writer->setR4EncryptionParametersInsecure(
739 739 user_password,
740 740 owner_password,
741 741 allow_accessibility != QPDF_FALSE,
... ...
manual/cli.rst
... ... @@ -470,12 +470,18 @@ Related Options
470 470 option is necessary to create 40-bit files or 128-bit files that
471 471 use RC4 encryption.
472 472  
473   - Starting with version 10.4, qpdf issues warnings when requested to
474   - create files using RC4 encryption. This option suppresses those
475   - warnings. In future versions of qpdf, qpdf will refuse to create
476   - files with weak cryptography when this flag is not given. See
  473 + Encrypted PDF files using 40-bit keys or 128-bit keys without AES
  474 + use the insecure *RC4* encryption algorithm. Starting with version
  475 + 11.0, qpdf's default behavior is to refuse to write files using RC4
  476 + encryption. Use this option to allow creation of such files. In
  477 + versions 10.4 through 10.6, attempting to create weak encrypted
  478 + files was a warning, rather than an error, without this flag. See
477 479 :ref:`weak-crypto` for additional details.
478 480  
  481 + No check is performed for weak crypto when preserving encryption
  482 + parameters from or copying encryption parameters from other files.
  483 + The rationale for this is discussed in :ref:`weak-crypto`.
  484 +
479 485 .. qpdf:option:: --keep-files-open=[y|n]
480 486  
481 487 .. help: manage keeping multiple files open
... ... @@ -741,6 +747,9 @@ Related Options
741 747 file without having to manual specify all the individual settings.
742 748 See also :qpdf:ref:`--decrypt`.
743 749  
  750 + Checks for weak cryptographic algorithms are intentionally not made
  751 + by this operation. See :ref:`weak-crypto` for the rationale.
  752 +
744 753 .. qpdf:option:: --encryption-file-password=password
745 754  
746 755 .. help: supply password for --copy-encryption
... ...
manual/release-notes.rst
... ... @@ -62,6 +62,10 @@ For a detailed list of changes, please see the file
62 62 - The default json output version when :qpdf:ref:`--json` is
63 63 specified has been changed from ``1`` to ``latest``.
64 64  
  65 + - The :qpdf:ref:`--allow-weak-crypto` flag is now mandatory when
  66 + explicitly creating files with weak cryptographic algorithms.
  67 + See :ref:`weak-crypto` for a discussion.
  68 +
65 69 - API: breaking changes
66 70  
67 71 - Remove
... ... @@ -73,6 +77,19 @@ For a detailed list of changes, please see the file
73 77 ``QPDFNumberTreeObjectHelper`` constructors that don't take a
74 78 ``QPDF&`` argument.
75 79  
  80 + - Intentionally break API to call attention to operations that
  81 + write files with insecure encryption:
  82 +
  83 + - Remove pre qpdf-8.4.0 encryption API methods from ``QPDFWriter``
  84 + and their corresponding C API functions
  85 +
  86 + - Add ``Insecure`` to the names of some ``QPDFWriter`` methods
  87 + and ``_insecure`` to the names of some C API functions without
  88 + otherwise changing their behavior
  89 +
  90 + - See :ref:`breaking-crypto-api` for specific details, and see
  91 + :ref:`weak-crypto` for a general discussion.
  92 +
76 93 - Library Enhancements
77 94  
78 95 - Support for more fluent programming with ``QPDFObjectHandle``.
... ...
manual/weak-crypto.rst
... ... @@ -3,24 +3,55 @@
3 3 Weak Cryptography
4 4 =================
5 5  
6   -Start with version 10.4, qpdf is taking steps to reduce the likelihood
7   -of a user *accidentally* creating PDF files with insecure cryptography
8   -but will continue to allow creation of such files indefinitely with
9   -explicit acknowledgment.
10   -
11   -The PDF file format makes use of RC4, which is known to be a weak
12   -cryptography algorithm, and MD5, which is a weak hashing algorithm. In
13   -version 10.4, qpdf generates warnings for some (but not all) cases of
14   -writing files with weak cryptography when invoked from the command-line.
15   -These warnings can be suppressed using the
16   -:qpdf:ref:`--allow-weak-crypto` option.
  6 +For help with compiler errors in qpdf 11.0 or newer, see
  7 +:ref:`breaking-crypto-api`.
  8 +
  9 +Since 2006, the PDF specification has offered ways to create encrypted
  10 +PDF files without using weak cryptography, though it took a few years
  11 +for many PDF readers and writers to catch up. It is still necessary to
  12 +support weak encryption algorithms to read encrypted PDF files that
  13 +were created using weak encryption algorithms, including all PDF files
  14 +created before the modern formats were introduced or widely supported.
  15 +
  16 +Starting with version 10.4, qpdf began taking steps to reduce the
  17 +likelihood of a user *accidentally* creating PDF files with insecure
  18 +cryptography but will continue to allow creation of such files
  19 +indefinitely with explicit acknowledgment. The restrictions on use of
  20 +weak cryptography were made stricter with qpdf 11.
  21 +
  22 +Definition of Weak Cryptographic Algorithm
  23 +------------------------------------------
  24 +
  25 +We divide weak cryptographic algorithms into two categories: weak
  26 +encryption and weak hashing. Encryption is encoding data such that a
  27 +key of some sort is required to decode it. Hashing is creating a short
  28 +value from data in such a way that it is extremely improbable to find
  29 +two documents with the same hash (known has a hash collision) and
  30 +extremely difficult to intentionally create a document with a specific
  31 +hash or two documents with the same hash.
17 32  
18   -It is planned for qpdf version 11 to be stricter, making it an error to
19   -write files with insecure cryptography from the command-line tool in
20   -most cases without specifying the
21   -:qpdf:ref:`--allow-weak-crypto` flag and also to require
22   -explicit steps when using the C++ library to enable use of insecure
23   -cryptography.
  33 +When we say that an encryption algorithm is weak, we either mean that
  34 +a mathematical flaw has been discovered that makes it inherently
  35 +crackable or that it is sufficiently simple that modern computer
  36 +technology makes it possible to use "brute force" to crack. For
  37 +example, when 40-bit keys were originally introduced, it wasn't
  38 +practical to consider trying all possible keys, but today such a thing
  39 +is possible.
  40 +
  41 +When we say that a hashing algorithm is weak, we mean that, either
  42 +because of mathematical flaw or insufficient complexity, it is
  43 +computationally feasible to intentionally construct a hash collision.
  44 +
  45 +While weak encryption should always be avoided, there are cases in
  46 +which it is safe to use a weak hashing algorithm when security is not
  47 +a factor. For example, a weak hashing algorithm should not be used as
  48 +the only mechanism to test whether a file has been tampered with. In
  49 +other words, you can't use a weak hash as a digital signature. There
  50 +is no harm, however, in using a weak hash as a way to sort or index
  51 +documents as long as hash collisions are tolerated. It is also common
  52 +to use weak hashes as checksums, which are often used a check that a
  53 +file wasn't damanged in transit or storage, though for true integrity,
  54 +a strong hash would be better.
24 55  
25 56 Note that qpdf must always retain support for weak cryptographic
26 57 algorithms since this is required for reading older PDF files that use
... ... @@ -31,3 +62,135 @@ since these are sometimes needed to test or work with older versions of
31 62 software. Even if other cryptography libraries drop support for RC4 or
32 63 MD5, qpdf can always fall back to its internal implementations of those
33 64 algorithms, so they are not going to disappear from qpdf.
  65 +
  66 +Uses of Weak Encryption in qpdf
  67 +---------------------------------
  68 +
  69 +When PDF files are encrypted using 40-bit encryption or 128-bit
  70 +encryption without AES, then the weak *RC4* algorithm is used. You can
  71 +avoid using weak encryption in qpdf by always using 256-bit
  72 +encryption. Unless you are trying to create files that need to be
  73 +opened with PDF readers from before about 2010 (by which time most
  74 +readers had added support for the stronger encryption algorithms) or
  75 +are creating insecure files explicitly for testing or some similar
  76 +purpose, there is no reason to use anything other than 256-bit
  77 +encryption.
  78 +
  79 +By default, qpdf refuses to write a file that uses weak encryption.
  80 +You can explicitly allow this by specifying the
  81 +:qpdf:ref:`--allow-weak-crypto` option.
  82 +
  83 +In qpdf 11, all library methods that could potentially cause files to
  84 +be written with weak encryption were deprecated, and methods to enable
  85 +weak encryption were either given explicit names indicating this or
  86 +take required arguments to enable the insecure behavior.
  87 +
  88 +There is one exception: when encryption parameters are copied from the
  89 +input file or another file to the output file, there is no prohibition
  90 +or even warning against using insecure encryption. The reason is that
  91 +many qpdf operations simply preserve whatever encryption is there, and
  92 +requiring confirmation to *preserve* insecure encryption would cause
  93 +qpdf to break when non-encryption-related operations were performed on
  94 +files that happened to be encrypted. Failing or generating warnings in
  95 +this case would likely have the effect of making people use the
  96 +:qpdf:ref:`--allow-weak-crypto` option blindly, which would be worse
  97 +than just letting those files go so that explicit, conscious selection
  98 +of weak crypto would be more likely to be noticed. Why, you might ask,
  99 +does this apply to :qpdf:ref:`--copy-encryption` as well as to the
  100 +default behavior preserving encryption? The answer is that
  101 +:qpdf:ref:`--copy-encryption` works with an unencrypted file as input,
  102 +which enables workflows where one may start with a file, decrypt it
  103 +*just in case*, perform a series of operations, and then reapply the
  104 +original encryption, *if any*. Also, one may have a template used for
  105 +encryption that one may apply to a variety of output files, and it
  106 +would be annoying to be warned about it for every output file.
  107 +
  108 +Uses of Weak Hashing In QPDF
  109 +----------------------------
  110 +
  111 +The PDF specification makes use the weak *MD5* hashing algorithm in
  112 +several places. While it is used in the encryption algorithms,
  113 +breaking MD5 would not be adequate to crack an encrypted file when
  114 +256-bit encryption is in use, so using 256-bit encryption is adequate
  115 +for avoiding the use of MD5 for anything security-sensitive.
  116 +
  117 +MD5 is used in the following non-security-sensitive ways:
  118 +
  119 +- Generation of the document ID. The document ID is an input parameter
  120 + to the document encryption but is not itself considered to be
  121 + secure. They are supposed to be unique, but they are not
  122 + tamper-resistent in non-encrypted PDF files, and hash collisions
  123 + must be tolerated.
  124 +
  125 + The PDF specification recommends but does not require the use of MD5
  126 + in generation of document IDs. Usually there is also a random
  127 + component to document ID generation. There is a qpdf-specific
  128 + feature of generating a *deterministic ID* (see
  129 + :qpdf:ref:`--deterministic-id`) which also uses MD5. While it would
  130 + certainly be possible to change the deterministic ID algorithm to
  131 + not use MD5, doing so would break all previous deterministic IDs
  132 + (which would render the feature useless for many cases) and would
  133 + offer very little benefit since even a securely generated document
  134 + ID is not itself a security-sensitive value.
  135 +
  136 +- Checksums in embedded file streams -- the PDF specification
  137 + specifies the use of MD5.
  138 +
  139 +It is therefore not possible completely avoid the use of MD5 with
  140 +qpdf, but as long as you are using 256-bit encryption, it is not used
  141 +in a securty-sensitive fashion.
  142 +
  143 +.. _breaking-crypto-api:
  144 +
  145 +API-Breaking Changes in qpdf 11.0
  146 +---------------------------------
  147 +
  148 +In qpdf 11, several deprecated functions and methods were removed.
  149 +These methods provided an incomplete API. Alternatives were added in
  150 +qpdf 8.4.0. The removed functions are
  151 +
  152 +- C API: ``qpdf_set_r3_encryption_parameters``,
  153 + ``qpdf_set_r4_encryption_parameters``,
  154 + ``qpdf_set_r5_encryption_parameters``,
  155 + ``qpdf_set_r6_encryption_parameters``
  156 +
  157 +- ``QPDFWriter``: overloaded versions of these methods with fewer
  158 + arguments: ``setR3EncryptionParameters``,
  159 + ``setR4EncryptionParameters``, ``setR5EncryptionParameters``, and
  160 + ``setR6EncryptionParameters``
  161 +
  162 +Additionally, remaining functions/methods had their names changed to
  163 +signal that they are insecure and to force developers to make a
  164 +decision. If you intentionally want to continue to use insecure
  165 +cryptographic algorithms and create insecure files, you can change
  166 +your code just add ``_insecure`` or ``Insecure`` to the end of the
  167 +function as needed. (Note the disappearance of ``2`` in some of the C
  168 +functions as well.) Better, you should migrate your code to use more
  169 +secure encryption as documented in :file:`QPDFWriter.hh`. Use the
  170 +``R6`` methods (or their corresponding C functions) to create files
  171 +with 256-bit encryption.
  172 +
  173 +.. list-table:: Renamed Functions
  174 + :widths: 50 50
  175 + :header-rows: 1
  176 +
  177 + - - Old Name
  178 + - New Name
  179 +
  180 + - - qpdf_set_r2_encryption_parameters
  181 + - qpdf_set_r2_encryption_parameters_insecure
  182 +
  183 + - - qpdf_set_r3_encryption_parameters2
  184 + - qpdf_set_r3_encryption_parameters_insecure
  185 +
  186 + - - qpdf_set_r4_encryption_parameters2
  187 + - qpdf_set_r2_encryption_parameters_insecure
  188 +
  189 + - - QPDFWriter::setR2EncryptionParameters
  190 + - QPDFWriter::setR2EncryptionParametersInsecure
  191 +
  192 + - - QPDFWriter::setR3EncryptionParameters
  193 + - QPDFWriter::setR3EncryptionParametersInsecure
  194 +
  195 + - - QPDFWriter::setR4EncryptionParameters
  196 + - QPDFWriter::setR4EncryptionParametersInsecure
... ...
qpdf/qpdf-ctest.c
... ... @@ -320,7 +320,7 @@ test11(
320 320 qpdf_read(qpdf, infile, password);
321 321 qpdf_init_write(qpdf, outfile);
322 322 qpdf_set_static_ID(qpdf, QPDF_TRUE);
323   - qpdf_set_r2_encryption_parameters(
  323 + qpdf_set_r2_encryption_parameters_insecure(
324 324 qpdf, "user1", "owner1", QPDF_FALSE, QPDF_TRUE, QPDF_TRUE, QPDF_TRUE);
325 325 qpdf_write(qpdf);
326 326 report_errors();
... ... @@ -336,7 +336,7 @@ test12(
336 336 qpdf_read(qpdf, infile, password);
337 337 qpdf_init_write(qpdf, outfile);
338 338 qpdf_set_static_ID(qpdf, QPDF_TRUE);
339   - qpdf_set_r3_encryption_parameters2(
  339 + qpdf_set_r3_encryption_parameters_insecure(
340 340 qpdf,
341 341 "user2",
342 342 "owner2",
... ... @@ -397,7 +397,7 @@ test15(
397 397 qpdf_init_write(qpdf, outfile);
398 398 qpdf_set_static_ID(qpdf, QPDF_TRUE);
399 399 qpdf_set_static_aes_IV(qpdf, QPDF_TRUE);
400   - qpdf_set_r4_encryption_parameters2(
  400 + qpdf_set_r4_encryption_parameters_insecure(
401 401 qpdf,
402 402 "user2",
403 403 "owner2",
... ...
qpdf/qpdf.testcov
... ... @@ -130,8 +130,8 @@ qpdf-c called qpdf_set_qdf_mode 0
130 130 qpdf-c called qpdf_set_static_ID 0
131 131 qpdf-c called qpdf_set_suppress_original_object_IDs 0
132 132 qpdf-c called qpdf_set_preserve_encryption 0
133   -qpdf-c called qpdf_set_r2_encryption_parameters 0
134   -qpdf-c called qpdf_set_r3_encryption_parameters 0
  133 +qpdf-c called qpdf_set_r2_encryption_parameters_insecure 0
  134 +qpdf-c called qpdf_set_r3_encryption_parameters_insecure 0
135 135 qpdf-c called qpdf_set_linearization 0
136 136 qpdf-c called qpdf_write 1
137 137 qpdf-c called qpdf_allow_accessibility 0
... ... @@ -158,7 +158,7 @@ QPDF_encryption cleartext metadata 0
158 158 QPDF_encryption aes decode stream 0
159 159 QPDFWriter forcing object stream disable 0
160 160 QPDFWriter forced version disabled encryption 0
161   -qpdf-c called qpdf_set_r4_encryption_parameters 0
  161 +qpdf-c called qpdf_set_r4_encryption_parameters_insecure 0
162 162 qpdf-c called qpdf_set_static_aes_IV 0
163 163 QPDF_encryption stream crypt filter 0
164 164 QPDF ERR object stream with wrong type 0
... ...