Commit aab00a1a04a759df02b9abd6d4ef2ae4ff8575d7

Authored by m-holger
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&amp; 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&amp; 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&amp; 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()));
... ...