Coverage Report

Created: 2026-06-09 07:01

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