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,10 +22,11 @@
22 #include <cstring> 22 #include <cstring>
23 23
24 using namespace qpdf; 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 static unsigned int const key_bytes = 32; 31 static unsigned int const key_bytes = 32;
31 32
@@ -159,46 +160,35 @@ QPDF::EncryptionData::setV5EncryptionParameters( @@ -159,46 +160,35 @@ QPDF::EncryptionData::setV5EncryptionParameters(
159 this->Perms = Perms; 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 void 163 void
172 QPDF::trim_user_password(std::string& user_password) 164 QPDF::trim_user_password(std::string& user_password)
173 { 165 {
174 // Although unnecessary, this routine trims the padding string from the end of a user password. 166 // Although unnecessary, this routine trims the padding string from the end of a user password.
175 // Its only purpose is for recovery of user passwords which is done in the test suite. 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 return; 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 return; 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 static std::string 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 static std::string 194 static std::string
@@ -381,7 +371,7 @@ QPDF::compute_data_key( @@ -381,7 +371,7 @@ QPDF::compute_data_key(
381 } 371 }
382 372
383 MD5 md5; 373 MD5 md5;
384 - md5.encodeDataIncrementally(result.c_str(), result.length()); 374 + md5.encodeDataIncrementally(result);
385 MD5::Digest digest; 375 MD5::Digest digest;
386 md5.digest(digest); 376 md5.digest(digest);
387 return {reinterpret_cast<char*>(digest), std::min(result.length(), toS(16))}; 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,20 +408,18 @@ QPDF::EncryptionData::compute_encryption_key_from_password(std::string const&amp; pa
418 // password to be presented in its final form. 408 // password to be presented in its final form.
419 409
420 MD5 md5; 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 char pbytes[4]; 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 md5.encodeDataIncrementally(pbytes, 4); 419 md5.encodeDataIncrementally(pbytes, 4);
430 - md5.encodeDataIncrementally(getId1().c_str(), getId1().length()); 420 + md5.encodeDataIncrementally(getId1());
431 if (getR() >= 4 && !getEncryptMetadata()) { 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 MD5::Digest digest; 424 MD5::Digest digest;
437 int key_len = std::min(toI(sizeof(digest)), getLengthBytes()); 425 int key_len = std::min(toI(sizeof(digest)), getLengthBytes());
@@ -453,7 +441,7 @@ QPDF::EncryptionData::compute_O_rc4_key( @@ -453,7 +441,7 @@ QPDF::EncryptionData::compute_O_rc4_key(
453 password = user_password; 441 password = user_password;
454 } 442 }
455 MD5 md5; 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 MD5::Digest digest; 445 MD5::Digest digest;
458 int key_len = std::min(QIntC::to_int(sizeof(digest)), getLengthBytes()); 446 int key_len = std::min(QIntC::to_int(sizeof(digest)), getLengthBytes());
459 iterate_md5_digest(md5, digest, (getR() >= 3 ? 50 : 0), key_len); 447 iterate_md5_digest(md5, digest, (getR() >= 3 ? 50 : 0), key_len);
@@ -469,8 +457,7 @@ QPDF::EncryptionData::compute_O_value( @@ -469,8 +457,7 @@ QPDF::EncryptionData::compute_O_value(
469 unsigned char O_key[OU_key_bytes_V4]; 457 unsigned char O_key[OU_key_bytes_V4];
470 compute_O_rc4_key(user_password, owner_password, O_key); 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 std::string k1(reinterpret_cast<char*>(O_key), OU_key_bytes_V4); 461 std::string k1(reinterpret_cast<char*>(O_key), OU_key_bytes_V4);
475 pad_short_parameter(k1, QIntC::to_size(getLengthBytes())); 462 pad_short_parameter(k1, QIntC::to_size(getLengthBytes()));
476 iterate_rc4( 463 iterate_rc4(
@@ -480,7 +467,7 @@ QPDF::EncryptionData::compute_O_value( @@ -480,7 +467,7 @@ QPDF::EncryptionData::compute_O_value(
480 getLengthBytes(), 467 getLengthBytes(),
481 getR() >= 3 ? 20 : 1, 468 getR() >= 3 ? 20 : 1,
482 false); 469 false);
483 - return {upass, key_bytes}; 470 + return upass;
484 } 471 }
485 472
486 std::string 473 std::string
@@ -489,17 +476,16 @@ QPDF::EncryptionData::compute_U_value_R2(std::string const&amp; user_password) const @@ -489,17 +476,16 @@ QPDF::EncryptionData::compute_U_value_R2(std::string const&amp; user_password) const
489 // Algorithm 3.4 from the PDF 1.7 Reference Manual 476 // Algorithm 3.4 from the PDF 1.7 Reference Manual
490 477
491 std::string k1 = compute_encryption_key(user_password); 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 pad_short_parameter(k1, QIntC::to_size(getLengthBytes())); 480 pad_short_parameter(k1, QIntC::to_size(getLengthBytes()));
495 iterate_rc4( 481 iterate_rc4(
496 - QUtil::unsigned_char_pointer(udata), 482 + QUtil::unsigned_char_pointer(udata.data()),
497 key_bytes, 483 key_bytes,
498 QUtil::unsigned_char_pointer(k1), 484 QUtil::unsigned_char_pointer(k1),
499 getLengthBytes(), 485 getLengthBytes(),
500 1, 486 1,
501 false); 487 false);
502 - return {udata, key_bytes}; 488 + return udata;
503 } 489 }
504 490
505 std::string 491 std::string
@@ -509,8 +495,8 @@ QPDF::EncryptionData::compute_U_value_R3(std::string const&amp; user_password) const @@ -509,8 +495,8 @@ QPDF::EncryptionData::compute_U_value_R3(std::string const&amp; user_password) const
509 495
510 std::string k1 = compute_encryption_key(user_password); 496 std::string k1 = compute_encryption_key(user_password);
511 MD5 md5; 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 MD5::Digest digest; 500 MD5::Digest digest;
515 md5.digest(digest); 501 md5.digest(digest);
516 pad_short_parameter(k1, QIntC::to_size(getLengthBytes())); 502 pad_short_parameter(k1, QIntC::to_size(getLengthBytes()));