aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2022-05-30 16:55:07 +0200
committerJay Berkenbilt <ejb@ql.org>2022-05-31 02:03:08 +0200
commitb7bbf12e85fa46e7971d84143d1597c992045af1 (patch)
tree615ac14943d0701c5fed9d2e27f80f70044c695a
parentf049a77c5962a0e41723bc83900656ece821d916 (diff)
downloadqpdf-b7bbf12e85fa46e7971d84143d1597c992045af1.tar.zst
In json mode, reveal recovered user password when otherwise unavailable
-rw-r--r--ChangeLog5
-rw-r--r--TODO2
-rw-r--r--libqpdf/QPDFJob.cc10
-rw-r--r--manual/release-notes.rst6
-rw-r--r--qpdf/qtest/encryption.test4
-rw-r--r--qpdf/qtest/qpdf/json-V4-aes-encrypt---show-encryption-key-v1.out1
-rw-r--r--qpdf/qtest/qpdf/json-V4-aes-encrypt---show-encryption-key-v2.out1
-rw-r--r--qpdf/qtest/qpdf/json-V4-aes-encrypt-v1.out1
-rw-r--r--qpdf/qtest/qpdf/json-V4-aes-encrypt-v2.out1
-rw-r--r--qpdf/qtest/qpdf/json-attachment-fields-v1.out1
-rw-r--r--qpdf/qtest/qpdf/json-attachment-fields-v2.out1
-rw-r--r--qpdf/qtest/qpdf/json-field-types---show-encryption-key-v1.out1
-rw-r--r--qpdf/qtest/qpdf/json-field-types---show-encryption-key-v2.out1
-rw-r--r--qpdf/qtest/qpdf/json-field-types-v1.out1
-rw-r--r--qpdf/qtest/qpdf/json-field-types-v2.out1
-rw-r--r--qpdf/qtest/qpdf/json-image-streams-all-v1.out1
-rw-r--r--qpdf/qtest/qpdf/json-image-streams-all-v2.out1
-rw-r--r--qpdf/qtest/qpdf/json-image-streams-small-v1.out1
-rw-r--r--qpdf/qtest/qpdf/json-image-streams-small-v2.out1
-rw-r--r--qpdf/qtest/qpdf/json-image-streams-specialized-v1.out1
-rw-r--r--qpdf/qtest/qpdf/json-image-streams-specialized-v2.out1
-rw-r--r--qpdf/qtest/qpdf/json-image-streams-v1.out1
-rw-r--r--qpdf/qtest/qpdf/json-image-streams-v2.out1
-rw-r--r--qpdf/qtest/qpdf/json-outlines-with-actions-v1.out1
-rw-r--r--qpdf/qtest/qpdf/json-outlines-with-actions-v2.out1
-rw-r--r--qpdf/qtest/qpdf/json-outlines-with-old-root-dests-v1.out1
-rw-r--r--qpdf/qtest/qpdf/json-outlines-with-old-root-dests-v2.out1
-rw-r--r--qpdf/qtest/qpdf/json-page-labels-and-outlines-v1.out1
-rw-r--r--qpdf/qtest/qpdf/json-page-labels-and-outlines-v2.out1
-rw-r--r--qpdf/qtest/qpdf/json-page-labels-num-tree-v1.out1
-rw-r--r--qpdf/qtest/qpdf/json-page-labels-num-tree-v2.out1
31 files changed, 51 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index 0d60467d..2013020a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
2022-05-30 Jay Berkenbilt <ejb@ql.org>
+ * When showing encryption data in json output, when the user
+ password was recovered with by the owner password and the
+ specified password does not match the user password, reveal the
+ user password. This is not possible with 256-bit keys.
+
* Include additional information in --list-attachments --verbose
and in --json --json-key=attachments.
diff --git a/TODO b/TODO
index 663dbb40..b52dd93a 100644
--- a/TODO
+++ b/TODO
@@ -70,8 +70,6 @@ Remaining work:
* --show-xref: add
- * --encryption: show recovered user password when available
-
* Consider having --check, --show-encryption, etc., just select the
right keys when in json mode. I don't think I want check on by
default, so that might be different.
diff --git a/libqpdf/QPDFJob.cc b/libqpdf/QPDFJob.cc
index d7cc66cf..b6ba4b4f 100644
--- a/libqpdf/QPDFJob.cc
+++ b/libqpdf/QPDFJob.cc
@@ -1382,6 +1382,15 @@ QPDFJob::doJSONEncrypt(Pipeline* p, bool& first, QPDF& pdf)
j_encrypt.addDictionaryMember(
"ownerpasswordmatched",
JSON::makeBool(is_encrypted && pdf.ownerPasswordMatched()));
+ if (is_encrypted && (V < 5) && pdf.ownerPasswordMatched() &&
+ (!pdf.userPasswordMatched())) {
+ std::string user_password = pdf.getTrimmedUserPassword();
+ j_encrypt.addDictionaryMember(
+ "recovereduserpassword", JSON::makeString(user_password));
+ } else {
+ j_encrypt.addDictionaryMember(
+ "recovereduserpassword", JSON::makeNull());
+ }
JSON j_capabilities =
j_encrypt.addDictionaryMember("capabilities", JSON::makeDictionary());
j_capabilities.addDictionaryMember(
@@ -1669,6 +1678,7 @@ QPDFJob::json_schema(int json_version, std::set<std::string>* keys)
},
"encrypted": "whether the document is encrypted",
"ownerpasswordmatched": "whether supplied password matched owner password; always false for non-encrypted files",
+ "recovereduserpassword": "If the owner password was used to recover the user password, reveal user password; otherwise null",
"parameters": {
"P": "P value from Encrypt dictionary",
"R": "R value from Encrypt dictionary",
diff --git a/manual/release-notes.rst b/manual/release-notes.rst
index d106ec11..ad8d14f9 100644
--- a/manual/release-notes.rst
+++ b/manual/release-notes.rst
@@ -103,6 +103,12 @@ For a detailed list of changes, please see the file
attachments is also included in the ``attachments`` json key
with ``--json``.
+ - For encrypted files, ``qpdf --json`` reveals the user password
+ when the specified password did not match the user password and
+ the owner password was used to recover the user password. The
+ user password is not recoverable from the owner password when
+ 256-bit keys are in use.
+
- Library Enhancements
- New methods ``insertItemAndGet``, ``appendItemAndGet``,
diff --git a/qpdf/qtest/encryption.test b/qpdf/qtest/encryption.test
index 622c595b..27974a82 100644
--- a/qpdf/qtest/encryption.test
+++ b/qpdf/qtest/encryption.test
@@ -219,6 +219,7 @@ foreach my $d (@encrypted_files)
" \"streammethod\": \"---method---\",\n" .
" \"stringmethod\": \"---method---\"\n" .
" },\n" .
+ " \"recovereduserpassword\": ---rup---,\n" .
" \"userpasswordmatched\": ---upm---\n" .
" }\n" .
"}\n";
@@ -267,6 +268,8 @@ foreach my $d (@encrypted_files)
my $method = $bits == 256 ? "AESv3" : "RC4";
my $opm = ($pass eq $opass ? "true" : "false");
my $upm = ($pass eq $upass ? "true" : "false");
+ my $rup = (($pass eq $opass) && ($pass ne $upass) && ($V < 5))
+ ? "\"$upass\"" : "null";
$enc_json =~ s/---R---/$R/;
$enc_json =~ s/---P---/$P/;
$enc_json =~ s/---V---/$V/;
@@ -274,6 +277,7 @@ foreach my $d (@encrypted_files)
$enc_json =~ s/---method---/$method/g;
$enc_json =~ s/---opm---/$opm/;
$enc_json =~ s/---upm---/$upm/;
+ $enc_json =~ s/---rup---/$rup/;
my $eflags = "--allow-weak-crypto" .
" -encrypt \"$upass\" \"$opass\" $bits $xeflags --";
diff --git a/qpdf/qtest/qpdf/json-V4-aes-encrypt---show-encryption-key-v1.out b/qpdf/qtest/qpdf/json-V4-aes-encrypt---show-encryption-key-v1.out
index 4fd5eb7f..234d38c4 100644
--- a/qpdf/qtest/qpdf/json-V4-aes-encrypt---show-encryption-key-v1.out
+++ b/qpdf/qtest/qpdf/json-V4-aes-encrypt---show-encryption-key-v1.out
@@ -28,6 +28,7 @@
"streammethod": "AESv2",
"stringmethod": "AESv2"
},
+ "recovereduserpassword": null,
"userpasswordmatched": true
}
}
diff --git a/qpdf/qtest/qpdf/json-V4-aes-encrypt---show-encryption-key-v2.out b/qpdf/qtest/qpdf/json-V4-aes-encrypt---show-encryption-key-v2.out
index 5f32eb44..c400571f 100644
--- a/qpdf/qtest/qpdf/json-V4-aes-encrypt---show-encryption-key-v2.out
+++ b/qpdf/qtest/qpdf/json-V4-aes-encrypt---show-encryption-key-v2.out
@@ -28,6 +28,7 @@
"streammethod": "AESv2",
"stringmethod": "AESv2"
},
+ "recovereduserpassword": null,
"userpasswordmatched": true
}
}
diff --git a/qpdf/qtest/qpdf/json-V4-aes-encrypt-v1.out b/qpdf/qtest/qpdf/json-V4-aes-encrypt-v1.out
index f67c29f6..f1247a5a 100644
--- a/qpdf/qtest/qpdf/json-V4-aes-encrypt-v1.out
+++ b/qpdf/qtest/qpdf/json-V4-aes-encrypt-v1.out
@@ -28,6 +28,7 @@
"streammethod": "AESv2",
"stringmethod": "AESv2"
},
+ "recovereduserpassword": null,
"userpasswordmatched": true
}
}
diff --git a/qpdf/qtest/qpdf/json-V4-aes-encrypt-v2.out b/qpdf/qtest/qpdf/json-V4-aes-encrypt-v2.out
index 959f0103..b516a301 100644
--- a/qpdf/qtest/qpdf/json-V4-aes-encrypt-v2.out
+++ b/qpdf/qtest/qpdf/json-V4-aes-encrypt-v2.out
@@ -28,6 +28,7 @@
"streammethod": "AESv2",
"stringmethod": "AESv2"
},
+ "recovereduserpassword": null,
"userpasswordmatched": true
}
}
diff --git a/qpdf/qtest/qpdf/json-attachment-fields-v1.out b/qpdf/qtest/qpdf/json-attachment-fields-v1.out
index 21fe88be..fbb07895 100644
--- a/qpdf/qtest/qpdf/json-attachment-fields-v1.out
+++ b/qpdf/qtest/qpdf/json-attachment-fields-v1.out
@@ -96,6 +96,7 @@
"streammethod": "none",
"stringmethod": "none"
},
+ "recovereduserpassword": null,
"userpasswordmatched": false
},
"outlines": [],
diff --git a/qpdf/qtest/qpdf/json-attachment-fields-v2.out b/qpdf/qtest/qpdf/json-attachment-fields-v2.out
index e94e05dc..0241dc15 100644
--- a/qpdf/qtest/qpdf/json-attachment-fields-v2.out
+++ b/qpdf/qtest/qpdf/json-attachment-fields-v2.out
@@ -96,6 +96,7 @@
"streammethod": "none",
"stringmethod": "none"
},
+ "recovereduserpassword": null,
"userpasswordmatched": false
},
"outlines": [],
diff --git a/qpdf/qtest/qpdf/json-field-types---show-encryption-key-v1.out b/qpdf/qtest/qpdf/json-field-types---show-encryption-key-v1.out
index 43e07e53..9c9371b8 100644
--- a/qpdf/qtest/qpdf/json-field-types---show-encryption-key-v1.out
+++ b/qpdf/qtest/qpdf/json-field-types---show-encryption-key-v1.out
@@ -428,6 +428,7 @@
"streammethod": "none",
"stringmethod": "none"
},
+ "recovereduserpassword": null,
"userpasswordmatched": false
},
"outlines": [],
diff --git a/qpdf/qtest/qpdf/json-field-types---show-encryption-key-v2.out b/qpdf/qtest/qpdf/json-field-types---show-encryption-key-v2.out
index f5229296..51c75655 100644
--- a/qpdf/qtest/qpdf/json-field-types---show-encryption-key-v2.out
+++ b/qpdf/qtest/qpdf/json-field-types---show-encryption-key-v2.out
@@ -428,6 +428,7 @@
"streammethod": "none",
"stringmethod": "none"
},
+ "recovereduserpassword": null,
"userpasswordmatched": false
},
"outlines": [],
diff --git a/qpdf/qtest/qpdf/json-field-types-v1.out b/qpdf/qtest/qpdf/json-field-types-v1.out
index 43e07e53..9c9371b8 100644
--- a/qpdf/qtest/qpdf/json-field-types-v1.out
+++ b/qpdf/qtest/qpdf/json-field-types-v1.out
@@ -428,6 +428,7 @@
"streammethod": "none",
"stringmethod": "none"
},
+ "recovereduserpassword": null,
"userpasswordmatched": false
},
"outlines": [],
diff --git a/qpdf/qtest/qpdf/json-field-types-v2.out b/qpdf/qtest/qpdf/json-field-types-v2.out
index f5229296..51c75655 100644
--- a/qpdf/qtest/qpdf/json-field-types-v2.out
+++ b/qpdf/qtest/qpdf/json-field-types-v2.out
@@ -428,6 +428,7 @@
"streammethod": "none",
"stringmethod": "none"
},
+ "recovereduserpassword": null,
"userpasswordmatched": false
},
"outlines": [],
diff --git a/qpdf/qtest/qpdf/json-image-streams-all-v1.out b/qpdf/qtest/qpdf/json-image-streams-all-v1.out
index e8dba0e9..75881c03 100644
--- a/qpdf/qtest/qpdf/json-image-streams-all-v1.out
+++ b/qpdf/qtest/qpdf/json-image-streams-all-v1.out
@@ -271,6 +271,7 @@
"streammethod": "none",
"stringmethod": "none"
},
+ "recovereduserpassword": null,
"userpasswordmatched": false
},
"outlines": [],
diff --git a/qpdf/qtest/qpdf/json-image-streams-all-v2.out b/qpdf/qtest/qpdf/json-image-streams-all-v2.out
index 18e2e7b9..5f09fe46 100644
--- a/qpdf/qtest/qpdf/json-image-streams-all-v2.out
+++ b/qpdf/qtest/qpdf/json-image-streams-all-v2.out
@@ -271,6 +271,7 @@
"streammethod": "none",
"stringmethod": "none"
},
+ "recovereduserpassword": null,
"userpasswordmatched": false
},
"outlines": [],
diff --git a/qpdf/qtest/qpdf/json-image-streams-small-v1.out b/qpdf/qtest/qpdf/json-image-streams-small-v1.out
index 0f6ef237..606b5875 100644
--- a/qpdf/qtest/qpdf/json-image-streams-small-v1.out
+++ b/qpdf/qtest/qpdf/json-image-streams-small-v1.out
@@ -271,6 +271,7 @@
"streammethod": "none",
"stringmethod": "none"
},
+ "recovereduserpassword": null,
"userpasswordmatched": false
},
"outlines": [],
diff --git a/qpdf/qtest/qpdf/json-image-streams-small-v2.out b/qpdf/qtest/qpdf/json-image-streams-small-v2.out
index 515192e1..c5f7abbe 100644
--- a/qpdf/qtest/qpdf/json-image-streams-small-v2.out
+++ b/qpdf/qtest/qpdf/json-image-streams-small-v2.out
@@ -271,6 +271,7 @@
"streammethod": "none",
"stringmethod": "none"
},
+ "recovereduserpassword": null,
"userpasswordmatched": false
},
"outlines": [],
diff --git a/qpdf/qtest/qpdf/json-image-streams-specialized-v1.out b/qpdf/qtest/qpdf/json-image-streams-specialized-v1.out
index 558baaf8..f4e24c63 100644
--- a/qpdf/qtest/qpdf/json-image-streams-specialized-v1.out
+++ b/qpdf/qtest/qpdf/json-image-streams-specialized-v1.out
@@ -271,6 +271,7 @@
"streammethod": "none",
"stringmethod": "none"
},
+ "recovereduserpassword": null,
"userpasswordmatched": false
},
"outlines": [],
diff --git a/qpdf/qtest/qpdf/json-image-streams-specialized-v2.out b/qpdf/qtest/qpdf/json-image-streams-specialized-v2.out
index d5a0eba9..773a1ba6 100644
--- a/qpdf/qtest/qpdf/json-image-streams-specialized-v2.out
+++ b/qpdf/qtest/qpdf/json-image-streams-specialized-v2.out
@@ -271,6 +271,7 @@
"streammethod": "none",
"stringmethod": "none"
},
+ "recovereduserpassword": null,
"userpasswordmatched": false
},
"outlines": [],
diff --git a/qpdf/qtest/qpdf/json-image-streams-v1.out b/qpdf/qtest/qpdf/json-image-streams-v1.out
index 9cb0f859..98dc7f0f 100644
--- a/qpdf/qtest/qpdf/json-image-streams-v1.out
+++ b/qpdf/qtest/qpdf/json-image-streams-v1.out
@@ -271,6 +271,7 @@
"streammethod": "none",
"stringmethod": "none"
},
+ "recovereduserpassword": null,
"userpasswordmatched": false
},
"outlines": [],
diff --git a/qpdf/qtest/qpdf/json-image-streams-v2.out b/qpdf/qtest/qpdf/json-image-streams-v2.out
index 6169cb3c..f0fa7775 100644
--- a/qpdf/qtest/qpdf/json-image-streams-v2.out
+++ b/qpdf/qtest/qpdf/json-image-streams-v2.out
@@ -271,6 +271,7 @@
"streammethod": "none",
"stringmethod": "none"
},
+ "recovereduserpassword": null,
"userpasswordmatched": false
},
"outlines": [],
diff --git a/qpdf/qtest/qpdf/json-outlines-with-actions-v1.out b/qpdf/qtest/qpdf/json-outlines-with-actions-v1.out
index c52e9b58..b7959c23 100644
--- a/qpdf/qtest/qpdf/json-outlines-with-actions-v1.out
+++ b/qpdf/qtest/qpdf/json-outlines-with-actions-v1.out
@@ -462,6 +462,7 @@
"streammethod": "none",
"stringmethod": "none"
},
+ "recovereduserpassword": null,
"userpasswordmatched": false
},
"outlines": [
diff --git a/qpdf/qtest/qpdf/json-outlines-with-actions-v2.out b/qpdf/qtest/qpdf/json-outlines-with-actions-v2.out
index f235dec4..224f5d8d 100644
--- a/qpdf/qtest/qpdf/json-outlines-with-actions-v2.out
+++ b/qpdf/qtest/qpdf/json-outlines-with-actions-v2.out
@@ -462,6 +462,7 @@
"streammethod": "none",
"stringmethod": "none"
},
+ "recovereduserpassword": null,
"userpasswordmatched": false
},
"outlines": [
diff --git a/qpdf/qtest/qpdf/json-outlines-with-old-root-dests-v1.out b/qpdf/qtest/qpdf/json-outlines-with-old-root-dests-v1.out
index 49ecb410..c82e6128 100644
--- a/qpdf/qtest/qpdf/json-outlines-with-old-root-dests-v1.out
+++ b/qpdf/qtest/qpdf/json-outlines-with-old-root-dests-v1.out
@@ -567,6 +567,7 @@
"streammethod": "none",
"stringmethod": "none"
},
+ "recovereduserpassword": null,
"userpasswordmatched": false
},
"outlines": [
diff --git a/qpdf/qtest/qpdf/json-outlines-with-old-root-dests-v2.out b/qpdf/qtest/qpdf/json-outlines-with-old-root-dests-v2.out
index 357e99d2..25b59719 100644
--- a/qpdf/qtest/qpdf/json-outlines-with-old-root-dests-v2.out
+++ b/qpdf/qtest/qpdf/json-outlines-with-old-root-dests-v2.out
@@ -567,6 +567,7 @@
"streammethod": "none",
"stringmethod": "none"
},
+ "recovereduserpassword": null,
"userpasswordmatched": false
},
"outlines": [
diff --git a/qpdf/qtest/qpdf/json-page-labels-and-outlines-v1.out b/qpdf/qtest/qpdf/json-page-labels-and-outlines-v1.out
index 4154693d..d51face5 100644
--- a/qpdf/qtest/qpdf/json-page-labels-and-outlines-v1.out
+++ b/qpdf/qtest/qpdf/json-page-labels-and-outlines-v1.out
@@ -637,6 +637,7 @@
"streammethod": "none",
"stringmethod": "none"
},
+ "recovereduserpassword": null,
"userpasswordmatched": false
},
"outlines": [
diff --git a/qpdf/qtest/qpdf/json-page-labels-and-outlines-v2.out b/qpdf/qtest/qpdf/json-page-labels-and-outlines-v2.out
index 14775582..5e73a3d6 100644
--- a/qpdf/qtest/qpdf/json-page-labels-and-outlines-v2.out
+++ b/qpdf/qtest/qpdf/json-page-labels-and-outlines-v2.out
@@ -637,6 +637,7 @@
"streammethod": "none",
"stringmethod": "none"
},
+ "recovereduserpassword": null,
"userpasswordmatched": false
},
"outlines": [
diff --git a/qpdf/qtest/qpdf/json-page-labels-num-tree-v1.out b/qpdf/qtest/qpdf/json-page-labels-num-tree-v1.out
index a4bc2cfa..ac67bcec 100644
--- a/qpdf/qtest/qpdf/json-page-labels-num-tree-v1.out
+++ b/qpdf/qtest/qpdf/json-page-labels-num-tree-v1.out
@@ -534,6 +534,7 @@
"streammethod": "none",
"stringmethod": "none"
},
+ "recovereduserpassword": null,
"userpasswordmatched": false
},
"outlines": [],
diff --git a/qpdf/qtest/qpdf/json-page-labels-num-tree-v2.out b/qpdf/qtest/qpdf/json-page-labels-num-tree-v2.out
index 1bfa1ad3..902223fc 100644
--- a/qpdf/qtest/qpdf/json-page-labels-num-tree-v2.out
+++ b/qpdf/qtest/qpdf/json-page-labels-num-tree-v2.out
@@ -534,6 +534,7 @@
"streammethod": "none",
"stringmethod": "none"
},
+ "recovereduserpassword": null,
"userpasswordmatched": false
},
"outlines": [],