Coverage Report

Created: 2025-07-18 07:03

/src/qpdf/libqpdf/QPDF_encryption.cc
Line
Count
Source (jump to first uncovered line)
1
// This file implements methods from the QPDF class that involve
2
// encryption.
3
4
#include <qpdf/assert_debug.h>
5
6
#include <qpdf/QPDF_private.hh>
7
8
#include <qpdf/QPDFExc.hh>
9
10
#include <qpdf/MD5.hh>
11
#include <qpdf/Pl_AES_PDF.hh>
12
#include <qpdf/Pl_Buffer.hh>
13
#include <qpdf/Pl_RC4.hh>
14
#include <qpdf/Pl_SHA2.hh>
15
#include <qpdf/QPDFObjectHandle_private.hh>
16
#include <qpdf/QTC.hh>
17
#include <qpdf/QUtil.hh>
18
#include <qpdf/RC4.hh>
19
#include <qpdf/Util.hh>
20
21
#include <algorithm>
22
#include <cstring>
23
24
using namespace qpdf;
25
using namespace std::literals;
26
27
static std::string padding_string =
28
    "\x28\xbf\x4e\x5e\x4e\x75\x8a\x41\x64\x00\x4e\x56\xff\xfa\x01\x08"
29
    "\x2e\x2e\x00\xb6\xd0\x68\x3e\x80\x2f\x0c\xa9\xfe\x64\x53\x69\x7a"s;
30
31
static unsigned int const key_bytes = 32;
32
33
static unsigned int const OU_key_bytes_V5 = 48;
34
static unsigned int const OUE_key_bytes_V5 = 32;
35
static unsigned int const Perms_key_bytes_V5 = 16;
36
37
int
38
QPDF::EncryptionData::getV() const
39
782k
{
40
782k
    return this->V;
41
782k
}
42
43
int
44
QPDF::EncryptionData::getR() const
45
923k
{
46
923k
    return this->R;
47
923k
}
48
49
int
50
QPDF::EncryptionData::getLengthBytes() const
51
142k
{
52
142k
    return this->Length_bytes;
53
142k
}
54
55
int
56
QPDF::EncryptionData::getP() const
57
102k
{
58
102k
    return static_cast<int>(P.to_ulong());
59
102k
}
60
61
bool
62
QPDF::EncryptionData::getP(size_t bit) const
63
0
{
64
0
    qpdf_assert_debug(bit);
65
0
    return P.test(bit - 1);
66
0
}
67
68
bool
69
QPDF::EncryptionParameters::P(size_t bit) const
70
0
{
71
0
    qpdf_assert_debug(bit);
72
0
    return P_.test(bit - 1);
73
0
}
74
75
std::string const&
76
QPDF::EncryptionData::getO() const
77
100k
{
78
100k
    return this->O;
79
100k
}
80
81
std::string const&
82
QPDF::EncryptionData::getU() const
83
76.8k
{
84
76.8k
    return this->U;
85
76.8k
}
86
87
std::string const&
88
QPDF::EncryptionData::getOE() const
89
28.6k
{
90
28.6k
    return this->OE;
91
28.6k
}
92
93
std::string const&
94
QPDF::EncryptionData::getUE() const
95
30.9k
{
96
30.9k
    return this->UE;
97
30.9k
}
98
99
std::string const&
100
QPDF::EncryptionData::getPerms() const
101
31.3k
{
102
31.3k
    return this->Perms;
103
31.3k
}
104
105
std::string const&
106
QPDF::EncryptionData::getId1() const
107
61.2k
{
108
61.2k
    return this->id1;
109
61.2k
}
110
111
bool
112
QPDF::EncryptionData::getEncryptMetadata() const
113
57.0k
{
114
57.0k
    return this->encrypt_metadata;
115
57.0k
}
116
117
void
118
QPDF::EncryptionData::setO(std::string const& O)
119
0
{
120
0
    this->O = O;
121
0
}
122
123
void
124
QPDF::EncryptionData::setU(std::string const& U)
125
0
{
126
0
    this->U = U;
127
0
}
128
129
void
130
QPDF::EncryptionData::setP(size_t bit, bool val)
131
0
{
132
0
    qpdf_assert_debug(bit);
133
0
    P.set(bit - 1, val);
134
0
}
135
136
void
137
QPDF::EncryptionData::setP(unsigned long val)
138
0
{
139
0
    P = std::bitset<32>(val);
140
0
}
141
142
void
143
QPDF::EncryptionData::setId1(std::string const& val)
144
31.8k
{
145
31.8k
    id1 = val;
146
31.8k
}
147
148
void
149
QPDF::EncryptionData::setV5EncryptionParameters(
150
    std::string const& O,
151
    std::string const& OE,
152
    std::string const& U,
153
    std::string const& UE,
154
    std::string const& Perms)
155
0
{
156
0
    this->O = O;
157
0
    this->OE = OE;
158
0
    this->U = U;
159
0
    this->UE = UE;
160
0
    this->Perms = Perms;
161
0
}
162
163
void
164
QPDF::trim_user_password(std::string& user_password)
165
255
{
166
    // Although unnecessary, this routine trims the padding string from the end of a user password.
167
    // Its only purpose is for recovery of user passwords which is done in the test suite.
168
255
    if (user_password.size() < key_bytes) {
169
0
        return;
170
0
    }
171
172
255
    auto idx = user_password.find('\x28');
173
174
264
    while (idx != user_password.npos) {
175
9
        if (padding_string.starts_with(user_password.substr(idx))) {
176
0
            user_password.resize(idx);
177
0
            return;
178
0
        }
179
9
        QTC::TC("qpdf", "QPDF_encryption skip 0x28");
180
9
        idx = user_password.find('\x28', ++idx);
181
9
    }
182
255
}
183
184
static std::string
185
pad_or_truncate_password_V4(std::string password)
186
74.1k
{
187
74.1k
    if (password.size() < key_bytes) {
188
70.5k
        password.append(padding_string);
189
70.5k
    }
190
74.1k
    password.resize(key_bytes);
191
74.1k
    return password;
192
74.1k
}
193
194
static std::string
195
iterate_md5_digest(MD5& md5, int iterations, int key_len)
196
58.7k
{
197
58.7k
    MD5::Digest digest;
198
58.7k
    md5.digest(digest);
199
58.7k
    auto len = std::min(QIntC::to_size(key_len), sizeof(digest));
200
2.94M
    for (int i = 0; i < iterations; ++i) {
201
2.88M
        MD5 m;
202
2.88M
        m.encodeDataIncrementally(reinterpret_cast<char*>(digest), len);
203
2.88M
        m.digest(digest);
204
2.88M
    }
205
58.7k
    return {reinterpret_cast<char*>(digest), len};
206
58.7k
}
207
208
static void
209
iterate_rc4(std::string& data, std::string_view okey, int iterations, bool reverse)
210
40.7k
{
211
40.7k
    auto len = okey.size();
212
40.7k
    std::string key(len, '\0');
213
838k
    for (int i = 0; i < iterations; ++i) {
214
797k
        int const xor_value = (reverse ? iterations - 1 - i : i);
215
13.5M
        for (size_t j = 0; j < len; ++j) {
216
12.7M
            key[j] = static_cast<char>(okey[j] ^ xor_value);
217
12.7M
        }
218
797k
        RC4::process(key, data);
219
797k
    }
220
40.7k
}
221
222
static std::string
223
process_with_aes(
224
    std::string const& key,
225
    bool encrypt,
226
    std::string const& data,
227
    size_t outlength = 0,
228
    unsigned int repetitions = 1,
229
    unsigned char const* iv = nullptr,
230
    size_t iv_length = 0)
231
5.93M
{
232
5.93M
    Pl_Buffer buffer("buffer");
233
5.93M
    Pl_AES_PDF aes(
234
5.93M
        "aes", &buffer, encrypt, QUtil::unsigned_char_pointer(key), QIntC::to_uint(key.length()));
235
5.93M
    if (iv) {
236
5.87M
        aes.setIV(iv, iv_length);
237
5.87M
    } else {
238
55.4k
        aes.useZeroIV();
239
55.4k
    }
240
5.93M
    aes.disablePadding();
241
382M
    for (unsigned int i = 0; i < repetitions; ++i) {
242
376M
        aes.writeString(data);
243
376M
    }
244
5.93M
    aes.finish();
245
5.93M
    if (outlength == 0) {
246
5.93M
        return buffer.getString();
247
5.93M
    } else {
248
0
        return buffer.getString().substr(0, outlength);
249
0
    }
250
5.93M
}
251
252
std::string
253
QPDF::EncryptionData::hash_V5(
254
    std::string const& password, std::string const& salt, std::string const& udata) const
255
85.0k
{
256
85.0k
    Pl_SHA2 hash(256);
257
85.0k
    hash.writeString(password);
258
85.0k
    hash.writeString(salt);
259
85.0k
    hash.writeString(udata);
260
85.0k
    hash.finish();
261
85.0k
    std::string K = hash.getRawDigest();
262
263
85.0k
    std::string result;
264
85.0k
    if (getR() < 6) {
265
922
        result = K;
266
84.1k
    } else {
267
        // Algorithm 2.B from ISO 32000-1 chapter 7: Computing a hash
268
269
84.1k
        int round_number = 0;
270
84.1k
        bool done = false;
271
5.96M
        while (!done) {
272
            // The hash algorithm has us setting K initially to the R5 value and then repeating a
273
            // series of steps 64 times before starting with the termination case testing.  The
274
            // wording of the specification is very unclear as to the exact number of times it
275
            // should be run since the wording about whether the initial setup counts as round 0 or
276
            // not is ambiguous.  This code counts the initial setup (R5) value as round 0, which
277
            // appears to be correct.  This was determined to be correct by increasing or decreasing
278
            // the number of rounds by 1 or 2 from this value and generating 20 test files.  In this
279
            // interpretation, all the test files worked with Adobe Reader X.  In the other
280
            // configurations, many of the files did not work, and we were accurately able to
281
            // predict which files didn't work by looking at the conditions under which we
282
            // terminated repetition.
283
284
5.87M
            ++round_number;
285
5.87M
            std::string K1 = password + K + udata;
286
5.87M
            qpdf_assert_debug(K.length() >= 32);
287
5.87M
            std::string E = process_with_aes(
288
5.87M
                K.substr(0, 16),
289
5.87M
                true,
290
5.87M
                K1,
291
5.87M
                0,
292
5.87M
                64,
293
5.87M
                QUtil::unsigned_char_pointer(K.substr(16, 16)),
294
5.87M
                16);
295
296
            // E_mod_3 is supposed to be mod 3 of the first 16 bytes of E taken as as a (128-bit)
297
            // big-endian number.  Since (xy mod n) is equal to ((x mod n) + (y mod n)) mod n and
298
            // since 256 mod n is 1, we can just take the sums of the the mod 3s of each byte to get
299
            // the same result.
300
5.87M
            int E_mod_3 = 0;
301
99.9M
            for (unsigned int i = 0; i < 16; ++i) {
302
94.0M
                E_mod_3 += static_cast<unsigned char>(E.at(i));
303
94.0M
            }
304
5.87M
            E_mod_3 %= 3;
305
5.87M
            int next_hash = ((E_mod_3 == 0) ? 256 : (E_mod_3 == 1) ? 384 : 512);
306
5.87M
            Pl_SHA2 sha2(next_hash);
307
5.87M
            sha2.writeString(E);
308
5.87M
            sha2.finish();
309
5.87M
            K = sha2.getRawDigest();
310
311
5.87M
            if (round_number >= 64) {
312
579k
                unsigned int ch = static_cast<unsigned char>(*(E.rbegin()));
313
314
579k
                if (ch <= QIntC::to_uint(round_number - 32)) {
315
84.1k
                    done = true;
316
84.1k
                }
317
579k
            }
318
5.87M
        }
319
84.1k
        result = K.substr(0, 32);
320
84.1k
    }
321
322
85.0k
    return result;
323
85.0k
}
324
325
static void
326
pad_short_parameter(std::string& param, size_t max_len)
327
74.3k
{
328
74.3k
    if (param.length() < max_len) {
329
11.5k
        QTC::TC("qpdf", "QPDF_encryption pad short parameter");
330
11.5k
        param.append(max_len - param.length(), '\0');
331
11.5k
    }
332
74.3k
}
333
334
std::string
335
QPDF::compute_data_key(
336
    std::string const& encryption_key,
337
    int objid,
338
    int generation,
339
    bool use_aes,
340
    int encryption_V,
341
    int encryption_R)
342
667k
{
343
    // Algorithm 3.1 from the PDF 1.7 Reference Manual
344
345
667k
    std::string result = encryption_key;
346
347
667k
    if (encryption_V >= 5) {
348
        // Algorithm 3.1a (PDF 1.7 extension level 3): just use encryption key straight.
349
485k
        return result;
350
485k
    }
351
352
    // Append low three bytes of object ID and low two bytes of generation
353
182k
    result.append(1, static_cast<char>(objid & 0xff));
354
182k
    result.append(1, static_cast<char>((objid >> 8) & 0xff));
355
182k
    result.append(1, static_cast<char>((objid >> 16) & 0xff));
356
182k
    result.append(1, static_cast<char>(generation & 0xff));
357
182k
    result.append(1, static_cast<char>((generation >> 8) & 0xff));
358
182k
    if (use_aes) {
359
14.7k
        result += "sAlT";
360
14.7k
    }
361
182k
    return MD5::digest(result).substr(0, result.size());
362
667k
}
363
364
std::string
365
QPDF::compute_encryption_key(std::string const& password, EncryptionData const& data)
366
0
{
367
0
    return data.compute_encryption_key(password);
368
0
}
369
370
std::string
371
QPDF::EncryptionData::compute_encryption_key(std::string const& password) const
372
39.9k
{
373
39.9k
    if (getV() >= 5) {
374
        // For V >= 5, the encryption key is generated and stored in the file, encrypted separately
375
        // with both user and owner passwords.
376
0
        return recover_encryption_key_with_password(password);
377
39.9k
    } else {
378
        // For V < 5, the encryption key is derived from the user
379
        // password.
380
39.9k
        return compute_encryption_key_from_password(password);
381
39.9k
    }
382
39.9k
}
383
384
std::string
385
QPDF::EncryptionData::compute_encryption_key_from_password(std::string const& password) const
386
39.9k
{
387
    // Algorithm 3.2 from the PDF 1.7 Reference Manual
388
389
    // This code does not properly handle Unicode passwords. Passwords are supposed to be converted
390
    // from OS codepage characters to PDFDocEncoding.  Unicode passwords are supposed to be
391
    // converted to OS codepage before converting to PDFDocEncoding.  We instead require the
392
    // password to be presented in its final form.
393
394
39.9k
    MD5 md5;
395
39.9k
    md5.encodeDataIncrementally(pad_or_truncate_password_V4(password));
396
39.9k
    md5.encodeDataIncrementally(getO());
397
39.9k
    char pbytes[4];
398
39.9k
    int p = getP();
399
39.9k
    pbytes[0] = static_cast<char>(p & 0xff);
400
39.9k
    pbytes[1] = static_cast<char>((p >> 8) & 0xff);
401
39.9k
    pbytes[2] = static_cast<char>((p >> 16) & 0xff);
402
39.9k
    pbytes[3] = static_cast<char>((p >> 24) & 0xff);
403
39.9k
    md5.encodeDataIncrementally(pbytes, 4);
404
39.9k
    md5.encodeDataIncrementally(getId1());
405
39.9k
    if (getR() >= 4 && !getEncryptMetadata()) {
406
24
        md5.encodeDataIncrementally("\xff\xff\xff\xff");
407
24
    }
408
39.9k
    return iterate_md5_digest(md5, (getR() >= 3 ? 50 : 0), getLengthBytes());
409
39.9k
}
410
411
std::string
412
QPDF::EncryptionData::compute_O_rc4_key(
413
    std::string const& user_password, std::string const& owner_password) const
414
18.8k
{
415
18.8k
    if (getV() >= 5) {
416
0
        throw std::logic_error("compute_O_rc4_key called for file with V >= 5");
417
0
    }
418
18.8k
    std::string password = owner_password.empty() ? user_password : owner_password;
419
18.8k
    MD5 md5;
420
18.8k
    md5.encodeDataIncrementally(pad_or_truncate_password_V4(password));
421
18.8k
    return iterate_md5_digest(md5, (getR() >= 3 ? 50 : 0), getLengthBytes());
422
18.8k
}
423
424
std::string
425
QPDF::EncryptionData::compute_O_value(
426
    std::string const& user_password, std::string const& owner_password) const
427
15.4k
{
428
    // Algorithm 3.3 from the PDF 1.7 Reference Manual
429
430
15.4k
    auto upass = pad_or_truncate_password_V4(user_password);
431
15.4k
    std::string O_key = compute_O_rc4_key(user_password, owner_password);
432
15.4k
    pad_short_parameter(O_key, QIntC::to_size(getLengthBytes()));
433
15.4k
    iterate_rc4(upass, O_key, getR() >= 3 ? 20 : 1, false);
434
15.4k
    return upass;
435
15.4k
}
436
437
std::string
438
QPDF::EncryptionData::compute_U_value_R2(std::string const& user_password) const
439
626
{
440
    // Algorithm 3.4 from the PDF 1.7 Reference Manual
441
442
626
    std::string k1 = compute_encryption_key(user_password);
443
626
    auto udata = padding_string;
444
626
    pad_short_parameter(k1, QIntC::to_size(getLengthBytes()));
445
626
    iterate_rc4(udata, k1, 1, false);
446
626
    return udata;
447
626
}
448
449
std::string
450
QPDF::EncryptionData::compute_U_value_R3(std::string const& user_password) const
451
21.3k
{
452
    // Algorithm 3.5 from the PDF 1.7 Reference Manual
453
454
21.3k
    std::string k1 = compute_encryption_key(user_password);
455
21.3k
    MD5 md5;
456
21.3k
    md5.encodeDataIncrementally(padding_string);
457
21.3k
    md5.encodeDataIncrementally(getId1());
458
21.3k
    auto result = md5.digest();
459
21.3k
    pad_short_parameter(k1, QIntC::to_size(getLengthBytes()));
460
21.3k
    iterate_rc4(result, k1, 20, false);
461
    // pad with arbitrary data -- make it consistent for the sake of testing
462
21.3k
    result += "\x0\x21\x44\x69\x90\xb9\xe4\x11\x40\x71\xa4\xd9\x10\x49\x84\xc1"s;
463
21.3k
    return result;
464
21.3k
}
465
466
std::string
467
QPDF::EncryptionData::compute_U_value(std::string const& user_password) const
468
21.9k
{
469
21.9k
    if (getR() >= 3) {
470
21.3k
        return compute_U_value_R3(user_password);
471
21.3k
    }
472
473
626
    return compute_U_value_R2(user_password);
474
21.9k
}
475
476
bool
477
QPDF::EncryptionData::check_user_password_V4(std::string const& user_password) const
478
6.54k
{
479
    // Algorithm 3.6 from the PDF 1.7 Reference Manual
480
481
6.54k
    std::string u_value = compute_U_value(user_password);
482
6.54k
    size_t to_compare = (getR() >= 3 ? sizeof(MD5::Digest) : key_bytes);
483
6.54k
    return memcmp(getU().c_str(), u_value.c_str(), to_compare) == 0;
484
6.54k
}
485
486
bool
487
QPDF::EncryptionData::check_user_password_V5(std::string const& user_password) const
488
7.91k
{
489
    // Algorithm 3.11 from the PDF 1.7 extension level 3
490
491
7.91k
    std::string user_data = getU().substr(0, 32);
492
7.91k
    std::string validation_salt = getU().substr(32, 8);
493
7.91k
    std::string password = user_password.substr(0, 127);
494
7.91k
    return hash_V5(user_password.substr(0, 127), validation_salt, "") == user_data;
495
7.91k
}
496
497
bool
498
QPDF::EncryptionData::check_user_password(std::string const& user_password) const
499
11.8k
{
500
11.8k
    if (getV() < 5) {
501
6.54k
        return check_user_password_V4(user_password);
502
6.54k
    } else {
503
5.26k
        return check_user_password_V5(user_password);
504
5.26k
    }
505
11.8k
}
506
507
bool
508
QPDF::EncryptionData::check_owner_password_V4(
509
    std::string& user_password, std::string const& owner_password) const
510
3.40k
{
511
    // Algorithm 3.7 from the PDF 1.7 Reference Manual
512
513
3.40k
    auto key = compute_O_rc4_key(user_password, owner_password);
514
3.40k
    pad_short_parameter(key, QIntC::to_size(getLengthBytes()));
515
3.40k
    auto new_user_password = O.substr(0, key_bytes);
516
3.40k
    iterate_rc4(new_user_password, key, (getR() >= 3) ? 20 : 1, true);
517
3.40k
    if (check_user_password(new_user_password)) {
518
255
        user_password = new_user_password;
519
255
        return true;
520
255
    }
521
3.14k
    return false;
522
3.40k
}
523
524
bool
525
QPDF::EncryptionData::check_owner_password_V5(std::string const& owner_password) const
526
8.30k
{
527
    // Algorithm 3.12 from the PDF 1.7 extension level 3
528
529
8.30k
    std::string user_data = getU().substr(0, 48);
530
8.30k
    std::string owner_data = getO().substr(0, 32);
531
8.30k
    std::string validation_salt = getO().substr(32, 8);
532
8.30k
    return hash_V5(owner_password.substr(0, 127), validation_salt, user_data) == owner_data;
533
8.30k
}
534
535
bool
536
QPDF::EncryptionData::check_owner_password(
537
    std::string& user_password, std::string const& owner_password) const
538
8.66k
{
539
8.66k
    if (getV() < 5) {
540
3.40k
        return check_owner_password_V4(user_password, owner_password);
541
5.26k
    } else {
542
5.26k
        return check_owner_password_V5(owner_password);
543
5.26k
    }
544
8.66k
}
545
546
std::string
547
QPDF::EncryptionData::recover_encryption_key_with_password(std::string const& password) const
548
0
{
549
    // Disregard whether Perms is valid.
550
0
    bool disregard;
551
0
    return recover_encryption_key_with_password(password, disregard);
552
0
}
553
554
std::string
555
QPDF::EncryptionData::compute_Perms_value_V5_clear() const
556
19.4k
{
557
    // From algorithm 3.10 from the PDF 1.7 extension level 3
558
19.4k
    std::string k = "    \xff\xff\xff\xffTadb    ";
559
19.4k
    int perms = getP();
560
97.4k
    for (size_t i = 0; i < 4; ++i) {
561
77.9k
        k[i] = static_cast<char>(perms & 0xff);
562
77.9k
        perms >>= 8;
563
77.9k
    }
564
19.4k
    if (!getEncryptMetadata()) {
565
0
        k[8] = 'F';
566
0
    }
567
19.4k
    QUtil::initializeWithRandomBytes(reinterpret_cast<unsigned char*>(&k[12]), 4);
568
19.4k
    return k;
569
19.4k
}
570
571
std::string
572
QPDF::EncryptionData::recover_encryption_key_with_password(
573
    std::string const& password, bool& perms_valid) const
574
3.03k
{
575
    // Algorithm 3.2a from the PDF 1.7 extension level 3
576
577
    // This code does not handle Unicode passwords correctly. Empirical evidence suggests that most
578
    // viewers don't.  We are supposed to process the input string with the SASLprep (RFC 4013)
579
    // profile of stringprep (RFC 3454) and then convert the result to UTF-8.
580
581
3.03k
    perms_valid = false;
582
3.03k
    std::string key_password = password.substr(0, 127);
583
3.03k
    std::string key_salt;
584
3.03k
    std::string user_data;
585
3.03k
    std::string encrypted_file_key;
586
3.03k
    if (check_owner_password_V5(key_password)) {
587
387
        key_salt = getO().substr(40, 8);
588
387
        user_data = getU().substr(0, 48);
589
387
        encrypted_file_key = getOE().substr(0, 32);
590
2.65k
    } else if (check_user_password_V5(key_password)) {
591
2.65k
        key_salt = getU().substr(40, 8);
592
2.65k
        encrypted_file_key = getUE().substr(0, 32);
593
2.65k
    }
594
3.03k
    std::string intermediate_key = hash_V5(key_password, key_salt, user_data);
595
3.03k
    std::string file_key = process_with_aes(intermediate_key, false, encrypted_file_key);
596
597
    // Decrypt Perms and check against expected value
598
3.03k
    auto perms_check = process_with_aes(file_key, false, getPerms()).substr(0, 12);
599
3.03k
    perms_valid = compute_Perms_value_V5_clear().substr(0, 12) == perms_check;
600
3.03k
    return file_key;
601
3.03k
}
602
603
QPDF::encryption_method_e
604
QPDF::EncryptionParameters::interpretCF(QPDFObjectHandle const& cf) const
605
15.5k
{
606
15.5k
    if (!cf.isName()) {
607
        // Default: /Identity
608
4.09k
        return e_none;
609
4.09k
    }
610
11.4k
    std::string filter = cf.getName();
611
11.4k
    auto it = crypt_filters.find(filter);
612
11.4k
    if (it != crypt_filters.end()) {
613
3.61k
        return it->second;
614
3.61k
    }
615
7.82k
    if (filter == "/Identity") {
616
35
        return e_none;
617
35
    }
618
7.79k
    return e_unknown;
619
7.82k
}
620
621
void
622
QPDF::initializeEncryption()
623
112k
{
624
112k
    m->encp->initialize(*this);
625
112k
}
626
627
void
628
QPDF::EncryptionParameters::initialize(QPDF& qpdf)
629
112k
{
630
112k
    if (encryption_initialized) {
631
121
        return;
632
121
    }
633
111k
    encryption_initialized = true;
634
635
111k
    auto& qm = *qpdf.m;
636
111k
    auto& trailer = qm.trailer;
637
111k
    auto& file = qm.file;
638
639
111k
    auto warn_damaged_pdf = [&qpdf](std::string const& msg) {
640
2.75k
        qpdf.warn(qpdf.damagedPDF("encryption dictionary", msg));
641
2.75k
    };
642
111k
    auto throw_damaged_pdf = [&qpdf](std::string const& msg) {
643
714
        throw qpdf.damagedPDF("encryption dictionary", msg);
644
714
    };
645
111k
    auto unsupported = [&file](std::string const& msg) -> QPDFExc {
646
624
        return {
647
624
            qpdf_e_unsupported,
648
624
            file->getName(),
649
624
            "encryption dictionary",
650
624
            file->getLastOffset(),
651
624
            msg};
652
624
    };
653
654
    // After we initialize encryption parameters, we must use stored key information and never look
655
    // at /Encrypt again.  Otherwise, things could go wrong if someone mutates the encryption
656
    // dictionary.
657
658
111k
    if (!trailer.hasKey("/Encrypt")) {
659
101k
        return;
660
101k
    }
661
662
    // Go ahead and set m->encrypted here.  That way, isEncrypted will return true even if there
663
    // were errors reading the encryption dictionary.
664
10.0k
    encrypted = true;
665
666
10.0k
    std::string id1;
667
10.0k
    auto id_obj = trailer.getKey("/ID");
668
10.0k
    if (!id_obj.isArray() || id_obj.getArrayNItems() != 2 || !id_obj.getArrayItem(0).isString()) {
669
        // Treating a missing ID as the empty string enables qpdf to decrypt some invalid encrypted
670
        // files with no /ID that poppler can read but Adobe Reader can't.
671
5.79k
        qpdf.warn(qpdf.damagedPDF("trailer", "invalid /ID in trailer dictionary"));
672
5.79k
    } else {
673
4.29k
        id1 = id_obj.getArrayItem(0).getStringValue();
674
4.29k
    }
675
676
10.0k
    auto encryption_dict = trailer.getKey("/Encrypt");
677
10.0k
    if (!encryption_dict.isDictionary()) {
678
20
        throw qpdf.damagedPDF("/Encrypt in trailer dictionary is not a dictionary");
679
20
    }
680
681
10.0k
    if (!(encryption_dict.getKey("/Filter").isName() &&
682
10.0k
          (encryption_dict.getKey("/Filter").getName() == "/Standard"))) {
683
260
        throw unsupported("unsupported encryption filter");
684
260
    }
685
9.80k
    if (!encryption_dict.getKey("/SubFilter").isNull()) {
686
22
        qpdf.warn(unsupported("file uses encryption SubFilters, which qpdf does not support"));
687
22
    }
688
689
9.80k
    if (!(encryption_dict.getKey("/V").isInteger() && encryption_dict.getKey("/R").isInteger() &&
690
9.80k
          encryption_dict.getKey("/O").isString() && encryption_dict.getKey("/U").isString() &&
691
9.80k
          encryption_dict.getKey("/P").isInteger())) {
692
540
        throw_damaged_pdf("some encryption dictionary parameters are missing or the wrong type");
693
540
    }
694
695
9.80k
    int V = encryption_dict.getKey("/V").getIntValueAsInt();
696
9.80k
    int R = encryption_dict.getKey("/R").getIntValueAsInt();
697
9.80k
    std::string O = encryption_dict.getKey("/O").getStringValue();
698
9.80k
    std::string U = encryption_dict.getKey("/U").getStringValue();
699
9.80k
    int p = static_cast<int>(encryption_dict.getKey("/P").getIntValue());
700
701
    // If supporting new encryption R/V values, remember to update error message inside this if
702
    // statement.
703
9.80k
    if (!(2 <= R && R <= 6 && (V == 1 || V == 2 || V == 4 || V == 5))) {
704
342
        throw unsupported(
705
342
            "Unsupported /R or /V in encryption dictionary; R = " + std::to_string(R) +
706
342
            " (max 6), V = " + std::to_string(V) + " (max 5)");
707
342
    }
708
709
9.46k
    P_ = std::bitset<32>(static_cast<unsigned long long>(p));
710
9.46k
    encryption_V = V;
711
9.46k
    R_ = R;
712
713
    // OE, UE, and Perms are only present if V >= 5.
714
9.46k
    std::string OE;
715
9.46k
    std::string UE;
716
9.46k
    std::string Perms;
717
718
9.46k
    if (V < 5) {
719
        // These must be exactly the right number of bytes.
720
3.53k
        pad_short_parameter(O, key_bytes);
721
3.53k
        pad_short_parameter(U, key_bytes);
722
3.53k
        if (!(O.length() == key_bytes && U.length() == key_bytes)) {
723
127
            throw_damaged_pdf("incorrect length for /O and/or /U in encryption dictionary");
724
127
        }
725
5.93k
    } else {
726
5.93k
        if (!(encryption_dict.getKey("/OE").isString() &&
727
5.93k
              encryption_dict.getKey("/UE").isString() &&
728
5.93k
              encryption_dict.getKey("/Perms").isString())) {
729
47
            throw_damaged_pdf(
730
47
                "some V=5 encryption dictionary parameters are missing or the wrong type");
731
47
        }
732
5.93k
        OE = encryption_dict.getKey("/OE").getStringValue();
733
5.93k
        UE = encryption_dict.getKey("/UE").getStringValue();
734
5.93k
        Perms = encryption_dict.getKey("/Perms").getStringValue();
735
736
        // These may be longer than the minimum number of bytes.
737
5.93k
        pad_short_parameter(O, OU_key_bytes_V5);
738
5.93k
        pad_short_parameter(U, OU_key_bytes_V5);
739
5.93k
        pad_short_parameter(OE, OUE_key_bytes_V5);
740
5.93k
        pad_short_parameter(UE, OUE_key_bytes_V5);
741
5.93k
        pad_short_parameter(Perms, Perms_key_bytes_V5);
742
5.93k
    }
743
744
9.46k
    int Length = 128; // Just take a guess.
745
9.46k
    if (V <= 1) {
746
244
        Length = 40;
747
9.22k
    } else if (V == 4) {
748
2.31k
        Length = 128;
749
6.90k
    } else if (V == 5) {
750
5.29k
        Length = 256;
751
5.29k
    } else {
752
1.61k
        if (encryption_dict.getKey("/Length").isInteger()) {
753
429
            Length = encryption_dict.getKey("/Length").getIntValueAsInt();
754
429
            if (Length % 8 || Length < 40 || Length > 128) {
755
137
                Length = 128; // Just take a guess.
756
137
            }
757
429
        }
758
1.61k
    }
759
760
9.46k
    encrypt_metadata = true;
761
9.46k
    if (V >= 4 && encryption_dict.getKey("/EncryptMetadata").isBool()) {
762
176
        encrypt_metadata = encryption_dict.getKey("/EncryptMetadata").getBoolValue();
763
176
    }
764
765
9.46k
    if (V == 4 || V == 5) {
766
7.60k
        auto CF = encryption_dict.getKey("/CF");
767
38.4k
        for (auto const& [filter, cdict]: CF.as_dictionary()) {
768
38.4k
            if (cdict.isDictionary()) {
769
15.6k
                encryption_method_e method = e_none;
770
15.6k
                if (cdict.getKey("/CFM").isName()) {
771
5.11k
                    std::string method_name = cdict.getKey("/CFM").getName();
772
5.11k
                    if (method_name == "/V2") {
773
325
                        QTC::TC("qpdf", "QPDF_encryption CFM V2");
774
325
                        method = e_rc4;
775
4.79k
                    } else if (method_name == "/AESV2") {
776
1.10k
                        QTC::TC("qpdf", "QPDF_encryption CFM AESV2");
777
1.10k
                        method = e_aes;
778
3.68k
                    } else if (method_name == "/AESV3") {
779
1.39k
                        QTC::TC("qpdf", "QPDF_encryption CFM AESV3");
780
1.39k
                        method = e_aesv3;
781
2.29k
                    } else {
782
                        // Don't complain now -- maybe we won't need to reference this type.
783
2.29k
                        method = e_unknown;
784
2.29k
                    }
785
5.11k
                }
786
15.6k
                crypt_filters[filter] = method;
787
15.6k
            }
788
38.4k
        }
789
790
7.60k
        cf_stream = interpretCF(encryption_dict.getKey("/StmF"));
791
7.60k
        cf_string = interpretCF(encryption_dict.getKey("/StrF"));
792
7.60k
        if (auto EFF = encryption_dict.getKey("/EFF"); EFF.isName()) {
793
            // qpdf does not use this for anything other than informational purposes. This is
794
            // intended to instruct conforming writers on which crypt filter should be used when new
795
            // file attachments are added to a PDF file, but qpdf never generates encrypted files
796
            // with non-default crypt filters. Prior to 10.2, I was under the mistaken impression
797
            // that this was supposed to be used for decrypting attachments, but the code was wrong
798
            // in a way that turns out not to have mattered because no writers were generating files
799
            // the way I was imagining. Still, providing this information could be useful when
800
            // looking at a file generated by something else, such as Acrobat when specifying that
801
            // only attachments should be encrypted.
802
380
            cf_file = interpretCF(EFF);
803
7.22k
        } else {
804
7.22k
            cf_file = cf_stream;
805
7.22k
        }
806
7.60k
    }
807
808
9.46k
    EncryptionData data(V, R, Length / 8, p, O, U, OE, UE, Perms, id1, encrypt_metadata);
809
9.46k
    if (qm.provided_password_is_hex_key) {
810
        // ignore passwords in file
811
0
        encryption_key = QUtil::hex_decode(provided_password);
812
0
        return;
813
0
    }
814
815
9.46k
    owner_password_matched = data.check_owner_password(user_password, provided_password);
816
9.46k
    if (owner_password_matched && V < 5) {
817
        // password supplied was owner password; user_password has been initialized for V < 5
818
255
        if (qpdf.getTrimmedUserPassword() == provided_password) {
819
0
            user_password_matched = true;
820
0
            QTC::TC("qpdf", "QPDF_encryption user matches owner V < 5");
821
0
        }
822
9.20k
    } else {
823
9.20k
        user_password_matched = data.check_user_password(provided_password);
824
9.20k
        if (user_password_matched) {
825
4.98k
            user_password = provided_password;
826
4.98k
        }
827
9.20k
    }
828
9.46k
    if (user_password_matched && owner_password_matched) {
829
20
        QTC::TC("qpdf", "QPDF_encryption same password", (V < 5) ? 0 : 1);
830
20
    }
831
9.46k
    if (!(owner_password_matched || user_password_matched)) {
832
3.06k
        throw QPDFExc(qpdf_e_password, file->getName(), "", 0, "invalid password");
833
3.06k
    }
834
835
6.40k
    if (V < 5) {
836
        // For V < 5, the user password is encrypted with the owner password, and the user password
837
        // is always used for computing the encryption key.
838
2.56k
        encryption_key = data.compute_encryption_key(user_password);
839
3.83k
    } else {
840
        // For V >= 5, either password can be used independently to compute the encryption key, and
841
        // neither password can be used to recover the other.
842
3.83k
        bool perms_valid;
843
3.83k
        encryption_key = data.recover_encryption_key_with_password(provided_password, perms_valid);
844
3.83k
        if (!perms_valid) {
845
2.75k
            warn_damaged_pdf("/Perms field in encryption dictionary doesn't match expected value");
846
2.75k
        }
847
3.83k
    }
848
6.40k
}
849
850
std::string
851
QPDF::getKeyForObject(std::shared_ptr<EncryptionParameters> encp, QPDFObjGen og, bool use_aes)
852
200k
{
853
200k
    if (!encp->encrypted) {
854
0
        throw std::logic_error("request for encryption key in non-encrypted PDF");
855
0
    }
856
857
200k
    if (og != encp->cached_key_og) {
858
50.2k
        encp->cached_object_encryption_key = compute_data_key(
859
50.2k
            encp->encryption_key, og.getObj(), og.getGen(), use_aes, encp->encryption_V, encp->R());
860
50.2k
        encp->cached_key_og = og;
861
50.2k
    }
862
863
200k
    return encp->cached_object_encryption_key;
864
200k
}
865
866
void
867
QPDF::decryptString(std::string& str, QPDFObjGen og)
868
174k
{
869
174k
    if (!og.isIndirect()) {
870
0
        return;
871
0
    }
872
174k
    bool use_aes = false;
873
174k
    if (m->encp->encryption_V >= 4) {
874
123k
        switch (m->encp->cf_string) {
875
9.20k
        case e_none:
876
9.20k
            return;
877
878
95.1k
        case e_aes:
879
95.1k
            use_aes = true;
880
95.1k
            break;
881
882
13.1k
        case e_aesv3:
883
13.1k
            use_aes = true;
884
13.1k
            break;
885
886
3.69k
        case e_rc4:
887
3.69k
            break;
888
889
1.76k
        default:
890
1.76k
            warn(damagedPDF(
891
1.76k
                "unknown encryption filter for strings (check /StrF in "
892
1.76k
                "/Encrypt dictionary); strings may be decrypted improperly"));
893
            // To avoid repeated warnings, reset cf_string.  Assume we'd want to use AES if V == 4.
894
1.76k
            m->encp->cf_string = e_aes;
895
1.76k
            use_aes = true;
896
1.76k
            break;
897
123k
        }
898
123k
    }
899
900
164k
    std::string key = getKeyForObject(m->encp, og, use_aes);
901
164k
    try {
902
164k
        if (use_aes) {
903
109k
            QTC::TC("qpdf", "QPDF_encryption aes decode string");
904
109k
            Pl_Buffer bufpl("decrypted string");
905
109k
            Pl_AES_PDF pl(
906
109k
                "aes decrypt string",
907
109k
                &bufpl,
908
109k
                false,
909
109k
                QUtil::unsigned_char_pointer(key),
910
109k
                key.length());
911
109k
            pl.writeString(str);
912
109k
            pl.finish();
913
109k
            str = bufpl.getString();
914
109k
        } else {
915
54.9k
            QTC::TC("qpdf", "QPDF_encryption rc4 decode string");
916
54.9k
            size_t vlen = str.length();
917
            // Using std::shared_ptr guarantees that tmp will be freed even if rc4.process throws an
918
            // exception.
919
54.9k
            auto tmp = QUtil::make_unique_cstr(str);
920
54.9k
            RC4 rc4(QUtil::unsigned_char_pointer(key), toI(key.length()));
921
54.9k
            auto data = QUtil::unsigned_char_pointer(tmp.get());
922
54.9k
            rc4.process(data, vlen, data);
923
54.9k
            str = std::string(tmp.get(), vlen);
924
54.9k
        }
925
164k
    } catch (QPDFExc&) {
926
0
        throw;
927
21
    } catch (std::runtime_error& e) {
928
21
        throw damagedPDF("error decrypting string for object " + og.unparse() + ": " + e.what());
929
21
    }
930
164k
}
931
932
// Prepend a decryption pipeline to 'pipeline'. The decryption pipeline (returned as
933
// 'decrypt_pipeline' must be owned by the caller to ensure that it stays alive while the pipeline
934
// is in use.
935
void
936
QPDF::decryptStream(
937
    std::shared_ptr<EncryptionParameters> encp,
938
    std::shared_ptr<InputSource> file,
939
    QPDF& qpdf_for_warning,
940
    Pipeline*& pipeline,
941
    QPDFObjGen og,
942
    QPDFObjectHandle& stream_dict,
943
    bool is_root_metadata,
944
    std::unique_ptr<Pipeline>& decrypt_pipeline)
945
38.2k
{
946
38.2k
    std::string type;
947
38.2k
    if (stream_dict.getKey("/Type").isName()) {
948
10.1k
        type = stream_dict.getKey("/Type").getName();
949
10.1k
    }
950
38.2k
    if (type == "/XRef") {
951
422
        QTC::TC("qpdf", "QPDF_encryption xref stream from encrypted file");
952
422
        return;
953
422
    }
954
37.8k
    bool use_aes = false;
955
37.8k
    if (encp->encryption_V >= 4) {
956
27.8k
        encryption_method_e method = e_unknown;
957
27.8k
        std::string method_source = "/StmF from /Encrypt dictionary";
958
959
27.8k
        if (stream_dict.getKey("/Filter").isOrHasName("/Crypt")) {
960
357
            if (stream_dict.getKey("/DecodeParms").isDictionary()) {
961
66
                QPDFObjectHandle decode_parms = stream_dict.getKey("/DecodeParms");
962
66
                if (decode_parms.isDictionaryOfType("/CryptFilterDecodeParms")) {
963
0
                    QTC::TC("qpdf", "QPDF_encryption stream crypt filter");
964
0
                    method = encp->interpretCF(decode_parms.getKey("/Name"));
965
0
                    method_source = "stream's Crypt decode parameters";
966
0
                }
967
291
            } else if (
968
291
                stream_dict.getKey("/DecodeParms").isArray() &&
969
291
                stream_dict.getKey("/Filter").isArray()) {
970
138
                QPDFObjectHandle filter = stream_dict.getKey("/Filter");
971
138
                QPDFObjectHandle decode = stream_dict.getKey("/DecodeParms");
972
138
                if (filter.getArrayNItems() == decode.getArrayNItems()) {
973
362
                    for (int i = 0; i < filter.getArrayNItems(); ++i) {
974
273
                        if (filter.getArrayItem(i).isNameAndEquals("/Crypt")) {
975
89
                            QPDFObjectHandle crypt_params = decode.getArrayItem(i);
976
89
                            if (crypt_params.isDictionary() &&
977
89
                                crypt_params.getKey("/Name").isName()) {
978
0
                                QTC::TC("qpdf", "QPDF_encrypt crypt array");
979
0
                                method = encp->interpretCF(crypt_params.getKey("/Name"));
980
0
                                method_source = "stream's Crypt decode parameters (array)";
981
0
                            }
982
89
                        }
983
273
                    }
984
89
                }
985
138
            }
986
357
        }
987
988
27.8k
        if (method == e_unknown) {
989
27.8k
            if ((!encp->encrypt_metadata) && is_root_metadata) {
990
0
                QTC::TC("qpdf", "QPDF_encryption cleartext metadata");
991
0
                method = e_none;
992
27.8k
            } else {
993
27.8k
                method = encp->cf_stream;
994
27.8k
            }
995
27.8k
        }
996
27.8k
        use_aes = false;
997
27.8k
        switch (method) {
998
2.52k
        case e_none:
999
2.52k
            return;
1000
0
            break;
1001
1002
19.2k
        case e_aes:
1003
19.2k
            use_aes = true;
1004
19.2k
            break;
1005
1006
4.40k
        case e_aesv3:
1007
4.40k
            use_aes = true;
1008
4.40k
            break;
1009
1010
468
        case e_rc4:
1011
468
            break;
1012
1013
1.15k
        default:
1014
            // filter local to this stream.
1015
1.15k
            qpdf_for_warning.warn(QPDFExc(
1016
1.15k
                qpdf_e_damaged_pdf,
1017
1.15k
                file->getName(),
1018
1.15k
                "",
1019
1.15k
                file->getLastOffset(),
1020
1.15k
                "unknown encryption filter for streams (check " + method_source +
1021
1.15k
                    "); streams may be decrypted improperly"));
1022
            // To avoid repeated warnings, reset cf_stream.  Assume we'd want to use AES if V == 4.
1023
1.15k
            encp->cf_stream = e_aes;
1024
1.15k
            use_aes = true;
1025
1.15k
            break;
1026
27.8k
        }
1027
27.8k
    }
1028
35.2k
    std::string key = getKeyForObject(encp, og, use_aes);
1029
35.2k
    if (use_aes) {
1030
24.7k
        QTC::TC("qpdf", "QPDF_encryption aes decode stream");
1031
24.7k
        decrypt_pipeline = std::make_unique<Pl_AES_PDF>(
1032
24.7k
            "AES stream decryption",
1033
24.7k
            pipeline,
1034
24.7k
            false,
1035
24.7k
            QUtil::unsigned_char_pointer(key),
1036
24.7k
            key.length());
1037
24.7k
    } else {
1038
10.4k
        QTC::TC("qpdf", "QPDF_encryption rc4 decode stream");
1039
10.4k
        decrypt_pipeline = std::make_unique<Pl_RC4>(
1040
10.4k
            "RC4 stream decryption",
1041
10.4k
            pipeline,
1042
10.4k
            QUtil::unsigned_char_pointer(key),
1043
10.4k
            toI(key.length()));
1044
10.4k
    }
1045
35.2k
    pipeline = decrypt_pipeline.get();
1046
35.2k
}
1047
1048
void
1049
QPDF::compute_encryption_O_U(
1050
    char const* user_password,
1051
    char const* owner_password,
1052
    int V,
1053
    int R,
1054
    int key_len,
1055
    int P,
1056
    bool encrypt_metadata,
1057
    std::string const& id1,
1058
    std::string& out_O,
1059
    std::string& out_U)
1060
0
{
1061
0
    EncryptionData data(V, R, key_len, P, "", "", "", "", "", id1, encrypt_metadata);
1062
0
    data.compute_encryption_O_U(user_password, owner_password);
1063
0
    out_O = data.getO();
1064
0
    out_U = data.getU();
1065
0
}
1066
1067
void
1068
QPDF::EncryptionData::compute_encryption_O_U(char const* user_password, char const* owner_password)
1069
15.4k
{
1070
15.4k
    if (V >= 5) {
1071
0
        throw std::logic_error("compute_encryption_O_U called for file with V >= 5");
1072
0
    }
1073
15.4k
    O = compute_O_value(user_password, owner_password);
1074
15.4k
    U = compute_U_value(user_password);
1075
15.4k
}
1076
1077
void
1078
QPDF::compute_encryption_parameters_V5(
1079
    char const* user_password,
1080
    char const* owner_password,
1081
    int V,
1082
    int R,
1083
    int key_len,
1084
    int P,
1085
    bool encrypt_metadata,
1086
    std::string const& id1,
1087
    std::string& encryption_key,
1088
    std::string& out_O,
1089
    std::string& out_U,
1090
    std::string& out_OE,
1091
    std::string& out_UE,
1092
    std::string& out_Perms)
1093
0
{
1094
0
    EncryptionData data(V, R, key_len, P, "", "", "", "", "", id1, encrypt_metadata);
1095
0
    encryption_key = data.compute_encryption_parameters_V5(user_password, owner_password);
1096
1097
0
    out_O = data.getO();
1098
0
    out_U = data.getU();
1099
0
    out_OE = data.getOE();
1100
0
    out_UE = data.getUE();
1101
0
    out_Perms = data.getPerms();
1102
0
}
1103
1104
std::string
1105
QPDF::EncryptionData::compute_encryption_parameters_V5(
1106
    char const* user_password, char const* owner_password)
1107
16.4k
{
1108
16.4k
    auto out_encryption_key = util::random_string(key_bytes);
1109
    // Algorithm 8 from the PDF 2.0
1110
16.4k
    auto validation_salt = util::random_string(8);
1111
16.4k
    auto key_salt = util::random_string(8);
1112
16.4k
    U = hash_V5(user_password, validation_salt, "").append(validation_salt).append(key_salt);
1113
16.4k
    auto intermediate_key = hash_V5(user_password, key_salt, "");
1114
16.4k
    UE = process_with_aes(intermediate_key, true, out_encryption_key);
1115
    // Algorithm 9 from the PDF 2.0
1116
16.4k
    validation_salt = util::random_string(8);
1117
16.4k
    key_salt = util::random_string(8);
1118
16.4k
    O = hash_V5(owner_password, validation_salt, U) + validation_salt + key_salt;
1119
16.4k
    intermediate_key = hash_V5(owner_password, key_salt, U);
1120
16.4k
    OE = process_with_aes(intermediate_key, true, out_encryption_key);
1121
    // Algorithm 10 from the PDF 2.0
1122
16.4k
    Perms = process_with_aes(out_encryption_key, true, compute_Perms_value_V5_clear());
1123
16.4k
    return out_encryption_key;
1124
16.4k
}
1125
1126
std::string
1127
QPDF::EncryptionData::compute_parameters(char const* user_password, char const* owner_password)
1128
31.8k
{
1129
31.8k
    if (V < 5) {
1130
15.4k
        compute_encryption_O_U(user_password, owner_password);
1131
15.4k
        return compute_encryption_key(user_password);
1132
16.4k
    } else {
1133
16.4k
        return compute_encryption_parameters_V5(user_password, owner_password);
1134
16.4k
    }
1135
31.8k
}
1136
1137
std::string const&
1138
QPDF::getPaddedUserPassword() const
1139
0
{
1140
0
    return m->encp->user_password;
1141
0
}
1142
1143
std::string
1144
QPDF::getTrimmedUserPassword() const
1145
255
{
1146
255
    std::string result = m->encp->user_password;
1147
255
    trim_user_password(result);
1148
255
    return result;
1149
255
}
1150
1151
std::string
1152
QPDF::getEncryptionKey() const
1153
0
{
1154
0
    return m->encp->encryption_key;
1155
0
}
1156
1157
bool
1158
QPDF::isEncrypted() const
1159
0
{
1160
0
    return m->encp->encrypted;
1161
0
}
1162
1163
bool
1164
QPDF::isEncrypted(int& R, int& P)
1165
0
{
1166
0
    if (!m->encp->encrypted) {
1167
0
        return false;
1168
0
    }
1169
0
    P = m->encp->P();
1170
0
    R = m->encp->R();
1171
0
    return true;
1172
0
}
1173
1174
bool
1175
QPDF::isEncrypted(
1176
    int& R,
1177
    int& P,
1178
    int& V,
1179
    encryption_method_e& stream_method,
1180
    encryption_method_e& string_method,
1181
    encryption_method_e& file_method)
1182
0
{
1183
0
    if (!m->encp->encrypted) {
1184
0
        return false;
1185
0
    }
1186
0
    P = m->encp->P();
1187
0
    R = m->encp->R();
1188
0
    V = m->encp->encryption_V;
1189
0
    stream_method = m->encp->cf_stream;
1190
0
    string_method = m->encp->cf_string;
1191
0
    file_method = m->encp->cf_file;
1192
0
    return true;
1193
0
}
1194
1195
bool
1196
QPDF::ownerPasswordMatched() const
1197
0
{
1198
0
    return m->encp->owner_password_matched;
1199
0
}
1200
1201
bool
1202
QPDF::userPasswordMatched() const
1203
0
{
1204
0
    return m->encp->user_password_matched;
1205
0
}
1206
1207
bool
1208
QPDF::allowAccessibility()
1209
0
{
1210
0
    return m->encp->R() < 3 ? m->encp->P(5) : m->encp->P(10);
1211
0
}
1212
1213
bool
1214
QPDF::allowExtractAll()
1215
0
{
1216
0
    return m->encp->P(5);
1217
0
}
1218
1219
bool
1220
QPDF::allowPrintLowRes()
1221
0
{
1222
0
    return m->encp->P(3);
1223
0
}
1224
1225
bool
1226
QPDF::allowPrintHighRes()
1227
0
{
1228
0
    return allowPrintLowRes() && (m->encp->R() < 3 ? true : m->encp->P(12));
1229
0
}
1230
1231
bool
1232
QPDF::allowModifyAssembly()
1233
0
{
1234
0
    return m->encp->R() < 3 ? m->encp->P(4) : m->encp->P(11);
1235
0
}
1236
1237
bool
1238
QPDF::allowModifyForm()
1239
0
{
1240
0
    return m->encp->R() < 3 ? m->encp->P(6) : m->encp->P(9);
1241
0
}
1242
1243
bool
1244
QPDF::allowModifyAnnotation()
1245
0
{
1246
0
    return m->encp->P(6);
1247
0
}
1248
1249
bool
1250
QPDF::allowModifyOther()
1251
0
{
1252
0
    return m->encp->P(4);
1253
0
}
1254
1255
bool
1256
QPDF::allowModifyAll()
1257
0
{
1258
0
    return allowModifyAnnotation() && allowModifyOther() &&
1259
0
        (m->encp->R() < 3 ? true : allowModifyForm() && allowModifyAssembly());
1260
0
}