mirror of
https://github.com/qpdf/qpdf.git
synced 2024-12-22 10:58:58 +00:00
Mark weak encryption with API changes (fixes #576)
This commit is contained in:
parent
2213ed0c3d
commit
8ccd3a8a89
26
ChangeLog
26
ChangeLog
@ -1,8 +1,32 @@
|
||||
2022-04-30 Jay Berkenbilt <ejb@ql.org>
|
||||
|
||||
* QPDFWriter: change encryption API calls
|
||||
- Remove deprecated versions of setR*EncryptionParameters
|
||||
methods from before qpdf 8.4.0
|
||||
- Replace setR2EncryptionParameters with
|
||||
setR2EncryptionParametersInsecure
|
||||
- Replace setR3EncryptionParameters with
|
||||
setR3EncryptionParametersInsecure
|
||||
- Replace setR4EncryptionParameters with
|
||||
setR4EncryptionParametersInsecure
|
||||
|
||||
* C API: change encryption API calls to match C++ interface
|
||||
- Remove pre-8.4.0 functions:
|
||||
- qpdf_set_r3_encryption_parameters
|
||||
- qpdf_set_r4_encryption_parameters
|
||||
- qpdf_set_r5_encryption_parameters
|
||||
- qpdf_set_r6_encryption_parameters
|
||||
- Add "_insecure" to insecure encryption triggers:
|
||||
- Replace void qpdf_set_r2_encryption_parameters
|
||||
with qpdf_set_r2_encryption_parameters_insecure
|
||||
- Replace void qpdf_set_r3_encryption_parameters2
|
||||
with qpdf_set_r3_encryption_parameters_insecure
|
||||
- Replace void qpdf_set_r4_encryption_parameters2
|
||||
with qpdf_set_r4_encryption_parameters_insecure
|
||||
|
||||
* Make attempting to write encrypted files that use RC4 (40-bit or
|
||||
128-bit without AES) an error rather than a warning when
|
||||
--allow-weak-crypto is not specified.
|
||||
--allow-weak-crypto is not specified. Fixes #576.
|
||||
|
||||
2022-04-29 Jay Berkenbilt <ejb@ql.org>
|
||||
|
||||
|
12
TODO
12
TODO
@ -475,18 +475,6 @@ Comments appear in the code prefixed by "ABI". Always Search for ABI
|
||||
in source and header files to find items not listed here. Also search
|
||||
for "[[deprecated" to find deprecated APIs that can be removed.
|
||||
|
||||
* 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. There should be some API change so that, when
|
||||
people recompile with qpdf 11, their code won't suddenly stop
|
||||
working. Getting this right will take careful consideration of the
|
||||
developer and user experience. We don't want to create a situation
|
||||
where exactly the same code fails to work in 11 but worked on 10.
|
||||
See #576 for latest notes.
|
||||
|
||||
Page splitting/merging
|
||||
======================
|
||||
|
@ -107,7 +107,7 @@ FuzzHelper::testWrite()
|
||||
w = getWriter(q);
|
||||
w->setStaticID(true);
|
||||
w->setObjectStreamMode(qpdf_o_disable);
|
||||
w->setR3EncryptionParameters(
|
||||
w->setR3EncryptionParametersInsecure(
|
||||
"u", "o", true, true, true, true, true, true, qpdf_r3p_full);
|
||||
doWrite(w);
|
||||
|
||||
|
@ -366,10 +366,12 @@ class QPDFWriter
|
||||
// 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.
|
||||
// R2 uses RC4, which is a weak cryptographic algorithm. Don't use
|
||||
// it unless you have to. See "Weak Cryptography" in the manual.
|
||||
// This encryption format is deprecated in the PDF 2.0
|
||||
// specification.
|
||||
QPDF_DLL
|
||||
void setR2EncryptionParameters(
|
||||
void setR2EncryptionParametersInsecure(
|
||||
char const* user_password,
|
||||
char const* owner_password,
|
||||
bool allow_print,
|
||||
@ -377,9 +379,11 @@ class QPDFWriter
|
||||
bool allow_extract,
|
||||
bool allow_annotate);
|
||||
// R3 uses RC4, which is a weak cryptographic algorithm. Don't use
|
||||
// it unless you have to.
|
||||
// it unless you have to. See "Weak Cryptography" in the manual.
|
||||
// This encryption format is deprecated in the PDF 2.0
|
||||
// specification.
|
||||
QPDF_DLL
|
||||
void setR3EncryptionParameters(
|
||||
void setR3EncryptionParametersInsecure(
|
||||
char const* user_password,
|
||||
char const* owner_password,
|
||||
bool allow_accessibility,
|
||||
@ -389,10 +393,13 @@ class QPDFWriter
|
||||
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.
|
||||
// When use_aes=false, this call enables R4 with RC4, which is a
|
||||
// weak cryptographic algorithm. Even with use_aes=true, the
|
||||
// overall encryption scheme is weak. Don't use it unless you have
|
||||
// to. See "Weak Cryptography" in the manual. This encryption
|
||||
// format is deprecated in the PDF 2.0 specification.
|
||||
QPDF_DLL
|
||||
void setR4EncryptionParameters(
|
||||
void setR4EncryptionParametersInsecure(
|
||||
char const* user_password,
|
||||
char const* owner_password,
|
||||
bool allow_accessibility,
|
||||
@ -419,6 +426,8 @@ class QPDFWriter
|
||||
bool allow_modify_other,
|
||||
qpdf_r3_print_e print,
|
||||
bool encrypt_metadata);
|
||||
// This is the only password-based encryption format supported by
|
||||
// the PDF specification.
|
||||
QPDF_DLL
|
||||
void setR6EncryptionParameters(
|
||||
char const* user_password,
|
||||
|
@ -458,8 +458,13 @@ extern "C" {
|
||||
QPDF_DLL
|
||||
void qpdf_set_preserve_encryption(qpdf_data qpdf, QPDF_BOOL value);
|
||||
|
||||
/* The *_insecure functions are identical to the old versions but
|
||||
* have been renamed as a an alert to the caller that they are
|
||||
* insecure. See "Weak Cryptographic" in the manual for
|
||||
* details.
|
||||
*/
|
||||
QPDF_DLL
|
||||
void qpdf_set_r2_encryption_parameters(
|
||||
void qpdf_set_r2_encryption_parameters_insecure(
|
||||
qpdf_data qpdf,
|
||||
char const* user_password,
|
||||
char const* owner_password,
|
||||
@ -469,7 +474,7 @@ extern "C" {
|
||||
QPDF_BOOL allow_annotate);
|
||||
|
||||
QPDF_DLL
|
||||
void qpdf_set_r3_encryption_parameters2(
|
||||
void qpdf_set_r3_encryption_parameters_insecure(
|
||||
qpdf_data qpdf,
|
||||
char const* user_password,
|
||||
char const* owner_password,
|
||||
@ -482,7 +487,7 @@ extern "C" {
|
||||
enum qpdf_r3_print_e print);
|
||||
|
||||
QPDF_DLL
|
||||
void qpdf_set_r4_encryption_parameters2(
|
||||
void qpdf_set_r4_encryption_parameters_insecure(
|
||||
qpdf_data qpdf,
|
||||
char const* user_password,
|
||||
char const* owner_password,
|
||||
|
2
job.sums
2
job.sums
@ -14,4 +14,4 @@ libqpdf/qpdf/auto_job_json_decl.hh 06caa46eaf71db8a50c046f91866baa8087745a947431
|
||||
libqpdf/qpdf/auto_job_json_init.hh 06d51f11c117011256e175386eee9946441f3c22b49dd91fc591bbc1fa3bbeec
|
||||
libqpdf/qpdf/auto_job_schema.hh 43273b9edfc48b1f4cccbff1d2b31916a9057c474ef97d2936b2f1f14170885b
|
||||
manual/_ext/qpdf.py e9ac9d6c70642a3d29281ee5ad92ae2422dee8be9306fb8a0bc9dba0ed5e28f3
|
||||
manual/cli.rst 6a2d99acedbd207370a8dc2807f6657323c42bccbe51ebdc6bc2d00f6851219c
|
||||
manual/cli.rst 70258db13d89b0476248e9703bf5f50ffe28fce2a179dfeca241582dd28b455c
|
||||
|
@ -2815,19 +2815,22 @@ QPDFJob::setEncryptionOptions(QPDF& pdf, QPDFWriter& w)
|
||||
QTC::TC("qpdf", "QPDFJob weak crypto error");
|
||||
*(this->m->cerr)
|
||||
<< this->m->message_prefix
|
||||
<< ": refusing to write a file with RC4, a weak cryptographic algorithm"
|
||||
<< ": refusing to write 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 enable writing insecure files."
|
||||
<< std::endl
|
||||
<< "See also https://qpdf.readthedocs.io/en/stable/weak-crypto.html"
|
||||
<< "See also "
|
||||
"https://qpdf.readthedocs.io/en/stable/weak-crypto.html"
|
||||
<< std::endl;
|
||||
throw std::runtime_error("refusing to write a file with weak crypto");
|
||||
throw std::runtime_error(
|
||||
"refusing to write a file with weak crypto");
|
||||
}
|
||||
}
|
||||
switch (R) {
|
||||
case 2:
|
||||
w.setR2EncryptionParameters(
|
||||
w.setR2EncryptionParametersInsecure(
|
||||
m->user_password.c_str(),
|
||||
m->owner_password.c_str(),
|
||||
m->r2_print,
|
||||
@ -2836,7 +2839,7 @@ QPDFJob::setEncryptionOptions(QPDF& pdf, QPDFWriter& w)
|
||||
m->r2_annotate);
|
||||
break;
|
||||
case 3:
|
||||
w.setR3EncryptionParameters(
|
||||
w.setR3EncryptionParametersInsecure(
|
||||
m->user_password.c_str(),
|
||||
m->owner_password.c_str(),
|
||||
m->r3_accessibility,
|
||||
@ -2848,7 +2851,7 @@ QPDFJob::setEncryptionOptions(QPDF& pdf, QPDFWriter& w)
|
||||
m->r3_print);
|
||||
break;
|
||||
case 4:
|
||||
w.setR4EncryptionParameters(
|
||||
w.setR4EncryptionParametersInsecure(
|
||||
m->user_password.c_str(),
|
||||
m->owner_password.c_str(),
|
||||
m->r3_accessibility,
|
||||
|
@ -365,7 +365,7 @@ QPDFWriter::setPCLm(bool val)
|
||||
}
|
||||
|
||||
void
|
||||
QPDFWriter::setR2EncryptionParameters(
|
||||
QPDFWriter::setR2EncryptionParametersInsecure(
|
||||
char const* user_password,
|
||||
char const* owner_password,
|
||||
bool allow_print,
|
||||
@ -391,7 +391,7 @@ QPDFWriter::setR2EncryptionParameters(
|
||||
}
|
||||
|
||||
void
|
||||
QPDFWriter::setR3EncryptionParameters(
|
||||
QPDFWriter::setR3EncryptionParametersInsecure(
|
||||
char const* user_password,
|
||||
char const* owner_password,
|
||||
bool allow_accessibility,
|
||||
@ -419,7 +419,7 @@ QPDFWriter::setR3EncryptionParameters(
|
||||
}
|
||||
|
||||
void
|
||||
QPDFWriter::setR4EncryptionParameters(
|
||||
QPDFWriter::setR4EncryptionParametersInsecure(
|
||||
char const* user_password,
|
||||
char const* owner_password,
|
||||
bool allow_accessibility,
|
||||
|
@ -674,7 +674,7 @@ qpdf_set_preserve_encryption(qpdf_data qpdf, QPDF_BOOL value)
|
||||
}
|
||||
|
||||
void
|
||||
qpdf_set_r2_encryption_parameters(
|
||||
qpdf_set_r2_encryption_parameters_insecure(
|
||||
qpdf_data qpdf,
|
||||
char const* user_password,
|
||||
char const* owner_password,
|
||||
@ -683,8 +683,8 @@ qpdf_set_r2_encryption_parameters(
|
||||
QPDF_BOOL allow_extract,
|
||||
QPDF_BOOL allow_annotate)
|
||||
{
|
||||
QTC::TC("qpdf", "qpdf-c called qpdf_set_r2_encryption_parameters");
|
||||
qpdf->qpdf_writer->setR2EncryptionParameters(
|
||||
QTC::TC("qpdf", "qpdf-c called qpdf_set_r2_encryption_parameters_insecure");
|
||||
qpdf->qpdf_writer->setR2EncryptionParametersInsecure(
|
||||
user_password,
|
||||
owner_password,
|
||||
allow_print != QPDF_FALSE,
|
||||
@ -694,7 +694,7 @@ qpdf_set_r2_encryption_parameters(
|
||||
}
|
||||
|
||||
void
|
||||
qpdf_set_r3_encryption_parameters2(
|
||||
qpdf_set_r3_encryption_parameters_insecure(
|
||||
qpdf_data qpdf,
|
||||
char const* user_password,
|
||||
char const* owner_password,
|
||||
@ -706,8 +706,8 @@ qpdf_set_r3_encryption_parameters2(
|
||||
QPDF_BOOL allow_modify_other,
|
||||
enum qpdf_r3_print_e print)
|
||||
{
|
||||
QTC::TC("qpdf", "qpdf-c called qpdf_set_r3_encryption_parameters");
|
||||
qpdf->qpdf_writer->setR3EncryptionParameters(
|
||||
QTC::TC("qpdf", "qpdf-c called qpdf_set_r3_encryption_parameters_insecure");
|
||||
qpdf->qpdf_writer->setR3EncryptionParametersInsecure(
|
||||
user_password,
|
||||
owner_password,
|
||||
allow_accessibility != QPDF_FALSE,
|
||||
@ -720,7 +720,7 @@ qpdf_set_r3_encryption_parameters2(
|
||||
}
|
||||
|
||||
void
|
||||
qpdf_set_r4_encryption_parameters2(
|
||||
qpdf_set_r4_encryption_parameters_insecure(
|
||||
qpdf_data qpdf,
|
||||
char const* user_password,
|
||||
char const* owner_password,
|
||||
@ -734,8 +734,8 @@ qpdf_set_r4_encryption_parameters2(
|
||||
QPDF_BOOL encrypt_metadata,
|
||||
QPDF_BOOL use_aes)
|
||||
{
|
||||
QTC::TC("qpdf", "qpdf-c called qpdf_set_r4_encryption_parameters");
|
||||
qpdf->qpdf_writer->setR4EncryptionParameters(
|
||||
QTC::TC("qpdf", "qpdf-c called qpdf_set_r4_encryption_parameters_insecure");
|
||||
qpdf->qpdf_writer->setR4EncryptionParametersInsecure(
|
||||
user_password,
|
||||
owner_password,
|
||||
allow_accessibility != QPDF_FALSE,
|
||||
|
@ -470,12 +470,18 @@ Related Options
|
||||
option is necessary to create 40-bit files or 128-bit files that
|
||||
use RC4 encryption.
|
||||
|
||||
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
|
||||
Encrypted PDF files using 40-bit keys or 128-bit keys without AES
|
||||
use the insecure *RC4* encryption algorithm. Starting with version
|
||||
11.0, qpdf's default behavior is to refuse to write files using RC4
|
||||
encryption. Use this option to allow creation of such files. In
|
||||
versions 10.4 through 10.6, attempting to create weak encrypted
|
||||
files was a warning, rather than an error, without this flag. See
|
||||
:ref:`weak-crypto` for additional details.
|
||||
|
||||
No check is performed for weak crypto when preserving encryption
|
||||
parameters from or copying encryption parameters from other files.
|
||||
The rationale for this is discussed in :ref:`weak-crypto`.
|
||||
|
||||
.. qpdf:option:: --keep-files-open=[y|n]
|
||||
|
||||
.. help: manage keeping multiple files open
|
||||
@ -741,6 +747,9 @@ Related Options
|
||||
file without having to manual specify all the individual settings.
|
||||
See also :qpdf:ref:`--decrypt`.
|
||||
|
||||
Checks for weak cryptographic algorithms are intentionally not made
|
||||
by this operation. See :ref:`weak-crypto` for the rationale.
|
||||
|
||||
.. qpdf:option:: --encryption-file-password=password
|
||||
|
||||
.. help: supply password for --copy-encryption
|
||||
|
@ -62,6 +62,10 @@ For a detailed list of changes, please see the file
|
||||
- The default json output version when :qpdf:ref:`--json` is
|
||||
specified has been changed from ``1`` to ``latest``.
|
||||
|
||||
- The :qpdf:ref:`--allow-weak-crypto` flag is now mandatory when
|
||||
explicitly creating files with weak cryptographic algorithms.
|
||||
See :ref:`weak-crypto` for a discussion.
|
||||
|
||||
- API: breaking changes
|
||||
|
||||
- Remove
|
||||
@ -73,6 +77,19 @@ For a detailed list of changes, please see the file
|
||||
``QPDFNumberTreeObjectHelper`` constructors that don't take a
|
||||
``QPDF&`` argument.
|
||||
|
||||
- Intentionally break API to call attention to operations that
|
||||
write files with insecure encryption:
|
||||
|
||||
- Remove pre qpdf-8.4.0 encryption API methods from ``QPDFWriter``
|
||||
and their corresponding C API functions
|
||||
|
||||
- Add ``Insecure`` to the names of some ``QPDFWriter`` methods
|
||||
and ``_insecure`` to the names of some C API functions without
|
||||
otherwise changing their behavior
|
||||
|
||||
- See :ref:`breaking-crypto-api` for specific details, and see
|
||||
:ref:`weak-crypto` for a general discussion.
|
||||
|
||||
- Library Enhancements
|
||||
|
||||
- Support for more fluent programming with ``QPDFObjectHandle``.
|
||||
|
@ -3,24 +3,55 @@
|
||||
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.
|
||||
For help with compiler errors in qpdf 11.0 or newer, see
|
||||
:ref:`breaking-crypto-api`.
|
||||
|
||||
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
|
||||
:qpdf:ref:`--allow-weak-crypto` option.
|
||||
Since 2006, the PDF specification has offered ways to create encrypted
|
||||
PDF files without using weak cryptography, though it took a few years
|
||||
for many PDF readers and writers to catch up. It is still necessary to
|
||||
support weak encryption algorithms to read encrypted PDF files that
|
||||
were created using weak encryption algorithms, including all PDF files
|
||||
created before the modern formats were introduced or widely supported.
|
||||
|
||||
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
|
||||
:qpdf:ref:`--allow-weak-crypto` flag and also to require
|
||||
explicit steps when using the C++ library to enable use of insecure
|
||||
cryptography.
|
||||
Starting with version 10.4, qpdf began 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 restrictions on use of
|
||||
weak cryptography were made stricter with qpdf 11.
|
||||
|
||||
Definition of Weak Cryptographic Algorithm
|
||||
------------------------------------------
|
||||
|
||||
We divide weak cryptographic algorithms into two categories: weak
|
||||
encryption and weak hashing. Encryption is encoding data such that a
|
||||
key of some sort is required to decode it. Hashing is creating a short
|
||||
value from data in such a way that it is extremely improbable to find
|
||||
two documents with the same hash (known has a hash collision) and
|
||||
extremely difficult to intentionally create a document with a specific
|
||||
hash or two documents with the same hash.
|
||||
|
||||
When we say that an encryption algorithm is weak, we either mean that
|
||||
a mathematical flaw has been discovered that makes it inherently
|
||||
crackable or that it is sufficiently simple that modern computer
|
||||
technology makes it possible to use "brute force" to crack. For
|
||||
example, when 40-bit keys were originally introduced, it wasn't
|
||||
practical to consider trying all possible keys, but today such a thing
|
||||
is possible.
|
||||
|
||||
When we say that a hashing algorithm is weak, we mean that, either
|
||||
because of mathematical flaw or insufficient complexity, it is
|
||||
computationally feasible to intentionally construct a hash collision.
|
||||
|
||||
While weak encryption should always be avoided, there are cases in
|
||||
which it is safe to use a weak hashing algorithm when security is not
|
||||
a factor. For example, a weak hashing algorithm should not be used as
|
||||
the only mechanism to test whether a file has been tampered with. In
|
||||
other words, you can't use a weak hash as a digital signature. There
|
||||
is no harm, however, in using a weak hash as a way to sort or index
|
||||
documents as long as hash collisions are tolerated. It is also common
|
||||
to use weak hashes as checksums, which are often used a check that a
|
||||
file wasn't damanged in transit or storage, though for true integrity,
|
||||
a strong hash would be better.
|
||||
|
||||
Note that qpdf must always retain support for weak cryptographic
|
||||
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
|
||||
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.
|
||||
|
||||
Uses of Weak Encryption in qpdf
|
||||
---------------------------------
|
||||
|
||||
When PDF files are encrypted using 40-bit encryption or 128-bit
|
||||
encryption without AES, then the weak *RC4* algorithm is used. You can
|
||||
avoid using weak encryption in qpdf by always using 256-bit
|
||||
encryption. Unless you are trying to create files that need to be
|
||||
opened with PDF readers from before about 2010 (by which time most
|
||||
readers had added support for the stronger encryption algorithms) or
|
||||
are creating insecure files explicitly for testing or some similar
|
||||
purpose, there is no reason to use anything other than 256-bit
|
||||
encryption.
|
||||
|
||||
By default, qpdf refuses to write a file that uses weak encryption.
|
||||
You can explicitly allow this by specifying the
|
||||
:qpdf:ref:`--allow-weak-crypto` option.
|
||||
|
||||
In qpdf 11, all library methods that could potentially cause files to
|
||||
be written with weak encryption were deprecated, and methods to enable
|
||||
weak encryption were either given explicit names indicating this or
|
||||
take required arguments to enable the insecure behavior.
|
||||
|
||||
There is one exception: when encryption parameters are copied from the
|
||||
input file or another file to the output file, there is no prohibition
|
||||
or even warning against using insecure encryption. The reason is that
|
||||
many qpdf operations simply preserve whatever encryption is there, and
|
||||
requiring confirmation to *preserve* insecure encryption would cause
|
||||
qpdf to break when non-encryption-related operations were performed on
|
||||
files that happened to be encrypted. Failing or generating warnings in
|
||||
this case would likely have the effect of making people use the
|
||||
:qpdf:ref:`--allow-weak-crypto` option blindly, which would be worse
|
||||
than just letting those files go so that explicit, conscious selection
|
||||
of weak crypto would be more likely to be noticed. Why, you might ask,
|
||||
does this apply to :qpdf:ref:`--copy-encryption` as well as to the
|
||||
default behavior preserving encryption? The answer is that
|
||||
:qpdf:ref:`--copy-encryption` works with an unencrypted file as input,
|
||||
which enables workflows where one may start with a file, decrypt it
|
||||
*just in case*, perform a series of operations, and then reapply the
|
||||
original encryption, *if any*. Also, one may have a template used for
|
||||
encryption that one may apply to a variety of output files, and it
|
||||
would be annoying to be warned about it for every output file.
|
||||
|
||||
Uses of Weak Hashing In QPDF
|
||||
----------------------------
|
||||
|
||||
The PDF specification makes use the weak *MD5* hashing algorithm in
|
||||
several places. While it is used in the encryption algorithms,
|
||||
breaking MD5 would not be adequate to crack an encrypted file when
|
||||
256-bit encryption is in use, so using 256-bit encryption is adequate
|
||||
for avoiding the use of MD5 for anything security-sensitive.
|
||||
|
||||
MD5 is used in the following non-security-sensitive ways:
|
||||
|
||||
- Generation of the document ID. The document ID is an input parameter
|
||||
to the document encryption but is not itself considered to be
|
||||
secure. They are supposed to be unique, but they are not
|
||||
tamper-resistent in non-encrypted PDF files, and hash collisions
|
||||
must be tolerated.
|
||||
|
||||
The PDF specification recommends but does not require the use of MD5
|
||||
in generation of document IDs. Usually there is also a random
|
||||
component to document ID generation. There is a qpdf-specific
|
||||
feature of generating a *deterministic ID* (see
|
||||
:qpdf:ref:`--deterministic-id`) which also uses MD5. While it would
|
||||
certainly be possible to change the deterministic ID algorithm to
|
||||
not use MD5, doing so would break all previous deterministic IDs
|
||||
(which would render the feature useless for many cases) and would
|
||||
offer very little benefit since even a securely generated document
|
||||
ID is not itself a security-sensitive value.
|
||||
|
||||
- Checksums in embedded file streams -- the PDF specification
|
||||
specifies the use of MD5.
|
||||
|
||||
It is therefore not possible completely avoid the use of MD5 with
|
||||
qpdf, but as long as you are using 256-bit encryption, it is not used
|
||||
in a securty-sensitive fashion.
|
||||
|
||||
.. _breaking-crypto-api:
|
||||
|
||||
API-Breaking Changes in qpdf 11.0
|
||||
---------------------------------
|
||||
|
||||
In qpdf 11, several deprecated functions and methods were removed.
|
||||
These methods provided an incomplete API. Alternatives were added in
|
||||
qpdf 8.4.0. The removed functions are
|
||||
|
||||
- C API: ``qpdf_set_r3_encryption_parameters``,
|
||||
``qpdf_set_r4_encryption_parameters``,
|
||||
``qpdf_set_r5_encryption_parameters``,
|
||||
``qpdf_set_r6_encryption_parameters``
|
||||
|
||||
- ``QPDFWriter``: overloaded versions of these methods with fewer
|
||||
arguments: ``setR3EncryptionParameters``,
|
||||
``setR4EncryptionParameters``, ``setR5EncryptionParameters``, and
|
||||
``setR6EncryptionParameters``
|
||||
|
||||
Additionally, remaining functions/methods had their names changed to
|
||||
signal that they are insecure and to force developers to make a
|
||||
decision. If you intentionally want to continue to use insecure
|
||||
cryptographic algorithms and create insecure files, you can change
|
||||
your code just add ``_insecure`` or ``Insecure`` to the end of the
|
||||
function as needed. (Note the disappearance of ``2`` in some of the C
|
||||
functions as well.) Better, you should migrate your code to use more
|
||||
secure encryption as documented in :file:`QPDFWriter.hh`. Use the
|
||||
``R6`` methods (or their corresponding C functions) to create files
|
||||
with 256-bit encryption.
|
||||
|
||||
.. list-table:: Renamed Functions
|
||||
:widths: 50 50
|
||||
:header-rows: 1
|
||||
|
||||
- - Old Name
|
||||
- New Name
|
||||
|
||||
- - qpdf_set_r2_encryption_parameters
|
||||
- qpdf_set_r2_encryption_parameters_insecure
|
||||
|
||||
- - qpdf_set_r3_encryption_parameters2
|
||||
- qpdf_set_r3_encryption_parameters_insecure
|
||||
|
||||
- - qpdf_set_r4_encryption_parameters2
|
||||
- qpdf_set_r2_encryption_parameters_insecure
|
||||
|
||||
- - QPDFWriter::setR2EncryptionParameters
|
||||
- QPDFWriter::setR2EncryptionParametersInsecure
|
||||
|
||||
- - QPDFWriter::setR3EncryptionParameters
|
||||
- QPDFWriter::setR3EncryptionParametersInsecure
|
||||
|
||||
- - QPDFWriter::setR4EncryptionParameters
|
||||
- QPDFWriter::setR4EncryptionParametersInsecure
|
||||
|
@ -320,7 +320,7 @@ test11(
|
||||
qpdf_read(qpdf, infile, password);
|
||||
qpdf_init_write(qpdf, outfile);
|
||||
qpdf_set_static_ID(qpdf, QPDF_TRUE);
|
||||
qpdf_set_r2_encryption_parameters(
|
||||
qpdf_set_r2_encryption_parameters_insecure(
|
||||
qpdf, "user1", "owner1", QPDF_FALSE, QPDF_TRUE, QPDF_TRUE, QPDF_TRUE);
|
||||
qpdf_write(qpdf);
|
||||
report_errors();
|
||||
@ -336,7 +336,7 @@ test12(
|
||||
qpdf_read(qpdf, infile, password);
|
||||
qpdf_init_write(qpdf, outfile);
|
||||
qpdf_set_static_ID(qpdf, QPDF_TRUE);
|
||||
qpdf_set_r3_encryption_parameters2(
|
||||
qpdf_set_r3_encryption_parameters_insecure(
|
||||
qpdf,
|
||||
"user2",
|
||||
"owner2",
|
||||
@ -397,7 +397,7 @@ test15(
|
||||
qpdf_init_write(qpdf, outfile);
|
||||
qpdf_set_static_ID(qpdf, QPDF_TRUE);
|
||||
qpdf_set_static_aes_IV(qpdf, QPDF_TRUE);
|
||||
qpdf_set_r4_encryption_parameters2(
|
||||
qpdf_set_r4_encryption_parameters_insecure(
|
||||
qpdf,
|
||||
"user2",
|
||||
"owner2",
|
||||
|
@ -130,8 +130,8 @@ qpdf-c called qpdf_set_qdf_mode 0
|
||||
qpdf-c called qpdf_set_static_ID 0
|
||||
qpdf-c called qpdf_set_suppress_original_object_IDs 0
|
||||
qpdf-c called qpdf_set_preserve_encryption 0
|
||||
qpdf-c called qpdf_set_r2_encryption_parameters 0
|
||||
qpdf-c called qpdf_set_r3_encryption_parameters 0
|
||||
qpdf-c called qpdf_set_r2_encryption_parameters_insecure 0
|
||||
qpdf-c called qpdf_set_r3_encryption_parameters_insecure 0
|
||||
qpdf-c called qpdf_set_linearization 0
|
||||
qpdf-c called qpdf_write 1
|
||||
qpdf-c called qpdf_allow_accessibility 0
|
||||
@ -158,7 +158,7 @@ QPDF_encryption cleartext metadata 0
|
||||
QPDF_encryption aes decode stream 0
|
||||
QPDFWriter forcing object stream disable 0
|
||||
QPDFWriter forced version disabled encryption 0
|
||||
qpdf-c called qpdf_set_r4_encryption_parameters 0
|
||||
qpdf-c called qpdf_set_r4_encryption_parameters_insecure 0
|
||||
qpdf-c called qpdf_set_static_aes_IV 0
|
||||
QPDF_encryption stream crypt filter 0
|
||||
QPDF ERR object stream with wrong type 0
|
||||
|
Loading…
Reference in New Issue
Block a user