7#include "core/fpdfapi/parser/cpdf_security_handler.h"
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"
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};
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()));
52 pdfium::span<uint8_t> key,
58 GetPassCode(password, passcode);
61 CRYPT_MD5Update(&md5, passcode);
64 CRYPT_MD5Update(&md5, okey.unsigned_span());
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());
72 if (!ignore_metadata && is_revision_3_or_greater &&
74 constexpr uint32_t tag = 0xFFFFFFFF;
75 CRYPT_MD5Update(&md5,
pdfium::byte_span_from_ref(tag));
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);
86 fxcrt::Copy(digest_span, key);
93 return keylen == 16 || keylen == 24 || keylen == 32;
97 return keylen >= 5 && keylen <= 16;
103int BigOrder64BitsMod3(pdfium::span<
const uint8_t> data) {
105 for (
int i = 0; i < 4; ++i) {
107 ret |= fxcrt::GetUInt32MSBFirst(data);
109 data = data.subspan(4);
111 return static_cast<
int>(ret);
114void Revision6_Hash(
const ByteString& password,
116 const uint8_t* vector,
120 CRYPT_SHA256Update(&sha, password.unsigned_span());
126 CRYPT_SHA256Finish(&sha, digest);
128 DataVector<uint8_t> encrypted_output;
129 DataVector<uint8_t> inter_digest;
130 uint8_t* input = digest;
131 uint8_t* key = input;
134 size_t block_size = 32;
137 size_t round_size = password.GetLength() + block_size;
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);
150 content.insert(
std::end(content), vector, vector + 48);
154 CHECK_EQ(content.size(), encrypted_output.size());
157 CRYPT_AESEncrypt(&aes, encrypted_output_span, content);
159 switch (BigOrder64BitsMod3(encrypted_output_span)) {
162 inter_digest = CRYPT_SHA256Generate(encrypted_output_span);
166 inter_digest = CRYPT_SHA384Generate(encrypted_output_span);
170 inter_digest = CRYPT_SHA512Generate(encrypted_output_span);
173 input = inter_digest.data();
177 }
while (i < 64 || i - 32 < encrypted_output.back());
185CPDF_SecurityHandler::CPDF_SecurityHandler() =
default;
193 m_FileId = pIdArray->GetByteStringAt(0);
196 if (!LoadDict(pEncryptDict))
200 if (!CheckSecurity(password))
207bool CPDF_SecurityHandler::CheckSecurity(
const ByteString& password) {
208 if (!password.IsEmpty() && CheckPassword(password,
true)) {
209 m_bOwnerUnlocked =
true;
212 return CheckPassword(password,
false);
216 uint32_t dwPermission =
217 m_bOwnerUnlocked && get_owner_perms ? 0xFFFFFFFF : m_Permissions;
218 if (m_pEncryptDict &&
219 m_pEncryptDict->GetByteStringFor(
"Filter") ==
"Standard") {
221 dwPermission &= 0xFFFFFFFC;
222 dwPermission |= 0xFFFFF0C0;
230 size_t* keylen_out) {
237 pEncryptDict->GetDictFor(
"CF");
241 if (name
== "Identity") {
245 pCryptFilters->GetDictFor(name);
251 nKeyBits = pDefFilter->GetIntegerFor(
"Length", 0);
264 keylen = nKeyBits / 8;
265 ByteString cipher_name = pDefFilter->GetByteStringFor(
"CFM");
266 if (cipher_name
== "AESV2" || cipher_name
== "AESV3")
273 if (keylen < 0 || keylen > 32)
275 if (!IsValidKeyLengthForCipher(*cipher, keylen))
278 *keylen_out = keylen;
282bool CPDF_SecurityHandler::LoadDict(
const CPDF_Dictionary* pEncryptDict) {
283 m_pEncryptDict.Reset(pEncryptDict);
288 return LoadCryptInfo(pEncryptDict, ByteString(), &m_Cipher, &m_KeyLen);
292 if (stmf_name
!= strf_name)
295 return LoadCryptInfo(pEncryptDict, strf_name, &m_Cipher, &m_KeyLen);
298bool CPDF_SecurityHandler::LoadDict(
const CPDF_Dictionary* pEncryptDict,
301 m_pEncryptDict.Reset(pEncryptDict);
308 if (m_Version >= 4) {
311 if (stmf_name
!= strf_name)
314 if (!LoadCryptInfo(pEncryptDict, strf_name, cipher, key_len))
322bool CPDF_SecurityHandler::AES256_CheckPassword(
const ByteString& password,
327 ByteString okey = m_pEncryptDict->GetByteStringFor(
"O");
328 if (okey.GetLength() < 48)
331 ByteString ukey = m_pEncryptDict->GetByteStringFor(
"U");
332 if (ukey.GetLength() < 48)
335 const uint8_t* pkey = bOwner ? okey.unsigned_str() : ukey.unsigned_str();
338 if (m_Revision >= 6) {
339 Revision6_Hash(password,
UNSAFE_TODO((
const uint8_t*)pkey + 32),
340 bOwner ? ukey.unsigned_str() :
nullptr, digest);
343 CRYPT_SHA256Update(&sha, password.unsigned_span());
346 CRYPT_SHA256Update(&sha, ukey.unsigned_span().first(48u));
348 CRYPT_SHA256Finish(&sha, digest);
350 if (memcmp(digest, pkey, 32) != 0)
353 if (m_Revision >= 6) {
355 bOwner ? ukey.unsigned_str() :
nullptr, digest);
358 CRYPT_SHA256Update(&sha, password.unsigned_span());
361 CRYPT_SHA256Update(&sha, ukey.unsigned_span().first(48u));
363 CRYPT_SHA256Finish(&sha, digest);
365 ByteString ekey = m_pEncryptDict->GetByteStringFor(bOwner ?
"OE" :
"UE");
366 if (ekey.GetLength() < 32)
373 CRYPT_AESDecrypt(&aes, m_EncryptKey.data(), ekey.unsigned_str(), 32);
374 CRYPT_AESSetKey(&aes, m_EncryptKey.data(), m_EncryptKey.size());
376 ByteString perms = m_pEncryptDict->GetByteStringFor(
"Perms");
380 uint8_t perms_buf[16] = {};
382 std::min(
sizeof(perms_buf),
static_cast<size_t>(perms.GetLength()));
383 UNSAFE_TODO(FXSYS_memcpy(perms_buf, perms.unsigned_str(), copy_len));
386 if (buf[9] !=
'a' || buf[10] !=
'd' || buf[11] !=
'b')
401bool CPDF_SecurityHandler::CheckPassword(
const ByteString& password,
403 DCHECK_EQ(kUnknown, m_PasswordEncodingConversion);
404 if (CheckPasswordImpl(password, bOwner)) {
405 m_PasswordEncodingConversion = kNone;
410 if (password_view.IsASCII())
413 if (m_Revision >= 5) {
415 if (!CheckPasswordImpl(utf8_password, bOwner))
418 m_PasswordEncodingConversion = kLatin1ToUtf8;
423 if (!CheckPasswordImpl(latin1_password, bOwner))
426 m_PasswordEncodingConversion = kUtf8toLatin1;
430bool CPDF_SecurityHandler::CheckPasswordImpl(
const ByteString& password,
433 return AES256_CheckPassword(password, bOwner);
436 return CheckOwnerPassword(password);
438 return CheckUserPassword(password,
false) ||
439 CheckUserPassword(password,
true);
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);
448 m_pEncryptDict ? m_pEncryptDict->GetByteStringFor(
"U") : ByteString();
449 if (ukey.GetLength() < 16) {
454 if (m_Revision == 2) {
457 CRYPT_ArcFourCryptBlock(ukeybuf,
458 pdfium::make_span(m_EncryptKey).first(m_KeyLen));
459 return memcmp(ukey.c_str(), ukeybuf, 16) == 0;
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));
470 CRYPT_ArcFourCryptBlock(test, pdfium::make_span(tmpkey).first(m_KeyLen));
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;
480ByteString CPDF_SecurityHandler::GetUserPassword(
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)
489 uint8_t passcode[32];
490 GetPassCode(owner_password, passcode);
492 CRYPT_MD5Generate(passcode, digest);
493 if (m_Revision >= 3) {
494 for (uint32_t i = 0; i < 50; i++)
495 CRYPT_MD5Generate(digest, digest);
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);
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));
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));
514 CRYPT_ArcFourCryptBlock(okey_span,
515 pdfium::make_span(tempkey).first(m_KeyLen));
518 size_t len = kRequiredOkeyLength;
520 while (len && kDefaultPasscode[len - 1] == okey_span[len - 1]) {
527bool CPDF_SecurityHandler::CheckOwnerPassword(
const ByteString& password) {
528 ByteString user_pass = GetUserPassword(password);
529 return CheckUserPassword(user_pass,
false) ||
530 CheckUserPassword(user_pass,
true);
534 return m_pEncryptDict->GetBooleanFor(
"EncryptMetadata",
true);
539 switch (m_PasswordEncodingConversion) {
559 if (!LoadDict(pEncryptDict, &cipher, &key_len)) {
563 if (m_Revision >= 5) {
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);
577 file_id = pIdArray->GetByteStringAt(0);
579 CalcEncryptKey(m_pEncryptDict.Get(), password,
580 pdfium::make_span(m_EncryptKey).first(key_len),
false,
582 if (m_Revision < 3) {
586 CRYPT_ArcFourCryptBlock(tempbuf,
587 pdfium::make_span(m_EncryptKey).first(key_len));
588 pEncryptDict->SetNewFor<CPDF_String>(
592 CRYPT_MD5Update(&md5, kDefaultPasscode);
593 if (!file_id.IsEmpty())
594 CRYPT_MD5Update(&md5, file_id.unsigned_span());
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));
603 for (uint8_t i = 1; i <= 19; i++) {
604 for (size_t j = 0; j < key_len; j++) {
607 CRYPT_ArcFourCryptBlock(partial_digest_span,
608 pdfium::make_span(tempkey).first(key_len));
610 CRYPT_MD5Generate(partial_digest_span, remaining_digest_span);
611 pEncryptDict->SetNewFor<CPDF_String>(
618void CPDF_SecurityHandler::AES256_SetPassword(
CPDF_Dictionary* pEncryptDict,
622 CRYPT_SHA1Update(&sha, m_EncryptKey);
623 CRYPT_SHA1Update(&sha, pdfium::as_byte_span(
"hello").first<5u>());
626 CRYPT_SHA1Finish(&sha, digest);
630 if (m_Revision >= 6) {
631 Revision6_Hash(password, digest,
nullptr, digest1);
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>());
639 pEncryptDict->SetNewFor<CPDF_String>(
641 if (m_Revision >= 6) {
642 Revision6_Hash(password,
UNSAFE_TODO(digest + 8),
nullptr, digest1);
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>());
653 CRYPT_AESEncrypt(&aes, digest1, m_EncryptKey);
654 pEncryptDict->SetNewFor<CPDF_String>(
655 "UE", ByteString(ByteStringView(pdfium::make_span(digest1).first<32>())));
658void CPDF_SecurityHandler::AES256_SetPerms(
CPDF_Dictionary* pEncryptDict) {
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);
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>());
681 CRYPT_AESSetKey(&aes, m_EncryptKey.data(), m_EncryptKey.size());
687 CRYPT_AESEncrypt(&aes, dest, buf);
688 pEncryptDict->SetNewFor<CPDF_String>(
692void CPDF_SecurityHandler::InitCryptoHandler() {
693 m_pCryptoHandler = std::make_unique<CPDF_CryptoHandler>(
694 m_Cipher, pdfium::make_span(m_EncryptKey).first(m_KeyLen));
fxcrt::ByteString ByteString
std::vector< RetainPtr< CPDF_Object > >::const_iterator const_iterator
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 IsMetadataEncrypted() const
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
bool operator==(const char *ptr) const
bool operator!=(const ByteString &other) const
ByteString & operator=(ByteString &&that) noexcept
static WideString FromUTF8(ByteStringView str)
static WideString FromLatin1(ByteStringView str)
static bool LoadCryptInfo(const CPDF_Dictionary *pEncryptDict, const ByteString &name, CPDF_CryptoHandler::Cipher *cipher, size_t *keylen_out)
CRYPT_md5_context CRYPT_MD5Start()
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)
#define NOTREACHED_NORETURN()
fxcrt::ByteStringView ByteStringView
fxcrt::WideString WideString