Commit cb3c4c55d4cd721f647fa544a98bc0cb24c97823

Authored by m-holger
1 parent 34f52682

Refactor `QPDF::EncryptionData` to encapsulate encryption logic, reduce redundan…

…t parameter passing, and improve maintainability. Change static functions and QPDF methods to EncryptionData methods.
include/qpdf/QPDF.hh
... ... @@ -497,10 +497,68 @@ class QPDF
497 497 std::string const& UE,
498 498 std::string const& Perms);
499 499  
  500 + std::string compute_encryption_key(std::string const& password) const;
  501 +
  502 + bool
  503 + check_owner_password(std::string& user_password, std::string const& owner_password) const;
  504 +
  505 + bool check_user_password(std::string const& user_password) const;
  506 +
  507 + std::string
  508 + recover_encryption_key_with_password(std::string const& password, bool& perms_valid) const;
  509 +
  510 + void compute_encryption_O_U(
  511 + char const* user_password, char const* owner_password, std::string& O, std::string& U);
  512 +
  513 + void compute_encryption_parameters_V5(
  514 + char const* user_password,
  515 + char const* owner_password,
  516 + std::string& encryption_key,
  517 + std::string& O,
  518 + std::string& U,
  519 + std::string& OE,
  520 + std::string& UE,
  521 + std::string& Perms);
  522 +
500 523 private:
  524 + static constexpr unsigned int OU_key_bytes_V4 = 16; // ( == sizeof(MD5::Digest)
  525 +
501 526 EncryptionData(EncryptionData const&) = delete;
502 527 EncryptionData& operator=(EncryptionData const&) = delete;
503 528  
  529 + std::string hash_V5(
  530 + std::string const& password, std::string const& salt, std::string const& udata) const;
  531 + std::string compute_Perms_value_V5(std::string const& encryption_key) const;
  532 + std::string
  533 + compute_O_value(std::string const& user_password, std::string const& owner_password) const;
  534 + std::string compute_U_value(std::string const& user_password) const;
  535 + void compute_O_OE_value_V5(
  536 + std::string const& owner_password,
  537 + std::string const& encryption_key,
  538 + std::string const& U,
  539 + std::string& O,
  540 + std::string& OE) const;
  541 + void compute_U_UE_value_V5(
  542 + std::string const& user_password,
  543 + std::string const& encryption_key,
  544 + std::string& U,
  545 + std::string& UE) const;
  546 + std::string compute_encryption_key_from_password(std::string const& password) const;
  547 + std::string recover_encryption_key_with_password(std::string const& password) const;
  548 + bool check_owner_password_V4(
  549 + std::string& user_password, std::string const& owner_password) const;
  550 + bool check_owner_password_V5(std::string const& owner_passworda) const;
  551 + void
  552 + compute_Perms_value_V5_clear(std::string const& encryption_key, unsigned char k[16]) const;
  553 + void compute_O_rc4_key(
  554 + std::string const& user_password,
  555 + std::string const& owner_password,
  556 + unsigned char key[OU_key_bytes_V4]) const;
  557 + std::string compute_U_value_R2(std::string const& user_password) const;
  558 + std::string compute_U_value_R3(std::string const& user_password) const;
  559 + bool check_user_password_V4(std::string const& user_password) const;
  560 + bool check_user_password_V5(std::string const& user_password) const;
  561 +
504 562 int V;
505 563 int R;
506 564 int Length_bytes;
... ... @@ -912,12 +970,6 @@ class QPDF
912 970 static std::string
913 971 getKeyForObject(std::shared_ptr<EncryptionParameters> encp, QPDFObjGen og, bool use_aes);
914 972 void decryptString(std::string&, QPDFObjGen og);
915   - static std::string
916   - compute_encryption_key_from_password(std::string const& password, EncryptionData const& data);
917   - static std::string
918   - recover_encryption_key_with_password(std::string const& password, EncryptionData const& data);
919   - static std::string recover_encryption_key_with_password(
920   - std::string const& password, EncryptionData const& data, bool& perms_valid);
921 973 static void decryptStream(
922 974 std::shared_ptr<EncryptionParameters> encp,
923 975 std::shared_ptr<InputSource> file,
... ...
libqpdf/QPDF_encryption.cc
... ... @@ -25,9 +25,6 @@ static unsigned char const padding_string[] = {
25 25  
26 26 static unsigned int const key_bytes = 32;
27 27  
28   -// V4 key lengths apply to V <= 4
29   -static unsigned int const OU_key_bytes_V4 = sizeof(MD5::Digest);
30   -
31 28 static unsigned int const OU_key_bytes_V5 = 48;
32 29 static unsigned int const OUE_key_bytes_V5 = 32;
33 30 static unsigned int const Perms_key_bytes_V5 = 16;
... ... @@ -236,12 +233,9 @@ process_with_aes(
236 233 }
237 234 }
238 235  
239   -static std::string
240   -hash_V5(
241   - std::string const& password,
242   - std::string const& salt,
243   - std::string const& udata,
244   - QPDF::EncryptionData const& data)
  236 +std::string
  237 +QPDF::EncryptionData::hash_V5(
  238 + std::string const& password, std::string const& salt, std::string const& udata) const
245 239 {
246 240 Pl_SHA2 hash(256);
247 241 hash.writeString(password);
... ... @@ -251,7 +245,7 @@ hash_V5(
251 245 std::string K = hash.getRawDigest();
252 246  
253 247 std::string result;
254   - if (data.getR() < 6) {
  248 + if (getR() < 6) {
255 249 result = K;
256 250 } else {
257 251 // Algorithm 2.B from ISO 32000-1 chapter 7: Computing a hash
... ... @@ -359,19 +353,25 @@ QPDF::compute_data_key(
359 353 std::string
360 354 QPDF::compute_encryption_key(std::string const& password, EncryptionData const& data)
361 355 {
362   - if (data.getV() >= 5) {
  356 + return data.compute_encryption_key(password);
  357 +}
  358 +
  359 +std::string
  360 +QPDF::EncryptionData::compute_encryption_key(std::string const& password) const
  361 +{
  362 + if (getV() >= 5) {
363 363 // For V >= 5, the encryption key is generated and stored in the file, encrypted separately
364 364 // with both user and owner passwords.
365   - return recover_encryption_key_with_password(password, data);
  365 + return recover_encryption_key_with_password(password);
366 366 } else {
367 367 // For V < 5, the encryption key is derived from the user
368 368 // password.
369   - return compute_encryption_key_from_password(password, data);
  369 + return compute_encryption_key_from_password(password);
370 370 }
371 371 }
372 372  
373 373 std::string
374   -QPDF::compute_encryption_key_from_password(std::string const& password, EncryptionData const& data)
  374 +QPDF::EncryptionData::compute_encryption_key_from_password(std::string const& password) const
375 375 {
376 376 // Algorithm 3.2 from the PDF 1.7 Reference Manual
377 377  
... ... @@ -382,34 +382,33 @@ QPDF::compute_encryption_key_from_password(std::string const&amp; password, Encrypti
382 382  
383 383 MD5 md5;
384 384 md5.encodeDataIncrementally(pad_or_truncate_password_V4(password).c_str(), key_bytes);
385   - md5.encodeDataIncrementally(data.getO().c_str(), key_bytes);
  385 + md5.encodeDataIncrementally(getO().c_str(), key_bytes);
386 386 char pbytes[4];
387   - int P = data.getP();
  387 + int P = getP();
388 388 pbytes[0] = static_cast<char>(P & 0xff);
389 389 pbytes[1] = static_cast<char>((P >> 8) & 0xff);
390 390 pbytes[2] = static_cast<char>((P >> 16) & 0xff);
391 391 pbytes[3] = static_cast<char>((P >> 24) & 0xff);
392 392 md5.encodeDataIncrementally(pbytes, 4);
393   - md5.encodeDataIncrementally(data.getId1().c_str(), data.getId1().length());
394   - if ((data.getR() >= 4) && (!data.getEncryptMetadata())) {
  393 + md5.encodeDataIncrementally(getId1().c_str(), getId1().length());
  394 + if (getR() >= 4 && !getEncryptMetadata()) {
395 395 char bytes[4];
396 396 memset(bytes, 0xff, 4);
397 397 md5.encodeDataIncrementally(bytes, 4);
398 398 }
399 399 MD5::Digest digest;
400   - int key_len = std::min(toI(sizeof(digest)), data.getLengthBytes());
401   - iterate_md5_digest(md5, digest, ((data.getR() >= 3) ? 50 : 0), key_len);
  400 + int key_len = std::min(toI(sizeof(digest)), getLengthBytes());
  401 + iterate_md5_digest(md5, digest, (getR() >= 3 ? 50 : 0), key_len);
402 402 return {reinterpret_cast<char*>(digest), toS(key_len)};
403 403 }
404 404  
405   -static void
406   -compute_O_rc4_key(
  405 +void
  406 +QPDF::EncryptionData::compute_O_rc4_key(
407 407 std::string const& user_password,
408 408 std::string const& owner_password,
409   - QPDF::EncryptionData const& data,
410   - unsigned char key[OU_key_bytes_V4])
  409 + unsigned char key[OU_key_bytes_V4]) const
411 410 {
412   - if (data.getV() >= 5) {
  411 + if (getV() >= 5) {
413 412 throw std::logic_error("compute_O_rc4_key called for file with V >= 5");
414 413 }
415 414 std::string password = owner_password;
... ... @@ -419,252 +418,241 @@ compute_O_rc4_key(
419 418 MD5 md5;
420 419 md5.encodeDataIncrementally(pad_or_truncate_password_V4(password).c_str(), key_bytes);
421 420 MD5::Digest digest;
422   - int key_len = std::min(QIntC::to_int(sizeof(digest)), data.getLengthBytes());
423   - iterate_md5_digest(md5, digest, ((data.getR() >= 3) ? 50 : 0), key_len);
  421 + int key_len = std::min(QIntC::to_int(sizeof(digest)), getLengthBytes());
  422 + iterate_md5_digest(md5, digest, (getR() >= 3 ? 50 : 0), key_len);
424 423 memcpy(key, digest, OU_key_bytes_V4);
425 424 }
426 425  
427   -static std::string
428   -compute_O_value(
429   - std::string const& user_password,
430   - std::string const& owner_password,
431   - QPDF::EncryptionData const& data)
  426 +std::string
  427 +QPDF::EncryptionData::compute_O_value(
  428 + std::string const& user_password, std::string const& owner_password) const
432 429 {
433 430 // Algorithm 3.3 from the PDF 1.7 Reference Manual
434 431  
435 432 unsigned char O_key[OU_key_bytes_V4];
436   - compute_O_rc4_key(user_password, owner_password, data, O_key);
  433 + compute_O_rc4_key(user_password, owner_password, O_key);
437 434  
438 435 char upass[key_bytes];
439 436 pad_or_truncate_password_V4(user_password, upass);
440 437 std::string k1(reinterpret_cast<char*>(O_key), OU_key_bytes_V4);
441   - pad_short_parameter(k1, QIntC::to_size(data.getLengthBytes()));
  438 + pad_short_parameter(k1, QIntC::to_size(getLengthBytes()));
442 439 iterate_rc4(
443 440 QUtil::unsigned_char_pointer(upass),
444 441 key_bytes,
445 442 O_key,
446   - data.getLengthBytes(),
447   - (data.getR() >= 3) ? 20 : 1,
  443 + getLengthBytes(),
  444 + getR() >= 3 ? 20 : 1,
448 445 false);
449 446 return {upass, key_bytes};
450 447 }
451 448  
452   -static std::string
453   -compute_U_value_R2(std::string const& user_password, QPDF::EncryptionData const& data)
  449 +std::string
  450 +QPDF::EncryptionData::compute_U_value_R2(std::string const& user_password) const
454 451 {
455 452 // Algorithm 3.4 from the PDF 1.7 Reference Manual
456 453  
457   - std::string k1 = QPDF::compute_encryption_key(user_password, data);
  454 + std::string k1 = compute_encryption_key(user_password);
458 455 char udata[key_bytes];
459 456 pad_or_truncate_password_V4("", udata);
460   - pad_short_parameter(k1, QIntC::to_size(data.getLengthBytes()));
  457 + pad_short_parameter(k1, QIntC::to_size(getLengthBytes()));
461 458 iterate_rc4(
462 459 QUtil::unsigned_char_pointer(udata),
463 460 key_bytes,
464 461 QUtil::unsigned_char_pointer(k1),
465   - data.getLengthBytes(),
  462 + getLengthBytes(),
466 463 1,
467 464 false);
468 465 return {udata, key_bytes};
469 466 }
470 467  
471   -static std::string
472   -compute_U_value_R3(std::string const& user_password, QPDF::EncryptionData const& data)
  468 +std::string
  469 +QPDF::EncryptionData::compute_U_value_R3(std::string const& user_password) const
473 470 {
474 471 // Algorithm 3.5 from the PDF 1.7 Reference Manual
475 472  
476   - std::string k1 = QPDF::compute_encryption_key(user_password, data);
  473 + std::string k1 = compute_encryption_key(user_password);
477 474 MD5 md5;
478 475 md5.encodeDataIncrementally(pad_or_truncate_password_V4("").c_str(), key_bytes);
479   - md5.encodeDataIncrementally(data.getId1().c_str(), data.getId1().length());
  476 + md5.encodeDataIncrementally(getId1().c_str(), getId1().length());
480 477 MD5::Digest digest;
481 478 md5.digest(digest);
482   - pad_short_parameter(k1, QIntC::to_size(data.getLengthBytes()));
  479 + pad_short_parameter(k1, QIntC::to_size(getLengthBytes()));
483 480 iterate_rc4(
484   - digest,
485   - sizeof(MD5::Digest),
486   - QUtil::unsigned_char_pointer(k1),
487   - data.getLengthBytes(),
488   - 20,
489   - false);
  481 + digest, sizeof(MD5::Digest), QUtil::unsigned_char_pointer(k1), getLengthBytes(), 20, false);
490 482 char result[key_bytes];
491 483 memcpy(result, digest, sizeof(MD5::Digest));
492   - // pad with arbitrary data -- make it consistent for the sake of
493   - // testing
  484 + // pad with arbitrary data -- make it consistent for the sake of testing
494 485 for (unsigned int i = sizeof(MD5::Digest); i < key_bytes; ++i) {
495 486 result[i] = static_cast<char>((i * i) % 0xff);
496 487 }
497 488 return {result, key_bytes};
498 489 }
499 490  
500   -static std::string
501   -compute_U_value(std::string const& user_password, QPDF::EncryptionData const& data)
  491 +std::string
  492 +QPDF::EncryptionData::compute_U_value(std::string const& user_password) const
502 493 {
503   - if (data.getR() >= 3) {
504   - return compute_U_value_R3(user_password, data);
  494 + if (getR() >= 3) {
  495 + return compute_U_value_R3(user_password);
505 496 }
506 497  
507   - return compute_U_value_R2(user_password, data);
  498 + return compute_U_value_R2(user_password);
508 499 }
509 500  
510   -static bool
511   -check_user_password_V4(std::string const& user_password, QPDF::EncryptionData const& data)
  501 +bool
  502 +QPDF::EncryptionData::check_user_password_V4(std::string const& user_password) const
512 503 {
513 504 // Algorithm 3.6 from the PDF 1.7 Reference Manual
514 505  
515   - std::string u_value = compute_U_value(user_password, data);
516   - size_t to_compare = ((data.getR() >= 3) ? sizeof(MD5::Digest) : key_bytes);
517   - return (memcmp(data.getU().c_str(), u_value.c_str(), to_compare) == 0);
  506 + std::string u_value = compute_U_value(user_password);
  507 + size_t to_compare = (getR() >= 3 ? sizeof(MD5::Digest) : key_bytes);
  508 + return memcmp(getU().c_str(), u_value.c_str(), to_compare) == 0;
518 509 }
519 510  
520   -static bool
521   -check_user_password_V5(std::string const& user_password, QPDF::EncryptionData const& data)
  511 +bool
  512 +QPDF::EncryptionData::check_user_password_V5(std::string const& user_password) const
522 513 {
523 514 // Algorithm 3.11 from the PDF 1.7 extension level 3
524 515  
525   - std::string user_data = data.getU().substr(0, 32);
526   - std::string validation_salt = data.getU().substr(32, 8);
  516 + std::string user_data = getU().substr(0, 32);
  517 + std::string validation_salt = getU().substr(32, 8);
527 518 std::string password = truncate_password_V5(user_password);
528   - return (hash_V5(password, validation_salt, "", data) == user_data);
  519 + return hash_V5(password, validation_salt, "") == user_data;
529 520 }
530 521  
531   -static bool
532   -check_user_password(std::string const& user_password, QPDF::EncryptionData const& data)
  522 +bool
  523 +QPDF::EncryptionData::check_user_password(std::string const& user_password) const
533 524 {
534   - if (data.getV() < 5) {
535   - return check_user_password_V4(user_password, data);
  525 + if (getV() < 5) {
  526 + return check_user_password_V4(user_password);
536 527 } else {
537   - return check_user_password_V5(user_password, data);
  528 + return check_user_password_V5(user_password);
538 529 }
539 530 }
540 531  
541   -static bool
542   -check_owner_password_V4(
543   - std::string& user_password, std::string const& owner_password, QPDF::EncryptionData const& data)
  532 +bool
  533 +QPDF::EncryptionData::check_owner_password_V4(
  534 + std::string& user_password, std::string const& owner_password) const
544 535 {
545 536 // Algorithm 3.7 from the PDF 1.7 Reference Manual
546 537  
547 538 unsigned char key[OU_key_bytes_V4];
548   - compute_O_rc4_key(user_password, owner_password, data, key);
  539 + compute_O_rc4_key(user_password, owner_password, key);
549 540 unsigned char O_data[key_bytes];
550   - memcpy(O_data, QUtil::unsigned_char_pointer(data.getO()), key_bytes);
  541 + memcpy(O_data, QUtil::unsigned_char_pointer(getO()), key_bytes);
551 542 std::string k1(reinterpret_cast<char*>(key), OU_key_bytes_V4);
552   - pad_short_parameter(k1, QIntC::to_size(data.getLengthBytes()));
  543 + pad_short_parameter(k1, QIntC::to_size(getLengthBytes()));
553 544 iterate_rc4(
554 545 O_data,
555 546 key_bytes,
556 547 QUtil::unsigned_char_pointer(k1),
557   - data.getLengthBytes(),
558   - (data.getR() >= 3) ? 20 : 1,
  548 + getLengthBytes(),
  549 + (getR() >= 3) ? 20 : 1,
559 550 true);
560 551 std::string new_user_password = std::string(reinterpret_cast<char*>(O_data), key_bytes);
561   - bool result = false;
562   - if (check_user_password(new_user_password, data)) {
563   - result = true;
  552 + if (check_user_password(new_user_password)) {
564 553 user_password = new_user_password;
  554 + return true;
565 555 }
566   - return result;
  556 + return false;
567 557 }
568 558  
569   -static bool
570   -check_owner_password_V5(std::string const& owner_password, QPDF::EncryptionData const& data)
  559 +bool
  560 +QPDF::EncryptionData::check_owner_password_V5(std::string const& owner_password) const
571 561 {
572 562 // Algorithm 3.12 from the PDF 1.7 extension level 3
573 563  
574   - std::string user_data = data.getU().substr(0, 48);
575   - std::string owner_data = data.getO().substr(0, 32);
576   - std::string validation_salt = data.getO().substr(32, 8);
  564 + std::string user_data = getU().substr(0, 48);
  565 + std::string owner_data = getO().substr(0, 32);
  566 + std::string validation_salt = getO().substr(32, 8);
577 567 std::string password = truncate_password_V5(owner_password);
578   - return (hash_V5(password, validation_salt, user_data, data) == owner_data);
  568 + return hash_V5(password, validation_salt, user_data) == owner_data;
579 569 }
580 570  
581   -static bool
582   -check_owner_password(
583   - std::string& user_password, std::string const& owner_password, QPDF::EncryptionData const& data)
  571 +bool
  572 +QPDF::EncryptionData::check_owner_password(
  573 + std::string& user_password, std::string const& owner_password) const
584 574 {
585   - if (data.getV() < 5) {
586   - return check_owner_password_V4(user_password, owner_password, data);
  575 + if (getV() < 5) {
  576 + return check_owner_password_V4(user_password, owner_password);
587 577 } else {
588   - return check_owner_password_V5(owner_password, data);
  578 + return check_owner_password_V5(owner_password);
589 579 }
590 580 }
591 581  
592 582 std::string
593   -QPDF::recover_encryption_key_with_password(std::string const& password, EncryptionData const& data)
  583 +QPDF::EncryptionData::recover_encryption_key_with_password(std::string const& password) const
594 584 {
595 585 // Disregard whether Perms is valid.
596 586 bool disregard;
597   - return recover_encryption_key_with_password(password, data, disregard);
  587 + return recover_encryption_key_with_password(password, disregard);
598 588 }
599 589  
600   -static void
601   -compute_U_UE_value_V5(
  590 +void
  591 +QPDF::EncryptionData::compute_U_UE_value_V5(
602 592 std::string const& user_password,
603 593 std::string const& encryption_key,
604   - QPDF::EncryptionData const& data,
605   - std::string& U,
606   - std::string& UE)
  594 + std::string& out_U,
  595 + std::string& out_UE) const
607 596 {
608 597 // Algorithm 3.8 from the PDF 1.7 extension level 3
609 598 char k[16];
610 599 QUtil::initializeWithRandomBytes(reinterpret_cast<unsigned char*>(k), sizeof(k));
611 600 std::string validation_salt(k, 8);
612 601 std::string key_salt(k + 8, 8);
613   - U = hash_V5(user_password, validation_salt, "", data) + validation_salt + key_salt;
614   - std::string intermediate_key = hash_V5(user_password, key_salt, "", data);
615   - UE = process_with_aes(intermediate_key, true, encryption_key);
  602 + out_U = hash_V5(user_password, validation_salt, "") + validation_salt + key_salt;
  603 + std::string intermediate_key = hash_V5(user_password, key_salt, "");
  604 + out_UE = process_with_aes(intermediate_key, true, encryption_key);
616 605 }
617 606  
618   -static void
619   -compute_O_OE_value_V5(
  607 +void
  608 +QPDF::EncryptionData::compute_O_OE_value_V5(
620 609 std::string const& owner_password,
621 610 std::string const& encryption_key,
622   - QPDF::EncryptionData const& data,
623   - std::string const& U,
624   - std::string& O,
625   - std::string& OE)
  611 + std::string const& in_U,
  612 + std::string& out_O,
  613 + std::string& out_OE) const
626 614 {
627 615 // Algorithm 3.9 from the PDF 1.7 extension level 3
628 616 char k[16];
629 617 QUtil::initializeWithRandomBytes(reinterpret_cast<unsigned char*>(k), sizeof(k));
630 618 std::string validation_salt(k, 8);
631 619 std::string key_salt(k + 8, 8);
632   - O = hash_V5(owner_password, validation_salt, U, data) + validation_salt + key_salt;
633   - std::string intermediate_key = hash_V5(owner_password, key_salt, U, data);
634   - OE = process_with_aes(intermediate_key, true, encryption_key);
  620 + out_O = hash_V5(owner_password, validation_salt, in_U) + validation_salt + key_salt;
  621 + std::string intermediate_key = hash_V5(owner_password, key_salt, in_U);
  622 + out_OE = process_with_aes(intermediate_key, true, encryption_key);
635 623 }
636 624  
637 625 void
638   -compute_Perms_value_V5_clear(
639   - std::string const& encryption_key, QPDF::EncryptionData const& data, unsigned char k[16])
  626 +QPDF::EncryptionData::compute_Perms_value_V5_clear(
  627 + std::string const& encryption_key, unsigned char k[16]) const
640 628 {
641 629 // From algorithm 3.10 from the PDF 1.7 extension level 3
642 630 unsigned long long extended_perms =
643   - 0xffffffff00000000LL | static_cast<unsigned long long>(data.getP());
  631 + 0xffffffff00000000LL | static_cast<unsigned long long>(getP());
644 632 for (int i = 0; i < 8; ++i) {
645 633 k[i] = static_cast<unsigned char>(extended_perms & 0xff);
646 634 extended_perms >>= 8;
647 635 }
648   - k[8] = data.getEncryptMetadata() ? 'T' : 'F';
  636 + k[8] = getEncryptMetadata() ? 'T' : 'F';
649 637 k[9] = 'a';
650 638 k[10] = 'd';
651 639 k[11] = 'b';
652 640 QUtil::initializeWithRandomBytes(k + 12, 4);
653 641 }
654 642  
655   -static std::string
656   -compute_Perms_value_V5(std::string const& encryption_key, QPDF::EncryptionData const& data)
  643 +std::string
  644 +QPDF::EncryptionData::compute_Perms_value_V5(std::string const& encryption_key) const
657 645 {
658 646 // Algorithm 3.10 from the PDF 1.7 extension level 3
659 647 unsigned char k[16];
660   - compute_Perms_value_V5_clear(encryption_key, data, k);
  648 + compute_Perms_value_V5_clear(encryption_key, k);
661 649 return process_with_aes(
662 650 encryption_key, true, std::string(reinterpret_cast<char*>(k), sizeof(k)));
663 651 }
664 652  
665 653 std::string
666   -QPDF::recover_encryption_key_with_password(
667   - std::string const& password, EncryptionData const& data, bool& perms_valid)
  654 +QPDF::EncryptionData::recover_encryption_key_with_password(
  655 + std::string const& password, bool& perms_valid) const
668 656 {
669 657 // Algorithm 3.2a from the PDF 1.7 extension level 3
670 658  
... ... @@ -677,21 +665,21 @@ QPDF::recover_encryption_key_with_password(
677 665 std::string key_salt;
678 666 std::string user_data;
679 667 std::string encrypted_file_key;
680   - if (check_owner_password_V5(key_password, data)) {
681   - key_salt = data.getO().substr(40, 8);
682   - user_data = data.getU().substr(0, 48);
683   - encrypted_file_key = data.getOE().substr(0, 32);
684   - } else if (check_user_password_V5(key_password, data)) {
685   - key_salt = data.getU().substr(40, 8);
686   - encrypted_file_key = data.getUE().substr(0, 32);
  668 + if (check_owner_password_V5(key_password)) {
  669 + key_salt = getO().substr(40, 8);
  670 + user_data = getU().substr(0, 48);
  671 + encrypted_file_key = getOE().substr(0, 32);
  672 + } else if (check_user_password_V5(key_password)) {
  673 + key_salt = getU().substr(40, 8);
  674 + encrypted_file_key = getUE().substr(0, 32);
687 675 }
688   - std::string intermediate_key = hash_V5(key_password, key_salt, user_data, data);
  676 + std::string intermediate_key = hash_V5(key_password, key_salt, user_data);
689 677 std::string file_key = process_with_aes(intermediate_key, false, encrypted_file_key);
690 678  
691 679 // Decrypt Perms and check against expected value
692   - std::string perms_check = process_with_aes(file_key, false, data.getPerms(), 12);
  680 + auto perms_check = process_with_aes(file_key, false, getPerms()).substr(0, 12);
693 681 unsigned char k[16];
694   - compute_Perms_value_V5_clear(file_key, data, k);
  682 + compute_Perms_value_V5_clear(file_key, k);
695 683 perms_valid = (memcmp(perms_check.c_str(), k, 12) == 0);
696 684  
697 685 return file_key;
... ... @@ -909,7 +897,7 @@ QPDF::initializeEncryption()
909 897 // ignore passwords in file
910 898 } else {
911 899 m->encp->owner_password_matched =
912   - check_owner_password(m->encp->user_password, m->encp->provided_password, data);
  900 + data.check_owner_password(m->encp->user_password, m->encp->provided_password);
913 901 if (m->encp->owner_password_matched && (V < 5)) {
914 902 // password supplied was owner password; user_password has been initialized for V < 5
915 903 if (getTrimmedUserPassword() == m->encp->provided_password) {
... ... @@ -917,7 +905,7 @@ QPDF::initializeEncryption()
917 905 QTC::TC("qpdf", "QPDF_encryption user matches owner V < 5");
918 906 }
919 907 } else {
920   - m->encp->user_password_matched = check_user_password(m->encp->provided_password, data);
  908 + m->encp->user_password_matched = data.check_user_password(m->encp->provided_password);
921 909 if (m->encp->user_password_matched) {
922 910 m->encp->user_password = m->encp->provided_password;
923 911 }
... ... @@ -941,12 +929,11 @@ QPDF::initializeEncryption()
941 929 // neither password can be used to recover the other.
942 930 bool perms_valid;
943 931 m->encp->encryption_key =
944   - recover_encryption_key_with_password(m->encp->provided_password, data, perms_valid);
  932 + data.recover_encryption_key_with_password(m->encp->provided_password, perms_valid);
945 933 if (!perms_valid) {
946 934 warn(damagedPDF(
947 935 "encryption dictionary",
948   - "/Perms field in encryption dictionary doesn't match expected "
949   - "value"));
  936 + "/Perms field in encryption dictionary doesn't match expected value"));
950 937 }
951 938 }
952 939 }
... ... @@ -1167,14 +1154,20 @@ QPDF::compute_encryption_O_U(
1167 1154 std::string& O,
1168 1155 std::string& U)
1169 1156 {
  1157 + EncryptionData(V, R, key_len, P, "", "", "", "", "", id1, encrypt_metadata)
  1158 + .compute_encryption_O_U(user_password, owner_password, O, U);
  1159 +}
  1160 +
  1161 +void
  1162 +QPDF::EncryptionData::compute_encryption_O_U(
  1163 + char const* user_password, char const* owner_password, std::string& out_O, std::string& out_U)
  1164 +{
1170 1165 if (V >= 5) {
1171 1166 throw std::logic_error("compute_encryption_O_U called for file with V >= 5");
1172 1167 }
1173   - EncryptionData data(V, R, key_len, P, "", "", "", "", "", id1, encrypt_metadata);
1174   - data.setO(compute_O_value(user_password, owner_password, data));
1175   - O = data.getO();
1176   - data.setU(compute_U_value(user_password, data));
1177   - U = data.getU();
  1168 + setO(compute_O_value(user_password, owner_password));
  1169 + out_O = getO();
  1170 + out_U = compute_U_value(user_password);
1178 1171 }
1179 1172  
1180 1173 void
... ... @@ -1194,14 +1187,29 @@ QPDF::compute_encryption_parameters_V5(
1194 1187 std::string& UE,
1195 1188 std::string& Perms)
1196 1189 {
1197   - EncryptionData data(V, R, key_len, P, "", "", "", "", "", id1, encrypt_metadata);
  1190 + EncryptionData(V, R, key_len, P, "", "", "", "", "", id1, encrypt_metadata)
  1191 + .compute_encryption_parameters_V5(
  1192 + user_password, owner_password, encryption_key, O, U, OE, UE, Perms);
  1193 +}
  1194 +
  1195 +void
  1196 +QPDF::EncryptionData::compute_encryption_parameters_V5(
  1197 + char const* user_password,
  1198 + char const* owner_password,
  1199 + std::string& out_encryption_key,
  1200 + std::string& out_O,
  1201 + std::string& out_U,
  1202 + std::string& out_OE,
  1203 + std::string& out_UE,
  1204 + std::string& out_Perms)
  1205 +{
1198 1206 unsigned char k[key_bytes];
1199 1207 QUtil::initializeWithRandomBytes(k, key_bytes);
1200   - encryption_key = std::string(reinterpret_cast<char*>(k), key_bytes);
1201   - compute_U_UE_value_V5(user_password, encryption_key, data, U, UE);
1202   - compute_O_OE_value_V5(owner_password, encryption_key, data, U, O, OE);
1203   - Perms = compute_Perms_value_V5(encryption_key, data);
1204   - data.setV5EncryptionParameters(O, OE, U, UE, Perms);
  1208 + out_encryption_key = std::string(reinterpret_cast<char*>(k), key_bytes);
  1209 + compute_U_UE_value_V5(user_password, out_encryption_key, out_U, out_UE);
  1210 + compute_O_OE_value_V5(owner_password, out_encryption_key, out_U, out_O, out_OE);
  1211 + out_Perms = compute_Perms_value_V5(out_encryption_key);
  1212 + setV5EncryptionParameters(out_O, out_OE, out_U, out_UE, out_Perms);
1205 1213 }
1206 1214  
1207 1215 std::string const&
... ...