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,8 +552,7 @@ class QPDF
552 bool check_owner_password_V4( 552 bool check_owner_password_V4(
553 std::string& user_password, std::string const& owner_password) const; 553 std::string& user_password, std::string const& owner_password) const;
554 bool check_owner_password_V5(std::string const& owner_passworda) const; 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 void compute_O_rc4_key( 556 void compute_O_rc4_key(
558 std::string const& user_password, 557 std::string const& user_password,
559 std::string const& owner_password, 558 std::string const& owner_password,
libqpdf/QPDF_encryption.cc
@@ -16,10 +16,13 @@ @@ -16,10 +16,13 @@
16 #include <qpdf/QTC.hh> 16 #include <qpdf/QTC.hh>
17 #include <qpdf/QUtil.hh> 17 #include <qpdf/QUtil.hh>
18 #include <qpdf/RC4.hh> 18 #include <qpdf/RC4.hh>
  19 +#include <qpdf/Util.hh>
19 20
20 #include <algorithm> 21 #include <algorithm>
21 #include <cstring> 22 #include <cstring>
22 23
  24 +using namespace qpdf;
  25 +
23 static unsigned char const padding_string[] = { 26 static unsigned char const padding_string[] = {
24 0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, 0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa, 0x01, 0x08, 27 0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, 0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa, 0x01, 0x08,
25 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80, 0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a}; 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,12 +620,10 @@ QPDF::EncryptionData::compute_U_UE_value_V5(
617 std::string& out_UE) const 620 std::string& out_UE) const
618 { 621 {
619 // Algorithm 3.8 from the PDF 1.7 extension level 3 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 out_UE = process_with_aes(intermediate_key, true, encryption_key); 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,41 +636,35 @@ QPDF::EncryptionData::compute_O_OE_value_V5(
635 std::string& out_OE) const 636 std::string& out_OE) const
636 { 637 {
637 // Algorithm 3.9 from the PDF 1.7 extension level 3 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 out_O = hash_V5(owner_password, validation_salt, in_U) + validation_salt + key_salt; 641 out_O = hash_V5(owner_password, validation_salt, in_U) + validation_salt + key_salt;
643 std::string intermediate_key = hash_V5(owner_password, key_salt, in_U); 642 std::string intermediate_key = hash_V5(owner_password, key_salt, in_U);
644 out_OE = process_with_aes(intermediate_key, true, encryption_key); 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 // From algorithm 3.10 from the PDF 1.7 extension level 3 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 std::string 663 std::string
666 QPDF::EncryptionData::compute_Perms_value_V5(std::string const& encryption_key) const 664 QPDF::EncryptionData::compute_Perms_value_V5(std::string const& encryption_key) const
667 { 665 {
668 // Algorithm 3.10 from the PDF 1.7 extension level 3 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 std::string 670 std::string
@@ -700,10 +695,7 @@ QPDF::EncryptionData::recover_encryption_key_with_password( @@ -700,10 +695,7 @@ QPDF::EncryptionData::recover_encryption_key_with_password(
700 695
701 // Decrypt Perms and check against expected value 696 // Decrypt Perms and check against expected value
702 auto perms_check = process_with_aes(file_key, false, getPerms()).substr(0, 12); 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 return file_key; 699 return file_key;
708 } 700 }
709 701
@@ -1214,9 +1206,7 @@ QPDF::EncryptionData::compute_encryption_parameters_V5( @@ -1214,9 +1206,7 @@ QPDF::EncryptionData::compute_encryption_parameters_V5(
1214 std::string& out_UE, 1206 std::string& out_UE,
1215 std::string& out_Perms) 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 compute_U_UE_value_V5(user_password, out_encryption_key, out_U, out_UE); 1210 compute_U_UE_value_V5(user_password, out_encryption_key, out_U, out_UE);
1221 compute_O_OE_value_V5(owner_password, out_encryption_key, out_U, out_O, out_OE); 1211 compute_O_OE_value_V5(owner_password, out_encryption_key, out_U, out_O, out_OE);
1222 out_Perms = compute_Perms_value_V5(out_encryption_key); 1212 out_Perms = compute_Perms_value_V5(out_encryption_key);
libqpdf/QUtil.cc
@@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
2 #include <qpdf/qpdf-config.h> 2 #include <qpdf/qpdf-config.h>
3 3
4 #include <qpdf/QUtil.hh> 4 #include <qpdf/QUtil.hh>
  5 +#include <qpdf/Util.hh>
5 6
6 #include <qpdf/CryptoRandomDataProvider.hh> 7 #include <qpdf/CryptoRandomDataProvider.hh>
7 #include <qpdf/Pipeline.hh> 8 #include <qpdf/Pipeline.hh>
@@ -1131,6 +1132,14 @@ QUtil::initializeWithRandomBytes(unsigned char* data, size_t len) @@ -1131,6 +1132,14 @@ QUtil::initializeWithRandomBytes(unsigned char* data, size_t len)
1131 getRandomDataProvider()->provideRandomData(data, len); 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 long 1143 long
1135 QUtil::random() 1144 QUtil::random()
1136 { 1145 {
libqpdf/qpdf/Util.hh
@@ -59,6 +59,8 @@ namespace qpdf::util @@ -59,6 +59,8 @@ namespace qpdf::util
59 s.insert(0, 1, '1'); 59 s.insert(0, 1, '1');
60 } 60 }
61 61
  62 + std::string random_string(size_t len);
  63 +
62 } // namespace qpdf::util 64 } // namespace qpdf::util
63 65
64 #endif // UTIL_HH 66 #endif // UTIL_HH