Commit 11266b14f6e18a08e2c25cc09c1a8641c67fc683

Authored by m-holger
1 parent 8417be17

Refactor `QPDF_encryption` to simplify random string generation using `util::ran…

…dom_string`, improve readability of salts and keys handling, and streamline `compute_Perms_value_V5_clear` logic by returning strings directly.
include/qpdf/QPDF.hh
... ... @@ -552,8 +552,7 @@ class QPDF
552 552 bool check_owner_password_V4(
553 553 std::string& user_password, std::string const& owner_password) const;
554 554 bool check_owner_password_V5(std::string const& owner_passworda) const;
555   - void
556   - compute_Perms_value_V5_clear(std::string const& encryption_key, unsigned char k[16]) const;
  555 + std::string compute_Perms_value_V5_clear() const;
557 556 void compute_O_rc4_key(
558 557 std::string const& user_password,
559 558 std::string const& owner_password,
... ...
libqpdf/QPDF_encryption.cc
... ... @@ -16,10 +16,13 @@
16 16 #include <qpdf/QTC.hh>
17 17 #include <qpdf/QUtil.hh>
18 18 #include <qpdf/RC4.hh>
  19 +#include <qpdf/Util.hh>
19 20  
20 21 #include <algorithm>
21 22 #include <cstring>
22 23  
  24 +using namespace qpdf;
  25 +
23 26 static unsigned char const padding_string[] = {
24 27 0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, 0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa, 0x01, 0x08,
25 28 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80, 0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a};
... ... @@ -617,12 +620,10 @@ QPDF::EncryptionData::compute_U_UE_value_V5(
617 620 std::string& out_UE) const
618 621 {
619 622 // Algorithm 3.8 from the PDF 1.7 extension level 3
620   - char k[16];
621   - QUtil::initializeWithRandomBytes(reinterpret_cast<unsigned char*>(k), sizeof(k));
622   - std::string validation_salt(k, 8);
623   - std::string key_salt(k + 8, 8);
624   - out_U = hash_V5(user_password, validation_salt, "") + validation_salt + key_salt;
625   - std::string intermediate_key = hash_V5(user_password, key_salt, "");
  623 + auto validation_salt = util::random_string(8);
  624 + auto key_salt = util::random_string(8);
  625 + out_U = hash_V5(user_password, validation_salt, "").append(validation_salt).append(key_salt);
  626 + auto intermediate_key = hash_V5(user_password, key_salt, "");
626 627 out_UE = process_with_aes(intermediate_key, true, encryption_key);
627 628 }
628 629  
... ... @@ -635,41 +636,35 @@ QPDF::EncryptionData::compute_O_OE_value_V5(
635 636 std::string& out_OE) const
636 637 {
637 638 // Algorithm 3.9 from the PDF 1.7 extension level 3
638   - char k[16];
639   - QUtil::initializeWithRandomBytes(reinterpret_cast<unsigned char*>(k), sizeof(k));
640   - std::string validation_salt(k, 8);
641   - std::string key_salt(k + 8, 8);
  639 + auto validation_salt = util::random_string(8);
  640 + auto key_salt = util::random_string(8);
642 641 out_O = hash_V5(owner_password, validation_salt, in_U) + validation_salt + key_salt;
643 642 std::string intermediate_key = hash_V5(owner_password, key_salt, in_U);
644 643 out_OE = process_with_aes(intermediate_key, true, encryption_key);
645 644 }
646 645  
647   -void
648   -QPDF::EncryptionData::compute_Perms_value_V5_clear(
649   - std::string const& encryption_key, unsigned char k[16]) const
  646 +std::string
  647 +QPDF::EncryptionData::compute_Perms_value_V5_clear() const
650 648 {
651 649 // From algorithm 3.10 from the PDF 1.7 extension level 3
652   - unsigned long long extended_perms =
653   - 0xffffffff00000000LL | static_cast<unsigned long long>(getP());
654   - for (int i = 0; i < 8; ++i) {
655   - k[i] = static_cast<unsigned char>(extended_perms & 0xff);
656   - extended_perms >>= 8;
  650 + std::string k = " \xff\xff\xff\xffTadb ";
  651 + int perms = getP();
  652 + for (size_t i = 0; i < 4; ++i) {
  653 + k[i] = static_cast<char>(perms & 0xff);
  654 + perms >>= 8;
657 655 }
658   - k[8] = getEncryptMetadata() ? 'T' : 'F';
659   - k[9] = 'a';
660   - k[10] = 'd';
661   - k[11] = 'b';
662   - QUtil::initializeWithRandomBytes(k + 12, 4);
  656 + if (!getEncryptMetadata()) {
  657 + k[8] = 'F';
  658 + }
  659 + QUtil::initializeWithRandomBytes(reinterpret_cast<unsigned char*>(&k[12]), 4);
  660 + return k;
663 661 }
664 662  
665 663 std::string
666 664 QPDF::EncryptionData::compute_Perms_value_V5(std::string const& encryption_key) const
667 665 {
668 666 // Algorithm 3.10 from the PDF 1.7 extension level 3
669   - unsigned char k[16];
670   - compute_Perms_value_V5_clear(encryption_key, k);
671   - return process_with_aes(
672   - encryption_key, true, std::string(reinterpret_cast<char*>(k), sizeof(k)));
  667 + return process_with_aes(encryption_key, true, compute_Perms_value_V5_clear());
673 668 }
674 669  
675 670 std::string
... ... @@ -700,10 +695,7 @@ QPDF::EncryptionData::recover_encryption_key_with_password(
700 695  
701 696 // Decrypt Perms and check against expected value
702 697 auto perms_check = process_with_aes(file_key, false, getPerms()).substr(0, 12);
703   - unsigned char k[16];
704   - compute_Perms_value_V5_clear(file_key, k);
705   - perms_valid = (memcmp(perms_check.c_str(), k, 12) == 0);
706   -
  698 + perms_valid = compute_Perms_value_V5_clear().substr(0, 12) == perms_check;
707 699 return file_key;
708 700 }
709 701  
... ... @@ -1214,9 +1206,7 @@ QPDF::EncryptionData::compute_encryption_parameters_V5(
1214 1206 std::string& out_UE,
1215 1207 std::string& out_Perms)
1216 1208 {
1217   - unsigned char k[key_bytes];
1218   - QUtil::initializeWithRandomBytes(k, key_bytes);
1219   - out_encryption_key = std::string(reinterpret_cast<char*>(k), key_bytes);
  1209 + out_encryption_key = util::random_string(key_bytes);
1220 1210 compute_U_UE_value_V5(user_password, out_encryption_key, out_U, out_UE);
1221 1211 compute_O_OE_value_V5(owner_password, out_encryption_key, out_U, out_O, out_OE);
1222 1212 out_Perms = compute_Perms_value_V5(out_encryption_key);
... ...
libqpdf/QUtil.cc
... ... @@ -2,6 +2,7 @@
2 2 #include <qpdf/qpdf-config.h>
3 3  
4 4 #include <qpdf/QUtil.hh>
  5 +#include <qpdf/Util.hh>
5 6  
6 7 #include <qpdf/CryptoRandomDataProvider.hh>
7 8 #include <qpdf/Pipeline.hh>
... ... @@ -1131,6 +1132,14 @@ QUtil::initializeWithRandomBytes(unsigned char* data, size_t len)
1131 1132 getRandomDataProvider()->provideRandomData(data, len);
1132 1133 }
1133 1134  
  1135 +std::string
  1136 +util::random_string(size_t len)
  1137 +{
  1138 + std::string result(len, '\0');
  1139 + QUtil::initializeWithRandomBytes(reinterpret_cast<unsigned char*>(result.data()), len);
  1140 + return result;
  1141 +}
  1142 +
1134 1143 long
1135 1144 QUtil::random()
1136 1145 {
... ...
libqpdf/qpdf/Util.hh
... ... @@ -59,6 +59,8 @@ namespace qpdf::util
59 59 s.insert(0, 1, '1');
60 60 }
61 61  
  62 + std::string random_string(size_t len);
  63 +
62 64 } // namespace qpdf::util
63 65  
64 66 #endif // UTIL_HH
... ...