From a237e9244512951e47cca0251aed00d8094de469 Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Fri, 18 Oct 2013 09:18:45 -0400 Subject: [PATCH] Warn when -accessibility=n will be ignored Also accept -accessibility=n with 256 bit keys even though it will be ignored. --- ChangeLog | 8 +++++ libqpdf/QPDFWriter.cc | 4 ++- qpdf/qpdf.cc | 70 ++++++++++++++++++++++++++++++------------- qpdf/qtest/qpdf.test | 15 ++++++++-- 4 files changed, 73 insertions(+), 24 deletions(-) diff --git a/ChangeLog b/ChangeLog index 951d9d03..460cdd89 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2013-10-18 Jay Berkenbilt + + * Warn when -accessibility=n is specified with a modern encryption + format (R > 3). Also, accept this flag (and ignore with warning) + with 256-bit encryption. qpdf has always ignored the + accessibility setting with R > 3, but it previously did so + silently. + 2013-10-05 Jay Berkenbilt * Replace operator[] in std::string and std::vector with "at" in diff --git a/libqpdf/QPDFWriter.cc b/libqpdf/QPDFWriter.cc index 833637d3..4e917469 100644 --- a/libqpdf/QPDFWriter.cc +++ b/libqpdf/QPDFWriter.cc @@ -462,7 +462,9 @@ QPDFWriter::setEncryptionParameters( if (R > 3) { - // Bit 10 is deprecated and should always be set. + // Bit 10 is deprecated and should always be set. This used + // to mean accessibility. There is no way to disable + // accessibility with R > 3. bits_to_clear.erase(10); } diff --git a/qpdf/qpdf.cc b/qpdf/qpdf.cc index ed648129..be8198e6 100644 --- a/qpdf/qpdf.cc +++ b/qpdf/qpdf.cc @@ -740,13 +740,13 @@ parse_encrypt_options( { usage("invalid -accessibility parameter"); } - if (keylen == 128) + if (keylen == 40) { - r3_accessibility = result; + usage("-accessibility invalid for 40-bit keys"); } else { - usage("-accessibility invalid for 40-bit keys"); + r3_accessibility = result; } } else if (strcmp(arg, "cleartext-metadata") == 0) @@ -1730,49 +1730,77 @@ int main(int argc, char* argv[]) } if (encrypt) { + int R = 0; if (keylen == 40) { - w.setR2EncryptionParameters( - user_password.c_str(), owner_password.c_str(), - r2_print, r2_modify, r2_extract, r2_annotate); + R = 2; } else if (keylen == 128) { if (force_V4 || cleartext_metadata || use_aes) { - w.setR4EncryptionParameters( - user_password.c_str(), owner_password.c_str(), - r3_accessibility, r3_extract, r3_print, r3_modify, - !cleartext_metadata, use_aes); + R = 4; } else { - w.setR3EncryptionParameters( - user_password.c_str(), owner_password.c_str(), - r3_accessibility, r3_extract, r3_print, r3_modify); + R = 3; } } else if (keylen == 256) { if (force_R5) { - w.setR5EncryptionParameters( - user_password.c_str(), owner_password.c_str(), - r3_accessibility, r3_extract, r3_print, r3_modify, - !cleartext_metadata); + R = 5; } else { - w.setR6EncryptionParameters( - user_password.c_str(), owner_password.c_str(), - r3_accessibility, r3_extract, r3_print, r3_modify, - !cleartext_metadata); + R = 6; } } else { throw std::logic_error("bad encryption keylen"); } + if ((R > 3) && (r3_accessibility == false)) + { + std::cerr << whoami + << ": -accessibility=n is ignored for modern" + << " encryption formats" << std::endl; + } + switch (R) + { + case 2: + w.setR2EncryptionParameters( + user_password.c_str(), owner_password.c_str(), + r2_print, r2_modify, r2_extract, r2_annotate); + break; + case 3: + w.setR3EncryptionParameters( + user_password.c_str(), owner_password.c_str(), + r3_accessibility, r3_extract, r3_print, r3_modify); + break; + case 4: + w.setR4EncryptionParameters( + user_password.c_str(), owner_password.c_str(), + r3_accessibility, r3_extract, r3_print, r3_modify, + !cleartext_metadata, use_aes); + break; + case 5: + w.setR5EncryptionParameters( + user_password.c_str(), owner_password.c_str(), + r3_accessibility, r3_extract, r3_print, r3_modify, + !cleartext_metadata); + break; + case 6: + w.setR6EncryptionParameters( + user_password.c_str(), owner_password.c_str(), + r3_accessibility, r3_extract, r3_print, r3_modify, + !cleartext_metadata); + break; + default: + throw std::logic_error("bad encryption R value"); + break; + } } if (linearize) { diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test index d07a54c5..1aff3d21 100644 --- a/qpdf/qtest/qpdf.test +++ b/qpdf/qtest/qpdf.test @@ -1399,6 +1399,9 @@ my @encrypted_files = ['XI-R6,V5,U=view,O=master', 'master', '-print=low', -2052, 1, 1, 1, 0, 1, 1, 1, 1, 1], + ['XI-R6,V5,U=view,O=master', 'master', + '-accessibility=n', -4, # -accessibility=n has no effect + 1, 1, 1, 1, 1, 1, 1, 1, 1], ['XI-long-password', 'qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm'], ['XI-long-password', 'qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcv'], ); @@ -1501,12 +1504,20 @@ foreach my $d (@encrypted_files) # password. $upass = ""; } + my $accessibility_warning = ""; + if (($R > 3) && ($eflags =~ /accessibility=n/)) + { + $accessibility_warning = + "qpdf: -accessibility=n is ignored" . + " for modern encryption formats\n"; + } $td->runtest("encrypt $file", {$td->COMMAND => "qpdf --static-id --no-original-object-ids -qdf" . " $eflags $file.enc $file.enc2"}, - {$td->STRING => "", - $td->EXIT_STATUS => 0}); + {$td->STRING => $accessibility_warning, + $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); $td->runtest("check /P", {$td->COMMAND => "qpdf --show-encryption --password=\"$pass\"" .