Commit dea704f0ab7f625e1e7b3f9a1110b45b63157317
1 parent
021c2293
Pad keys to avoid memory errors (fixes #147)
Showing
1 changed file
with
10 additions
and
14 deletions
libqpdf/QPDF_encryption.cc
| @@ -479,6 +479,8 @@ compute_O_value(std::string const& user_password, | @@ -479,6 +479,8 @@ compute_O_value(std::string const& user_password, | ||
| 479 | 479 | ||
| 480 | char upass[key_bytes]; | 480 | char upass[key_bytes]; |
| 481 | pad_or_truncate_password_V4(user_password, upass); | 481 | pad_or_truncate_password_V4(user_password, upass); |
| 482 | + std::string k1(reinterpret_cast<char*>(O_key), OU_key_bytes_V4); | ||
| 483 | + pad_short_parameter(k1, data.getLengthBytes()); | ||
| 482 | iterate_rc4(QUtil::unsigned_char_pointer(upass), key_bytes, | 484 | iterate_rc4(QUtil::unsigned_char_pointer(upass), key_bytes, |
| 483 | O_key, data.getLengthBytes(), | 485 | O_key, data.getLengthBytes(), |
| 484 | (data.getR() >= 3) ? 20 : 1, false); | 486 | (data.getR() >= 3) ? 20 : 1, false); |
| @@ -495,6 +497,7 @@ compute_U_value_R2(std::string const& user_password, | @@ -495,6 +497,7 @@ compute_U_value_R2(std::string const& user_password, | ||
| 495 | std::string k1 = QPDF::compute_encryption_key(user_password, data); | 497 | std::string k1 = QPDF::compute_encryption_key(user_password, data); |
| 496 | char udata[key_bytes]; | 498 | char udata[key_bytes]; |
| 497 | pad_or_truncate_password_V4("", udata); | 499 | pad_or_truncate_password_V4("", udata); |
| 500 | + pad_short_parameter(k1, data.getLengthBytes()); | ||
| 498 | iterate_rc4(QUtil::unsigned_char_pointer(udata), key_bytes, | 501 | iterate_rc4(QUtil::unsigned_char_pointer(udata), key_bytes, |
| 499 | QUtil::unsigned_char_pointer(k1), | 502 | QUtil::unsigned_char_pointer(k1), |
| 500 | data.getLengthBytes(), 1, false); | 503 | data.getLengthBytes(), 1, false); |
| @@ -516,6 +519,7 @@ compute_U_value_R3(std::string const& user_password, | @@ -516,6 +519,7 @@ compute_U_value_R3(std::string const& user_password, | ||
| 516 | data.getId1().length()); | 519 | data.getId1().length()); |
| 517 | MD5::Digest digest; | 520 | MD5::Digest digest; |
| 518 | md5.digest(digest); | 521 | md5.digest(digest); |
| 522 | + pad_short_parameter(k1, data.getLengthBytes()); | ||
| 519 | iterate_rc4(digest, sizeof(MD5::Digest), | 523 | iterate_rc4(digest, sizeof(MD5::Digest), |
| 520 | QUtil::unsigned_char_pointer(k1), | 524 | QUtil::unsigned_char_pointer(k1), |
| 521 | data.getLengthBytes(), 20, false); | 525 | data.getLengthBytes(), 20, false); |
| @@ -591,7 +595,10 @@ check_owner_password_V4(std::string& user_password, | @@ -591,7 +595,10 @@ check_owner_password_V4(std::string& user_password, | ||
| 591 | compute_O_rc4_key(user_password, owner_password, data, key); | 595 | compute_O_rc4_key(user_password, owner_password, data, key); |
| 592 | unsigned char O_data[key_bytes]; | 596 | unsigned char O_data[key_bytes]; |
| 593 | memcpy(O_data, QUtil::unsigned_char_pointer(data.getO()), key_bytes); | 597 | memcpy(O_data, QUtil::unsigned_char_pointer(data.getO()), key_bytes); |
| 594 | - iterate_rc4(O_data, key_bytes, key, data.getLengthBytes(), | 598 | + std::string k1(reinterpret_cast<char*>(key), OU_key_bytes_V4); |
| 599 | + pad_short_parameter(k1, data.getLengthBytes()); | ||
| 600 | + iterate_rc4(O_data, key_bytes, QUtil::unsigned_char_pointer(k1), | ||
| 601 | + data.getLengthBytes(), | ||
| 595 | (data.getR() >= 3) ? 20 : 1, true); | 602 | (data.getR() >= 3) ? 20 : 1, true); |
| 596 | std::string new_user_password = | 603 | std::string new_user_password = |
| 597 | std::string(reinterpret_cast<char*>(O_data), key_bytes); | 604 | std::string(reinterpret_cast<char*>(O_data), key_bytes); |
| @@ -886,6 +893,7 @@ QPDF::initializeEncryption() | @@ -886,6 +893,7 @@ QPDF::initializeEncryption() | ||
| 886 | 893 | ||
| 887 | if (V < 5) | 894 | if (V < 5) |
| 888 | { | 895 | { |
| 896 | + // These must be exactly the right number of bytes. | ||
| 889 | pad_short_parameter(O, key_bytes); | 897 | pad_short_parameter(O, key_bytes); |
| 890 | pad_short_parameter(U, key_bytes); | 898 | pad_short_parameter(U, key_bytes); |
| 891 | if (! ((O.length() == key_bytes) && (U.length() == key_bytes))) | 899 | if (! ((O.length() == key_bytes) && (U.length() == key_bytes))) |
| @@ -913,24 +921,12 @@ QPDF::initializeEncryption() | @@ -913,24 +921,12 @@ QPDF::initializeEncryption() | ||
| 913 | UE = encryption_dict.getKey("/UE").getStringValue(); | 921 | UE = encryption_dict.getKey("/UE").getStringValue(); |
| 914 | Perms = encryption_dict.getKey("/Perms").getStringValue(); | 922 | Perms = encryption_dict.getKey("/Perms").getStringValue(); |
| 915 | 923 | ||
| 924 | + // These may be longer than the minimum number of bytes. | ||
| 916 | pad_short_parameter(O, OU_key_bytes_V5); | 925 | pad_short_parameter(O, OU_key_bytes_V5); |
| 917 | pad_short_parameter(U, OU_key_bytes_V5); | 926 | pad_short_parameter(U, OU_key_bytes_V5); |
| 918 | pad_short_parameter(OE, OUE_key_bytes_V5); | 927 | pad_short_parameter(OE, OUE_key_bytes_V5); |
| 919 | pad_short_parameter(UE, OUE_key_bytes_V5); | 928 | pad_short_parameter(UE, OUE_key_bytes_V5); |
| 920 | pad_short_parameter(Perms, Perms_key_bytes_V5); | 929 | pad_short_parameter(Perms, Perms_key_bytes_V5); |
| 921 | - if ((O.length() < OU_key_bytes_V5) || | ||
| 922 | - (U.length() < OU_key_bytes_V5) || | ||
| 923 | - (OE.length() < OUE_key_bytes_V5) || | ||
| 924 | - (UE.length() < OUE_key_bytes_V5) || | ||
| 925 | - (Perms.length() < Perms_key_bytes_V5)) | ||
| 926 | - { | ||
| 927 | - throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), | ||
| 928 | - "encryption dictionary", | ||
| 929 | - this->m->file->getLastOffset(), | ||
| 930 | - "incorrect length for some of" | ||
| 931 | - " /O, /U, /OE, /UE, or /Perms in" | ||
| 932 | - " encryption dictionary"); | ||
| 933 | - } | ||
| 934 | } | 930 | } |
| 935 | 931 | ||
| 936 | int Length = 40; | 932 | int Length = 40; |