Commit cb3c4c55d4cd721f647fa544a98bc0cb24c97823

Authored by m-holger
1 parent 34f52682

Refactor `QPDF::EncryptionData` to encapsulate encryption logic, reduce redundan…

…t parameter passing, and improve maintainability. Change static functions and QPDF methods to EncryptionData methods.
include/qpdf/QPDF.hh
@@ -497,10 +497,68 @@ class QPDF @@ -497,10 +497,68 @@ class QPDF
497 std::string const& UE, 497 std::string const& UE,
498 std::string const& Perms); 498 std::string const& Perms);
499 499
  500 + std::string compute_encryption_key(std::string const& password) const;
  501 +
  502 + bool
  503 + check_owner_password(std::string& user_password, std::string const& owner_password) const;
  504 +
  505 + bool check_user_password(std::string const& user_password) const;
  506 +
  507 + std::string
  508 + recover_encryption_key_with_password(std::string const& password, bool& perms_valid) const;
  509 +
  510 + void compute_encryption_O_U(
  511 + char const* user_password, char const* owner_password, std::string& O, std::string& U);
  512 +
  513 + void compute_encryption_parameters_V5(
  514 + char const* user_password,
  515 + char const* owner_password,
  516 + std::string& encryption_key,
  517 + std::string& O,
  518 + std::string& U,
  519 + std::string& OE,
  520 + std::string& UE,
  521 + std::string& Perms);
  522 +
500 private: 523 private:
  524 + static constexpr unsigned int OU_key_bytes_V4 = 16; // ( == sizeof(MD5::Digest)
  525 +
501 EncryptionData(EncryptionData const&) = delete; 526 EncryptionData(EncryptionData const&) = delete;
502 EncryptionData& operator=(EncryptionData const&) = delete; 527 EncryptionData& operator=(EncryptionData const&) = delete;
503 528
  529 + std::string hash_V5(
  530 + std::string const& password, std::string const& salt, std::string const& udata) const;
  531 + std::string compute_Perms_value_V5(std::string const& encryption_key) const;
  532 + std::string
  533 + compute_O_value(std::string const& user_password, std::string const& owner_password) const;
  534 + std::string compute_U_value(std::string const& user_password) const;
  535 + void compute_O_OE_value_V5(
  536 + std::string const& owner_password,
  537 + std::string const& encryption_key,
  538 + std::string const& U,
  539 + std::string& O,
  540 + std::string& OE) const;
  541 + void compute_U_UE_value_V5(
  542 + std::string const& user_password,
  543 + std::string const& encryption_key,
  544 + std::string& U,
  545 + std::string& UE) const;
  546 + std::string compute_encryption_key_from_password(std::string const& password) const;
  547 + std::string recover_encryption_key_with_password(std::string const& password) const;
  548 + bool check_owner_password_V4(
  549 + std::string& user_password, std::string const& owner_password) const;
  550 + bool check_owner_password_V5(std::string const& owner_passworda) const;
  551 + void
  552 + compute_Perms_value_V5_clear(std::string const& encryption_key, unsigned char k[16]) const;
  553 + void compute_O_rc4_key(
  554 + std::string const& user_password,
  555 + std::string const& owner_password,
  556 + unsigned char key[OU_key_bytes_V4]) const;
  557 + std::string compute_U_value_R2(std::string const& user_password) const;
  558 + std::string compute_U_value_R3(std::string const& user_password) const;
  559 + bool check_user_password_V4(std::string const& user_password) const;
  560 + bool check_user_password_V5(std::string const& user_password) const;
  561 +
504 int V; 562 int V;
505 int R; 563 int R;
506 int Length_bytes; 564 int Length_bytes;
@@ -912,12 +970,6 @@ class QPDF @@ -912,12 +970,6 @@ class QPDF
912 static std::string 970 static std::string
913 getKeyForObject(std::shared_ptr<EncryptionParameters> encp, QPDFObjGen og, bool use_aes); 971 getKeyForObject(std::shared_ptr<EncryptionParameters> encp, QPDFObjGen og, bool use_aes);
914 void decryptString(std::string&, QPDFObjGen og); 972 void decryptString(std::string&, QPDFObjGen og);
915 - static std::string  
916 - compute_encryption_key_from_password(std::string const& password, EncryptionData const& data);  
917 - static std::string  
918 - recover_encryption_key_with_password(std::string const& password, EncryptionData const& data);  
919 - static std::string recover_encryption_key_with_password(  
920 - std::string const& password, EncryptionData const& data, bool& perms_valid);  
921 static void decryptStream( 973 static void decryptStream(
922 std::shared_ptr<EncryptionParameters> encp, 974 std::shared_ptr<EncryptionParameters> encp,
923 std::shared_ptr<InputSource> file, 975 std::shared_ptr<InputSource> file,
libqpdf/QPDF_encryption.cc
@@ -25,9 +25,6 @@ static unsigned char const padding_string[] = { @@ -25,9 +25,6 @@ static unsigned char const padding_string[] = {
25 25
26 static unsigned int const key_bytes = 32; 26 static unsigned int const key_bytes = 32;
27 27
28 -// V4 key lengths apply to V <= 4  
29 -static unsigned int const OU_key_bytes_V4 = sizeof(MD5::Digest);  
30 -  
31 static unsigned int const OU_key_bytes_V5 = 48; 28 static unsigned int const OU_key_bytes_V5 = 48;
32 static unsigned int const OUE_key_bytes_V5 = 32; 29 static unsigned int const OUE_key_bytes_V5 = 32;
33 static unsigned int const Perms_key_bytes_V5 = 16; 30 static unsigned int const Perms_key_bytes_V5 = 16;
@@ -236,12 +233,9 @@ process_with_aes( @@ -236,12 +233,9 @@ process_with_aes(
236 } 233 }
237 } 234 }
238 235
239 -static std::string  
240 -hash_V5(  
241 - std::string const& password,  
242 - std::string const& salt,  
243 - std::string const& udata,  
244 - QPDF::EncryptionData const& data) 236 +std::string
  237 +QPDF::EncryptionData::hash_V5(
  238 + std::string const& password, std::string const& salt, std::string const& udata) const
245 { 239 {
246 Pl_SHA2 hash(256); 240 Pl_SHA2 hash(256);
247 hash.writeString(password); 241 hash.writeString(password);
@@ -251,7 +245,7 @@ hash_V5( @@ -251,7 +245,7 @@ hash_V5(
251 std::string K = hash.getRawDigest(); 245 std::string K = hash.getRawDigest();
252 246
253 std::string result; 247 std::string result;
254 - if (data.getR() < 6) { 248 + if (getR() < 6) {
255 result = K; 249 result = K;
256 } else { 250 } else {
257 // Algorithm 2.B from ISO 32000-1 chapter 7: Computing a hash 251 // Algorithm 2.B from ISO 32000-1 chapter 7: Computing a hash
@@ -359,19 +353,25 @@ QPDF::compute_data_key( @@ -359,19 +353,25 @@ QPDF::compute_data_key(
359 std::string 353 std::string
360 QPDF::compute_encryption_key(std::string const& password, EncryptionData const& data) 354 QPDF::compute_encryption_key(std::string const& password, EncryptionData const& data)
361 { 355 {
362 - if (data.getV() >= 5) { 356 + return data.compute_encryption_key(password);
  357 +}
  358 +
  359 +std::string
  360 +QPDF::EncryptionData::compute_encryption_key(std::string const& password) const
  361 +{
  362 + if (getV() >= 5) {
363 // For V >= 5, the encryption key is generated and stored in the file, encrypted separately 363 // For V >= 5, the encryption key is generated and stored in the file, encrypted separately
364 // with both user and owner passwords. 364 // with both user and owner passwords.
365 - return recover_encryption_key_with_password(password, data); 365 + return recover_encryption_key_with_password(password);
366 } else { 366 } else {
367 // For V < 5, the encryption key is derived from the user 367 // For V < 5, the encryption key is derived from the user
368 // password. 368 // password.
369 - return compute_encryption_key_from_password(password, data); 369 + return compute_encryption_key_from_password(password);
370 } 370 }
371 } 371 }
372 372
373 std::string 373 std::string
374 -QPDF::compute_encryption_key_from_password(std::string const& password, EncryptionData const& data) 374 +QPDF::EncryptionData::compute_encryption_key_from_password(std::string const& password) const
375 { 375 {
376 // Algorithm 3.2 from the PDF 1.7 Reference Manual 376 // Algorithm 3.2 from the PDF 1.7 Reference Manual
377 377
@@ -382,34 +382,33 @@ QPDF::compute_encryption_key_from_password(std::string const&amp; password, Encrypti @@ -382,34 +382,33 @@ QPDF::compute_encryption_key_from_password(std::string const&amp; password, Encrypti
382 382
383 MD5 md5; 383 MD5 md5;
384 md5.encodeDataIncrementally(pad_or_truncate_password_V4(password).c_str(), key_bytes); 384 md5.encodeDataIncrementally(pad_or_truncate_password_V4(password).c_str(), key_bytes);
385 - md5.encodeDataIncrementally(data.getO().c_str(), key_bytes); 385 + md5.encodeDataIncrementally(getO().c_str(), key_bytes);
386 char pbytes[4]; 386 char pbytes[4];
387 - int P = data.getP(); 387 + int P = getP();
388 pbytes[0] = static_cast<char>(P & 0xff); 388 pbytes[0] = static_cast<char>(P & 0xff);
389 pbytes[1] = static_cast<char>((P >> 8) & 0xff); 389 pbytes[1] = static_cast<char>((P >> 8) & 0xff);
390 pbytes[2] = static_cast<char>((P >> 16) & 0xff); 390 pbytes[2] = static_cast<char>((P >> 16) & 0xff);
391 pbytes[3] = static_cast<char>((P >> 24) & 0xff); 391 pbytes[3] = static_cast<char>((P >> 24) & 0xff);
392 md5.encodeDataIncrementally(pbytes, 4); 392 md5.encodeDataIncrementally(pbytes, 4);
393 - md5.encodeDataIncrementally(data.getId1().c_str(), data.getId1().length());  
394 - if ((data.getR() >= 4) && (!data.getEncryptMetadata())) { 393 + md5.encodeDataIncrementally(getId1().c_str(), getId1().length());
  394 + if (getR() >= 4 && !getEncryptMetadata()) {
395 char bytes[4]; 395 char bytes[4];
396 memset(bytes, 0xff, 4); 396 memset(bytes, 0xff, 4);
397 md5.encodeDataIncrementally(bytes, 4); 397 md5.encodeDataIncrementally(bytes, 4);
398 } 398 }
399 MD5::Digest digest; 399 MD5::Digest digest;
400 - int key_len = std::min(toI(sizeof(digest)), data.getLengthBytes());  
401 - iterate_md5_digest(md5, digest, ((data.getR() >= 3) ? 50 : 0), key_len); 400 + int key_len = std::min(toI(sizeof(digest)), getLengthBytes());
  401 + iterate_md5_digest(md5, digest, (getR() >= 3 ? 50 : 0), key_len);
402 return {reinterpret_cast<char*>(digest), toS(key_len)}; 402 return {reinterpret_cast<char*>(digest), toS(key_len)};
403 } 403 }
404 404
405 -static void  
406 -compute_O_rc4_key( 405 +void
  406 +QPDF::EncryptionData::compute_O_rc4_key(
407 std::string const& user_password, 407 std::string const& user_password,
408 std::string const& owner_password, 408 std::string const& owner_password,
409 - QPDF::EncryptionData const& data,  
410 - unsigned char key[OU_key_bytes_V4]) 409 + unsigned char key[OU_key_bytes_V4]) const
411 { 410 {
412 - if (data.getV() >= 5) { 411 + if (getV() >= 5) {
413 throw std::logic_error("compute_O_rc4_key called for file with V >= 5"); 412 throw std::logic_error("compute_O_rc4_key called for file with V >= 5");
414 } 413 }
415 std::string password = owner_password; 414 std::string password = owner_password;
@@ -419,252 +418,241 @@ compute_O_rc4_key( @@ -419,252 +418,241 @@ compute_O_rc4_key(
419 MD5 md5; 418 MD5 md5;
420 md5.encodeDataIncrementally(pad_or_truncate_password_V4(password).c_str(), key_bytes); 419 md5.encodeDataIncrementally(pad_or_truncate_password_V4(password).c_str(), key_bytes);
421 MD5::Digest digest; 420 MD5::Digest digest;
422 - int key_len = std::min(QIntC::to_int(sizeof(digest)), data.getLengthBytes());  
423 - iterate_md5_digest(md5, digest, ((data.getR() >= 3) ? 50 : 0), key_len); 421 + int key_len = std::min(QIntC::to_int(sizeof(digest)), getLengthBytes());
  422 + iterate_md5_digest(md5, digest, (getR() >= 3 ? 50 : 0), key_len);
424 memcpy(key, digest, OU_key_bytes_V4); 423 memcpy(key, digest, OU_key_bytes_V4);
425 } 424 }
426 425
427 -static std::string  
428 -compute_O_value(  
429 - std::string const& user_password,  
430 - std::string const& owner_password,  
431 - QPDF::EncryptionData const& data) 426 +std::string
  427 +QPDF::EncryptionData::compute_O_value(
  428 + std::string const& user_password, std::string const& owner_password) const
432 { 429 {
433 // Algorithm 3.3 from the PDF 1.7 Reference Manual 430 // Algorithm 3.3 from the PDF 1.7 Reference Manual
434 431
435 unsigned char O_key[OU_key_bytes_V4]; 432 unsigned char O_key[OU_key_bytes_V4];
436 - compute_O_rc4_key(user_password, owner_password, data, O_key); 433 + compute_O_rc4_key(user_password, owner_password, O_key);
437 434
438 char upass[key_bytes]; 435 char upass[key_bytes];
439 pad_or_truncate_password_V4(user_password, upass); 436 pad_or_truncate_password_V4(user_password, upass);
440 std::string k1(reinterpret_cast<char*>(O_key), OU_key_bytes_V4); 437 std::string k1(reinterpret_cast<char*>(O_key), OU_key_bytes_V4);
441 - pad_short_parameter(k1, QIntC::to_size(data.getLengthBytes())); 438 + pad_short_parameter(k1, QIntC::to_size(getLengthBytes()));
442 iterate_rc4( 439 iterate_rc4(
443 QUtil::unsigned_char_pointer(upass), 440 QUtil::unsigned_char_pointer(upass),
444 key_bytes, 441 key_bytes,
445 O_key, 442 O_key,
446 - data.getLengthBytes(),  
447 - (data.getR() >= 3) ? 20 : 1, 443 + getLengthBytes(),
  444 + getR() >= 3 ? 20 : 1,
448 false); 445 false);
449 return {upass, key_bytes}; 446 return {upass, key_bytes};
450 } 447 }
451 448
452 -static std::string  
453 -compute_U_value_R2(std::string const& user_password, QPDF::EncryptionData const& data) 449 +std::string
  450 +QPDF::EncryptionData::compute_U_value_R2(std::string const& user_password) const
454 { 451 {
455 // Algorithm 3.4 from the PDF 1.7 Reference Manual 452 // Algorithm 3.4 from the PDF 1.7 Reference Manual
456 453
457 - std::string k1 = QPDF::compute_encryption_key(user_password, data); 454 + std::string k1 = compute_encryption_key(user_password);
458 char udata[key_bytes]; 455 char udata[key_bytes];
459 pad_or_truncate_password_V4("", udata); 456 pad_or_truncate_password_V4("", udata);
460 - pad_short_parameter(k1, QIntC::to_size(data.getLengthBytes())); 457 + pad_short_parameter(k1, QIntC::to_size(getLengthBytes()));
461 iterate_rc4( 458 iterate_rc4(
462 QUtil::unsigned_char_pointer(udata), 459 QUtil::unsigned_char_pointer(udata),
463 key_bytes, 460 key_bytes,
464 QUtil::unsigned_char_pointer(k1), 461 QUtil::unsigned_char_pointer(k1),
465 - data.getLengthBytes(), 462 + getLengthBytes(),
466 1, 463 1,
467 false); 464 false);
468 return {udata, key_bytes}; 465 return {udata, key_bytes};
469 } 466 }
470 467
471 -static std::string  
472 -compute_U_value_R3(std::string const& user_password, QPDF::EncryptionData const& data) 468 +std::string
  469 +QPDF::EncryptionData::compute_U_value_R3(std::string const& user_password) const
473 { 470 {
474 // Algorithm 3.5 from the PDF 1.7 Reference Manual 471 // Algorithm 3.5 from the PDF 1.7 Reference Manual
475 472
476 - std::string k1 = QPDF::compute_encryption_key(user_password, data); 473 + std::string k1 = compute_encryption_key(user_password);
477 MD5 md5; 474 MD5 md5;
478 md5.encodeDataIncrementally(pad_or_truncate_password_V4("").c_str(), key_bytes); 475 md5.encodeDataIncrementally(pad_or_truncate_password_V4("").c_str(), key_bytes);
479 - md5.encodeDataIncrementally(data.getId1().c_str(), data.getId1().length()); 476 + md5.encodeDataIncrementally(getId1().c_str(), getId1().length());
480 MD5::Digest digest; 477 MD5::Digest digest;
481 md5.digest(digest); 478 md5.digest(digest);
482 - pad_short_parameter(k1, QIntC::to_size(data.getLengthBytes())); 479 + pad_short_parameter(k1, QIntC::to_size(getLengthBytes()));
483 iterate_rc4( 480 iterate_rc4(
484 - digest,  
485 - sizeof(MD5::Digest),  
486 - QUtil::unsigned_char_pointer(k1),  
487 - data.getLengthBytes(),  
488 - 20,  
489 - false); 481 + digest, sizeof(MD5::Digest), QUtil::unsigned_char_pointer(k1), getLengthBytes(), 20, false);
490 char result[key_bytes]; 482 char result[key_bytes];
491 memcpy(result, digest, sizeof(MD5::Digest)); 483 memcpy(result, digest, sizeof(MD5::Digest));
492 - // pad with arbitrary data -- make it consistent for the sake of  
493 - // testing 484 + // pad with arbitrary data -- make it consistent for the sake of testing
494 for (unsigned int i = sizeof(MD5::Digest); i < key_bytes; ++i) { 485 for (unsigned int i = sizeof(MD5::Digest); i < key_bytes; ++i) {
495 result[i] = static_cast<char>((i * i) % 0xff); 486 result[i] = static_cast<char>((i * i) % 0xff);
496 } 487 }
497 return {result, key_bytes}; 488 return {result, key_bytes};
498 } 489 }
499 490
500 -static std::string  
501 -compute_U_value(std::string const& user_password, QPDF::EncryptionData const& data) 491 +std::string
  492 +QPDF::EncryptionData::compute_U_value(std::string const& user_password) const
502 { 493 {
503 - if (data.getR() >= 3) {  
504 - return compute_U_value_R3(user_password, data); 494 + if (getR() >= 3) {
  495 + return compute_U_value_R3(user_password);
505 } 496 }
506 497
507 - return compute_U_value_R2(user_password, data); 498 + return compute_U_value_R2(user_password);
508 } 499 }
509 500
510 -static bool  
511 -check_user_password_V4(std::string const& user_password, QPDF::EncryptionData const& data) 501 +bool
  502 +QPDF::EncryptionData::check_user_password_V4(std::string const& user_password) const
512 { 503 {
513 // Algorithm 3.6 from the PDF 1.7 Reference Manual 504 // Algorithm 3.6 from the PDF 1.7 Reference Manual
514 505
515 - std::string u_value = compute_U_value(user_password, data);  
516 - size_t to_compare = ((data.getR() >= 3) ? sizeof(MD5::Digest) : key_bytes);  
517 - return (memcmp(data.getU().c_str(), u_value.c_str(), to_compare) == 0); 506 + std::string u_value = compute_U_value(user_password);
  507 + size_t to_compare = (getR() >= 3 ? sizeof(MD5::Digest) : key_bytes);
  508 + return memcmp(getU().c_str(), u_value.c_str(), to_compare) == 0;
518 } 509 }
519 510
520 -static bool  
521 -check_user_password_V5(std::string const& user_password, QPDF::EncryptionData const& data) 511 +bool
  512 +QPDF::EncryptionData::check_user_password_V5(std::string const& user_password) const
522 { 513 {
523 // Algorithm 3.11 from the PDF 1.7 extension level 3 514 // Algorithm 3.11 from the PDF 1.7 extension level 3
524 515
525 - std::string user_data = data.getU().substr(0, 32);  
526 - std::string validation_salt = data.getU().substr(32, 8); 516 + std::string user_data = getU().substr(0, 32);
  517 + std::string validation_salt = getU().substr(32, 8);
527 std::string password = truncate_password_V5(user_password); 518 std::string password = truncate_password_V5(user_password);
528 - return (hash_V5(password, validation_salt, "", data) == user_data); 519 + return hash_V5(password, validation_salt, "") == user_data;
529 } 520 }
530 521
531 -static bool  
532 -check_user_password(std::string const& user_password, QPDF::EncryptionData const& data) 522 +bool
  523 +QPDF::EncryptionData::check_user_password(std::string const& user_password) const
533 { 524 {
534 - if (data.getV() < 5) {  
535 - return check_user_password_V4(user_password, data); 525 + if (getV() < 5) {
  526 + return check_user_password_V4(user_password);
536 } else { 527 } else {
537 - return check_user_password_V5(user_password, data); 528 + return check_user_password_V5(user_password);
538 } 529 }
539 } 530 }
540 531
541 -static bool  
542 -check_owner_password_V4(  
543 - std::string& user_password, std::string const& owner_password, QPDF::EncryptionData const& data) 532 +bool
  533 +QPDF::EncryptionData::check_owner_password_V4(
  534 + std::string& user_password, std::string const& owner_password) const
544 { 535 {
545 // Algorithm 3.7 from the PDF 1.7 Reference Manual 536 // Algorithm 3.7 from the PDF 1.7 Reference Manual
546 537
547 unsigned char key[OU_key_bytes_V4]; 538 unsigned char key[OU_key_bytes_V4];
548 - compute_O_rc4_key(user_password, owner_password, data, key); 539 + compute_O_rc4_key(user_password, owner_password, key);
549 unsigned char O_data[key_bytes]; 540 unsigned char O_data[key_bytes];
550 - memcpy(O_data, QUtil::unsigned_char_pointer(data.getO()), key_bytes); 541 + memcpy(O_data, QUtil::unsigned_char_pointer(getO()), key_bytes);
551 std::string k1(reinterpret_cast<char*>(key), OU_key_bytes_V4); 542 std::string k1(reinterpret_cast<char*>(key), OU_key_bytes_V4);
552 - pad_short_parameter(k1, QIntC::to_size(data.getLengthBytes())); 543 + pad_short_parameter(k1, QIntC::to_size(getLengthBytes()));
553 iterate_rc4( 544 iterate_rc4(
554 O_data, 545 O_data,
555 key_bytes, 546 key_bytes,
556 QUtil::unsigned_char_pointer(k1), 547 QUtil::unsigned_char_pointer(k1),
557 - data.getLengthBytes(),  
558 - (data.getR() >= 3) ? 20 : 1, 548 + getLengthBytes(),
  549 + (getR() >= 3) ? 20 : 1,
559 true); 550 true);
560 std::string new_user_password = std::string(reinterpret_cast<char*>(O_data), key_bytes); 551 std::string new_user_password = std::string(reinterpret_cast<char*>(O_data), key_bytes);
561 - bool result = false;  
562 - if (check_user_password(new_user_password, data)) {  
563 - result = true; 552 + if (check_user_password(new_user_password)) {
564 user_password = new_user_password; 553 user_password = new_user_password;
  554 + return true;
565 } 555 }
566 - return result; 556 + return false;
567 } 557 }
568 558
569 -static bool  
570 -check_owner_password_V5(std::string const& owner_password, QPDF::EncryptionData const& data) 559 +bool
  560 +QPDF::EncryptionData::check_owner_password_V5(std::string const& owner_password) const
571 { 561 {
572 // Algorithm 3.12 from the PDF 1.7 extension level 3 562 // Algorithm 3.12 from the PDF 1.7 extension level 3
573 563
574 - std::string user_data = data.getU().substr(0, 48);  
575 - std::string owner_data = data.getO().substr(0, 32);  
576 - std::string validation_salt = data.getO().substr(32, 8); 564 + std::string user_data = getU().substr(0, 48);
  565 + std::string owner_data = getO().substr(0, 32);
  566 + std::string validation_salt = getO().substr(32, 8);
577 std::string password = truncate_password_V5(owner_password); 567 std::string password = truncate_password_V5(owner_password);
578 - return (hash_V5(password, validation_salt, user_data, data) == owner_data); 568 + return hash_V5(password, validation_salt, user_data) == owner_data;
579 } 569 }
580 570
581 -static bool  
582 -check_owner_password(  
583 - std::string& user_password, std::string const& owner_password, QPDF::EncryptionData const& data) 571 +bool
  572 +QPDF::EncryptionData::check_owner_password(
  573 + std::string& user_password, std::string const& owner_password) const
584 { 574 {
585 - if (data.getV() < 5) {  
586 - return check_owner_password_V4(user_password, owner_password, data); 575 + if (getV() < 5) {
  576 + return check_owner_password_V4(user_password, owner_password);
587 } else { 577 } else {
588 - return check_owner_password_V5(owner_password, data); 578 + return check_owner_password_V5(owner_password);
589 } 579 }
590 } 580 }
591 581
592 std::string 582 std::string
593 -QPDF::recover_encryption_key_with_password(std::string const& password, EncryptionData const& data) 583 +QPDF::EncryptionData::recover_encryption_key_with_password(std::string const& password) const
594 { 584 {
595 // Disregard whether Perms is valid. 585 // Disregard whether Perms is valid.
596 bool disregard; 586 bool disregard;
597 - return recover_encryption_key_with_password(password, data, disregard); 587 + return recover_encryption_key_with_password(password, disregard);
598 } 588 }
599 589
600 -static void  
601 -compute_U_UE_value_V5( 590 +void
  591 +QPDF::EncryptionData::compute_U_UE_value_V5(
602 std::string const& user_password, 592 std::string const& user_password,
603 std::string const& encryption_key, 593 std::string const& encryption_key,
604 - QPDF::EncryptionData const& data,  
605 - std::string& U,  
606 - std::string& UE) 594 + std::string& out_U,
  595 + std::string& out_UE) const
607 { 596 {
608 // Algorithm 3.8 from the PDF 1.7 extension level 3 597 // Algorithm 3.8 from the PDF 1.7 extension level 3
609 char k[16]; 598 char k[16];
610 QUtil::initializeWithRandomBytes(reinterpret_cast<unsigned char*>(k), sizeof(k)); 599 QUtil::initializeWithRandomBytes(reinterpret_cast<unsigned char*>(k), sizeof(k));
611 std::string validation_salt(k, 8); 600 std::string validation_salt(k, 8);
612 std::string key_salt(k + 8, 8); 601 std::string key_salt(k + 8, 8);
613 - U = hash_V5(user_password, validation_salt, "", data) + validation_salt + key_salt;  
614 - std::string intermediate_key = hash_V5(user_password, key_salt, "", data);  
615 - UE = process_with_aes(intermediate_key, true, encryption_key); 602 + out_U = hash_V5(user_password, validation_salt, "") + validation_salt + key_salt;
  603 + std::string intermediate_key = hash_V5(user_password, key_salt, "");
  604 + out_UE = process_with_aes(intermediate_key, true, encryption_key);
616 } 605 }
617 606
618 -static void  
619 -compute_O_OE_value_V5( 607 +void
  608 +QPDF::EncryptionData::compute_O_OE_value_V5(
620 std::string const& owner_password, 609 std::string const& owner_password,
621 std::string const& encryption_key, 610 std::string const& encryption_key,
622 - QPDF::EncryptionData const& data,  
623 - std::string const& U,  
624 - std::string& O,  
625 - std::string& OE) 611 + std::string const& in_U,
  612 + std::string& out_O,
  613 + std::string& out_OE) const
626 { 614 {
627 // Algorithm 3.9 from the PDF 1.7 extension level 3 615 // Algorithm 3.9 from the PDF 1.7 extension level 3
628 char k[16]; 616 char k[16];
629 QUtil::initializeWithRandomBytes(reinterpret_cast<unsigned char*>(k), sizeof(k)); 617 QUtil::initializeWithRandomBytes(reinterpret_cast<unsigned char*>(k), sizeof(k));
630 std::string validation_salt(k, 8); 618 std::string validation_salt(k, 8);
631 std::string key_salt(k + 8, 8); 619 std::string key_salt(k + 8, 8);
632 - O = hash_V5(owner_password, validation_salt, U, data) + validation_salt + key_salt;  
633 - std::string intermediate_key = hash_V5(owner_password, key_salt, U, data);  
634 - OE = process_with_aes(intermediate_key, true, encryption_key); 620 + out_O = hash_V5(owner_password, validation_salt, in_U) + validation_salt + key_salt;
  621 + std::string intermediate_key = hash_V5(owner_password, key_salt, in_U);
  622 + out_OE = process_with_aes(intermediate_key, true, encryption_key);
635 } 623 }
636 624
637 void 625 void
638 -compute_Perms_value_V5_clear(  
639 - std::string const& encryption_key, QPDF::EncryptionData const& data, unsigned char k[16]) 626 +QPDF::EncryptionData::compute_Perms_value_V5_clear(
  627 + std::string const& encryption_key, unsigned char k[16]) const
640 { 628 {
641 // From algorithm 3.10 from the PDF 1.7 extension level 3 629 // From algorithm 3.10 from the PDF 1.7 extension level 3
642 unsigned long long extended_perms = 630 unsigned long long extended_perms =
643 - 0xffffffff00000000LL | static_cast<unsigned long long>(data.getP()); 631 + 0xffffffff00000000LL | static_cast<unsigned long long>(getP());
644 for (int i = 0; i < 8; ++i) { 632 for (int i = 0; i < 8; ++i) {
645 k[i] = static_cast<unsigned char>(extended_perms & 0xff); 633 k[i] = static_cast<unsigned char>(extended_perms & 0xff);
646 extended_perms >>= 8; 634 extended_perms >>= 8;
647 } 635 }
648 - k[8] = data.getEncryptMetadata() ? 'T' : 'F'; 636 + k[8] = getEncryptMetadata() ? 'T' : 'F';
649 k[9] = 'a'; 637 k[9] = 'a';
650 k[10] = 'd'; 638 k[10] = 'd';
651 k[11] = 'b'; 639 k[11] = 'b';
652 QUtil::initializeWithRandomBytes(k + 12, 4); 640 QUtil::initializeWithRandomBytes(k + 12, 4);
653 } 641 }
654 642
655 -static std::string  
656 -compute_Perms_value_V5(std::string const& encryption_key, QPDF::EncryptionData const& data) 643 +std::string
  644 +QPDF::EncryptionData::compute_Perms_value_V5(std::string const& encryption_key) const
657 { 645 {
658 // Algorithm 3.10 from the PDF 1.7 extension level 3 646 // Algorithm 3.10 from the PDF 1.7 extension level 3
659 unsigned char k[16]; 647 unsigned char k[16];
660 - compute_Perms_value_V5_clear(encryption_key, data, k); 648 + compute_Perms_value_V5_clear(encryption_key, k);
661 return process_with_aes( 649 return process_with_aes(
662 encryption_key, true, std::string(reinterpret_cast<char*>(k), sizeof(k))); 650 encryption_key, true, std::string(reinterpret_cast<char*>(k), sizeof(k)));
663 } 651 }
664 652
665 std::string 653 std::string
666 -QPDF::recover_encryption_key_with_password(  
667 - std::string const& password, EncryptionData const& data, bool& perms_valid) 654 +QPDF::EncryptionData::recover_encryption_key_with_password(
  655 + std::string const& password, bool& perms_valid) const
668 { 656 {
669 // Algorithm 3.2a from the PDF 1.7 extension level 3 657 // Algorithm 3.2a from the PDF 1.7 extension level 3
670 658
@@ -677,21 +665,21 @@ QPDF::recover_encryption_key_with_password( @@ -677,21 +665,21 @@ QPDF::recover_encryption_key_with_password(
677 std::string key_salt; 665 std::string key_salt;
678 std::string user_data; 666 std::string user_data;
679 std::string encrypted_file_key; 667 std::string encrypted_file_key;
680 - if (check_owner_password_V5(key_password, data)) {  
681 - key_salt = data.getO().substr(40, 8);  
682 - user_data = data.getU().substr(0, 48);  
683 - encrypted_file_key = data.getOE().substr(0, 32);  
684 - } else if (check_user_password_V5(key_password, data)) {  
685 - key_salt = data.getU().substr(40, 8);  
686 - encrypted_file_key = data.getUE().substr(0, 32); 668 + if (check_owner_password_V5(key_password)) {
  669 + key_salt = getO().substr(40, 8);
  670 + user_data = getU().substr(0, 48);
  671 + encrypted_file_key = getOE().substr(0, 32);
  672 + } else if (check_user_password_V5(key_password)) {
  673 + key_salt = getU().substr(40, 8);
  674 + encrypted_file_key = getUE().substr(0, 32);
687 } 675 }
688 - std::string intermediate_key = hash_V5(key_password, key_salt, user_data, data); 676 + std::string intermediate_key = hash_V5(key_password, key_salt, user_data);
689 std::string file_key = process_with_aes(intermediate_key, false, encrypted_file_key); 677 std::string file_key = process_with_aes(intermediate_key, false, encrypted_file_key);
690 678
691 // Decrypt Perms and check against expected value 679 // Decrypt Perms and check against expected value
692 - std::string perms_check = process_with_aes(file_key, false, data.getPerms(), 12); 680 + auto perms_check = process_with_aes(file_key, false, getPerms()).substr(0, 12);
693 unsigned char k[16]; 681 unsigned char k[16];
694 - compute_Perms_value_V5_clear(file_key, data, k); 682 + compute_Perms_value_V5_clear(file_key, k);
695 perms_valid = (memcmp(perms_check.c_str(), k, 12) == 0); 683 perms_valid = (memcmp(perms_check.c_str(), k, 12) == 0);
696 684
697 return file_key; 685 return file_key;
@@ -909,7 +897,7 @@ QPDF::initializeEncryption() @@ -909,7 +897,7 @@ QPDF::initializeEncryption()
909 // ignore passwords in file 897 // ignore passwords in file
910 } else { 898 } else {
911 m->encp->owner_password_matched = 899 m->encp->owner_password_matched =
912 - check_owner_password(m->encp->user_password, m->encp->provided_password, data); 900 + data.check_owner_password(m->encp->user_password, m->encp->provided_password);
913 if (m->encp->owner_password_matched && (V < 5)) { 901 if (m->encp->owner_password_matched && (V < 5)) {
914 // password supplied was owner password; user_password has been initialized for V < 5 902 // password supplied was owner password; user_password has been initialized for V < 5
915 if (getTrimmedUserPassword() == m->encp->provided_password) { 903 if (getTrimmedUserPassword() == m->encp->provided_password) {
@@ -917,7 +905,7 @@ QPDF::initializeEncryption() @@ -917,7 +905,7 @@ QPDF::initializeEncryption()
917 QTC::TC("qpdf", "QPDF_encryption user matches owner V < 5"); 905 QTC::TC("qpdf", "QPDF_encryption user matches owner V < 5");
918 } 906 }
919 } else { 907 } else {
920 - m->encp->user_password_matched = check_user_password(m->encp->provided_password, data); 908 + m->encp->user_password_matched = data.check_user_password(m->encp->provided_password);
921 if (m->encp->user_password_matched) { 909 if (m->encp->user_password_matched) {
922 m->encp->user_password = m->encp->provided_password; 910 m->encp->user_password = m->encp->provided_password;
923 } 911 }
@@ -941,12 +929,11 @@ QPDF::initializeEncryption() @@ -941,12 +929,11 @@ QPDF::initializeEncryption()
941 // neither password can be used to recover the other. 929 // neither password can be used to recover the other.
942 bool perms_valid; 930 bool perms_valid;
943 m->encp->encryption_key = 931 m->encp->encryption_key =
944 - recover_encryption_key_with_password(m->encp->provided_password, data, perms_valid); 932 + data.recover_encryption_key_with_password(m->encp->provided_password, perms_valid);
945 if (!perms_valid) { 933 if (!perms_valid) {
946 warn(damagedPDF( 934 warn(damagedPDF(
947 "encryption dictionary", 935 "encryption dictionary",
948 - "/Perms field in encryption dictionary doesn't match expected "  
949 - "value")); 936 + "/Perms field in encryption dictionary doesn't match expected value"));
950 } 937 }
951 } 938 }
952 } 939 }
@@ -1167,14 +1154,20 @@ QPDF::compute_encryption_O_U( @@ -1167,14 +1154,20 @@ QPDF::compute_encryption_O_U(
1167 std::string& O, 1154 std::string& O,
1168 std::string& U) 1155 std::string& U)
1169 { 1156 {
  1157 + EncryptionData(V, R, key_len, P, "", "", "", "", "", id1, encrypt_metadata)
  1158 + .compute_encryption_O_U(user_password, owner_password, O, U);
  1159 +}
  1160 +
  1161 +void
  1162 +QPDF::EncryptionData::compute_encryption_O_U(
  1163 + char const* user_password, char const* owner_password, std::string& out_O, std::string& out_U)
  1164 +{
1170 if (V >= 5) { 1165 if (V >= 5) {
1171 throw std::logic_error("compute_encryption_O_U called for file with V >= 5"); 1166 throw std::logic_error("compute_encryption_O_U called for file with V >= 5");
1172 } 1167 }
1173 - EncryptionData data(V, R, key_len, P, "", "", "", "", "", id1, encrypt_metadata);  
1174 - data.setO(compute_O_value(user_password, owner_password, data));  
1175 - O = data.getO();  
1176 - data.setU(compute_U_value(user_password, data));  
1177 - U = data.getU(); 1168 + setO(compute_O_value(user_password, owner_password));
  1169 + out_O = getO();
  1170 + out_U = compute_U_value(user_password);
1178 } 1171 }
1179 1172
1180 void 1173 void
@@ -1194,14 +1187,29 @@ QPDF::compute_encryption_parameters_V5( @@ -1194,14 +1187,29 @@ QPDF::compute_encryption_parameters_V5(
1194 std::string& UE, 1187 std::string& UE,
1195 std::string& Perms) 1188 std::string& Perms)
1196 { 1189 {
1197 - EncryptionData data(V, R, key_len, P, "", "", "", "", "", id1, encrypt_metadata); 1190 + EncryptionData(V, R, key_len, P, "", "", "", "", "", id1, encrypt_metadata)
  1191 + .compute_encryption_parameters_V5(
  1192 + user_password, owner_password, encryption_key, O, U, OE, UE, Perms);
  1193 +}
  1194 +
  1195 +void
  1196 +QPDF::EncryptionData::compute_encryption_parameters_V5(
  1197 + char const* user_password,
  1198 + char const* owner_password,
  1199 + std::string& out_encryption_key,
  1200 + std::string& out_O,
  1201 + std::string& out_U,
  1202 + std::string& out_OE,
  1203 + std::string& out_UE,
  1204 + std::string& out_Perms)
  1205 +{
1198 unsigned char k[key_bytes]; 1206 unsigned char k[key_bytes];
1199 QUtil::initializeWithRandomBytes(k, key_bytes); 1207 QUtil::initializeWithRandomBytes(k, key_bytes);
1200 - encryption_key = std::string(reinterpret_cast<char*>(k), key_bytes);  
1201 - compute_U_UE_value_V5(user_password, encryption_key, data, U, UE);  
1202 - compute_O_OE_value_V5(owner_password, encryption_key, data, U, O, OE);  
1203 - Perms = compute_Perms_value_V5(encryption_key, data);  
1204 - data.setV5EncryptionParameters(O, OE, U, UE, Perms); 1208 + out_encryption_key = std::string(reinterpret_cast<char*>(k), key_bytes);
  1209 + compute_U_UE_value_V5(user_password, out_encryption_key, out_U, out_UE);
  1210 + compute_O_OE_value_V5(owner_password, out_encryption_key, out_U, out_O, out_OE);
  1211 + out_Perms = compute_Perms_value_V5(out_encryption_key);
  1212 + setV5EncryptionParameters(out_O, out_OE, out_U, out_UE, out_Perms);
1205 } 1213 }
1206 1214
1207 std::string const& 1215 std::string const&