Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
cpdf_security_handler.cpp
Go to the documentation of this file.
1// Copyright 2014 The PDFium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7#include "core/fpdfapi/parser/cpdf_security_handler.h"
8
9#include <stdint.h>
10#include <time.h>
11
12#include <algorithm>
13#include <utility>
14
15#include "core/fdrm/fx_crypt.h"
16#include "core/fpdfapi/parser/cpdf_array.h"
17#include "core/fpdfapi/parser/cpdf_crypto_handler.h"
18#include "core/fpdfapi/parser/cpdf_dictionary.h"
19#include "core/fpdfapi/parser/cpdf_object.h"
20#include "core/fpdfapi/parser/cpdf_string.h"
21#include "core/fxcrt/byteorder.h"
22#include "core/fxcrt/check.h"
23#include "core/fxcrt/check_op.h"
24#include "core/fxcrt/compiler_specific.h"
25#include "core/fxcrt/data_vector.h"
26#include "core/fxcrt/fx_memcpy_wrappers.h"
27#include "core/fxcrt/fx_random.h"
28#include "core/fxcrt/notreached.h"
29#include "core/fxcrt/span.h"
30#include "core/fxcrt/span_util.h"
31#include "core/fxcrt/stl_util.h"
32
33namespace {
34
35const uint8_t kDefaultPasscode[32] = {
36 0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, 0x64, 0x00, 0x4e,
37 0x56, 0xff, 0xfa, 0x01, 0x08, 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68,
38 0x3e, 0x80, 0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a};
39
40void GetPassCode(const ByteString& password, pdfium::span<uint8_t> output) {
41 DCHECK_EQ(sizeof(kDefaultPasscode), output.size());
42 size_t len = std::min(password.GetLength(), output.size());
43 auto remaining = fxcrt::spancpy(output, password.unsigned_span().first(len));
44 if (!remaining.empty()) {
45 auto default_span = pdfium::make_span(kDefaultPasscode);
46 fxcrt::spancpy(remaining, default_span.first(remaining.size()));
47 }
48}
49
50void CalcEncryptKey(const CPDF_Dictionary* pEncrypt,
51 const ByteString& password,
52 pdfium::span<uint8_t> key,
53 bool ignore_metadata,
54 const ByteString& file_id) {
55 fxcrt::Fill(key, 0);
56
57 uint8_t passcode[32];
58 GetPassCode(password, passcode);
59
61 CRYPT_MD5Update(&md5, passcode);
62
63 ByteString okey = pEncrypt->GetByteStringFor("O");
64 CRYPT_MD5Update(&md5, okey.unsigned_span());
65
66 uint32_t perm = pEncrypt->GetIntegerFor("P");
67 CRYPT_MD5Update(&md5, pdfium::as_bytes(pdfium::span_from_ref(perm)));
68 if (!file_id.IsEmpty()) {
69 CRYPT_MD5Update(&md5, file_id.unsigned_span());
70 }
71 const bool is_revision_3_or_greater = pEncrypt->GetIntegerFor("R") >= 3;
72 if (!ignore_metadata && is_revision_3_or_greater &&
73 !pEncrypt->GetBooleanFor("EncryptMetadata", true)) {
74 constexpr uint32_t tag = 0xFFFFFFFF;
75 CRYPT_MD5Update(&md5, pdfium::byte_span_from_ref(tag));
76 }
77 uint8_t digest[16];
78 CRYPT_MD5Finish(&md5, digest);
79 size_t copy_len = std::min(key.size(), sizeof(digest));
80 auto digest_span = pdfium::make_span(digest).first(copy_len);
81 if (is_revision_3_or_greater) {
82 for (int i = 0; i < 50; i++) {
83 CRYPT_MD5Generate(digest_span, digest);
84 }
85 }
86 fxcrt::Copy(digest_span, key);
87}
88
89bool IsValidKeyLengthForCipher(CPDF_CryptoHandler::Cipher cipher,
90 size_t keylen) {
91 switch (cipher) {
93 return keylen == 16 || keylen == 24 || keylen == 32;
95 return keylen == 32;
97 return keylen >= 5 && keylen <= 16;
99 return true;
100 }
101}
102
103int BigOrder64BitsMod3(pdfium::span<const uint8_t> data) {
104 uint64_t ret = 0;
105 for (int i = 0; i < 4; ++i) {
106 ret <<= 32;
107 ret |= fxcrt::GetUInt32MSBFirst(data);
108 ret %= 3;
109 data = data.subspan(4);
110 }
111 return static_cast<int>(ret);
112}
113
114void Revision6_Hash(const ByteString& password,
115 const uint8_t* salt,
116 const uint8_t* vector,
117 uint8_t* hash) {
120 CRYPT_SHA256Update(&sha, password.unsigned_span());
121 CRYPT_SHA256Update(&sha, UNSAFE_TODO(pdfium::make_span(salt, 8)));
122 if (vector) {
123 CRYPT_SHA256Update(&sha, UNSAFE_TODO(pdfium::make_span(vector, 48)));
124 }
125 uint8_t digest[32];
126 CRYPT_SHA256Finish(&sha, digest);
127
128 DataVector<uint8_t> encrypted_output;
129 DataVector<uint8_t> inter_digest;
130 uint8_t* input = digest;
131 uint8_t* key = input;
132 uint8_t* iv = UNSAFE_TODO(input + 16);
133 int i = 0;
134 size_t block_size = 32;
135 CRYPT_aes_context aes = {};
136 do {
137 size_t round_size = password.GetLength() + block_size;
138 if (vector) {
139 round_size += 48;
140 }
141 encrypted_output.resize(round_size * 64);
142 auto encrypted_output_span = pdfium::make_span(encrypted_output);
143 DataVector<uint8_t> content;
144 for (int j = 0; j < 64; ++j) {
146 content.insert(std::end(content), password.unsigned_str(),
147 password.unsigned_str() + password.GetLength());
148 content.insert(std::end(content), input, input + block_size);
149 if (vector) {
150 content.insert(std::end(content), vector, vector + 48);
151 }
152 });
153 }
154 CHECK_EQ(content.size(), encrypted_output.size());
155 CRYPT_AESSetKey(&aes, key, 16);
156 CRYPT_AESSetIV(&aes, iv);
157 CRYPT_AESEncrypt(&aes, encrypted_output_span, content);
158
159 switch (BigOrder64BitsMod3(encrypted_output_span)) {
160 case 0:
161 block_size = 32;
162 inter_digest = CRYPT_SHA256Generate(encrypted_output_span);
163 break;
164 case 1:
165 block_size = 48;
166 inter_digest = CRYPT_SHA384Generate(encrypted_output_span);
167 break;
168 default:
169 block_size = 64;
170 inter_digest = CRYPT_SHA512Generate(encrypted_output_span);
171 break;
172 }
173 input = inter_digest.data();
174 key = input;
175 iv = UNSAFE_TODO(input + 16);
176 ++i;
177 } while (i < 64 || i - 32 < encrypted_output.back());
178 if (hash) {
179 UNSAFE_TODO(FXSYS_memcpy(hash, input, 32));
180 }
181}
182
183} // namespace
184
185CPDF_SecurityHandler::CPDF_SecurityHandler() = default;
186
187CPDF_SecurityHandler::~CPDF_SecurityHandler() = default;
188
189bool CPDF_SecurityHandler::OnInit(const CPDF_Dictionary* pEncryptDict,
190 RetainPtr<const CPDF_Array> pIdArray,
191 const ByteString& password) {
192 if (pIdArray)
193 m_FileId = pIdArray->GetByteStringAt(0);
194 else
195 m_FileId.clear();
196 if (!LoadDict(pEncryptDict))
197 return false;
198 if (m_Cipher == CPDF_CryptoHandler::Cipher::kNone)
199 return true;
200 if (!CheckSecurity(password))
201 return false;
202
203 InitCryptoHandler();
204 return true;
205}
206
207bool CPDF_SecurityHandler::CheckSecurity(const ByteString& password) {
208 if (!password.IsEmpty() && CheckPassword(password, true)) {
209 m_bOwnerUnlocked = true;
210 return true;
211 }
212 return CheckPassword(password, false);
213}
214
215uint32_t CPDF_SecurityHandler::GetPermissions(bool get_owner_perms) const {
216 uint32_t dwPermission =
217 m_bOwnerUnlocked && get_owner_perms ? 0xFFFFFFFF : m_Permissions;
218 if (m_pEncryptDict &&
219 m_pEncryptDict->GetByteStringFor("Filter") == "Standard") {
220 // See PDF Reference 1.7, page 123, table 3.20.
221 dwPermission &= 0xFFFFFFFC;
222 dwPermission |= 0xFFFFF0C0;
223 }
224 return dwPermission;
225}
226
227static bool LoadCryptInfo(const CPDF_Dictionary* pEncryptDict,
228 const ByteString& name,
229 CPDF_CryptoHandler::Cipher* cipher,
230 size_t* keylen_out) {
231 int Version = pEncryptDict->GetIntegerFor("V");
233 *keylen_out = 0;
234 int keylen = 0;
235 if (Version >= 4) {
236 RetainPtr<const CPDF_Dictionary> pCryptFilters =
237 pEncryptDict->GetDictFor("CF");
238 if (!pCryptFilters)
239 return false;
240
241 if (name == "Identity") {
243 } else {
244 RetainPtr<const CPDF_Dictionary> pDefFilter =
245 pCryptFilters->GetDictFor(name);
246 if (!pDefFilter)
247 return false;
248
249 int nKeyBits = 0;
250 if (Version == 4) {
251 nKeyBits = pDefFilter->GetIntegerFor("Length", 0);
252 if (nKeyBits == 0) {
253 nKeyBits = pEncryptDict->GetIntegerFor("Length", 128);
254 }
255 } else {
256 nKeyBits = pEncryptDict->GetIntegerFor("Length", 256);
257 }
258 if (nKeyBits < 0)
259 return false;
260
261 if (nKeyBits < 40) {
262 nKeyBits *= 8;
263 }
264 keylen = nKeyBits / 8;
265 ByteString cipher_name = pDefFilter->GetByteStringFor("CFM");
266 if (cipher_name == "AESV2" || cipher_name == "AESV3")
268 }
269 } else {
270 keylen = Version > 1 ? pEncryptDict->GetIntegerFor("Length", 40) / 8 : 5;
271 }
272
273 if (keylen < 0 || keylen > 32)
274 return false;
275 if (!IsValidKeyLengthForCipher(*cipher, keylen))
276 return false;
277
278 *keylen_out = keylen;
279 return true;
280}
281
282bool CPDF_SecurityHandler::LoadDict(const CPDF_Dictionary* pEncryptDict) {
283 m_pEncryptDict.Reset(pEncryptDict);
284 m_Version = pEncryptDict->GetIntegerFor("V");
285 m_Revision = pEncryptDict->GetIntegerFor("R");
286 m_Permissions = pEncryptDict->GetIntegerFor("P", -1);
287 if (m_Version < 4)
288 return LoadCryptInfo(pEncryptDict, ByteString(), &m_Cipher, &m_KeyLen);
289
290 ByteString stmf_name = pEncryptDict->GetByteStringFor("StmF");
291 ByteString strf_name = pEncryptDict->GetByteStringFor("StrF");
292 if (stmf_name != strf_name)
293 return false;
294
295 return LoadCryptInfo(pEncryptDict, strf_name, &m_Cipher, &m_KeyLen);
296}
297
298bool CPDF_SecurityHandler::LoadDict(const CPDF_Dictionary* pEncryptDict,
299 CPDF_CryptoHandler::Cipher* cipher,
300 size_t* key_len) {
301 m_pEncryptDict.Reset(pEncryptDict);
302 m_Version = pEncryptDict->GetIntegerFor("V");
303 m_Revision = pEncryptDict->GetIntegerFor("R");
304 m_Permissions = pEncryptDict->GetIntegerFor("P", -1);
305
306 ByteString strf_name;
307 ByteString stmf_name;
308 if (m_Version >= 4) {
309 stmf_name = pEncryptDict->GetByteStringFor("StmF");
310 strf_name = pEncryptDict->GetByteStringFor("StrF");
311 if (stmf_name != strf_name)
312 return false;
313 }
314 if (!LoadCryptInfo(pEncryptDict, strf_name, cipher, key_len))
315 return false;
316
317 m_Cipher = *cipher;
318 m_KeyLen = *key_len;
319 return true;
320}
321
322bool CPDF_SecurityHandler::AES256_CheckPassword(const ByteString& password,
323 bool bOwner) {
324 DCHECK(m_pEncryptDict);
325 DCHECK(m_Revision >= 5);
326
327 ByteString okey = m_pEncryptDict->GetByteStringFor("O");
328 if (okey.GetLength() < 48)
329 return false;
330
331 ByteString ukey = m_pEncryptDict->GetByteStringFor("U");
332 if (ukey.GetLength() < 48)
333 return false;
334
335 const uint8_t* pkey = bOwner ? okey.unsigned_str() : ukey.unsigned_str();
337 uint8_t digest[32];
338 if (m_Revision >= 6) {
339 Revision6_Hash(password, UNSAFE_TODO((const uint8_t*)pkey + 32),
340 bOwner ? ukey.unsigned_str() : nullptr, digest);
341 } else {
343 CRYPT_SHA256Update(&sha, password.unsigned_span());
344 CRYPT_SHA256Update(&sha, UNSAFE_TODO(pdfium::make_span(pkey + 32, 8)));
345 if (bOwner) {
346 CRYPT_SHA256Update(&sha, ukey.unsigned_span().first(48u));
347 }
348 CRYPT_SHA256Finish(&sha, digest);
349 }
350 if (memcmp(digest, pkey, 32) != 0)
351 return false;
352
353 if (m_Revision >= 6) {
354 Revision6_Hash(password, UNSAFE_TODO(pkey + 40),
355 bOwner ? ukey.unsigned_str() : nullptr, digest);
356 } else {
358 CRYPT_SHA256Update(&sha, password.unsigned_span());
359 CRYPT_SHA256Update(&sha, UNSAFE_TODO(pdfium::make_span(pkey + 40, 8)));
360 if (bOwner) {
361 CRYPT_SHA256Update(&sha, ukey.unsigned_span().first(48u));
362 }
363 CRYPT_SHA256Finish(&sha, digest);
364 }
365 ByteString ekey = m_pEncryptDict->GetByteStringFor(bOwner ? "OE" : "UE");
366 if (ekey.GetLength() < 32)
367 return false;
368
369 CRYPT_aes_context aes = {};
370 CRYPT_AESSetKey(&aes, digest, sizeof(digest));
371 uint8_t iv[16] = {};
372 CRYPT_AESSetIV(&aes, iv);
373 CRYPT_AESDecrypt(&aes, m_EncryptKey.data(), ekey.unsigned_str(), 32);
374 CRYPT_AESSetKey(&aes, m_EncryptKey.data(), m_EncryptKey.size());
375 CRYPT_AESSetIV(&aes, iv);
376 ByteString perms = m_pEncryptDict->GetByteStringFor("Perms");
377 if (perms.IsEmpty())
378 return false;
379
380 uint8_t perms_buf[16] = {};
381 size_t copy_len =
382 std::min(sizeof(perms_buf), static_cast<size_t>(perms.GetLength()));
383 UNSAFE_TODO(FXSYS_memcpy(perms_buf, perms.unsigned_str(), copy_len));
384 uint8_t buf[16];
385 CRYPT_AESDecrypt(&aes, buf, perms_buf, 16);
386 if (buf[9] != 'a' || buf[10] != 'd' || buf[11] != 'b')
387 return false;
388
389 if (fxcrt::GetUInt32LSBFirst(pdfium::make_span(buf).first(4u)) !=
390 m_Permissions) {
391 return false;
392 }
393
394 // Relax this check as there appear to be some non-conforming documents
395 // in the wild. The value in the buffer is the truth; if it requires us
396 // to encrypt metadata, but the dictionary says otherwise, then we may
397 // have a tampered doc. Otherwise, give it a pass.
398 return buf[8] == 'F' || IsMetadataEncrypted();
399}
400
401bool CPDF_SecurityHandler::CheckPassword(const ByteString& password,
402 bool bOwner) {
403 DCHECK_EQ(kUnknown, m_PasswordEncodingConversion);
404 if (CheckPasswordImpl(password, bOwner)) {
405 m_PasswordEncodingConversion = kNone;
406 return true;
407 }
408
409 ByteStringView password_view = password.AsStringView();
410 if (password_view.IsASCII())
411 return false;
412
413 if (m_Revision >= 5) {
414 ByteString utf8_password = WideString::FromLatin1(password_view).ToUTF8();
415 if (!CheckPasswordImpl(utf8_password, bOwner))
416 return false;
417
418 m_PasswordEncodingConversion = kLatin1ToUtf8;
419 return true;
420 }
421
422 ByteString latin1_password = WideString::FromUTF8(password_view).ToLatin1();
423 if (!CheckPasswordImpl(latin1_password, bOwner))
424 return false;
425
426 m_PasswordEncodingConversion = kUtf8toLatin1;
427 return true;
428}
429
430bool CPDF_SecurityHandler::CheckPasswordImpl(const ByteString& password,
431 bool bOwner) {
432 if (m_Revision >= 5)
433 return AES256_CheckPassword(password, bOwner);
434
435 if (bOwner)
436 return CheckOwnerPassword(password);
437
438 return CheckUserPassword(password, false) ||
439 CheckUserPassword(password, true);
440}
441
442bool CPDF_SecurityHandler::CheckUserPassword(const ByteString& password,
443 bool bIgnoreEncryptMeta) {
444 CalcEncryptKey(m_pEncryptDict.Get(), password,
445 pdfium::make_span(m_EncryptKey).first(m_KeyLen),
446 bIgnoreEncryptMeta, m_FileId);
447 ByteString ukey =
448 m_pEncryptDict ? m_pEncryptDict->GetByteStringFor("U") : ByteString();
449 if (ukey.GetLength() < 16) {
450 return false;
451 }
452
453 uint8_t ukeybuf[32];
454 if (m_Revision == 2) {
456 FXSYS_memcpy(ukeybuf, kDefaultPasscode, sizeof(kDefaultPasscode)));
457 CRYPT_ArcFourCryptBlock(ukeybuf,
458 pdfium::make_span(m_EncryptKey).first(m_KeyLen));
459 return memcmp(ukey.c_str(), ukeybuf, 16) == 0;
460 }
461
462 uint8_t test[32] = {};
463 uint8_t tmpkey[32] = {};
464 uint32_t copy_len = std::min(sizeof(test), ukey.GetLength());
465 UNSAFE_TODO(FXSYS_memcpy(test, ukey.c_str(), copy_len));
466 for (int32_t i = 19; i >= 0; i--) {
467 for (size_t j = 0; j < m_KeyLen; j++) {
468 UNSAFE_TODO(tmpkey[j] = m_EncryptKey[j] ^ static_cast<uint8_t>(i));
469 }
470 CRYPT_ArcFourCryptBlock(test, pdfium::make_span(tmpkey).first(m_KeyLen));
471 }
473 CRYPT_MD5Update(&md5, kDefaultPasscode);
474 if (!m_FileId.IsEmpty())
475 CRYPT_MD5Update(&md5, m_FileId.unsigned_span());
476 CRYPT_MD5Finish(&md5, pdfium::make_span(ukeybuf).first(16u));
477 return memcmp(test, ukeybuf, 16) == 0;
478}
479
480ByteString CPDF_SecurityHandler::GetUserPassword(
481 const ByteString& owner_password) const {
482 constexpr size_t kRequiredOkeyLength = 32;
483 ByteString okey = m_pEncryptDict->GetByteStringFor("O");
484 size_t okeylen = std::min<size_t>(okey.GetLength(), kRequiredOkeyLength);
485 if (okeylen < kRequiredOkeyLength)
486 return ByteString();
487
488 DCHECK_EQ(kRequiredOkeyLength, okeylen);
489 uint8_t passcode[32];
490 GetPassCode(owner_password, passcode);
491 uint8_t digest[16];
492 CRYPT_MD5Generate(passcode, digest);
493 if (m_Revision >= 3) {
494 for (uint32_t i = 0; i < 50; i++)
495 CRYPT_MD5Generate(digest, digest);
496 }
497 uint8_t enckey[32] = {};
498 uint8_t okeybuf[32] = {};
499 size_t copy_len = std::min(m_KeyLen, sizeof(digest));
501 FXSYS_memcpy(enckey, digest, copy_len);
502 FXSYS_memcpy(okeybuf, okey.c_str(), okeylen);
503 });
504 pdfium::span<uint8_t> okey_span = pdfium::make_span(okeybuf).first(okeylen);
505 if (m_Revision == 2) {
506 CRYPT_ArcFourCryptBlock(okey_span,
507 pdfium::make_span(enckey).first(m_KeyLen));
508 } else {
509 for (int32_t i = 19; i >= 0; i--) {
510 uint8_t tempkey[32] = {};
511 for (size_t j = 0; j < m_KeyLen; j++) {
512 UNSAFE_TODO(tempkey[j] = enckey[j] ^ static_cast<uint8_t>(i));
513 }
514 CRYPT_ArcFourCryptBlock(okey_span,
515 pdfium::make_span(tempkey).first(m_KeyLen));
516 }
517 }
518 size_t len = kRequiredOkeyLength;
520 while (len && kDefaultPasscode[len - 1] == okey_span[len - 1]) {
521 len--;
522 }
523 });
524 return ByteString(ByteStringView(pdfium::make_span(okeybuf).first(len)));
525}
526
527bool CPDF_SecurityHandler::CheckOwnerPassword(const ByteString& password) {
528 ByteString user_pass = GetUserPassword(password);
529 return CheckUserPassword(user_pass, false) ||
530 CheckUserPassword(user_pass, true);
531}
532
533bool CPDF_SecurityHandler::IsMetadataEncrypted() const {
534 return m_pEncryptDict->GetBooleanFor("EncryptMetadata", true);
535}
536
537ByteString CPDF_SecurityHandler::GetEncodedPassword(
538 ByteStringView password) const {
539 switch (m_PasswordEncodingConversion) {
540 case kNone:
541 // Do nothing.
542 return ByteString(password);
543 case kLatin1ToUtf8:
544 return WideString::FromLatin1(password).ToUTF8();
545 case kUtf8toLatin1:
546 return WideString::FromUTF8(password).ToLatin1();
547 default:
549 }
550}
551
552void CPDF_SecurityHandler::OnCreate(CPDF_Dictionary* pEncryptDict,
553 const CPDF_Array* pIdArray,
554 const ByteString& password) {
555 DCHECK(pEncryptDict);
556
558 size_t key_len = 0;
559 if (!LoadDict(pEncryptDict, &cipher, &key_len)) {
560 return;
561 }
562
563 if (m_Revision >= 5) {
564 uint32_t random[4];
565 FX_Random_GenerateMT(random);
568 CRYPT_SHA256Update(&sha, pdfium::as_byte_span(random));
569 CRYPT_SHA256Finish(&sha, m_EncryptKey);
570 AES256_SetPassword(pEncryptDict, password);
571 AES256_SetPerms(pEncryptDict);
572 return;
573 }
574
575 ByteString file_id;
576 if (pIdArray)
577 file_id = pIdArray->GetByteStringAt(0);
578
579 CalcEncryptKey(m_pEncryptDict.Get(), password,
580 pdfium::make_span(m_EncryptKey).first(key_len), false,
581 file_id);
582 if (m_Revision < 3) {
583 uint8_t tempbuf[32];
585 FXSYS_memcpy(tempbuf, kDefaultPasscode, sizeof(kDefaultPasscode)));
586 CRYPT_ArcFourCryptBlock(tempbuf,
587 pdfium::make_span(m_EncryptKey).first(key_len));
588 pEncryptDict->SetNewFor<CPDF_String>(
589 "U", ByteString(ByteStringView(pdfium::make_span(tempbuf))));
590 } else {
592 CRYPT_MD5Update(&md5, kDefaultPasscode);
593 if (!file_id.IsEmpty())
594 CRYPT_MD5Update(&md5, file_id.unsigned_span());
595
596 uint8_t digest[32];
597 auto partial_digest_span = pdfium::make_span(digest).first<16u>();
598 auto remaining_digest_span = pdfium::make_span(digest).subspan<16u>();
599 CRYPT_MD5Finish(&md5, partial_digest_span);
600 CRYPT_ArcFourCryptBlock(partial_digest_span,
601 pdfium::make_span(m_EncryptKey).first(key_len));
602 uint8_t tempkey[32];
603 for (uint8_t i = 1; i <= 19; i++) {
604 for (size_t j = 0; j < key_len; j++) {
605 UNSAFE_TODO(tempkey[j] = m_EncryptKey[j] ^ i);
606 }
607 CRYPT_ArcFourCryptBlock(partial_digest_span,
608 pdfium::make_span(tempkey).first(key_len));
609 }
610 CRYPT_MD5Generate(partial_digest_span, remaining_digest_span);
611 pEncryptDict->SetNewFor<CPDF_String>(
612 "U", ByteString(ByteStringView(pdfium::make_span(digest))));
613 }
614
615 InitCryptoHandler();
616}
617
618void CPDF_SecurityHandler::AES256_SetPassword(CPDF_Dictionary* pEncryptDict,
619 const ByteString& password) {
622 CRYPT_SHA1Update(&sha, m_EncryptKey);
623 CRYPT_SHA1Update(&sha, pdfium::as_byte_span("hello").first<5u>());
624
625 uint8_t digest[20];
626 CRYPT_SHA1Finish(&sha, digest);
627
629 uint8_t digest1[48];
630 if (m_Revision >= 6) {
631 Revision6_Hash(password, digest, nullptr, digest1);
632 } else {
634 CRYPT_SHA256Update(&sha2, password.unsigned_span());
635 CRYPT_SHA256Update(&sha2, pdfium::make_span(digest).first<8u>());
636 CRYPT_SHA256Finish(&sha2, pdfium::make_span(digest1).first<32u>());
637 }
638 UNSAFE_TODO(FXSYS_memcpy(digest1 + 32, digest, 16));
639 pEncryptDict->SetNewFor<CPDF_String>(
640 "U", ByteString(ByteStringView(pdfium::make_span(digest1))));
641 if (m_Revision >= 6) {
642 Revision6_Hash(password, UNSAFE_TODO(digest + 8), nullptr, digest1);
643 } else {
645 CRYPT_SHA256Update(&sha2, password.unsigned_span());
646 CRYPT_SHA256Update(&sha2, pdfium::make_span(digest).subspan<8, 8>());
647 CRYPT_SHA256Finish(&sha2, pdfium::make_span(digest1).first<32>());
648 }
649 CRYPT_aes_context aes = {};
650 CRYPT_AESSetKey(&aes, digest1, 32);
651 uint8_t iv[16] = {};
652 CRYPT_AESSetIV(&aes, iv);
653 CRYPT_AESEncrypt(&aes, digest1, m_EncryptKey);
654 pEncryptDict->SetNewFor<CPDF_String>(
655 "UE", ByteString(ByteStringView(pdfium::make_span(digest1).first<32>())));
656}
657
658void CPDF_SecurityHandler::AES256_SetPerms(CPDF_Dictionary* pEncryptDict) {
659 uint8_t buf[16];
660 buf[0] = static_cast<uint8_t>(m_Permissions);
661 buf[1] = static_cast<uint8_t>(m_Permissions >> 8);
662 buf[2] = static_cast<uint8_t>(m_Permissions >> 16);
663 buf[3] = static_cast<uint8_t>(m_Permissions >> 24);
664 buf[4] = 0xff;
665 buf[5] = 0xff;
666 buf[6] = 0xff;
667 buf[7] = 0xff;
668 buf[8] = pEncryptDict->GetBooleanFor("EncryptMetadata", true) ? 'T' : 'F';
669 buf[9] = 'a';
670 buf[10] = 'd';
671 buf[11] = 'b';
672
673 // In ISO 32000 Supplement for ExtensionLevel 3, Algorithm 3.10 says bytes 12
674 // to 15 should be random data.
675 uint32_t random_value;
676 FX_Random_GenerateMT(pdfium::span_from_ref(random_value));
677 fxcrt::Copy(pdfium::byte_span_from_ref(random_value),
678 pdfium::make_span(buf).subspan<12, 4>());
679
680 CRYPT_aes_context aes = {};
681 CRYPT_AESSetKey(&aes, m_EncryptKey.data(), m_EncryptKey.size());
682
683 uint8_t iv[16] = {};
684 CRYPT_AESSetIV(&aes, iv);
685
686 uint8_t dest[16];
687 CRYPT_AESEncrypt(&aes, dest, buf);
688 pEncryptDict->SetNewFor<CPDF_String>(
689 "Perms", ByteString(ByteStringView(pdfium::make_span(dest))));
690}
691
692void CPDF_SecurityHandler::InitCryptoHandler() {
693 m_pCryptoHandler = std::make_unique<CPDF_CryptoHandler>(
694 m_Cipher, pdfium::make_span(m_EncryptKey).first(m_KeyLen));
695}
fxcrt::ByteString ByteString
Definition bytestring.h:180
#define DCHECK
Definition check.h:33
#define CHECK_EQ(x, y)
Definition check_op.h:10
#define DCHECK_EQ(x, y)
Definition check_op.h:17
std::vector< RetainPtr< CPDF_Object > >::const_iterator const_iterator
Definition cpdf_array.h:29
int GetIntegerFor(const ByteString &key) const
bool GetBooleanFor(const ByteString &key, bool bDefault) const
ByteString GetByteStringFor(const ByteString &key) const
int GetIntegerFor(const ByteString &key, int default_int) const
std::map< ByteString, RetainPtr< CPDF_Object >, std::less<> > DictMap
bool OnInit(const CPDF_Dictionary *pEncryptDict, RetainPtr< const CPDF_Array > pIdArray, const ByteString &password)
~CPDF_SecurityHandler() override
uint32_t GetPermissions(bool get_owner_perms) const
void OnCreate(CPDF_Dictionary *pEncryptDict, const CPDF_Array *pIdArray, const ByteString &password)
ByteString GetEncodedPassword(ByteStringView password) const
ByteString()=default
bool operator==(const char *ptr) const
bool operator!=(const ByteString &other) const
Definition bytestring.h:67
ByteString & operator=(ByteString &&that) noexcept
static WideString FromUTF8(ByteStringView str)
static WideString FromLatin1(ByteStringView str)
#define UNSAFE_TODO(...)
static bool LoadCryptInfo(const CPDF_Dictionary *pEncryptDict, const ByteString &name, CPDF_CryptoHandler::Cipher *cipher, size_t *keylen_out)
CRYPT_md5_context CRYPT_MD5Start()
Definition fx_crypt.cpp:164
void CRYPT_AESSetIV(CRYPT_aes_context *ctx, const uint8_t *iv)
void CRYPT_AESDecrypt(CRYPT_aes_context *ctx, uint8_t *dest, const uint8_t *src, uint32_t size)
void CRYPT_AESSetKey(CRYPT_aes_context *ctx, const uint8_t *key, uint32_t keylen)
void CRYPT_SHA256Start(CRYPT_sha2_context *context)
void CRYPT_SHA1Start(CRYPT_sha1_context *context)
UNSAFE_BUFFER_USAGE void * FXSYS_memcpy(void *ptr1, const void *ptr2, size_t len)
uint32_t GetUInt32LSBFirst(pdfium::span< const uint8_t, 4 > span)
Definition byteorder.h:105
#define NOTREACHED_NORETURN()
Definition notreached.h:22
fxcrt::ByteStringView ByteStringView
fxcrt::WideString WideString
Definition widestring.h:207