1 // Copyright 2014 PDFium Authors. All rights reserved.
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 <time.h>
10 
11 #include <algorithm>
12 #include <utility>
13 #include <vector>
14 
15 #include "core/fdrm/crypto/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 
22 namespace {
23 
24 const uint8_t defpasscode[32] = {
25     0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, 0x64, 0x00, 0x4e,
26     0x56, 0xff, 0xfa, 0x01, 0x08, 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68,
27     0x3e, 0x80, 0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a};
28 
CalcEncryptKey(const CPDF_Dictionary * pEncrypt,const ByteString & password,uint8_t * key,int keylen,bool bIgnoreMeta,const ByteString & fileId)29 void CalcEncryptKey(const CPDF_Dictionary* pEncrypt,
30                     const ByteString& password,
31                     uint8_t* key,
32                     int keylen,
33                     bool bIgnoreMeta,
34                     const ByteString& fileId) {
35   int revision = pEncrypt->GetIntegerFor("R");
36   uint8_t passcode[32];
37   for (uint32_t i = 0; i < 32; i++) {
38     passcode[i] = i < password.GetLength()
39                       ? password[i]
40                       : defpasscode[i - password.GetLength()];
41   }
42   CRYPT_md5_context md5;
43   CRYPT_MD5Start(&md5);
44   CRYPT_MD5Update(&md5, passcode, 32);
45   ByteString okey = pEncrypt->GetStringFor("O");
46   CRYPT_MD5Update(&md5, (uint8_t*)okey.c_str(), okey.GetLength());
47   uint32_t perm = pEncrypt->GetIntegerFor("P");
48   CRYPT_MD5Update(&md5, (uint8_t*)&perm, 4);
49   if (!fileId.IsEmpty())
50     CRYPT_MD5Update(&md5, (uint8_t*)fileId.c_str(), fileId.GetLength());
51   if (!bIgnoreMeta && revision >= 3 &&
52       !pEncrypt->GetIntegerFor("EncryptMetadata", 1)) {
53     uint32_t tag = 0xFFFFFFFF;
54     CRYPT_MD5Update(&md5, (uint8_t*)&tag, 4);
55   }
56   uint8_t digest[16];
57   CRYPT_MD5Finish(&md5, digest);
58   uint32_t copy_len = keylen;
59   if (copy_len > sizeof(digest))
60     copy_len = sizeof(digest);
61   if (revision >= 3) {
62     for (int i = 0; i < 50; i++)
63       CRYPT_MD5Generate(digest, copy_len, digest);
64   }
65   memset(key, 0, keylen);
66   memcpy(key, digest, copy_len);
67 }
68 
IsValidKeyLengthForCipher(int cipher,int keylen)69 bool IsValidKeyLengthForCipher(int cipher, int keylen) {
70   switch (cipher) {
71     case FXCIPHER_AES:
72       return keylen == 16 || keylen == 24 || keylen == 32;
73     case FXCIPHER_AES2:
74       return keylen == 32;
75     case FXCIPHER_RC4:
76       return keylen >= 5 && keylen <= 16;
77     case FXCIPHER_NONE:
78       return true;
79     default:
80       NOTREACHED();
81   }
82   return false;
83 }
84 
85 }  // namespace
86 
CPDF_SecurityHandler()87 CPDF_SecurityHandler::CPDF_SecurityHandler()
88     : m_Version(0),
89       m_Revision(0),
90       m_Permissions(0),
91       m_Cipher(FXCIPHER_NONE),
92       m_KeyLen(0),
93       m_bOwnerUnlocked(false) {}
94 
~CPDF_SecurityHandler()95 CPDF_SecurityHandler::~CPDF_SecurityHandler() {}
96 
OnInit(const CPDF_Dictionary * pEncryptDict,const CPDF_Array * pIdArray,const ByteString & password)97 bool CPDF_SecurityHandler::OnInit(const CPDF_Dictionary* pEncryptDict,
98                                   const CPDF_Array* pIdArray,
99                                   const ByteString& password) {
100   m_FileId = pIdArray ? pIdArray->GetStringAt(0) : "";
101   if (!LoadDict(pEncryptDict))
102     return false;
103   if (m_Cipher == FXCIPHER_NONE)
104     return true;
105   if (!CheckSecurity(password))
106     return false;
107 
108   InitCryptoHandler();
109   return true;
110 }
111 
CheckSecurity(const ByteString & password)112 bool CPDF_SecurityHandler::CheckSecurity(const ByteString& password) {
113   if (!password.IsEmpty() &&
114       CheckPassword(password, true, m_EncryptKey, m_KeyLen)) {
115     m_bOwnerUnlocked = true;
116     return true;
117   }
118   return CheckPassword(password, false, m_EncryptKey, m_KeyLen);
119 }
120 
GetPermissions() const121 uint32_t CPDF_SecurityHandler::GetPermissions() const {
122   return m_bOwnerUnlocked ? 0xFFFFFFFF : m_Permissions;
123 }
124 
LoadCryptInfo(const CPDF_Dictionary * pEncryptDict,const ByteString & name,int & cipher,int & keylen)125 static bool LoadCryptInfo(const CPDF_Dictionary* pEncryptDict,
126                           const ByteString& name,
127                           int& cipher,
128                           int& keylen) {
129   int Version = pEncryptDict->GetIntegerFor("V");
130   cipher = FXCIPHER_RC4;
131   keylen = 0;
132   if (Version >= 4) {
133     CPDF_Dictionary* pCryptFilters = pEncryptDict->GetDictFor("CF");
134     if (!pCryptFilters) {
135       return false;
136     }
137     if (name == "Identity") {
138       cipher = FXCIPHER_NONE;
139     } else {
140       CPDF_Dictionary* pDefFilter = pCryptFilters->GetDictFor(name);
141       if (!pDefFilter) {
142         return false;
143       }
144       int nKeyBits = 0;
145       if (Version == 4) {
146         nKeyBits = pDefFilter->GetIntegerFor("Length", 0);
147         if (nKeyBits == 0) {
148           nKeyBits = pEncryptDict->GetIntegerFor("Length", 128);
149         }
150       } else {
151         nKeyBits = pEncryptDict->GetIntegerFor("Length", 256);
152       }
153       if (nKeyBits < 40) {
154         nKeyBits *= 8;
155       }
156       keylen = nKeyBits / 8;
157       ByteString cipher_name = pDefFilter->GetStringFor("CFM");
158       if (cipher_name == "AESV2" || cipher_name == "AESV3") {
159         cipher = FXCIPHER_AES;
160       }
161     }
162   } else {
163     keylen = Version > 1 ? pEncryptDict->GetIntegerFor("Length", 40) / 8 : 5;
164   }
165   if (keylen > 32 || keylen < 0) {
166     return false;
167   }
168   return IsValidKeyLengthForCipher(cipher, keylen);
169 }
170 
LoadDict(const CPDF_Dictionary * pEncryptDict)171 bool CPDF_SecurityHandler::LoadDict(const CPDF_Dictionary* pEncryptDict) {
172   m_pEncryptDict = pEncryptDict;
173   m_Version = pEncryptDict->GetIntegerFor("V");
174   m_Revision = pEncryptDict->GetIntegerFor("R");
175   m_Permissions = pEncryptDict->GetIntegerFor("P", -1);
176   if (m_Version < 4)
177     return LoadCryptInfo(pEncryptDict, ByteString(), m_Cipher, m_KeyLen);
178 
179   ByteString stmf_name = pEncryptDict->GetStringFor("StmF");
180   ByteString strf_name = pEncryptDict->GetStringFor("StrF");
181   if (stmf_name != strf_name)
182     return false;
183 
184   return LoadCryptInfo(pEncryptDict, strf_name, m_Cipher, m_KeyLen);
185 }
186 
LoadDict(const CPDF_Dictionary * pEncryptDict,int & cipher,int & key_len)187 bool CPDF_SecurityHandler::LoadDict(const CPDF_Dictionary* pEncryptDict,
188                                     int& cipher,
189                                     int& key_len) {
190   m_pEncryptDict = pEncryptDict;
191   m_Version = pEncryptDict->GetIntegerFor("V");
192   m_Revision = pEncryptDict->GetIntegerFor("R");
193   m_Permissions = pEncryptDict->GetIntegerFor("P", -1);
194 
195   ByteString strf_name;
196   ByteString stmf_name;
197   if (m_Version >= 4) {
198     stmf_name = pEncryptDict->GetStringFor("StmF");
199     strf_name = pEncryptDict->GetStringFor("StrF");
200     if (stmf_name != strf_name)
201       return false;
202   }
203   if (!LoadCryptInfo(pEncryptDict, strf_name, cipher, key_len))
204     return false;
205 
206   m_Cipher = cipher;
207   m_KeyLen = key_len;
208   return true;
209 }
210 
211 #define FX_GET_32WORD(n, b, i)                                        \
212   {                                                                   \
213     (n) = (uint32_t)(                                                 \
214         ((uint64_t)(b)[(i)] << 24) | ((uint64_t)(b)[(i) + 1] << 16) | \
215         ((uint64_t)(b)[(i) + 2] << 8) | ((uint64_t)(b)[(i) + 3]));    \
216   }
BigOrder64BitsMod3(uint8_t * data)217 int BigOrder64BitsMod3(uint8_t* data) {
218   uint64_t ret = 0;
219   for (int i = 0; i < 4; ++i) {
220     uint32_t value;
221     FX_GET_32WORD(value, data, 4 * i);
222     ret <<= 32;
223     ret |= value;
224     ret %= 3;
225   }
226   return (int)ret;
227 }
228 
Revision6_Hash(const ByteString & password,const uint8_t * salt,const uint8_t * vector,uint8_t * hash)229 void Revision6_Hash(const ByteString& password,
230                     const uint8_t* salt,
231                     const uint8_t* vector,
232                     uint8_t* hash) {
233   CRYPT_sha2_context sha;
234   CRYPT_SHA256Start(&sha);
235   CRYPT_SHA256Update(&sha, password.raw_str(), password.GetLength());
236   CRYPT_SHA256Update(&sha, salt, 8);
237   if (vector)
238     CRYPT_SHA256Update(&sha, vector, 48);
239 
240   uint8_t digest[32];
241   CRYPT_SHA256Finish(&sha, digest);
242 
243   std::vector<uint8_t> buf;
244   uint8_t* input = digest;
245   uint8_t* key = input;
246   uint8_t* iv = input + 16;
247   uint8_t* E = nullptr;
248   int iBufLen = 0;
249   std::vector<uint8_t> interDigest;
250   int i = 0;
251   int iBlockSize = 32;
252   CRYPT_aes_context aes;
253   memset(&aes, 0, sizeof(aes));
254   while (i < 64 || i < E[iBufLen - 1] + 32) {
255     int iRoundSize = password.GetLength() + iBlockSize;
256     if (vector) {
257       iRoundSize += 48;
258     }
259     iBufLen = iRoundSize * 64;
260     buf.resize(iBufLen);
261     E = buf.data();
262     std::vector<uint8_t> content;
263     for (int j = 0; j < 64; ++j) {
264       content.insert(std::end(content), password.raw_str(),
265                      password.raw_str() + password.GetLength());
266       content.insert(std::end(content), input, input + iBlockSize);
267       if (vector) {
268         content.insert(std::end(content), vector, vector + 48);
269       }
270     }
271     CRYPT_AESSetKey(&aes, 16, key, 16, true);
272     CRYPT_AESSetIV(&aes, iv);
273     CRYPT_AESEncrypt(&aes, E, content.data(), iBufLen);
274     int iHash = 0;
275     switch (BigOrder64BitsMod3(E)) {
276       case 0:
277         iHash = 0;
278         iBlockSize = 32;
279         break;
280       case 1:
281         iHash = 1;
282         iBlockSize = 48;
283         break;
284       default:
285         iHash = 2;
286         iBlockSize = 64;
287         break;
288     }
289     interDigest.resize(iBlockSize);
290     input = interDigest.data();
291     if (iHash == 0) {
292       CRYPT_SHA256Generate(E, iBufLen, input);
293     } else if (iHash == 1) {
294       CRYPT_SHA384Generate(E, iBufLen, input);
295     } else if (iHash == 2) {
296       CRYPT_SHA512Generate(E, iBufLen, input);
297     }
298     key = input;
299     iv = input + 16;
300     ++i;
301   }
302   if (hash) {
303     memcpy(hash, input, 32);
304   }
305 }
306 
AES256_CheckPassword(const ByteString & password,bool bOwner,uint8_t * key)307 bool CPDF_SecurityHandler::AES256_CheckPassword(const ByteString& password,
308                                                 bool bOwner,
309                                                 uint8_t* key) {
310   if (!m_pEncryptDict)
311     return false;
312 
313   ByteString okey = m_pEncryptDict->GetStringFor("O");
314   if (okey.GetLength() < 48)
315     return false;
316 
317   ByteString ukey = m_pEncryptDict->GetStringFor("U");
318   if (ukey.GetLength() < 48)
319     return false;
320 
321   const uint8_t* pkey = bOwner ? okey.raw_str() : ukey.raw_str();
322   CRYPT_sha2_context sha;
323   uint8_t digest[32];
324   if (m_Revision >= 6) {
325     Revision6_Hash(password, (const uint8_t*)pkey + 32,
326                    bOwner ? ukey.raw_str() : nullptr, digest);
327   } else {
328     CRYPT_SHA256Start(&sha);
329     CRYPT_SHA256Update(&sha, password.raw_str(), password.GetLength());
330     CRYPT_SHA256Update(&sha, pkey + 32, 8);
331     if (bOwner)
332       CRYPT_SHA256Update(&sha, ukey.raw_str(), 48);
333     CRYPT_SHA256Finish(&sha, digest);
334   }
335   if (memcmp(digest, pkey, 32) != 0)
336     return false;
337 
338   if (!key)
339     return true;
340 
341   if (m_Revision >= 6) {
342     Revision6_Hash(password, (const uint8_t*)pkey + 40,
343                    bOwner ? ukey.raw_str() : nullptr, digest);
344   } else {
345     CRYPT_SHA256Start(&sha);
346     CRYPT_SHA256Update(&sha, password.raw_str(), password.GetLength());
347     CRYPT_SHA256Update(&sha, pkey + 40, 8);
348     if (bOwner)
349       CRYPT_SHA256Update(&sha, ukey.raw_str(), 48);
350     CRYPT_SHA256Finish(&sha, digest);
351   }
352   ByteString ekey = m_pEncryptDict->GetStringFor(bOwner ? "OE" : "UE");
353   if (ekey.GetLength() < 32)
354     return false;
355 
356   CRYPT_aes_context aes;
357   memset(&aes, 0, sizeof(aes));
358   CRYPT_AESSetKey(&aes, 16, digest, 32, false);
359   uint8_t iv[16];
360   memset(iv, 0, 16);
361   CRYPT_AESSetIV(&aes, iv);
362   CRYPT_AESDecrypt(&aes, key, ekey.raw_str(), 32);
363   CRYPT_AESSetKey(&aes, 16, key, 32, false);
364   CRYPT_AESSetIV(&aes, iv);
365   ByteString perms = m_pEncryptDict->GetStringFor("Perms");
366   if (perms.IsEmpty())
367     return false;
368 
369   uint8_t perms_buf[16];
370   memset(perms_buf, 0, sizeof(perms_buf));
371   size_t copy_len =
372       std::min(sizeof(perms_buf), static_cast<size_t>(perms.GetLength()));
373   memcpy(perms_buf, perms.raw_str(), copy_len);
374   uint8_t buf[16];
375   CRYPT_AESDecrypt(&aes, buf, perms_buf, 16);
376   if (buf[9] != 'a' || buf[10] != 'd' || buf[11] != 'b')
377     return false;
378 
379   if (FXDWORD_GET_LSBFIRST(buf) != m_Permissions)
380     return false;
381 
382   // Relax this check as there appear to be some non-conforming documents
383   // in the wild. The value in the buffer is the truth; if it requires us
384   // to encrypt metadata, but the dictionary says otherwise, then we may
385   // have a tampered doc.  Otherwise, give it a pass.
386   return buf[8] == 'F' || IsMetadataEncrypted();
387 }
388 
CheckPassword(const ByteString & password,bool bOwner,uint8_t * key,int32_t key_len)389 bool CPDF_SecurityHandler::CheckPassword(const ByteString& password,
390                                          bool bOwner,
391                                          uint8_t* key,
392                                          int32_t key_len) {
393   if (m_Revision >= 5)
394     return AES256_CheckPassword(password, bOwner, key);
395 
396   uint8_t keybuf[32];
397   if (!key)
398     key = keybuf;
399 
400   if (bOwner)
401     return CheckOwnerPassword(password, key, key_len);
402 
403   return CheckUserPassword(password, false, key, key_len) ||
404          CheckUserPassword(password, true, key, key_len);
405 }
406 
CheckUserPassword(const ByteString & password,bool bIgnoreEncryptMeta,uint8_t * key,int32_t key_len)407 bool CPDF_SecurityHandler::CheckUserPassword(const ByteString& password,
408                                              bool bIgnoreEncryptMeta,
409                                              uint8_t* key,
410                                              int32_t key_len) {
411   CalcEncryptKey(m_pEncryptDict.Get(), password, key, key_len,
412                  bIgnoreEncryptMeta, m_FileId);
413   ByteString ukey =
414       m_pEncryptDict ? m_pEncryptDict->GetStringFor("U") : ByteString();
415   if (ukey.GetLength() < 16) {
416     return false;
417   }
418 
419   uint8_t ukeybuf[32];
420   if (m_Revision == 2) {
421     memcpy(ukeybuf, defpasscode, 32);
422     CRYPT_ArcFourCryptBlock(ukeybuf, 32, key, key_len);
423   } else {
424     uint8_t test[32], tmpkey[32];
425     uint32_t copy_len = sizeof(test);
426     if (copy_len > (uint32_t)ukey.GetLength()) {
427       copy_len = ukey.GetLength();
428     }
429     memset(test, 0, sizeof(test));
430     memset(tmpkey, 0, sizeof(tmpkey));
431     memcpy(test, ukey.c_str(), copy_len);
432     for (int32_t i = 19; i >= 0; i--) {
433       for (int j = 0; j < key_len; j++)
434         tmpkey[j] = key[j] ^ static_cast<uint8_t>(i);
435       CRYPT_ArcFourCryptBlock(test, 32, tmpkey, key_len);
436     }
437     CRYPT_md5_context md5;
438     CRYPT_MD5Start(&md5);
439     CRYPT_MD5Update(&md5, defpasscode, 32);
440     if (!m_FileId.IsEmpty()) {
441       CRYPT_MD5Update(&md5, (uint8_t*)m_FileId.c_str(), m_FileId.GetLength());
442     }
443     CRYPT_MD5Finish(&md5, ukeybuf);
444     return memcmp(test, ukeybuf, 16) == 0;
445   }
446   return memcmp(ukey.c_str(), ukeybuf, 16) == 0;
447 }
448 
GetUserPassword(const ByteString & owner_password,int32_t key_len) const449 ByteString CPDF_SecurityHandler::GetUserPassword(
450     const ByteString& owner_password,
451     int32_t key_len) const {
452   ByteString okey = m_pEncryptDict->GetStringFor("O");
453   uint8_t passcode[32];
454   for (uint32_t i = 0; i < 32; i++) {
455     passcode[i] = i < owner_password.GetLength()
456                       ? owner_password[i]
457                       : defpasscode[i - owner_password.GetLength()];
458   }
459   uint8_t digest[16];
460   CRYPT_MD5Generate(passcode, 32, digest);
461   if (m_Revision >= 3) {
462     for (uint32_t i = 0; i < 50; i++) {
463       CRYPT_MD5Generate(digest, 16, digest);
464     }
465   }
466   uint8_t enckey[32];
467   memset(enckey, 0, sizeof(enckey));
468   uint32_t copy_len = key_len;
469   if (copy_len > sizeof(digest)) {
470     copy_len = sizeof(digest);
471   }
472   memcpy(enckey, digest, copy_len);
473   int okeylen = okey.GetLength();
474   if (okeylen > 32) {
475     okeylen = 32;
476   }
477   uint8_t okeybuf[64];
478   memset(okeybuf, 0, sizeof(okeybuf));
479   memcpy(okeybuf, okey.c_str(), okeylen);
480   if (m_Revision == 2) {
481     CRYPT_ArcFourCryptBlock(okeybuf, okeylen, enckey, key_len);
482   } else {
483     for (int32_t i = 19; i >= 0; i--) {
484       uint8_t tempkey[32];
485       memset(tempkey, 0, sizeof(tempkey));
486       for (int j = 0; j < m_KeyLen; j++)
487         tempkey[j] = enckey[j] ^ static_cast<uint8_t>(i);
488       CRYPT_ArcFourCryptBlock(okeybuf, okeylen, tempkey, key_len);
489     }
490   }
491   int len = 32;
492   while (len && defpasscode[len - 1] == okeybuf[len - 1]) {
493     len--;
494   }
495   return ByteString(okeybuf, len);
496 }
497 
CheckOwnerPassword(const ByteString & password,uint8_t * key,int32_t key_len)498 bool CPDF_SecurityHandler::CheckOwnerPassword(const ByteString& password,
499                                               uint8_t* key,
500                                               int32_t key_len) {
501   ByteString user_pass = GetUserPassword(password, key_len);
502   if (CheckUserPassword(user_pass, false, key, key_len))
503     return true;
504   return CheckUserPassword(user_pass, true, key, key_len);
505 }
506 
IsMetadataEncrypted() const507 bool CPDF_SecurityHandler::IsMetadataEncrypted() const {
508   return m_pEncryptDict->GetBooleanFor("EncryptMetadata", true);
509 }
510 
OnCreateInternal(CPDF_Dictionary * pEncryptDict,const CPDF_Array * pIdArray,const ByteString & user_password,const ByteString & owner_password,bool bDefault)511 void CPDF_SecurityHandler::OnCreateInternal(CPDF_Dictionary* pEncryptDict,
512                                             const CPDF_Array* pIdArray,
513                                             const ByteString& user_password,
514                                             const ByteString& owner_password,
515                                             bool bDefault) {
516   ASSERT(pEncryptDict);
517 
518   int cipher = 0;
519   int key_len = 0;
520   if (!LoadDict(pEncryptDict, cipher, key_len)) {
521     return;
522   }
523   ByteString owner_password_copy = owner_password;
524   if (bDefault && owner_password.IsEmpty())
525     owner_password_copy = user_password;
526 
527   if (m_Revision >= 5) {
528     int t = (int)time(nullptr);
529     CRYPT_sha2_context sha;
530     CRYPT_SHA256Start(&sha);
531     CRYPT_SHA256Update(&sha, (uint8_t*)&t, sizeof t);
532     CRYPT_SHA256Update(&sha, m_EncryptKey, 32);
533     CRYPT_SHA256Update(&sha, (uint8_t*)"there", 5);
534     CRYPT_SHA256Finish(&sha, m_EncryptKey);
535     AES256_SetPassword(pEncryptDict, user_password, false, m_EncryptKey);
536     if (bDefault) {
537       AES256_SetPassword(pEncryptDict, owner_password_copy, true, m_EncryptKey);
538       AES256_SetPerms(pEncryptDict, m_Permissions,
539                       pEncryptDict->GetBooleanFor("EncryptMetadata", true),
540                       m_EncryptKey);
541     }
542     return;
543   }
544   if (bDefault) {
545     uint8_t passcode[32];
546     for (uint32_t i = 0; i < 32; i++) {
547       passcode[i] = i < owner_password_copy.GetLength()
548                         ? owner_password_copy[i]
549                         : defpasscode[i - owner_password_copy.GetLength()];
550     }
551     uint8_t digest[16];
552     CRYPT_MD5Generate(passcode, 32, digest);
553     if (m_Revision >= 3) {
554       for (uint32_t i = 0; i < 50; i++)
555         CRYPT_MD5Generate(digest, 16, digest);
556     }
557     uint8_t enckey[32];
558     memcpy(enckey, digest, key_len);
559     for (uint32_t i = 0; i < 32; i++) {
560       passcode[i] = i < user_password.GetLength()
561                         ? user_password[i]
562                         : defpasscode[i - user_password.GetLength()];
563     }
564     CRYPT_ArcFourCryptBlock(passcode, 32, enckey, key_len);
565     uint8_t tempkey[32];
566     if (m_Revision >= 3) {
567       for (uint8_t i = 1; i <= 19; i++) {
568         for (int j = 0; j < key_len; j++)
569           tempkey[j] = enckey[j] ^ i;
570         CRYPT_ArcFourCryptBlock(passcode, 32, tempkey, key_len);
571       }
572     }
573     pEncryptDict->SetNewFor<CPDF_String>("O", ByteString(passcode, 32), false);
574   }
575 
576   ByteString fileId;
577   if (pIdArray) {
578     fileId = pIdArray->GetStringAt(0);
579   }
580 
581   CalcEncryptKey(m_pEncryptDict.Get(), user_password, m_EncryptKey, key_len,
582                  false, fileId);
583   if (m_Revision < 3) {
584     uint8_t tempbuf[32];
585     memcpy(tempbuf, defpasscode, 32);
586     CRYPT_ArcFourCryptBlock(tempbuf, 32, m_EncryptKey, key_len);
587     pEncryptDict->SetNewFor<CPDF_String>("U", ByteString(tempbuf, 32), false);
588   } else {
589     CRYPT_md5_context md5;
590     CRYPT_MD5Start(&md5);
591     CRYPT_MD5Update(&md5, defpasscode, 32);
592     if (!fileId.IsEmpty()) {
593       CRYPT_MD5Update(&md5, (uint8_t*)fileId.c_str(), fileId.GetLength());
594     }
595     uint8_t digest[32];
596     CRYPT_MD5Finish(&md5, digest);
597     CRYPT_ArcFourCryptBlock(digest, 16, m_EncryptKey, key_len);
598     uint8_t tempkey[32];
599     for (uint8_t i = 1; i <= 19; i++) {
600       for (int j = 0; j < key_len; j++) {
601         tempkey[j] = m_EncryptKey[j] ^ i;
602       }
603       CRYPT_ArcFourCryptBlock(digest, 16, tempkey, key_len);
604     }
605     CRYPT_MD5Generate(digest, 16, digest + 16);
606     pEncryptDict->SetNewFor<CPDF_String>("U", ByteString(digest, 32), false);
607   }
608 }
609 
OnCreate(CPDF_Dictionary * pEncryptDict,const CPDF_Array * pIdArray,const ByteString & user_password,const ByteString & owner_password)610 void CPDF_SecurityHandler::OnCreate(CPDF_Dictionary* pEncryptDict,
611                                     const CPDF_Array* pIdArray,
612                                     const ByteString& user_password,
613                                     const ByteString& owner_password) {
614   OnCreateInternal(pEncryptDict, pIdArray, user_password, owner_password, true);
615   InitCryptoHandler();
616 }
617 
OnCreate(CPDF_Dictionary * pEncryptDict,const CPDF_Array * pIdArray,const ByteString & user_password)618 void CPDF_SecurityHandler::OnCreate(CPDF_Dictionary* pEncryptDict,
619                                     const CPDF_Array* pIdArray,
620                                     const ByteString& user_password) {
621   OnCreateInternal(pEncryptDict, pIdArray, user_password, ByteString(), false);
622   InitCryptoHandler();
623 }
624 
AES256_SetPassword(CPDF_Dictionary * pEncryptDict,const ByteString & password,bool bOwner,const uint8_t * key)625 void CPDF_SecurityHandler::AES256_SetPassword(CPDF_Dictionary* pEncryptDict,
626                                               const ByteString& password,
627                                               bool bOwner,
628                                               const uint8_t* key) {
629   CRYPT_sha1_context sha;
630   CRYPT_SHA1Start(&sha);
631   CRYPT_SHA1Update(&sha, key, 32);
632   CRYPT_SHA1Update(&sha, (uint8_t*)"hello", 5);
633 
634   uint8_t digest[20];
635   CRYPT_SHA1Finish(&sha, digest);
636 
637   ByteString ukey = pEncryptDict->GetStringFor("U");
638   CRYPT_sha2_context sha2;
639   uint8_t digest1[48];
640   if (m_Revision >= 6) {
641     Revision6_Hash(password, digest, bOwner ? ukey.raw_str() : nullptr,
642                    digest1);
643   } else {
644     CRYPT_SHA256Start(&sha2);
645     CRYPT_SHA256Update(&sha2, password.raw_str(), password.GetLength());
646     CRYPT_SHA256Update(&sha2, digest, 8);
647     if (bOwner) {
648       CRYPT_SHA256Update(&sha2, ukey.raw_str(), ukey.GetLength());
649     }
650     CRYPT_SHA256Finish(&sha2, digest1);
651   }
652   memcpy(digest1 + 32, digest, 16);
653   pEncryptDict->SetNewFor<CPDF_String>(bOwner ? "O" : "U",
654                                        ByteString(digest1, 48), false);
655   if (m_Revision >= 6) {
656     Revision6_Hash(password, digest + 8, bOwner ? ukey.raw_str() : nullptr,
657                    digest1);
658   } else {
659     CRYPT_SHA256Start(&sha2);
660     CRYPT_SHA256Update(&sha2, password.raw_str(), password.GetLength());
661     CRYPT_SHA256Update(&sha2, digest + 8, 8);
662     if (bOwner) {
663       CRYPT_SHA256Update(&sha2, ukey.raw_str(), ukey.GetLength());
664     }
665     CRYPT_SHA256Finish(&sha2, digest1);
666   }
667   CRYPT_aes_context aes;
668   memset(&aes, 0, sizeof(aes));
669   CRYPT_AESSetKey(&aes, 16, digest1, 32, true);
670   uint8_t iv[16];
671   memset(iv, 0, 16);
672   CRYPT_AESSetIV(&aes, iv);
673   CRYPT_AESEncrypt(&aes, digest1, key, 32);
674   pEncryptDict->SetNewFor<CPDF_String>(bOwner ? "OE" : "UE",
675                                        ByteString(digest1, 32), false);
676 }
677 
AES256_SetPerms(CPDF_Dictionary * pEncryptDict,uint32_t permissions,bool bEncryptMetadata,const uint8_t * key)678 void CPDF_SecurityHandler::AES256_SetPerms(CPDF_Dictionary* pEncryptDict,
679                                            uint32_t permissions,
680                                            bool bEncryptMetadata,
681                                            const uint8_t* key) {
682   uint8_t buf[16];
683   buf[0] = (uint8_t)permissions;
684   buf[1] = (uint8_t)(permissions >> 8);
685   buf[2] = (uint8_t)(permissions >> 16);
686   buf[3] = (uint8_t)(permissions >> 24);
687   buf[4] = 0xff;
688   buf[5] = 0xff;
689   buf[6] = 0xff;
690   buf[7] = 0xff;
691   buf[8] = bEncryptMetadata ? 'T' : 'F';
692   buf[9] = 'a';
693   buf[10] = 'd';
694   buf[11] = 'b';
695 
696   CRYPT_aes_context aes;
697   memset(&aes, 0, sizeof(aes));
698   CRYPT_AESSetKey(&aes, 16, key, 32, true);
699 
700   uint8_t iv[16];
701   memset(iv, 0, 16);
702   CRYPT_AESSetIV(&aes, iv);
703 
704   uint8_t buf1[16];
705   CRYPT_AESEncrypt(&aes, buf1, buf, 16);
706   pEncryptDict->SetNewFor<CPDF_String>("Perms", ByteString(buf1, 16), false);
707 }
708 
InitCryptoHandler()709 void CPDF_SecurityHandler::InitCryptoHandler() {
710   m_pCryptoHandler =
711       pdfium::MakeUnique<CPDF_CryptoHandler>(m_Cipher, m_EncryptKey, m_KeyLen);
712 }
713