Commit 11266b14f6e18a08e2c25cc09c1a8641c67fc683
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.
Showing
4 changed files
with
36 additions
and
36 deletions
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 | { | ... | ... |