aboutsummaryrefslogtreecommitdiffstats
path: root/qpdf/qtest/qpdf.test
diff options
context:
space:
mode:
Diffstat (limited to 'qpdf/qtest/qpdf.test')
-rw-r--r--qpdf/qtest/qpdf.test182
1 files changed, 182 insertions, 0 deletions
diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test
index 45f2a6f4..1ccd4d12 100644
--- a/qpdf/qtest/qpdf.test
+++ b/qpdf/qtest/qpdf.test
@@ -3222,6 +3222,188 @@ foreach my $d (@enc_key)
show_ntests();
# ----------
+$td->notify("--- Unicode Passwords ---");
+# $n_tests incremented below
+
+# Files with each of these passwords when properly encoded have been
+# tested manually with multiple PDF viewers. Adobe Reader, chrome,
+# xpdf, and gv can open all of them except R3 with "single-byte",
+# which can be opened by xpdf and gv but not the others. As of
+# 2019-01-19, okular and atril (evince) are not able to open R=6 files
+# with Unicode passwords as generated by qpdf but can open the R=3
+# files.
+
+# [bits, password-or-password-name, write-encoding, actual-encoding, xargs,
+# [[read-encoding, strict?, fail?, tried-others, xargs]]]
+my @unicode_pw_cases = (
+ [128, 'simple', 'pdf-doc', 'pdf-doc', '',
+ [['utf8', 0, 0, 1, ''],
+ ['utf8', 1, 1, 0, ''],
+ ['pdf-doc', 1, 0, 0, ''],
+ ]],
+ [128, 'simple', 'utf8', 'utf8', '--password-mode=bytes',
+ [['pdf-doc', 0, 0, 1, ''],
+ ['pdf-doc', 1, 1, 0, ''],
+ ['utf8', 1, 0, 0, ''],
+ ]],
+ [128, 'simple', 'utf8', 'pdf-doc', '--password-mode=unicode',
+ [['pdf-doc', 1, 0, 0, ''],
+ ]],
+ [128, 'simple', 'utf8', 'pdf-doc', '--password-mode=auto',
+ [['pdf-doc', 1, 0, 0, ''],
+ ]],
+ [128, 'single-byte', 'utf8', 'pdf-doc', '',
+ [['pdf-doc', 1, 0, 0, ''],
+ ['win-ansi', 0, 0, 1, ''],
+ ]],
+ [128, 'single-byte', 'utf8', 'pdf-doc', '--password-mode=unicode',
+ [['pdf-doc', 1, 0, 0, ''],
+ ['win-ansi', 0, 0, 1, ''],
+ ]],
+ [128, 'single-byte', 'win-ansi', '', '--password-mode=unicode',
+ "supplied password is not valid UTF-8\n",
+ ],
+ [128, 'single-byte', 'win-ansi', 'win-ansi', '',
+ [['win-ansi', 1, 0, 0, ''],
+ ]],
+ [128, 'single-byte', 'pdf-doc', 'pdf-doc', '',
+ [['pdf-doc', 1, 0, 0, ''],
+ ['win-ansi', 0, 0, 1, ''],
+ ['pdf-doc-hex', 1, 0, 0, '--password-mode=hex-bytes'],
+ ]],
+ [128, 'complex', 'utf8', '', '--password-mode=unicode',
+ "supplied password cannot be encoded for 40-bit or" .
+ " 128-bit encryption formats\n"
+ ],
+ [128, 'complex', 'utf8', 'utf8', '--password-mode=bytes',
+ [['utf8', 1, 0, 0, ''],
+ ]],
+ [256, 'single-byte', 'win-ansi', '', '--password-mode=unicode',
+ "supplied password is not valid UTF-8\n",
+ ],
+ [256, 'single-byte', 'win-ansi', '', '--password-mode=auto',
+ "supplied password is not a valid Unicode password, which is" .
+ " required for 256-bit encryption; to really use this password," .
+ " rerun with the --password-mode=bytes option\n",
+ ],
+ [256, 'single-byte', 'win-ansi', 'win-ansi', '--password-mode=bytes',
+ [['utf8', 0, 0, 1, ''],
+ ['utf8', 1, 1, 0, ''],
+ ['win-ansi', 1, 0, 0, ''],
+ ['win-ansi', 0, 0, 0, ''],
+ ['pdf-doc', 0, 0, 1, ''],
+ ['pdf-doc-hex', 0, 0, 1, '--password-mode=hex-bytes'],
+ ]],
+ [256, 'complex', 'utf8', 'utf8', '',
+ [['utf8', 1, 0, 0, ''],
+ ['utf8-hex', 1, 0, 0, '--password-mode=hex-bytes'],
+ ]],
+ [256, 'complex', 'utf8-hex', 'utf8', '--password-mode=hex-bytes',
+ [['utf8', 1, 0, 0, ''],
+ ['utf8-hex', 1, 0, 0, '--password-mode=hex-bytes'],
+ ]],
+ [256, 'complex', 'utf8', 'utf8', '--password-mode=unicode',
+ [['utf8', 1, 0, 0, ''],
+ ['password-arg-simple-utf8', 0, 1, 1, ''],
+ ]],
+ );
+
+for my $d (@unicode_pw_cases)
+{
+ my $decode_cases = $d->[5];
+ $n_tests += 1;
+ if (ref($decode_cases) eq 'ARRAY')
+ {
+ $n_tests += scalar(@$decode_cases);
+ }
+}
+
+foreach my $d (@unicode_pw_cases)
+{
+ my ($bits, $pw, $w_encoding, $a_encoding, $xargs, $decode_cases) = @$d;
+ my $w_pfile = "password-bare-$pw-$w_encoding";
+ my $upass;
+ if (-f $w_pfile)
+ {
+ $upass = '@' . $w_pfile;
+ }
+ else
+ {
+ $upass = "$pw";
+ }
+ my $outbase = "unicode-pw-$bits-$pw-$w_encoding-$xargs";
+ my $exp = '';
+ if (ref($decode_cases) ne 'ARRAY')
+ {
+ $exp = $decode_cases;
+ $decode_cases = [];
+ }
+ $td->runtest("encode $bits, $pw, $w_encoding",
+ {$td->COMMAND =>
+ "qpdf $xargs --static-id --static-aes-iv" .
+ " --encrypt $upass o $bits -- minimal.pdf a.pdf"},
+ {$td->STRING => $exp, $td->EXIT_STATUS => ($exp ? 2 : 0)},
+ $td->NORMALIZE_NEWLINES);
+ foreach my $d2 (@$decode_cases)
+ {
+ my ($r_encoding, $strict, $xfail, $tried_others, $r_xargs) = @$d2;
+ my $r_pfile = "password-arg-$pw-$r_encoding";
+ if (! -f $r_pfile)
+ {
+ $r_pfile = $r_encoding;
+ }
+ my $r_output = "";
+ $r_output .= "trying other\n" if $tried_others;
+ if ($xfail)
+ {
+ $r_output .= "a.pdf: invalid password\n";
+ }
+ else
+ {
+ $r_output .= "R = " . ($bits == 128 ? '3' : '6') . "\n";
+ open(F, "<password-bare-$pw-$a_encoding") or die;
+ chomp (my $apw = <F>);
+ close(F);
+ $r_output .= "User password = $apw\n";
+ }
+ $r_xargs .= $strict ? ' --suppress-password-recovery' : '';
+ $td->runtest("decrypt $pw, $r_encoding, strict=$strict",
+ {$td->COMMAND =>
+ "qpdf --show-encryption --verbose" .
+ " $r_xargs a.pdf \@$r_pfile",
+ $td->FILTER => "perl show-unicode-encryption.pl"},
+ {$td->STRING => "$r_output",
+ $td->EXIT_STATUS => ($xfail ? 2 : 0)},
+ $td->NORMALIZE_NEWLINES);
+ }
+}
+
+$n_tests += 2;
+$td->runtest("bytes fallback warning",
+ {$td->COMMAND =>
+ "qpdf --encrypt \@password-bare-complex-utf8 o 128 --" .
+ " minimal.pdf a.pdf"},
+ {$td->FILE => "bytes-fallback.out", $td->EXIT_STATUS => 0},
+ $td->NORMALIZE_NEWLINES);
+{ # local scope
+ my $r_output = "";
+ $r_output .= "R = 3\n";
+ open(F, "<password-bare-complex-utf8") or die;
+ chomp (my $apw = <F>);
+ close(F);
+ $r_output .= "User password = $apw\n";
+ $td->runtest("decrypt bytes fallback",
+ {$td->COMMAND =>
+ "qpdf --show-encryption --verbose" .
+ " a.pdf \@password-arg-complex-utf8" .
+ " --password-mode=bytes",
+ $td->FILTER => "perl show-unicode-encryption.pl"},
+ {$td->STRING => "$r_output", $td->EXIT_STATUS => 0},
+ $td->NORMALIZE_NEWLINES);
+}
+
+show_ntests();
+# ----------
$td->notify("--- Check from C API ---");
my @c_check_types = qw(warn clear);
$n_tests += scalar(@c_check_types);