Commit 8417be173db9c9e7699d3902a35cae01b9683e06
1 parent
34142a6c
Refactor encryption permissions handling by replacing integer-based logic with `…
…std::bitset`, reorganizing related methods, and simplifying access to improve clarity and maintainability.
Showing
3 changed files
with
66 additions
and
110 deletions
include/qpdf/QPDF.hh
| @@ -23,6 +23,7 @@ | @@ -23,6 +23,7 @@ | ||
| 23 | #include <qpdf/DLL.h> | 23 | #include <qpdf/DLL.h> |
| 24 | #include <qpdf/Types.h> | 24 | #include <qpdf/Types.h> |
| 25 | 25 | ||
| 26 | +#include <bitset> | ||
| 26 | #include <cstdio> | 27 | #include <cstdio> |
| 27 | #include <functional> | 28 | #include <functional> |
| 28 | #include <iostream> | 29 | #include <iostream> |
| @@ -465,7 +466,7 @@ class QPDF | @@ -465,7 +466,7 @@ class QPDF | ||
| 465 | V(V), | 466 | V(V), |
| 466 | R(R), | 467 | R(R), |
| 467 | Length_bytes(Length_bytes), | 468 | Length_bytes(Length_bytes), |
| 468 | - P(P), | 469 | + P(static_cast<unsigned long long>(P)), |
| 469 | O(O), | 470 | O(O), |
| 470 | U(U), | 471 | U(U), |
| 471 | OE(OE), | 472 | OE(OE), |
| @@ -480,6 +481,8 @@ class QPDF | @@ -480,6 +481,8 @@ class QPDF | ||
| 480 | int getR() const; | 481 | int getR() const; |
| 481 | int getLengthBytes() const; | 482 | int getLengthBytes() const; |
| 482 | int getP() const; | 483 | int getP() const; |
| 484 | + // Bits in P are numbered from 1 as in the PDF spec. | ||
| 485 | + bool getP(size_t bit) const; | ||
| 483 | std::string const& getO() const; | 486 | std::string const& getO() const; |
| 484 | std::string const& getU() const; | 487 | std::string const& getU() const; |
| 485 | std::string const& getOE() const; | 488 | std::string const& getOE() const; |
| @@ -487,7 +490,8 @@ class QPDF | @@ -487,7 +490,8 @@ class QPDF | ||
| 487 | std::string const& getPerms() const; | 490 | std::string const& getPerms() const; |
| 488 | std::string const& getId1() const; | 491 | std::string const& getId1() const; |
| 489 | bool getEncryptMetadata() const; | 492 | bool getEncryptMetadata() const; |
| 490 | - | 493 | + // Bits in P are numbered from 1 as in the PDF spec. |
| 494 | + void setP(size_t bit, bool val); | ||
| 491 | void setO(std::string const&); | 495 | void setO(std::string const&); |
| 492 | void setU(std::string const&); | 496 | void setU(std::string const&); |
| 493 | void setV5EncryptionParameters( | 497 | void setV5EncryptionParameters( |
| @@ -562,7 +566,7 @@ class QPDF | @@ -562,7 +566,7 @@ class QPDF | ||
| 562 | int V; | 566 | int V; |
| 563 | int R; | 567 | int R; |
| 564 | int Length_bytes; | 568 | int Length_bytes; |
| 565 | - int P; | 569 | + std::bitset<32> P{0xfffffffc}; // Specification always requires bits 1 and 2 to be cleared. |
| 566 | std::string O; | 570 | std::string O; |
| 567 | std::string U; | 571 | std::string U; |
| 568 | std::string OE; | 572 | std::string OE; |
libqpdf/QPDF_encryption.cc
| @@ -51,7 +51,21 @@ QPDF::EncryptionData::getLengthBytes() const | @@ -51,7 +51,21 @@ QPDF::EncryptionData::getLengthBytes() const | ||
| 51 | int | 51 | int |
| 52 | QPDF::EncryptionData::getP() const | 52 | QPDF::EncryptionData::getP() const |
| 53 | { | 53 | { |
| 54 | - return this->P; | 54 | + return static_cast<int>(P.to_ullong()); |
| 55 | +} | ||
| 56 | + | ||
| 57 | +bool | ||
| 58 | +QPDF::EncryptionData::getP(size_t bit) const | ||
| 59 | +{ | ||
| 60 | + qpdf_assert_debug(bit); | ||
| 61 | + return P.test(bit - 1); | ||
| 62 | +} | ||
| 63 | + | ||
| 64 | +bool | ||
| 65 | +QPDF::EncryptionParameters::P(size_t bit) const | ||
| 66 | +{ | ||
| 67 | + qpdf_assert_debug(bit); | ||
| 68 | + return P_.test(bit - 1); | ||
| 55 | } | 69 | } |
| 56 | 70 | ||
| 57 | std::string const& | 71 | std::string const& |
| @@ -109,6 +123,13 @@ QPDF::EncryptionData::setU(std::string const& U) | @@ -109,6 +123,13 @@ QPDF::EncryptionData::setU(std::string const& U) | ||
| 109 | } | 123 | } |
| 110 | 124 | ||
| 111 | void | 125 | void |
| 126 | +QPDF::EncryptionData::setP(size_t bit, bool val) | ||
| 127 | +{ | ||
| 128 | + qpdf_assert_debug(bit); | ||
| 129 | + P.set(bit - 1, val); | ||
| 130 | +} | ||
| 131 | + | ||
| 132 | +void | ||
| 112 | QPDF::EncryptionData::setV5EncryptionParameters( | 133 | QPDF::EncryptionData::setV5EncryptionParameters( |
| 113 | std::string const& O, | 134 | std::string const& O, |
| 114 | std::string const& OE, | 135 | std::string const& OE, |
| @@ -782,7 +803,7 @@ QPDF::EncryptionParameters::initialize(QPDF& qpdf) | @@ -782,7 +803,7 @@ QPDF::EncryptionParameters::initialize(QPDF& qpdf) | ||
| 782 | int R = encryption_dict.getKey("/R").getIntValueAsInt(); | 803 | int R = encryption_dict.getKey("/R").getIntValueAsInt(); |
| 783 | std::string O = encryption_dict.getKey("/O").getStringValue(); | 804 | std::string O = encryption_dict.getKey("/O").getStringValue(); |
| 784 | std::string U = encryption_dict.getKey("/U").getStringValue(); | 805 | std::string U = encryption_dict.getKey("/U").getStringValue(); |
| 785 | - int P = static_cast<int>(encryption_dict.getKey("/P").getIntValue()); | 806 | + int p = static_cast<int>(encryption_dict.getKey("/P").getIntValue()); |
| 786 | 807 | ||
| 787 | // If supporting new encryption R/V values, remember to update error message inside this if | 808 | // If supporting new encryption R/V values, remember to update error message inside this if |
| 788 | // statement. | 809 | // statement. |
| @@ -792,9 +813,9 @@ QPDF::EncryptionParameters::initialize(QPDF& qpdf) | @@ -792,9 +813,9 @@ QPDF::EncryptionParameters::initialize(QPDF& qpdf) | ||
| 792 | " (max 6), V = " + std::to_string(V) + " (max 5)"); | 813 | " (max 6), V = " + std::to_string(V) + " (max 5)"); |
| 793 | } | 814 | } |
| 794 | 815 | ||
| 795 | - encryption_P = P; | 816 | + P_ = std::bitset<32>(static_cast<unsigned long long>(p)); |
| 796 | encryption_V = V; | 817 | encryption_V = V; |
| 797 | - encryption_R = R; | 818 | + R_ = R; |
| 798 | 819 | ||
| 799 | // OE, UE, and Perms are only present if V >= 5. | 820 | // OE, UE, and Perms are only present if V >= 5. |
| 800 | std::string OE; | 821 | std::string OE; |
| @@ -891,7 +912,7 @@ QPDF::EncryptionParameters::initialize(QPDF& qpdf) | @@ -891,7 +912,7 @@ QPDF::EncryptionParameters::initialize(QPDF& qpdf) | ||
| 891 | } | 912 | } |
| 892 | } | 913 | } |
| 893 | 914 | ||
| 894 | - EncryptionData data(V, R, Length / 8, P, O, U, OE, UE, Perms, id1, encrypt_metadata); | 915 | + EncryptionData data(V, R, Length / 8, p, O, U, OE, UE, Perms, id1, encrypt_metadata); |
| 895 | if (qm.provided_password_is_hex_key) { | 916 | if (qm.provided_password_is_hex_key) { |
| 896 | // ignore passwords in file | 917 | // ignore passwords in file |
| 897 | encryption_key = QUtil::hex_decode(provided_password); | 918 | encryption_key = QUtil::hex_decode(provided_password); |
| @@ -942,12 +963,7 @@ QPDF::getKeyForObject(std::shared_ptr<EncryptionParameters> encp, QPDFObjGen og, | @@ -942,12 +963,7 @@ QPDF::getKeyForObject(std::shared_ptr<EncryptionParameters> encp, QPDFObjGen og, | ||
| 942 | 963 | ||
| 943 | if (og != encp->cached_key_og) { | 964 | if (og != encp->cached_key_og) { |
| 944 | encp->cached_object_encryption_key = compute_data_key( | 965 | encp->cached_object_encryption_key = compute_data_key( |
| 945 | - encp->encryption_key, | ||
| 946 | - og.getObj(), | ||
| 947 | - og.getGen(), | ||
| 948 | - use_aes, | ||
| 949 | - encp->encryption_V, | ||
| 950 | - encp->encryption_R); | 966 | + encp->encryption_key, og.getObj(), og.getGen(), use_aes, encp->encryption_V, encp->R()); |
| 951 | encp->cached_key_og = og; | 967 | encp->cached_key_og = og; |
| 952 | } | 968 | } |
| 953 | 969 | ||
| @@ -1239,8 +1255,8 @@ QPDF::isEncrypted(int& R, int& P) | @@ -1239,8 +1255,8 @@ QPDF::isEncrypted(int& R, int& P) | ||
| 1239 | if (!m->encp->encrypted) { | 1255 | if (!m->encp->encrypted) { |
| 1240 | return false; | 1256 | return false; |
| 1241 | } | 1257 | } |
| 1242 | - P = m->encp->encryption_P; | ||
| 1243 | - R = m->encp->encryption_R; | 1258 | + P = m->encp->P(); |
| 1259 | + R = m->encp->R(); | ||
| 1244 | return true; | 1260 | return true; |
| 1245 | } | 1261 | } |
| 1246 | 1262 | ||
| @@ -1256,8 +1272,8 @@ QPDF::isEncrypted( | @@ -1256,8 +1272,8 @@ QPDF::isEncrypted( | ||
| 1256 | if (!m->encp->encrypted) { | 1272 | if (!m->encp->encrypted) { |
| 1257 | return false; | 1273 | return false; |
| 1258 | } | 1274 | } |
| 1259 | - P = m->encp->encryption_P; | ||
| 1260 | - R = m->encp->encryption_R; | 1275 | + P = m->encp->P(); |
| 1276 | + R = m->encp->R(); | ||
| 1261 | V = m->encp->encryption_V; | 1277 | V = m->encp->encryption_V; |
| 1262 | stream_method = m->encp->cf_stream; | 1278 | stream_method = m->encp->cf_stream; |
| 1263 | string_method = m->encp->cf_string; | 1279 | string_method = m->encp->cf_string; |
| @@ -1277,135 +1293,57 @@ QPDF::userPasswordMatched() const | @@ -1277,135 +1293,57 @@ QPDF::userPasswordMatched() const | ||
| 1277 | return m->encp->user_password_matched; | 1293 | return m->encp->user_password_matched; |
| 1278 | } | 1294 | } |
| 1279 | 1295 | ||
| 1280 | -static bool | ||
| 1281 | -is_bit_set(int P, int bit) | ||
| 1282 | -{ | ||
| 1283 | - // Bits in P are numbered from 1 in the spec | ||
| 1284 | - return ((P & (1 << (bit - 1))) != 0); | ||
| 1285 | -} | ||
| 1286 | - | ||
| 1287 | bool | 1296 | bool |
| 1288 | QPDF::allowAccessibility() | 1297 | QPDF::allowAccessibility() |
| 1289 | { | 1298 | { |
| 1290 | - int R = 0; | ||
| 1291 | - int P = 0; | ||
| 1292 | - bool status = true; | ||
| 1293 | - if (isEncrypted(R, P)) { | ||
| 1294 | - if (R < 3) { | ||
| 1295 | - status = is_bit_set(P, 5); | ||
| 1296 | - } else { | ||
| 1297 | - status = is_bit_set(P, 10); | ||
| 1298 | - } | ||
| 1299 | - } | ||
| 1300 | - return status; | 1299 | + return m->encp->R() < 3 ? m->encp->P(5) : m->encp->P(10); |
| 1301 | } | 1300 | } |
| 1302 | 1301 | ||
| 1303 | bool | 1302 | bool |
| 1304 | QPDF::allowExtractAll() | 1303 | QPDF::allowExtractAll() |
| 1305 | { | 1304 | { |
| 1306 | - int R = 0; | ||
| 1307 | - int P = 0; | ||
| 1308 | - bool status = true; | ||
| 1309 | - if (isEncrypted(R, P)) { | ||
| 1310 | - status = is_bit_set(P, 5); | ||
| 1311 | - } | ||
| 1312 | - return status; | 1305 | + return m->encp->P(5); |
| 1313 | } | 1306 | } |
| 1314 | 1307 | ||
| 1315 | bool | 1308 | bool |
| 1316 | QPDF::allowPrintLowRes() | 1309 | QPDF::allowPrintLowRes() |
| 1317 | { | 1310 | { |
| 1318 | - int R = 0; | ||
| 1319 | - int P = 0; | ||
| 1320 | - bool status = true; | ||
| 1321 | - if (isEncrypted(R, P)) { | ||
| 1322 | - status = is_bit_set(P, 3); | ||
| 1323 | - } | ||
| 1324 | - return status; | 1311 | + return m->encp->P(3); |
| 1325 | } | 1312 | } |
| 1326 | 1313 | ||
| 1327 | bool | 1314 | bool |
| 1328 | QPDF::allowPrintHighRes() | 1315 | QPDF::allowPrintHighRes() |
| 1329 | { | 1316 | { |
| 1330 | - int R = 0; | ||
| 1331 | - int P = 0; | ||
| 1332 | - bool status = true; | ||
| 1333 | - if (isEncrypted(R, P)) { | ||
| 1334 | - status = is_bit_set(P, 3); | ||
| 1335 | - if ((R >= 3) && (!is_bit_set(P, 12))) { | ||
| 1336 | - status = false; | ||
| 1337 | - } | ||
| 1338 | - } | ||
| 1339 | - return status; | 1317 | + return allowPrintLowRes() && (m->encp->R() < 3 ? true : m->encp->P(12)); |
| 1340 | } | 1318 | } |
| 1341 | 1319 | ||
| 1342 | bool | 1320 | bool |
| 1343 | QPDF::allowModifyAssembly() | 1321 | QPDF::allowModifyAssembly() |
| 1344 | { | 1322 | { |
| 1345 | - int R = 0; | ||
| 1346 | - int P = 0; | ||
| 1347 | - bool status = true; | ||
| 1348 | - if (isEncrypted(R, P)) { | ||
| 1349 | - if (R < 3) { | ||
| 1350 | - status = is_bit_set(P, 4); | ||
| 1351 | - } else { | ||
| 1352 | - status = is_bit_set(P, 11); | ||
| 1353 | - } | ||
| 1354 | - } | ||
| 1355 | - return status; | 1323 | + return m->encp->R() < 3 ? m->encp->P(4) : m->encp->P(11); |
| 1356 | } | 1324 | } |
| 1357 | 1325 | ||
| 1358 | bool | 1326 | bool |
| 1359 | QPDF::allowModifyForm() | 1327 | QPDF::allowModifyForm() |
| 1360 | { | 1328 | { |
| 1361 | - int R = 0; | ||
| 1362 | - int P = 0; | ||
| 1363 | - bool status = true; | ||
| 1364 | - if (isEncrypted(R, P)) { | ||
| 1365 | - if (R < 3) { | ||
| 1366 | - status = is_bit_set(P, 6); | ||
| 1367 | - } else { | ||
| 1368 | - status = is_bit_set(P, 9); | ||
| 1369 | - } | ||
| 1370 | - } | ||
| 1371 | - return status; | 1329 | + return m->encp->R() < 3 ? m->encp->P(6) : m->encp->P(9); |
| 1372 | } | 1330 | } |
| 1373 | 1331 | ||
| 1374 | bool | 1332 | bool |
| 1375 | QPDF::allowModifyAnnotation() | 1333 | QPDF::allowModifyAnnotation() |
| 1376 | { | 1334 | { |
| 1377 | - int R = 0; | ||
| 1378 | - int P = 0; | ||
| 1379 | - bool status = true; | ||
| 1380 | - if (isEncrypted(R, P)) { | ||
| 1381 | - status = is_bit_set(P, 6); | ||
| 1382 | - } | ||
| 1383 | - return status; | 1335 | + return m->encp->P(6); |
| 1384 | } | 1336 | } |
| 1385 | 1337 | ||
| 1386 | bool | 1338 | bool |
| 1387 | QPDF::allowModifyOther() | 1339 | QPDF::allowModifyOther() |
| 1388 | { | 1340 | { |
| 1389 | - int R = 0; | ||
| 1390 | - int P = 0; | ||
| 1391 | - bool status = true; | ||
| 1392 | - if (isEncrypted(R, P)) { | ||
| 1393 | - status = is_bit_set(P, 4); | ||
| 1394 | - } | ||
| 1395 | - return status; | 1341 | + return m->encp->P(4); |
| 1396 | } | 1342 | } |
| 1397 | 1343 | ||
| 1398 | bool | 1344 | bool |
| 1399 | QPDF::allowModifyAll() | 1345 | QPDF::allowModifyAll() |
| 1400 | { | 1346 | { |
| 1401 | - int R = 0; | ||
| 1402 | - int P = 0; | ||
| 1403 | - bool status = true; | ||
| 1404 | - if (isEncrypted(R, P)) { | ||
| 1405 | - status = (is_bit_set(P, 4) && is_bit_set(P, 6)); | ||
| 1406 | - if (R >= 3) { | ||
| 1407 | - status = status && (is_bit_set(P, 9) && is_bit_set(P, 11)); | ||
| 1408 | - } | ||
| 1409 | - } | ||
| 1410 | - return status; | 1347 | + return allowModifyAnnotation() && allowModifyOther() && |
| 1348 | + (m->encp->R() < 3 ? true : allowModifyForm() && allowModifyAssembly()); | ||
| 1411 | } | 1349 | } |
libqpdf/qpdf/QPDF_private.hh
| @@ -187,16 +187,30 @@ class QPDF::EncryptionParameters | @@ -187,16 +187,30 @@ class QPDF::EncryptionParameters | ||
| 187 | public: | 187 | public: |
| 188 | EncryptionParameters() = default; | 188 | EncryptionParameters() = default; |
| 189 | 189 | ||
| 190 | - encryption_method_e interpretCF(QPDFObjectHandle const& cf) const; | 190 | + int |
| 191 | + P() const | ||
| 192 | + { | ||
| 193 | + return static_cast<int>(P_.to_ullong()); | ||
| 194 | + } | ||
| 195 | + | ||
| 196 | + // Bits in P are numbered from 1 as in the PDF spec. | ||
| 197 | + bool P(size_t bit) const; | ||
| 198 | + | ||
| 199 | + int | ||
| 200 | + R() | ||
| 201 | + { | ||
| 202 | + return R_; | ||
| 203 | + } | ||
| 191 | 204 | ||
| 192 | - private: | ||
| 193 | void initialize(QPDF& qpdf); | 205 | void initialize(QPDF& qpdf); |
| 206 | + encryption_method_e interpretCF(QPDFObjectHandle const& cf) const; | ||
| 194 | 207 | ||
| 208 | + private: | ||
| 195 | bool encrypted{false}; | 209 | bool encrypted{false}; |
| 196 | bool encryption_initialized{false}; | 210 | bool encryption_initialized{false}; |
| 197 | - int encryption_P{0}; | 211 | + std::bitset<32> P_{0xfffffffc}; // Specification always requires bits 1 and 2 to be cleared. |
| 198 | int encryption_V{0}; | 212 | int encryption_V{0}; |
| 199 | - int encryption_R{0}; | 213 | + int R_{0}; |
| 200 | bool encrypt_metadata{true}; | 214 | bool encrypt_metadata{true}; |
| 201 | std::map<std::string, encryption_method_e> crypt_filters; | 215 | std::map<std::string, encryption_method_e> crypt_filters; |
| 202 | encryption_method_e cf_stream{e_none}; | 216 | encryption_method_e cf_stream{e_none}; |