Commit e27ac682e00be12e9c420c26c218ee2a01fbf232
1 parent
005675ed
Move encryption parameters into a class
Showing
3 changed files
with
92 additions
and
75 deletions
include/qpdf/QPDF.hh
| ... | ... | @@ -1160,6 +1160,30 @@ class QPDF |
| 1160 | 1160 | std::set<QPDFObjGen>& visited, bool top); |
| 1161 | 1161 | void filterCompressedObjects(std::map<int, int> const& object_stream_data); |
| 1162 | 1162 | |
| 1163 | + class EncryptionParameters | |
| 1164 | + { | |
| 1165 | + friend class QPDF; | |
| 1166 | + public: | |
| 1167 | + EncryptionParameters(); | |
| 1168 | + | |
| 1169 | + private: | |
| 1170 | + bool encrypted; | |
| 1171 | + bool encryption_initialized; | |
| 1172 | + int encryption_V; | |
| 1173 | + int encryption_R; | |
| 1174 | + bool encrypt_metadata; | |
| 1175 | + std::map<std::string, encryption_method_e> crypt_filters; | |
| 1176 | + encryption_method_e cf_stream; | |
| 1177 | + encryption_method_e cf_string; | |
| 1178 | + encryption_method_e cf_file; | |
| 1179 | + std::string provided_password; | |
| 1180 | + std::string user_password; | |
| 1181 | + std::string encryption_key; | |
| 1182 | + std::string cached_object_encryption_key; | |
| 1183 | + int cached_key_objid; | |
| 1184 | + int cached_key_generation; | |
| 1185 | + }; | |
| 1186 | + | |
| 1163 | 1187 | class Members |
| 1164 | 1188 | { |
| 1165 | 1189 | friend class QPDF; |
| ... | ... | @@ -1176,26 +1200,12 @@ class QPDF |
| 1176 | 1200 | PointerHolder<InputSource> file; |
| 1177 | 1201 | std::string last_object_description; |
| 1178 | 1202 | bool provided_password_is_hex_key; |
| 1179 | - bool encrypted; | |
| 1180 | - bool encryption_initialized; | |
| 1181 | 1203 | bool ignore_xref_streams; |
| 1182 | 1204 | bool suppress_warnings; |
| 1183 | 1205 | std::ostream* out_stream; |
| 1184 | 1206 | std::ostream* err_stream; |
| 1185 | 1207 | bool attempt_recovery; |
| 1186 | - int encryption_V; | |
| 1187 | - int encryption_R; | |
| 1188 | - bool encrypt_metadata; | |
| 1189 | - std::map<std::string, encryption_method_e> crypt_filters; | |
| 1190 | - encryption_method_e cf_stream; | |
| 1191 | - encryption_method_e cf_string; | |
| 1192 | - encryption_method_e cf_file; | |
| 1193 | - std::string provided_password; | |
| 1194 | - std::string user_password; | |
| 1195 | - std::string encryption_key; | |
| 1196 | - std::string cached_object_encryption_key; | |
| 1197 | - int cached_key_objid; | |
| 1198 | - int cached_key_generation; | |
| 1208 | + PointerHolder<EncryptionParameters> encp; | |
| 1199 | 1209 | std::string pdf_version; |
| 1200 | 1210 | std::map<QPDFObjGen, QPDFXRefEntry> xref_table; |
| 1201 | 1211 | std::set<int> deleted_objects; | ... | ... |
libqpdf/QPDF.cc
| ... | ... | @@ -74,15 +74,9 @@ QPDF::QPDFVersion() |
| 74 | 74 | return QPDF::qpdf_version; |
| 75 | 75 | } |
| 76 | 76 | |
| 77 | -QPDF::Members::Members() : | |
| 78 | - provided_password_is_hex_key(false), | |
| 77 | +QPDF::EncryptionParameters::EncryptionParameters() : | |
| 79 | 78 | encrypted(false), |
| 80 | 79 | encryption_initialized(false), |
| 81 | - ignore_xref_streams(false), | |
| 82 | - suppress_warnings(false), | |
| 83 | - out_stream(&std::cout), | |
| 84 | - err_stream(&std::cerr), | |
| 85 | - attempt_recovery(true), | |
| 86 | 80 | encryption_V(0), |
| 87 | 81 | encryption_R(0), |
| 88 | 82 | encrypt_metadata(true), |
| ... | ... | @@ -90,7 +84,18 @@ QPDF::Members::Members() : |
| 90 | 84 | cf_string(e_none), |
| 91 | 85 | cf_file(e_none), |
| 92 | 86 | cached_key_objid(0), |
| 93 | - cached_key_generation(0), | |
| 87 | + cached_key_generation(0) | |
| 88 | +{ | |
| 89 | +} | |
| 90 | + | |
| 91 | +QPDF::Members::Members() : | |
| 92 | + provided_password_is_hex_key(false), | |
| 93 | + ignore_xref_streams(false), | |
| 94 | + suppress_warnings(false), | |
| 95 | + out_stream(&std::cout), | |
| 96 | + err_stream(&std::cerr), | |
| 97 | + attempt_recovery(true), | |
| 98 | + encp(new EncryptionParameters), | |
| 94 | 99 | pushed_inherited_attributes_to_pages(false), |
| 95 | 100 | copied_stream_data_provider(0), |
| 96 | 101 | reconstructed_xref(false), |
| ... | ... | @@ -293,7 +298,7 @@ QPDF::parse(char const* password) |
| 293 | 298 | { |
| 294 | 299 | if (password) |
| 295 | 300 | { |
| 296 | - this->m->provided_password = password; | |
| 301 | + this->m->encp->provided_password = password; | |
| 297 | 302 | } |
| 298 | 303 | |
| 299 | 304 | // Find the header anywhere in the first 1024 bytes of the file. |
| ... | ... | @@ -1383,7 +1388,7 @@ QPDF::readObject(PointerHolder<InputSource> input, |
| 1383 | 1388 | bool empty = false; |
| 1384 | 1389 | PointerHolder<StringDecrypter> decrypter_ph; |
| 1385 | 1390 | StringDecrypter* decrypter = 0; |
| 1386 | - if (this->m->encrypted && (! in_object_stream)) | |
| 1391 | + if (this->m->encp->encrypted && (! in_object_stream)) | |
| 1387 | 1392 | { |
| 1388 | 1393 | decrypter_ph = new StringDecrypter(this, objid, generation); |
| 1389 | 1394 | decrypter = decrypter_ph.getPointer(); |
| ... | ... | @@ -2509,7 +2514,7 @@ QPDF::pipeStreamData(int objid, int generation, |
| 2509 | 2514 | { |
| 2510 | 2515 | bool success = false; |
| 2511 | 2516 | std::vector<PointerHolder<Pipeline> > to_delete; |
| 2512 | - if (this->m->encrypted) | |
| 2517 | + if (this->m->encp->encrypted) | |
| 2513 | 2518 | { |
| 2514 | 2519 | decryptStream(pipeline, objid, generation, stream_dict, to_delete); |
| 2515 | 2520 | } | ... | ... |
libqpdf/QPDF_encryption.cc
| ... | ... | @@ -769,9 +769,9 @@ QPDF::interpretCF(QPDFObjectHandle cf) |
| 769 | 769 | if (cf.isName()) |
| 770 | 770 | { |
| 771 | 771 | std::string filter = cf.getName(); |
| 772 | - if (this->m->crypt_filters.count(filter) != 0) | |
| 772 | + if (this->m->encp->crypt_filters.count(filter) != 0) | |
| 773 | 773 | { |
| 774 | - return this->m->crypt_filters[filter]; | |
| 774 | + return this->m->encp->crypt_filters[filter]; | |
| 775 | 775 | } |
| 776 | 776 | else if (filter == "/Identity") |
| 777 | 777 | { |
| ... | ... | @@ -792,11 +792,11 @@ QPDF::interpretCF(QPDFObjectHandle cf) |
| 792 | 792 | void |
| 793 | 793 | QPDF::initializeEncryption() |
| 794 | 794 | { |
| 795 | - if (this->m->encryption_initialized) | |
| 795 | + if (this->m->encp->encryption_initialized) | |
| 796 | 796 | { |
| 797 | 797 | return; |
| 798 | 798 | } |
| 799 | - this->m->encryption_initialized = true; | |
| 799 | + this->m->encp->encryption_initialized = true; | |
| 800 | 800 | |
| 801 | 801 | // After we initialize encryption parameters, we must used stored |
| 802 | 802 | // key information and never look at /Encrypt again. Otherwise, |
| ... | ... | @@ -811,7 +811,7 @@ QPDF::initializeEncryption() |
| 811 | 811 | // Go ahead and set this->m->encrypted here. That way, isEncrypted |
| 812 | 812 | // will return true even if there were errors reading the |
| 813 | 813 | // encryption dictionary. |
| 814 | - this->m->encrypted = true; | |
| 814 | + this->m->encp->encrypted = true; | |
| 815 | 815 | |
| 816 | 816 | std::string id1; |
| 817 | 817 | QPDFObjectHandle id_obj = this->m->trailer.getKey("/ID"); |
| ... | ... | @@ -885,8 +885,8 @@ QPDF::initializeEncryption() |
| 885 | 885 | QUtil::int_to_string(V) + " (max 5)"); |
| 886 | 886 | } |
| 887 | 887 | |
| 888 | - this->m->encryption_V = V; | |
| 889 | - this->m->encryption_R = R; | |
| 888 | + this->m->encp->encryption_V = V; | |
| 889 | + this->m->encp->encryption_R = R; | |
| 890 | 890 | |
| 891 | 891 | // OE, UE, and Perms are only present if V >= 5. |
| 892 | 892 | std::string OE; |
| ... | ... | @@ -949,10 +949,10 @@ QPDF::initializeEncryption() |
| 949 | 949 | } |
| 950 | 950 | } |
| 951 | 951 | |
| 952 | - this->m->encrypt_metadata = true; | |
| 952 | + this->m->encp->encrypt_metadata = true; | |
| 953 | 953 | if ((V >= 4) && (encryption_dict.getKey("/EncryptMetadata").isBool())) |
| 954 | 954 | { |
| 955 | - this->m->encrypt_metadata = | |
| 955 | + this->m->encp->encrypt_metadata = | |
| 956 | 956 | encryption_dict.getKey("/EncryptMetadata").getBoolValue(); |
| 957 | 957 | } |
| 958 | 958 | |
| ... | ... | @@ -993,40 +993,41 @@ QPDF::initializeEncryption() |
| 993 | 993 | method = e_unknown; |
| 994 | 994 | } |
| 995 | 995 | } |
| 996 | - this->m->crypt_filters[filter] = method; | |
| 996 | + this->m->encp->crypt_filters[filter] = method; | |
| 997 | 997 | } |
| 998 | 998 | } |
| 999 | 999 | |
| 1000 | 1000 | QPDFObjectHandle StmF = encryption_dict.getKey("/StmF"); |
| 1001 | 1001 | QPDFObjectHandle StrF = encryption_dict.getKey("/StrF"); |
| 1002 | 1002 | QPDFObjectHandle EFF = encryption_dict.getKey("/EFF"); |
| 1003 | - this->m->cf_stream = interpretCF(StmF); | |
| 1004 | - this->m->cf_string = interpretCF(StrF); | |
| 1003 | + this->m->encp->cf_stream = interpretCF(StmF); | |
| 1004 | + this->m->encp->cf_string = interpretCF(StrF); | |
| 1005 | 1005 | if (EFF.isName()) |
| 1006 | 1006 | { |
| 1007 | - this->m->cf_file = interpretCF(EFF); | |
| 1007 | + this->m->encp->cf_file = interpretCF(EFF); | |
| 1008 | 1008 | } |
| 1009 | 1009 | else |
| 1010 | 1010 | { |
| 1011 | - this->m->cf_file = this->m->cf_stream; | |
| 1011 | + this->m->encp->cf_file = this->m->encp->cf_stream; | |
| 1012 | 1012 | } |
| 1013 | 1013 | } |
| 1014 | 1014 | |
| 1015 | 1015 | EncryptionData data(V, R, Length / 8, P, O, U, OE, UE, Perms, |
| 1016 | - id1, this->m->encrypt_metadata); | |
| 1016 | + id1, this->m->encp->encrypt_metadata); | |
| 1017 | 1017 | if (this->m->provided_password_is_hex_key) |
| 1018 | 1018 | { |
| 1019 | 1019 | // ignore passwords in file |
| 1020 | 1020 | } |
| 1021 | 1021 | else if (check_owner_password( |
| 1022 | - this->m->user_password, this->m->provided_password, data)) | |
| 1022 | + this->m->encp->user_password, | |
| 1023 | + this->m->encp->provided_password, data)) | |
| 1023 | 1024 | { |
| 1024 | 1025 | // password supplied was owner password; user_password has |
| 1025 | 1026 | // been initialized for V < 5 |
| 1026 | 1027 | } |
| 1027 | - else if (check_user_password(this->m->provided_password, data)) | |
| 1028 | + else if (check_user_password(this->m->encp->provided_password, data)) | |
| 1028 | 1029 | { |
| 1029 | - this->m->user_password = this->m->provided_password; | |
| 1030 | + this->m->encp->user_password = this->m->encp->provided_password; | |
| 1030 | 1031 | } |
| 1031 | 1032 | else |
| 1032 | 1033 | { |
| ... | ... | @@ -1036,15 +1037,16 @@ QPDF::initializeEncryption() |
| 1036 | 1037 | |
| 1037 | 1038 | if (this->m->provided_password_is_hex_key) |
| 1038 | 1039 | { |
| 1039 | - this->m->encryption_key = QUtil::hex_decode(this->m->provided_password); | |
| 1040 | + this->m->encp->encryption_key = | |
| 1041 | + QUtil::hex_decode(this->m->encp->provided_password); | |
| 1040 | 1042 | } |
| 1041 | 1043 | else if (V < 5) |
| 1042 | 1044 | { |
| 1043 | 1045 | // For V < 5, the user password is encrypted with the owner |
| 1044 | 1046 | // password, and the user password is always used for |
| 1045 | 1047 | // computing the encryption key. |
| 1046 | - this->m->encryption_key = compute_encryption_key( | |
| 1047 | - this->m->user_password, data); | |
| 1048 | + this->m->encp->encryption_key = compute_encryption_key( | |
| 1049 | + this->m->encp->user_password, data); | |
| 1048 | 1050 | } |
| 1049 | 1051 | else |
| 1050 | 1052 | { |
| ... | ... | @@ -1052,8 +1054,8 @@ QPDF::initializeEncryption() |
| 1052 | 1054 | // compute the encryption key, and neither password can be |
| 1053 | 1055 | // used to recover the other. |
| 1054 | 1056 | bool perms_valid; |
| 1055 | - this->m->encryption_key = recover_encryption_key_with_password( | |
| 1056 | - this->m->provided_password, data, perms_valid); | |
| 1057 | + this->m->encp->encryption_key = recover_encryption_key_with_password( | |
| 1058 | + this->m->encp->provided_password, data, perms_valid); | |
| 1057 | 1059 | if (! perms_valid) |
| 1058 | 1060 | { |
| 1059 | 1061 | warn(QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), |
| ... | ... | @@ -1068,24 +1070,24 @@ QPDF::initializeEncryption() |
| 1068 | 1070 | std::string |
| 1069 | 1071 | QPDF::getKeyForObject(int objid, int generation, bool use_aes) |
| 1070 | 1072 | { |
| 1071 | - if (! this->m->encrypted) | |
| 1073 | + if (! this->m->encp->encrypted) | |
| 1072 | 1074 | { |
| 1073 | 1075 | throw std::logic_error( |
| 1074 | 1076 | "request for encryption key in non-encrypted PDF"); |
| 1075 | 1077 | } |
| 1076 | 1078 | |
| 1077 | - if (! ((objid == this->m->cached_key_objid) && | |
| 1078 | - (generation == this->m->cached_key_generation))) | |
| 1079 | + if (! ((objid == this->m->encp->cached_key_objid) && | |
| 1080 | + (generation == this->m->encp->cached_key_generation))) | |
| 1079 | 1081 | { |
| 1080 | - this->m->cached_object_encryption_key = | |
| 1081 | - compute_data_key(this->m->encryption_key, objid, generation, | |
| 1082 | - use_aes, this->m->encryption_V, | |
| 1083 | - this->m->encryption_R); | |
| 1084 | - this->m->cached_key_objid = objid; | |
| 1085 | - this->m->cached_key_generation = generation; | |
| 1082 | + this->m->encp->cached_object_encryption_key = | |
| 1083 | + compute_data_key(this->m->encp->encryption_key, objid, generation, | |
| 1084 | + use_aes, this->m->encp->encryption_V, | |
| 1085 | + this->m->encp->encryption_R); | |
| 1086 | + this->m->encp->cached_key_objid = objid; | |
| 1087 | + this->m->encp->cached_key_generation = generation; | |
| 1086 | 1088 | } |
| 1087 | 1089 | |
| 1088 | - return this->m->cached_object_encryption_key; | |
| 1090 | + return this->m->encp->cached_object_encryption_key; | |
| 1089 | 1091 | } |
| 1090 | 1092 | |
| 1091 | 1093 | void |
| ... | ... | @@ -1096,9 +1098,9 @@ QPDF::decryptString(std::string& str, int objid, int generation) |
| 1096 | 1098 | return; |
| 1097 | 1099 | } |
| 1098 | 1100 | bool use_aes = false; |
| 1099 | - if (this->m->encryption_V >= 4) | |
| 1101 | + if (this->m->encp->encryption_V >= 4) | |
| 1100 | 1102 | { |
| 1101 | - switch (this->m->cf_string) | |
| 1103 | + switch (this->m->encp->cf_string) | |
| 1102 | 1104 | { |
| 1103 | 1105 | case e_none: |
| 1104 | 1106 | return; |
| ... | ... | @@ -1123,7 +1125,7 @@ QPDF::decryptString(std::string& str, int objid, int generation) |
| 1123 | 1125 | " strings may be decrypted improperly")); |
| 1124 | 1126 | // To avoid repeated warnings, reset cf_string. Assume |
| 1125 | 1127 | // we'd want to use AES if V == 4. |
| 1126 | - this->m->cf_string = e_aes; | |
| 1128 | + this->m->encp->cf_string = e_aes; | |
| 1127 | 1129 | use_aes = true; |
| 1128 | 1130 | break; |
| 1129 | 1131 | } |
| ... | ... | @@ -1188,7 +1190,7 @@ QPDF::decryptStream(Pipeline*& pipeline, int objid, int generation, |
| 1188 | 1190 | return; |
| 1189 | 1191 | } |
| 1190 | 1192 | bool use_aes = false; |
| 1191 | - if (this->m->encryption_V >= 4) | |
| 1193 | + if (this->m->encp->encryption_V >= 4) | |
| 1192 | 1194 | { |
| 1193 | 1195 | encryption_method_e method = e_unknown; |
| 1194 | 1196 | std::string method_source = "/StmF from /Encrypt dictionary"; |
| ... | ... | @@ -1239,7 +1241,7 @@ QPDF::decryptStream(Pipeline*& pipeline, int objid, int generation, |
| 1239 | 1241 | |
| 1240 | 1242 | if (method == e_unknown) |
| 1241 | 1243 | { |
| 1242 | - if ((! this->m->encrypt_metadata) && (type == "/Metadata")) | |
| 1244 | + if ((! this->m->encp->encrypt_metadata) && (type == "/Metadata")) | |
| 1243 | 1245 | { |
| 1244 | 1246 | QTC::TC("qpdf", "QPDF_encryption cleartext metadata"); |
| 1245 | 1247 | method = e_none; |
| ... | ... | @@ -1249,11 +1251,11 @@ QPDF::decryptStream(Pipeline*& pipeline, int objid, int generation, |
| 1249 | 1251 | if (this->m->attachment_streams.count( |
| 1250 | 1252 | QPDFObjGen(objid, generation)) > 0) |
| 1251 | 1253 | { |
| 1252 | - method = this->m->cf_file; | |
| 1254 | + method = this->m->encp->cf_file; | |
| 1253 | 1255 | } |
| 1254 | 1256 | else |
| 1255 | 1257 | { |
| 1256 | - method = this->m->cf_stream; | |
| 1258 | + method = this->m->encp->cf_stream; | |
| 1257 | 1259 | } |
| 1258 | 1260 | } |
| 1259 | 1261 | } |
| ... | ... | @@ -1285,7 +1287,7 @@ QPDF::decryptStream(Pipeline*& pipeline, int objid, int generation, |
| 1285 | 1287 | " streams may be decrypted improperly")); |
| 1286 | 1288 | // To avoid repeated warnings, reset cf_stream. Assume |
| 1287 | 1289 | // we'd want to use AES if V == 4. |
| 1288 | - this->m->cf_stream = e_aes; | |
| 1290 | + this->m->encp->cf_stream = e_aes; | |
| 1289 | 1291 | break; |
| 1290 | 1292 | } |
| 1291 | 1293 | } |
| ... | ... | @@ -1349,13 +1351,13 @@ QPDF::compute_encryption_parameters_V5( |
| 1349 | 1351 | std::string const& |
| 1350 | 1352 | QPDF::getPaddedUserPassword() const |
| 1351 | 1353 | { |
| 1352 | - return this->m->user_password; | |
| 1354 | + return this->m->encp->user_password; | |
| 1353 | 1355 | } |
| 1354 | 1356 | |
| 1355 | 1357 | std::string |
| 1356 | 1358 | QPDF::getTrimmedUserPassword() const |
| 1357 | 1359 | { |
| 1358 | - std::string result = this->m->user_password; | |
| 1360 | + std::string result = this->m->encp->user_password; | |
| 1359 | 1361 | trim_user_password(result); |
| 1360 | 1362 | return result; |
| 1361 | 1363 | } |
| ... | ... | @@ -1363,13 +1365,13 @@ QPDF::getTrimmedUserPassword() const |
| 1363 | 1365 | std::string |
| 1364 | 1366 | QPDF::getEncryptionKey() const |
| 1365 | 1367 | { |
| 1366 | - return this->m->encryption_key; | |
| 1368 | + return this->m->encp->encryption_key; | |
| 1367 | 1369 | } |
| 1368 | 1370 | |
| 1369 | 1371 | bool |
| 1370 | 1372 | QPDF::isEncrypted() const |
| 1371 | 1373 | { |
| 1372 | - return this->m->encrypted; | |
| 1374 | + return this->m->encp->encrypted; | |
| 1373 | 1375 | } |
| 1374 | 1376 | |
| 1375 | 1377 | bool |
| ... | ... | @@ -1386,7 +1388,7 @@ QPDF::isEncrypted(int& R, int& P, int& V, |
| 1386 | 1388 | encryption_method_e& string_method, |
| 1387 | 1389 | encryption_method_e& file_method) |
| 1388 | 1390 | { |
| 1389 | - if (this->m->encrypted) | |
| 1391 | + if (this->m->encp->encrypted) | |
| 1390 | 1392 | { |
| 1391 | 1393 | QPDFObjectHandle trailer = getTrailer(); |
| 1392 | 1394 | QPDFObjectHandle encrypt = trailer.getKey("/Encrypt"); |
| ... | ... | @@ -1396,9 +1398,9 @@ QPDF::isEncrypted(int& R, int& P, int& V, |
| 1396 | 1398 | P = Pkey.getIntValue(); |
| 1397 | 1399 | R = Rkey.getIntValue(); |
| 1398 | 1400 | V = Vkey.getIntValue(); |
| 1399 | - stream_method = this->m->cf_stream; | |
| 1400 | - string_method = this->m->cf_string; | |
| 1401 | - file_method = this->m->cf_file; | |
| 1401 | + stream_method = this->m->encp->cf_stream; | |
| 1402 | + string_method = this->m->encp->cf_string; | |
| 1403 | + file_method = this->m->encp->cf_file; | |
| 1402 | 1404 | return true; |
| 1403 | 1405 | } |
| 1404 | 1406 | else | ... | ... |