Commit b7bbf12e85fa46e7971d84143d1597c992045af1

Authored by Jay Berkenbilt
1 parent f049a77c

In json mode, reveal recovered user password when otherwise unavailable

ChangeLog
1 1 2022-05-30 Jay Berkenbilt <ejb@ql.org>
2 2  
  3 + * When showing encryption data in json output, when the user
  4 + password was recovered with by the owner password and the
  5 + specified password does not match the user password, reveal the
  6 + user password. This is not possible with 256-bit keys.
  7 +
3 8 * Include additional information in --list-attachments --verbose
4 9 and in --json --json-key=attachments.
5 10  
... ...
... ... @@ -70,8 +70,6 @@ Remaining work:
70 70  
71 71 * --show-xref: add
72 72  
73   - * --encryption: show recovered user password when available
74   -
75 73 * Consider having --check, --show-encryption, etc., just select the
76 74 right keys when in json mode. I don't think I want check on by
77 75 default, so that might be different.
... ...
libqpdf/QPDFJob.cc
... ... @@ -1382,6 +1382,15 @@ QPDFJob::doJSONEncrypt(Pipeline* p, bool&amp; first, QPDF&amp; pdf)
1382 1382 j_encrypt.addDictionaryMember(
1383 1383 "ownerpasswordmatched",
1384 1384 JSON::makeBool(is_encrypted && pdf.ownerPasswordMatched()));
  1385 + if (is_encrypted && (V < 5) && pdf.ownerPasswordMatched() &&
  1386 + (!pdf.userPasswordMatched())) {
  1387 + std::string user_password = pdf.getTrimmedUserPassword();
  1388 + j_encrypt.addDictionaryMember(
  1389 + "recovereduserpassword", JSON::makeString(user_password));
  1390 + } else {
  1391 + j_encrypt.addDictionaryMember(
  1392 + "recovereduserpassword", JSON::makeNull());
  1393 + }
1385 1394 JSON j_capabilities =
1386 1395 j_encrypt.addDictionaryMember("capabilities", JSON::makeDictionary());
1387 1396 j_capabilities.addDictionaryMember(
... ... @@ -1669,6 +1678,7 @@ QPDFJob::json_schema(int json_version, std::set&lt;std::string&gt;* keys)
1669 1678 },
1670 1679 "encrypted": "whether the document is encrypted",
1671 1680 "ownerpasswordmatched": "whether supplied password matched owner password; always false for non-encrypted files",
  1681 + "recovereduserpassword": "If the owner password was used to recover the user password, reveal user password; otherwise null",
1672 1682 "parameters": {
1673 1683 "P": "P value from Encrypt dictionary",
1674 1684 "R": "R value from Encrypt dictionary",
... ...
manual/release-notes.rst
... ... @@ -103,6 +103,12 @@ For a detailed list of changes, please see the file
103 103 attachments is also included in the ``attachments`` json key
104 104 with ``--json``.
105 105  
  106 + - For encrypted files, ``qpdf --json`` reveals the user password
  107 + when the specified password did not match the user password and
  108 + the owner password was used to recover the user password. The
  109 + user password is not recoverable from the owner password when
  110 + 256-bit keys are in use.
  111 +
106 112 - Library Enhancements
107 113  
108 114 - New methods ``insertItemAndGet``, ``appendItemAndGet``,
... ...
qpdf/qtest/encryption.test
... ... @@ -219,6 +219,7 @@ foreach my $d (@encrypted_files)
219 219 " \"streammethod\": \"---method---\",\n" .
220 220 " \"stringmethod\": \"---method---\"\n" .
221 221 " },\n" .
  222 + " \"recovereduserpassword\": ---rup---,\n" .
222 223 " \"userpasswordmatched\": ---upm---\n" .
223 224 " }\n" .
224 225 "}\n";
... ... @@ -267,6 +268,8 @@ foreach my $d (@encrypted_files)
267 268 my $method = $bits == 256 ? "AESv3" : "RC4";
268 269 my $opm = ($pass eq $opass ? "true" : "false");
269 270 my $upm = ($pass eq $upass ? "true" : "false");
  271 + my $rup = (($pass eq $opass) && ($pass ne $upass) && ($V < 5))
  272 + ? "\"$upass\"" : "null";
270 273 $enc_json =~ s/---R---/$R/;
271 274 $enc_json =~ s/---P---/$P/;
272 275 $enc_json =~ s/---V---/$V/;
... ... @@ -274,6 +277,7 @@ foreach my $d (@encrypted_files)
274 277 $enc_json =~ s/---method---/$method/g;
275 278 $enc_json =~ s/---opm---/$opm/;
276 279 $enc_json =~ s/---upm---/$upm/;
  280 + $enc_json =~ s/---rup---/$rup/;
277 281  
278 282 my $eflags = "--allow-weak-crypto" .
279 283 " -encrypt \"$upass\" \"$opass\" $bits $xeflags --";
... ...
qpdf/qtest/qpdf/json-V4-aes-encrypt---show-encryption-key-v1.out
... ... @@ -28,6 +28,7 @@
28 28 "streammethod": "AESv2",
29 29 "stringmethod": "AESv2"
30 30 },
  31 + "recovereduserpassword": null,
31 32 "userpasswordmatched": true
32 33 }
33 34 }
... ...
qpdf/qtest/qpdf/json-V4-aes-encrypt---show-encryption-key-v2.out
... ... @@ -28,6 +28,7 @@
28 28 "streammethod": "AESv2",
29 29 "stringmethod": "AESv2"
30 30 },
  31 + "recovereduserpassword": null,
31 32 "userpasswordmatched": true
32 33 }
33 34 }
... ...
qpdf/qtest/qpdf/json-V4-aes-encrypt-v1.out
... ... @@ -28,6 +28,7 @@
28 28 "streammethod": "AESv2",
29 29 "stringmethod": "AESv2"
30 30 },
  31 + "recovereduserpassword": null,
31 32 "userpasswordmatched": true
32 33 }
33 34 }
... ...
qpdf/qtest/qpdf/json-V4-aes-encrypt-v2.out
... ... @@ -28,6 +28,7 @@
28 28 "streammethod": "AESv2",
29 29 "stringmethod": "AESv2"
30 30 },
  31 + "recovereduserpassword": null,
31 32 "userpasswordmatched": true
32 33 }
33 34 }
... ...
qpdf/qtest/qpdf/json-attachment-fields-v1.out
... ... @@ -96,6 +96,7 @@
96 96 "streammethod": "none",
97 97 "stringmethod": "none"
98 98 },
  99 + "recovereduserpassword": null,
99 100 "userpasswordmatched": false
100 101 },
101 102 "outlines": [],
... ...
qpdf/qtest/qpdf/json-attachment-fields-v2.out
... ... @@ -96,6 +96,7 @@
96 96 "streammethod": "none",
97 97 "stringmethod": "none"
98 98 },
  99 + "recovereduserpassword": null,
99 100 "userpasswordmatched": false
100 101 },
101 102 "outlines": [],
... ...
qpdf/qtest/qpdf/json-field-types---show-encryption-key-v1.out
... ... @@ -428,6 +428,7 @@
428 428 "streammethod": "none",
429 429 "stringmethod": "none"
430 430 },
  431 + "recovereduserpassword": null,
431 432 "userpasswordmatched": false
432 433 },
433 434 "outlines": [],
... ...
qpdf/qtest/qpdf/json-field-types---show-encryption-key-v2.out
... ... @@ -428,6 +428,7 @@
428 428 "streammethod": "none",
429 429 "stringmethod": "none"
430 430 },
  431 + "recovereduserpassword": null,
431 432 "userpasswordmatched": false
432 433 },
433 434 "outlines": [],
... ...
qpdf/qtest/qpdf/json-field-types-v1.out
... ... @@ -428,6 +428,7 @@
428 428 "streammethod": "none",
429 429 "stringmethod": "none"
430 430 },
  431 + "recovereduserpassword": null,
431 432 "userpasswordmatched": false
432 433 },
433 434 "outlines": [],
... ...
qpdf/qtest/qpdf/json-field-types-v2.out
... ... @@ -428,6 +428,7 @@
428 428 "streammethod": "none",
429 429 "stringmethod": "none"
430 430 },
  431 + "recovereduserpassword": null,
431 432 "userpasswordmatched": false
432 433 },
433 434 "outlines": [],
... ...
qpdf/qtest/qpdf/json-image-streams-all-v1.out
... ... @@ -271,6 +271,7 @@
271 271 "streammethod": "none",
272 272 "stringmethod": "none"
273 273 },
  274 + "recovereduserpassword": null,
274 275 "userpasswordmatched": false
275 276 },
276 277 "outlines": [],
... ...
qpdf/qtest/qpdf/json-image-streams-all-v2.out
... ... @@ -271,6 +271,7 @@
271 271 "streammethod": "none",
272 272 "stringmethod": "none"
273 273 },
  274 + "recovereduserpassword": null,
274 275 "userpasswordmatched": false
275 276 },
276 277 "outlines": [],
... ...
qpdf/qtest/qpdf/json-image-streams-small-v1.out
... ... @@ -271,6 +271,7 @@
271 271 "streammethod": "none",
272 272 "stringmethod": "none"
273 273 },
  274 + "recovereduserpassword": null,
274 275 "userpasswordmatched": false
275 276 },
276 277 "outlines": [],
... ...
qpdf/qtest/qpdf/json-image-streams-small-v2.out
... ... @@ -271,6 +271,7 @@
271 271 "streammethod": "none",
272 272 "stringmethod": "none"
273 273 },
  274 + "recovereduserpassword": null,
274 275 "userpasswordmatched": false
275 276 },
276 277 "outlines": [],
... ...
qpdf/qtest/qpdf/json-image-streams-specialized-v1.out
... ... @@ -271,6 +271,7 @@
271 271 "streammethod": "none",
272 272 "stringmethod": "none"
273 273 },
  274 + "recovereduserpassword": null,
274 275 "userpasswordmatched": false
275 276 },
276 277 "outlines": [],
... ...
qpdf/qtest/qpdf/json-image-streams-specialized-v2.out
... ... @@ -271,6 +271,7 @@
271 271 "streammethod": "none",
272 272 "stringmethod": "none"
273 273 },
  274 + "recovereduserpassword": null,
274 275 "userpasswordmatched": false
275 276 },
276 277 "outlines": [],
... ...
qpdf/qtest/qpdf/json-image-streams-v1.out
... ... @@ -271,6 +271,7 @@
271 271 "streammethod": "none",
272 272 "stringmethod": "none"
273 273 },
  274 + "recovereduserpassword": null,
274 275 "userpasswordmatched": false
275 276 },
276 277 "outlines": [],
... ...
qpdf/qtest/qpdf/json-image-streams-v2.out
... ... @@ -271,6 +271,7 @@
271 271 "streammethod": "none",
272 272 "stringmethod": "none"
273 273 },
  274 + "recovereduserpassword": null,
274 275 "userpasswordmatched": false
275 276 },
276 277 "outlines": [],
... ...
qpdf/qtest/qpdf/json-outlines-with-actions-v1.out
... ... @@ -462,6 +462,7 @@
462 462 "streammethod": "none",
463 463 "stringmethod": "none"
464 464 },
  465 + "recovereduserpassword": null,
465 466 "userpasswordmatched": false
466 467 },
467 468 "outlines": [
... ...
qpdf/qtest/qpdf/json-outlines-with-actions-v2.out
... ... @@ -462,6 +462,7 @@
462 462 "streammethod": "none",
463 463 "stringmethod": "none"
464 464 },
  465 + "recovereduserpassword": null,
465 466 "userpasswordmatched": false
466 467 },
467 468 "outlines": [
... ...
qpdf/qtest/qpdf/json-outlines-with-old-root-dests-v1.out
... ... @@ -567,6 +567,7 @@
567 567 "streammethod": "none",
568 568 "stringmethod": "none"
569 569 },
  570 + "recovereduserpassword": null,
570 571 "userpasswordmatched": false
571 572 },
572 573 "outlines": [
... ...
qpdf/qtest/qpdf/json-outlines-with-old-root-dests-v2.out
... ... @@ -567,6 +567,7 @@
567 567 "streammethod": "none",
568 568 "stringmethod": "none"
569 569 },
  570 + "recovereduserpassword": null,
570 571 "userpasswordmatched": false
571 572 },
572 573 "outlines": [
... ...
qpdf/qtest/qpdf/json-page-labels-and-outlines-v1.out
... ... @@ -637,6 +637,7 @@
637 637 "streammethod": "none",
638 638 "stringmethod": "none"
639 639 },
  640 + "recovereduserpassword": null,
640 641 "userpasswordmatched": false
641 642 },
642 643 "outlines": [
... ...
qpdf/qtest/qpdf/json-page-labels-and-outlines-v2.out
... ... @@ -637,6 +637,7 @@
637 637 "streammethod": "none",
638 638 "stringmethod": "none"
639 639 },
  640 + "recovereduserpassword": null,
640 641 "userpasswordmatched": false
641 642 },
642 643 "outlines": [
... ...
qpdf/qtest/qpdf/json-page-labels-num-tree-v1.out
... ... @@ -534,6 +534,7 @@
534 534 "streammethod": "none",
535 535 "stringmethod": "none"
536 536 },
  537 + "recovereduserpassword": null,
537 538 "userpasswordmatched": false
538 539 },
539 540 "outlines": [],
... ...
qpdf/qtest/qpdf/json-page-labels-num-tree-v2.out
... ... @@ -534,6 +534,7 @@
534 534 "streammethod": "none",
535 535 "stringmethod": "none"
536 536 },
  537 + "recovereduserpassword": null,
537 538 "userpasswordmatched": false
538 539 },
539 540 "outlines": [],
... ...