Commit 04cc9df216a79689f8ba4e7746ceb0f14749f0cb
1 parent
e81abdcc
Refactor `QPDF_encryption` and `RC4` to replace raw arrays with `std::string`, c…
…onsolidate `iterate_rc4` logic, and streamline RC4 key processing.
Showing
3 changed files
with
26 additions
and
45 deletions
libqpdf/QPDF_encryption.cc
| @@ -170,7 +170,7 @@ QPDF::trim_user_password(std::string& user_password) | @@ -170,7 +170,7 @@ QPDF::trim_user_password(std::string& user_password) | ||
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | auto idx = user_password.find('\x28'); | 172 | auto idx = user_password.find('\x28'); |
| 173 | - ; | 173 | + |
| 174 | while (idx != user_password.npos) { | 174 | while (idx != user_password.npos) { |
| 175 | if (padding_string.starts_with(user_password.substr(idx))) { | 175 | if (padding_string.starts_with(user_password.substr(idx))) { |
| 176 | user_password.resize(idx); | 176 | user_password.resize(idx); |
| @@ -206,23 +206,16 @@ iterate_md5_digest(MD5& md5, int iterations, int key_len) | @@ -206,23 +206,16 @@ iterate_md5_digest(MD5& md5, int iterations, int key_len) | ||
| 206 | } | 206 | } |
| 207 | 207 | ||
| 208 | static void | 208 | static void |
| 209 | -iterate_rc4( | ||
| 210 | - unsigned char* data, | ||
| 211 | - size_t data_len, | ||
| 212 | - unsigned char* okey, | ||
| 213 | - int key_len, | ||
| 214 | - int iterations, | ||
| 215 | - bool reverse) | 209 | +iterate_rc4(std::string& data, std::string_view okey, int iterations, bool reverse) |
| 216 | { | 210 | { |
| 217 | - auto key_ph = std::make_unique<unsigned char[]>(QIntC::to_size(key_len)); | ||
| 218 | - unsigned char* key = key_ph.get(); | 211 | + auto len = okey.size(); |
| 212 | + std::string key(len, '\0'); | ||
| 219 | for (int i = 0; i < iterations; ++i) { | 213 | for (int i = 0; i < iterations; ++i) { |
| 220 | int const xor_value = (reverse ? iterations - 1 - i : i); | 214 | int const xor_value = (reverse ? iterations - 1 - i : i); |
| 221 | - for (int j = 0; j < key_len; ++j) { | ||
| 222 | - key[j] = static_cast<unsigned char>(okey[j] ^ xor_value); | 215 | + for (size_t j = 0; j < len; ++j) { |
| 216 | + key[j] = static_cast<char>(okey[j] ^ xor_value); | ||
| 223 | } | 217 | } |
| 224 | - RC4 rc4(key, QIntC::to_int(key_len)); | ||
| 225 | - rc4.process(data, data_len, data); | 218 | + RC4::process(key, data); |
| 226 | } | 219 | } |
| 227 | } | 220 | } |
| 228 | 221 | ||
| @@ -437,13 +430,7 @@ QPDF::EncryptionData::compute_O_value( | @@ -437,13 +430,7 @@ QPDF::EncryptionData::compute_O_value( | ||
| 437 | auto upass = pad_or_truncate_password_V4(user_password); | 430 | auto upass = pad_or_truncate_password_V4(user_password); |
| 438 | std::string O_key = compute_O_rc4_key(user_password, owner_password); | 431 | std::string O_key = compute_O_rc4_key(user_password, owner_password); |
| 439 | pad_short_parameter(O_key, QIntC::to_size(getLengthBytes())); | 432 | pad_short_parameter(O_key, QIntC::to_size(getLengthBytes())); |
| 440 | - iterate_rc4( | ||
| 441 | - QUtil::unsigned_char_pointer(upass), | ||
| 442 | - key_bytes, | ||
| 443 | - QUtil::unsigned_char_pointer(O_key.data()), | ||
| 444 | - getLengthBytes(), | ||
| 445 | - getR() >= 3 ? 20 : 1, | ||
| 446 | - false); | 433 | + iterate_rc4(upass, O_key, getR() >= 3 ? 20 : 1, false); |
| 447 | return upass; | 434 | return upass; |
| 448 | } | 435 | } |
| 449 | 436 | ||
| @@ -455,13 +442,7 @@ QPDF::EncryptionData::compute_U_value_R2(std::string const& user_password) const | @@ -455,13 +442,7 @@ QPDF::EncryptionData::compute_U_value_R2(std::string const& user_password) const | ||
| 455 | std::string k1 = compute_encryption_key(user_password); | 442 | std::string k1 = compute_encryption_key(user_password); |
| 456 | auto udata = padding_string; | 443 | auto udata = padding_string; |
| 457 | pad_short_parameter(k1, QIntC::to_size(getLengthBytes())); | 444 | pad_short_parameter(k1, QIntC::to_size(getLengthBytes())); |
| 458 | - iterate_rc4( | ||
| 459 | - QUtil::unsigned_char_pointer(udata.data()), | ||
| 460 | - key_bytes, | ||
| 461 | - QUtil::unsigned_char_pointer(k1), | ||
| 462 | - getLengthBytes(), | ||
| 463 | - 1, | ||
| 464 | - false); | 445 | + iterate_rc4(udata, k1, 1, false); |
| 465 | return udata; | 446 | return udata; |
| 466 | } | 447 | } |
| 467 | 448 | ||
| @@ -474,18 +455,12 @@ QPDF::EncryptionData::compute_U_value_R3(std::string const& user_password) const | @@ -474,18 +455,12 @@ QPDF::EncryptionData::compute_U_value_R3(std::string const& user_password) const | ||
| 474 | MD5 md5; | 455 | MD5 md5; |
| 475 | md5.encodeDataIncrementally(padding_string); | 456 | md5.encodeDataIncrementally(padding_string); |
| 476 | md5.encodeDataIncrementally(getId1()); | 457 | md5.encodeDataIncrementally(getId1()); |
| 477 | - MD5::Digest digest; | ||
| 478 | - md5.digest(digest); | 458 | + auto result = md5.digest(); |
| 479 | pad_short_parameter(k1, QIntC::to_size(getLengthBytes())); | 459 | pad_short_parameter(k1, QIntC::to_size(getLengthBytes())); |
| 480 | - iterate_rc4( | ||
| 481 | - digest, sizeof(MD5::Digest), QUtil::unsigned_char_pointer(k1), getLengthBytes(), 20, false); | ||
| 482 | - char result[key_bytes]; | ||
| 483 | - memcpy(result, digest, sizeof(MD5::Digest)); | 460 | + iterate_rc4(result, k1, 20, false); |
| 484 | // pad with arbitrary data -- make it consistent for the sake of testing | 461 | // pad with arbitrary data -- make it consistent for the sake of testing |
| 485 | - for (unsigned int i = sizeof(MD5::Digest); i < key_bytes; ++i) { | ||
| 486 | - result[i] = static_cast<char>((i * i) % 0xff); | ||
| 487 | - } | ||
| 488 | - return {result, key_bytes}; | 462 | + result += "\x0\x21\x44\x69\x90\xb9\xe4\x11\x40\x71\xa4\xd9\x10\x49\x84\xc1"s; |
| 463 | + return result; | ||
| 489 | } | 464 | } |
| 490 | 465 | ||
| 491 | std::string | 466 | std::string |
| @@ -538,13 +513,7 @@ QPDF::EncryptionData::check_owner_password_V4( | @@ -538,13 +513,7 @@ QPDF::EncryptionData::check_owner_password_V4( | ||
| 538 | auto key = compute_O_rc4_key(user_password, owner_password); | 513 | auto key = compute_O_rc4_key(user_password, owner_password); |
| 539 | pad_short_parameter(key, QIntC::to_size(getLengthBytes())); | 514 | pad_short_parameter(key, QIntC::to_size(getLengthBytes())); |
| 540 | auto new_user_password = O.substr(0, key_bytes); | 515 | auto new_user_password = O.substr(0, key_bytes); |
| 541 | - iterate_rc4( | ||
| 542 | - QUtil::unsigned_char_pointer(new_user_password.data()), | ||
| 543 | - key_bytes, | ||
| 544 | - QUtil::unsigned_char_pointer(key), | ||
| 545 | - getLengthBytes(), | ||
| 546 | - (getR() >= 3) ? 20 : 1, | ||
| 547 | - true); | 516 | + iterate_rc4(new_user_password, key, (getR() >= 3) ? 20 : 1, true); |
| 548 | if (check_user_password(new_user_password)) { | 517 | if (check_user_password(new_user_password)) { |
| 549 | user_password = new_user_password; | 518 | user_password = new_user_password; |
| 550 | return true; | 519 | return true; |
libqpdf/RC4.cc
| @@ -13,3 +13,13 @@ RC4::process(unsigned char const* in_data, size_t len, unsigned char* out_data) | @@ -13,3 +13,13 @@ RC4::process(unsigned char const* in_data, size_t len, unsigned char* out_data) | ||
| 13 | { | 13 | { |
| 14 | crypto->RC4_process(in_data, len, out_data); | 14 | crypto->RC4_process(in_data, len, out_data); |
| 15 | } | 15 | } |
| 16 | + | ||
| 17 | +void | ||
| 18 | +RC4::process(std::string_view key, std::string& data) | ||
| 19 | +{ | ||
| 20 | + RC4 rc4(reinterpret_cast<unsigned char const*>(key.data()), static_cast<int>(key.size())); | ||
| 21 | + rc4.process( | ||
| 22 | + reinterpret_cast<unsigned char const*>(data.data()), | ||
| 23 | + data.size(), | ||
| 24 | + reinterpret_cast<unsigned char*>(data.data())); | ||
| 25 | +} |
libqpdf/qpdf/RC4.hh
| @@ -14,6 +14,8 @@ class RC4 | @@ -14,6 +14,8 @@ class RC4 | ||
| 14 | // It is safe to pass the same pointer to in_data and out_data to encrypt/decrypt in place | 14 | // It is safe to pass the same pointer to in_data and out_data to encrypt/decrypt in place |
| 15 | void process(unsigned char const* in_data, size_t len, unsigned char* out_data); | 15 | void process(unsigned char const* in_data, size_t len, unsigned char* out_data); |
| 16 | 16 | ||
| 17 | + static void process(std::string_view key, std::string& data); | ||
| 18 | + | ||
| 17 | private: | 19 | private: |
| 18 | std::shared_ptr<QPDFCryptoImpl> crypto; | 20 | std::shared_ptr<QPDFCryptoImpl> crypto; |
| 19 | }; | 21 | }; |