Commit aab00a1a04a759df02b9abd6d4ef2ae4ff8575d7
1 parent
60d0ff6c
Refactor `QPDF_encryption` to replace raw character arrays with `std::string`, s…
…implify padding logic, and streamline password handling across methods.
Showing
1 changed file
with
36 additions
and
50 deletions
libqpdf/QPDF_encryption.cc
| ... | ... | @@ -22,10 +22,11 @@ |
| 22 | 22 | #include <cstring> |
| 23 | 23 | |
| 24 | 24 | using namespace qpdf; |
| 25 | +using namespace std::literals; | |
| 25 | 26 | |
| 26 | -static unsigned char const padding_string[] = { | |
| 27 | - 0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, 0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa, 0x01, 0x08, | |
| 28 | - 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80, 0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a}; | |
| 27 | +static std::string padding_string = | |
| 28 | + "\x28\xbf\x4e\x5e\x4e\x75\x8a\x41\x64\x00\x4e\x56\xff\xfa\x01\x08" | |
| 29 | + "\x2e\x2e\x00\xb6\xd0\x68\x3e\x80\x2f\x0c\xa9\xfe\x64\x53\x69\x7a"s; | |
| 29 | 30 | |
| 30 | 31 | static unsigned int const key_bytes = 32; |
| 31 | 32 | |
| ... | ... | @@ -159,46 +160,35 @@ QPDF::EncryptionData::setV5EncryptionParameters( |
| 159 | 160 | this->Perms = Perms; |
| 160 | 161 | } |
| 161 | 162 | |
| 162 | -static void | |
| 163 | -pad_or_truncate_password_V4(std::string const& password, char k1[key_bytes]) | |
| 164 | -{ | |
| 165 | - size_t password_bytes = std::min(QIntC::to_size(key_bytes), password.length()); | |
| 166 | - size_t pad_bytes = key_bytes - password_bytes; | |
| 167 | - memcpy(k1, password.c_str(), password_bytes); | |
| 168 | - memcpy(k1 + password_bytes, padding_string, pad_bytes); | |
| 169 | -} | |
| 170 | - | |
| 171 | 163 | void |
| 172 | 164 | QPDF::trim_user_password(std::string& user_password) |
| 173 | 165 | { |
| 174 | 166 | // Although unnecessary, this routine trims the padding string from the end of a user password. |
| 175 | 167 | // Its only purpose is for recovery of user passwords which is done in the test suite. |
| 176 | - char const* cstr = user_password.c_str(); | |
| 177 | - size_t len = user_password.length(); | |
| 178 | - if (len < key_bytes) { | |
| 168 | + if (user_password.size() < key_bytes) { | |
| 179 | 169 | return; |
| 180 | 170 | } |
| 181 | 171 | |
| 182 | - char const* p1 = cstr; | |
| 183 | - char const* p2 = nullptr; | |
| 184 | - while ((p2 = strchr(p1, '\x28')) != nullptr) { | |
| 185 | - size_t idx = toS(p2 - cstr); | |
| 186 | - if (memcmp(p2, padding_string, len - idx) == 0) { | |
| 187 | - user_password = user_password.substr(0, idx); | |
| 172 | + auto idx = user_password.find('\x28'); | |
| 173 | + ; | |
| 174 | + while (idx != user_password.npos) { | |
| 175 | + if (padding_string.starts_with(user_password.substr(idx))) { | |
| 176 | + user_password.resize(idx); | |
| 188 | 177 | return; |
| 189 | - } else { | |
| 190 | - QTC::TC("qpdf", "QPDF_encryption skip 0x28"); | |
| 191 | - p1 = p2 + 1; | |
| 192 | 178 | } |
| 179 | + QTC::TC("qpdf", "QPDF_encryption skip 0x28"); | |
| 180 | + idx = user_password.find('\x28', ++idx); | |
| 193 | 181 | } |
| 194 | 182 | } |
| 195 | 183 | |
| 196 | 184 | static std::string |
| 197 | -pad_or_truncate_password_V4(std::string const& password) | |
| 185 | +pad_or_truncate_password_V4(std::string password) | |
| 198 | 186 | { |
| 199 | - char k1[key_bytes]; | |
| 200 | - pad_or_truncate_password_V4(password, k1); | |
| 201 | - return {k1, key_bytes}; | |
| 187 | + if (password.size() < key_bytes) { | |
| 188 | + password.append(padding_string); | |
| 189 | + } | |
| 190 | + password.resize(key_bytes); | |
| 191 | + return password; | |
| 202 | 192 | } |
| 203 | 193 | |
| 204 | 194 | static std::string |
| ... | ... | @@ -381,7 +371,7 @@ QPDF::compute_data_key( |
| 381 | 371 | } |
| 382 | 372 | |
| 383 | 373 | MD5 md5; |
| 384 | - md5.encodeDataIncrementally(result.c_str(), result.length()); | |
| 374 | + md5.encodeDataIncrementally(result); | |
| 385 | 375 | MD5::Digest digest; |
| 386 | 376 | md5.digest(digest); |
| 387 | 377 | return {reinterpret_cast<char*>(digest), std::min(result.length(), toS(16))}; |
| ... | ... | @@ -418,20 +408,18 @@ QPDF::EncryptionData::compute_encryption_key_from_password(std::string const& pa |
| 418 | 408 | // password to be presented in its final form. |
| 419 | 409 | |
| 420 | 410 | MD5 md5; |
| 421 | - md5.encodeDataIncrementally(pad_or_truncate_password_V4(password).c_str(), key_bytes); | |
| 422 | - md5.encodeDataIncrementally(getO().c_str(), key_bytes); | |
| 411 | + md5.encodeDataIncrementally(pad_or_truncate_password_V4(password)); | |
| 412 | + md5.encodeDataIncrementally(getO()); | |
| 423 | 413 | char pbytes[4]; |
| 424 | - int P = getP(); | |
| 425 | - pbytes[0] = static_cast<char>(P & 0xff); | |
| 426 | - pbytes[1] = static_cast<char>((P >> 8) & 0xff); | |
| 427 | - pbytes[2] = static_cast<char>((P >> 16) & 0xff); | |
| 428 | - pbytes[3] = static_cast<char>((P >> 24) & 0xff); | |
| 414 | + int p = getP(); | |
| 415 | + pbytes[0] = static_cast<char>(p & 0xff); | |
| 416 | + pbytes[1] = static_cast<char>((p >> 8) & 0xff); | |
| 417 | + pbytes[2] = static_cast<char>((p >> 16) & 0xff); | |
| 418 | + pbytes[3] = static_cast<char>((p >> 24) & 0xff); | |
| 429 | 419 | md5.encodeDataIncrementally(pbytes, 4); |
| 430 | - md5.encodeDataIncrementally(getId1().c_str(), getId1().length()); | |
| 420 | + md5.encodeDataIncrementally(getId1()); | |
| 431 | 421 | if (getR() >= 4 && !getEncryptMetadata()) { |
| 432 | - char bytes[4]; | |
| 433 | - memset(bytes, 0xff, 4); | |
| 434 | - md5.encodeDataIncrementally(bytes, 4); | |
| 422 | + md5.encodeDataIncrementally("\xff\xff\xff\xff"); | |
| 435 | 423 | } |
| 436 | 424 | MD5::Digest digest; |
| 437 | 425 | int key_len = std::min(toI(sizeof(digest)), getLengthBytes()); |
| ... | ... | @@ -453,7 +441,7 @@ QPDF::EncryptionData::compute_O_rc4_key( |
| 453 | 441 | password = user_password; |
| 454 | 442 | } |
| 455 | 443 | MD5 md5; |
| 456 | - md5.encodeDataIncrementally(pad_or_truncate_password_V4(password).c_str(), key_bytes); | |
| 444 | + md5.encodeDataIncrementally(pad_or_truncate_password_V4(password)); | |
| 457 | 445 | MD5::Digest digest; |
| 458 | 446 | int key_len = std::min(QIntC::to_int(sizeof(digest)), getLengthBytes()); |
| 459 | 447 | iterate_md5_digest(md5, digest, (getR() >= 3 ? 50 : 0), key_len); |
| ... | ... | @@ -469,8 +457,7 @@ QPDF::EncryptionData::compute_O_value( |
| 469 | 457 | unsigned char O_key[OU_key_bytes_V4]; |
| 470 | 458 | compute_O_rc4_key(user_password, owner_password, O_key); |
| 471 | 459 | |
| 472 | - char upass[key_bytes]; | |
| 473 | - pad_or_truncate_password_V4(user_password, upass); | |
| 460 | + auto upass = pad_or_truncate_password_V4(user_password); | |
| 474 | 461 | std::string k1(reinterpret_cast<char*>(O_key), OU_key_bytes_V4); |
| 475 | 462 | pad_short_parameter(k1, QIntC::to_size(getLengthBytes())); |
| 476 | 463 | iterate_rc4( |
| ... | ... | @@ -480,7 +467,7 @@ QPDF::EncryptionData::compute_O_value( |
| 480 | 467 | getLengthBytes(), |
| 481 | 468 | getR() >= 3 ? 20 : 1, |
| 482 | 469 | false); |
| 483 | - return {upass, key_bytes}; | |
| 470 | + return upass; | |
| 484 | 471 | } |
| 485 | 472 | |
| 486 | 473 | std::string |
| ... | ... | @@ -489,17 +476,16 @@ QPDF::EncryptionData::compute_U_value_R2(std::string const& user_password) const |
| 489 | 476 | // Algorithm 3.4 from the PDF 1.7 Reference Manual |
| 490 | 477 | |
| 491 | 478 | std::string k1 = compute_encryption_key(user_password); |
| 492 | - char udata[key_bytes]; | |
| 493 | - pad_or_truncate_password_V4("", udata); | |
| 479 | + auto udata = padding_string; | |
| 494 | 480 | pad_short_parameter(k1, QIntC::to_size(getLengthBytes())); |
| 495 | 481 | iterate_rc4( |
| 496 | - QUtil::unsigned_char_pointer(udata), | |
| 482 | + QUtil::unsigned_char_pointer(udata.data()), | |
| 497 | 483 | key_bytes, |
| 498 | 484 | QUtil::unsigned_char_pointer(k1), |
| 499 | 485 | getLengthBytes(), |
| 500 | 486 | 1, |
| 501 | 487 | false); |
| 502 | - return {udata, key_bytes}; | |
| 488 | + return udata; | |
| 503 | 489 | } |
| 504 | 490 | |
| 505 | 491 | std::string |
| ... | ... | @@ -509,8 +495,8 @@ QPDF::EncryptionData::compute_U_value_R3(std::string const& user_password) const |
| 509 | 495 | |
| 510 | 496 | std::string k1 = compute_encryption_key(user_password); |
| 511 | 497 | MD5 md5; |
| 512 | - md5.encodeDataIncrementally(pad_or_truncate_password_V4("").c_str(), key_bytes); | |
| 513 | - md5.encodeDataIncrementally(getId1().c_str(), getId1().length()); | |
| 498 | + md5.encodeDataIncrementally(padding_string); | |
| 499 | + md5.encodeDataIncrementally(getId1()); | |
| 514 | 500 | MD5::Digest digest; |
| 515 | 501 | md5.digest(digest); |
| 516 | 502 | pad_short_parameter(k1, QIntC::to_size(getLengthBytes())); | ... | ... |