Commit 8417be173db9c9e7699d3902a35cae01b9683e06

Authored by m-holger
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.
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&amp; U) @@ -109,6 +123,13 @@ QPDF::EncryptionData::setU(std::string const&amp; 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&amp; qpdf) @@ -782,7 +803,7 @@ QPDF::EncryptionParameters::initialize(QPDF&amp; 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&amp; qpdf) @@ -792,9 +813,9 @@ QPDF::EncryptionParameters::initialize(QPDF&amp; 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&amp; qpdf) @@ -891,7 +912,7 @@ QPDF::EncryptionParameters::initialize(QPDF&amp; 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&lt;EncryptionParameters&gt; encp, QPDFObjGen og, @@ -942,12 +963,7 @@ QPDF::getKeyForObject(std::shared_ptr&lt;EncryptionParameters&gt; 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&amp; R, int&amp; P) @@ -1239,8 +1255,8 @@ QPDF::isEncrypted(int&amp; R, int&amp; 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};