• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_crypto_handler.h"
8 
9 #include <time.h>
10 
11 #include <algorithm>
12 #include <stack>
13 #include <utility>
14 
15 #include "constants/form_fields.h"
16 #include "core/fdrm/fx_crypt.h"
17 #include "core/fpdfapi/parser/cpdf_dictionary.h"
18 #include "core/fpdfapi/parser/cpdf_number.h"
19 #include "core/fpdfapi/parser/cpdf_object_walker.h"
20 #include "core/fpdfapi/parser/cpdf_parser.h"
21 #include "core/fpdfapi/parser/cpdf_security_handler.h"
22 #include "core/fpdfapi/parser/cpdf_simple_parser.h"
23 #include "core/fpdfapi/parser/cpdf_stream.h"
24 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
25 #include "core/fpdfapi/parser/cpdf_string.h"
26 #include "core/fxcrt/check.h"
27 #include "core/fxcrt/check_op.h"
28 #include "core/fxcrt/fx_memcpy_wrappers.h"
29 #include "core/fxcrt/stl_util.h"
30 
31 namespace {
32 
33 constexpr char kContentsKey[] = "Contents";
34 constexpr char kTypeKey[] = "Type";
35 
36 }  // namespace
37 
38 // static
IsSignatureDictionary(const CPDF_Dictionary * dictionary)39 bool CPDF_CryptoHandler::IsSignatureDictionary(
40     const CPDF_Dictionary* dictionary) {
41   if (!dictionary)
42     return false;
43   RetainPtr<const CPDF_Object> type_obj =
44       dictionary->GetDirectObjectFor(kTypeKey);
45   if (!type_obj)
46     type_obj = dictionary->GetDirectObjectFor(pdfium::form_fields::kFT);
47   return type_obj && type_obj->GetString() == pdfium::form_fields::kSig;
48 }
49 
EncryptContent(uint32_t objnum,uint32_t gennum,pdfium::span<const uint8_t> source) const50 DataVector<uint8_t> CPDF_CryptoHandler::EncryptContent(
51     uint32_t objnum,
52     uint32_t gennum,
53     pdfium::span<const uint8_t> source) const {
54   if (m_Cipher == Cipher::kNone) {
55     return DataVector<uint8_t>(source.begin(), source.end());
56   }
57   uint8_t realkey[16];
58   size_t realkeylen = sizeof(realkey);
59   if (m_Cipher != Cipher::kAES || m_KeyLen != 32) {
60     uint8_t key1[32];
61     PopulateKey(objnum, gennum, key1);
62     if (m_Cipher == Cipher::kAES) {
63       fxcrt::Copy(ByteStringView("sAlT").unsigned_span(),
64                   pdfium::make_span(key1).subspan(m_KeyLen + 5));
65     }
66     size_t len = m_Cipher == Cipher::kAES ? m_KeyLen + 9 : m_KeyLen + 5;
67     CRYPT_MD5Generate(pdfium::make_span(key1).first(len), realkey);
68     realkeylen = std::min(m_KeyLen + 5, sizeof(realkey));
69   }
70   if (m_Cipher == Cipher::kAES) {
71     CRYPT_AESSetKey(m_pAESContext.get(),
72                     m_KeyLen == 32 ? m_EncryptKey.data() : realkey, m_KeyLen);
73 
74     constexpr size_t kIVSize = 16;
75     constexpr size_t kPaddingSize = 16;
76     const size_t source_padding_size = source.size() % kPaddingSize;
77     const size_t source_data_size = source.size() - source_padding_size;
78 
79     DataVector<uint8_t> dest(kIVSize + source_data_size + kPaddingSize);
80     auto dest_span = pdfium::make_span(dest);
81     auto dest_iv_span = dest_span.first(kIVSize);
82     auto dest_data_span = dest_span.subspan(kIVSize, source_data_size);
83     auto dest_padding_span = dest_span.subspan(kIVSize + source_data_size);
84 
85     for (auto& v : dest_iv_span) {
86       v = static_cast<uint8_t>(rand());
87     }
88     CRYPT_AESSetIV(m_pAESContext.get(), dest_iv_span.data());
89 
90     CRYPT_AESEncrypt(m_pAESContext.get(), dest_data_span,
91                      source.first(source_data_size));
92 
93     std::array<uint8_t, kPaddingSize> padding;
94     fxcrt::Copy(source.subspan(source_data_size, source_padding_size), padding);
95     fxcrt::Fill(pdfium::make_span(padding).subspan(source_padding_size),
96                 16 - source_padding_size);
97     CRYPT_AESEncrypt(m_pAESContext.get(), dest_padding_span, padding);
98     return dest;
99   }
100   DataVector<uint8_t> dest(source.begin(), source.end());
101   CRYPT_ArcFourCryptBlock(dest, pdfium::make_span(realkey).first(realkeylen));
102   return dest;
103 }
104 
105 struct AESCryptContext {
106   bool m_bIV;
107   uint32_t m_BlockOffset;
108   CRYPT_aes_context m_Context;
109   uint8_t m_Block[16];
110 };
111 
DecryptStart(uint32_t objnum,uint32_t gennum)112 void* CPDF_CryptoHandler::DecryptStart(uint32_t objnum, uint32_t gennum) {
113   if (m_Cipher == Cipher::kNone)
114     return this;
115 
116   if (m_Cipher == Cipher::kAES && m_KeyLen == 32) {
117     AESCryptContext* pContext = FX_Alloc(AESCryptContext, 1);
118     pContext->m_bIV = true;
119     pContext->m_BlockOffset = 0;
120     CRYPT_AESSetKey(&pContext->m_Context, m_EncryptKey.data(), 32);
121     return pContext;
122   }
123   uint8_t key1[48];
124   PopulateKey(objnum, gennum, key1);
125 
126   if (m_Cipher == Cipher::kAES) {
127     UNSAFE_TODO(FXSYS_memcpy(key1 + m_KeyLen + 5, "sAlT", 4));
128   }
129 
130   uint8_t realkey[16];
131   size_t len = m_Cipher == Cipher::kAES ? m_KeyLen + 9 : m_KeyLen + 5;
132   CRYPT_MD5Generate(pdfium::make_span(key1).first(len), realkey);
133   size_t realkeylen = std::min(m_KeyLen + 5, sizeof(realkey));
134 
135   if (m_Cipher == Cipher::kAES) {
136     AESCryptContext* pContext = FX_Alloc(AESCryptContext, 1);
137     pContext->m_bIV = true;
138     pContext->m_BlockOffset = 0;
139     CRYPT_AESSetKey(&pContext->m_Context, realkey, 16);
140     return pContext;
141   }
142   CRYPT_rc4_context* pContext = FX_Alloc(CRYPT_rc4_context, 1);
143   CRYPT_ArcFourSetup(pContext, pdfium::make_span(realkey).first(realkeylen));
144   return pContext;
145 }
146 
DecryptStream(void * context,pdfium::span<const uint8_t> source,BinaryBuffer & dest_buf)147 bool CPDF_CryptoHandler::DecryptStream(void* context,
148                                        pdfium::span<const uint8_t> source,
149                                        BinaryBuffer& dest_buf) {
150   if (!context)
151     return false;
152 
153   if (m_Cipher == Cipher::kNone) {
154     dest_buf.AppendSpan(source);
155     return true;
156   }
157   if (m_Cipher == Cipher::kRC4) {
158     size_t old_size = dest_buf.GetSize();
159     dest_buf.AppendSpan(source);
160     CRYPT_ArcFourCrypt(
161         static_cast<CRYPT_rc4_context*>(context),
162         dest_buf.GetMutableSpan().subspan(old_size, source.size()));
163     return true;
164   }
165   AESCryptContext* pContext = static_cast<AESCryptContext*>(context);
166   uint32_t src_off = 0;
167   uint32_t src_left = source.size();
168   while (true) {
169     uint32_t copy_size = 16 - pContext->m_BlockOffset;
170     if (copy_size > src_left) {
171       copy_size = src_left;
172     }
173     UNSAFE_TODO(FXSYS_memcpy(pContext->m_Block + pContext->m_BlockOffset,
174                              source.data() + src_off, copy_size));
175     src_off += copy_size;
176     src_left -= copy_size;
177     pContext->m_BlockOffset += copy_size;
178     if (pContext->m_BlockOffset == 16) {
179       if (pContext->m_bIV) {
180         CRYPT_AESSetIV(&pContext->m_Context, pContext->m_Block);
181         pContext->m_bIV = false;
182         pContext->m_BlockOffset = 0;
183       } else if (src_off < source.size()) {
184         uint8_t block_buf[16];
185         CRYPT_AESDecrypt(&pContext->m_Context, block_buf, pContext->m_Block,
186                          16);
187         dest_buf.AppendSpan(block_buf);
188         pContext->m_BlockOffset = 0;
189       }
190     }
191     if (!src_left) {
192       break;
193     }
194   }
195   return true;
196 }
197 
DecryptFinish(void * context,BinaryBuffer & dest_buf)198 bool CPDF_CryptoHandler::DecryptFinish(void* context, BinaryBuffer& dest_buf) {
199   if (!context)
200     return false;
201 
202   if (m_Cipher == Cipher::kNone)
203     return true;
204 
205   if (m_Cipher == Cipher::kRC4) {
206     FX_Free(context);
207     return true;
208   }
209   auto* pContext = static_cast<AESCryptContext*>(context);
210   if (pContext->m_BlockOffset == 16) {
211     uint8_t block_buf[16];
212     CRYPT_AESDecrypt(&pContext->m_Context, block_buf, pContext->m_Block, 16);
213     if (block_buf[15] < 16) {
214       dest_buf.AppendSpan(
215           pdfium::make_span(block_buf).first(16 - block_buf[15]));
216     }
217   }
218   FX_Free(pContext);
219   return true;
220 }
221 
Decrypt(uint32_t objnum,uint32_t gennum,const ByteString & str)222 ByteString CPDF_CryptoHandler::Decrypt(uint32_t objnum,
223                                        uint32_t gennum,
224                                        const ByteString& str) {
225   BinaryBuffer dest_buf;
226   void* context = DecryptStart(objnum, gennum);
227   DecryptStream(context, str.unsigned_span(), dest_buf);
228   DecryptFinish(context, dest_buf);
229   return ByteString(ByteStringView(dest_buf.GetSpan()));
230 }
231 
DecryptGetSize(size_t src_size)232 size_t CPDF_CryptoHandler::DecryptGetSize(size_t src_size) {
233   return m_Cipher == Cipher::kAES ? src_size - 16 : src_size;
234 }
235 
IsCipherAES() const236 bool CPDF_CryptoHandler::IsCipherAES() const {
237   return m_Cipher == Cipher::kAES;
238 }
239 
DecryptObjectTree(RetainPtr<CPDF_Object> object)240 bool CPDF_CryptoHandler::DecryptObjectTree(RetainPtr<CPDF_Object> object) {
241   if (!object)
242     return false;
243 
244   struct MayBeSignature {
245     RetainPtr<const CPDF_Dictionary> parent;
246     RetainPtr<CPDF_Object> contents;
247   };
248 
249   std::stack<MayBeSignature> may_be_sign_dictionaries;
250   const uint32_t obj_num = object->GetObjNum();
251   const uint32_t gen_num = object->GetGenNum();
252 
253   RetainPtr<CPDF_Object> object_to_decrypt = object;
254   while (object_to_decrypt) {
255     CPDF_NonConstObjectWalker walker(std::move(object_to_decrypt));
256     while (RetainPtr<CPDF_Object> child = walker.GetNext()) {
257       RetainPtr<const CPDF_Dictionary> parent_dict =
258           walker.GetParent() ? walker.GetParent()->GetDict() : nullptr;
259       if (walker.dictionary_key() == kContentsKey &&
260           (parent_dict->KeyExist(kTypeKey) ||
261            parent_dict->KeyExist(pdfium::form_fields::kFT))) {
262         // This object may be contents of signature dictionary.
263         // But now values of 'Type' and 'FT' of dictionary keys are encrypted,
264         // and we can not check this.
265         // Temporary skip it, to prevent signature corruption.
266         // It will be decrypted on next interations, if this is not contents of
267         // signature dictionary.
268         may_be_sign_dictionaries.push(
269             {std::move(parent_dict), std::move(child)});
270         walker.SkipWalkIntoCurrentObject();
271         continue;
272       }
273       // Strings decryption.
274       if (child->IsString()) {
275         // TODO(art-snake): Move decryption into the CPDF_String class.
276         CPDF_String* str = child->AsMutableString();
277         str->SetString(Decrypt(obj_num, gen_num, str->GetString()));
278       }
279       // Stream decryption.
280       if (child->IsStream()) {
281         // TODO(art-snake): Move decryption into the CPDF_Stream class.
282         CPDF_Stream* stream = child->AsMutableStream();
283         auto stream_access =
284             pdfium::MakeRetain<CPDF_StreamAcc>(pdfium::WrapRetain(stream));
285         stream_access->LoadAllDataRaw();
286 
287         if (IsCipherAES() && stream_access->GetSize() < 16) {
288           stream->SetData({});
289           continue;
290         }
291 
292         BinaryBuffer decrypted_buf;
293         decrypted_buf.EstimateSize(DecryptGetSize(stream_access->GetSize()));
294 
295         void* context = DecryptStart(obj_num, gen_num);
296         bool decrypt_result =
297             DecryptStream(context, stream_access->GetSpan(), decrypted_buf);
298         decrypt_result &= DecryptFinish(context, decrypted_buf);
299         if (decrypt_result) {
300           stream->TakeData(decrypted_buf.DetachBuffer());
301         } else {
302           // Decryption failed, set the stream to empty
303           stream->SetData({});
304         }
305       }
306     }
307     // Signature dictionaries check.
308     while (!may_be_sign_dictionaries.empty()) {
309       auto dict_and_contents = may_be_sign_dictionaries.top();
310       may_be_sign_dictionaries.pop();
311       if (!IsSignatureDictionary(dict_and_contents.parent)) {
312         // This is not signature dictionary. Do decrypt its contents.
313         object_to_decrypt = dict_and_contents.contents;
314         break;
315       }
316     }
317   }
318   return true;
319 }
320 
CPDF_CryptoHandler(Cipher cipher,pdfium::span<const uint8_t> key)321 CPDF_CryptoHandler::CPDF_CryptoHandler(Cipher cipher,
322                                        pdfium::span<const uint8_t> key)
323     : m_KeyLen(std::min<size_t>(key.size(), 32)), m_Cipher(cipher) {
324   DCHECK(cipher != Cipher::kAES || key.size() == 16 || key.size() == 24 ||
325          key.size() == 32);
326   DCHECK(cipher != Cipher::kAES2 || key.size() == 32);
327   DCHECK(cipher != Cipher::kRC4 || (key.size() >= 5 && key.size() <= 16));
328 
329   if (m_Cipher != Cipher::kNone) {
330     fxcrt::Copy(key.first(m_KeyLen), m_EncryptKey);
331   }
332   if (m_Cipher == Cipher::kAES) {
333     m_pAESContext.reset(FX_Alloc(CRYPT_aes_context, 1));
334   }
335 }
336 
337 CPDF_CryptoHandler::~CPDF_CryptoHandler() = default;
338 
PopulateKey(uint32_t objnum,uint32_t gennum,uint8_t * key) const339 void CPDF_CryptoHandler::PopulateKey(uint32_t objnum,
340                                      uint32_t gennum,
341                                      uint8_t* key) const {
342   UNSAFE_TODO({
343     FXSYS_memcpy(key, m_EncryptKey.data(), m_KeyLen);
344     key[m_KeyLen + 0] = (uint8_t)objnum;
345     key[m_KeyLen + 1] = (uint8_t)(objnum >> 8);
346     key[m_KeyLen + 2] = (uint8_t)(objnum >> 16);
347     key[m_KeyLen + 3] = (uint8_t)gennum;
348     key[m_KeyLen + 4] = (uint8_t)(gennum >> 8);
349   });
350 }
351