summaryrefslogtreecommitdiff
path: root/core/fpdfapi/parser/cpdf_crypto_handler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/fpdfapi/parser/cpdf_crypto_handler.cpp')
-rw-r--r--core/fpdfapi/parser/cpdf_crypto_handler.cpp113
1 files changed, 113 insertions, 0 deletions
diff --git a/core/fpdfapi/parser/cpdf_crypto_handler.cpp b/core/fpdfapi/parser/cpdf_crypto_handler.cpp
index cae95f2c19..441ca8000d 100644
--- a/core/fpdfapi/parser/cpdf_crypto_handler.cpp
+++ b/core/fpdfapi/parser/cpdf_crypto_handler.cpp
@@ -8,10 +8,41 @@
#include <time.h>
+#include <stack>
+#include <utility>
+
#include "core/fdrm/crypto/fx_crypt.h"
+#include "core/fpdfapi/edit/cpdf_encryptor.h"
+#include "core/fpdfapi/edit/cpdf_flateencoder.h"
+#include "core/fpdfapi/parser/cpdf_dictionary.h"
+#include "core/fpdfapi/parser/cpdf_number.h"
+#include "core/fpdfapi/parser/cpdf_object_walker.h"
#include "core/fpdfapi/parser/cpdf_parser.h"
#include "core/fpdfapi/parser/cpdf_security_handler.h"
#include "core/fpdfapi/parser/cpdf_simple_parser.h"
+#include "core/fpdfapi/parser/cpdf_stream.h"
+#include "core/fpdfapi/parser/cpdf_stream_acc.h"
+#include "core/fpdfapi/parser/cpdf_string.h"
+
+namespace {
+
+constexpr char kContentsKey[] = "Contents";
+constexpr char kTypeKey[] = "Type";
+constexpr char kFTKey[] = "FT";
+constexpr char kSignTypeValue[] = "Sig";
+
+} // namespace
+
+// static
+bool CPDF_CryptoHandler::IsSignatureDictionary(
+ const CPDF_Dictionary* dictionary) {
+ if (!dictionary)
+ return false;
+ const CPDF_Object* type_obj = dictionary->GetDirectObjectFor(kTypeKey);
+ if (!type_obj)
+ type_obj = dictionary->GetDirectObjectFor(kFTKey);
+ return type_obj && type_obj->GetString() == kSignTypeValue;
+}
void CPDF_CryptoHandler::CryptBlock(bool bEncrypt,
uint32_t objnum,
@@ -301,6 +332,88 @@ bool CPDF_CryptoHandler::IsCipherAES() const {
return m_Cipher == FXCIPHER_AES;
}
+std::unique_ptr<CPDF_Object> CPDF_CryptoHandler::DecryptObjectTree(
+ std::unique_ptr<CPDF_Object> object) {
+ if (!object)
+ return nullptr;
+
+ struct MayBeSignature {
+ const CPDF_Dictionary* parent;
+ CPDF_Object* contents;
+ };
+
+ std::stack<MayBeSignature> may_be_sign_dictionaries;
+ const uint32_t obj_num = object->GetObjNum();
+ const uint32_t gen_num = object->GetGenNum();
+
+ CPDF_Object* object_to_decrypt = object.get();
+ while (object_to_decrypt) {
+ CPDF_NonConstObjectWalker walker(object_to_decrypt);
+ object_to_decrypt = nullptr;
+ while (CPDF_Object* child = walker.GetNext()) {
+ const CPDF_Dictionary* parent_dict =
+ walker.GetParent() ? walker.GetParent()->GetDict() : nullptr;
+ if (walker.dictionary_key() == kContentsKey &&
+ (parent_dict->KeyExist(kTypeKey) || parent_dict->KeyExist(kFTKey))) {
+ // This object may be contents of signature dictionary.
+ // But now values of 'Type' and 'FT' of dictionary keys are encrypted,
+ // and we can not check this.
+ // Temporary skip it, to prevent signature corruption.
+ // It will be decrypted on next interations, if this is not contents of
+ // signature dictionary.
+ may_be_sign_dictionaries.push(MayBeSignature({parent_dict, child}));
+ walker.SkipWalkIntoCurrentObject();
+ continue;
+ }
+ // Strings decryption.
+ if (child->IsString()) {
+ // TODO(art-snake): Move decryption into the CPDF_String class.
+ CPDF_String* str = child->AsString();
+ str->SetString(Decrypt(obj_num, gen_num, str->GetString()));
+ }
+ // Stream decryption.
+ if (child->IsStream()) {
+ // TODO(art-snake): Move decryption into the CPDF_Stream class.
+ CPDF_Stream* stream = child->AsStream();
+ auto stream_access = pdfium::MakeRetain<CPDF_StreamAcc>(stream);
+ stream_access->LoadAllData(true);
+
+ if (IsCipherAES() && stream_access->GetSize() < 16) {
+ stream->SetData(nullptr, 0);
+ continue;
+ }
+
+ CFX_BinaryBuf decrypted_buf;
+ decrypted_buf.EstimateSize(DecryptGetSize(stream_access->GetSize()));
+
+ void* context = DecryptStart(obj_num, gen_num);
+ bool decrypt_result =
+ DecryptStream(context, stream_access->GetData(),
+ stream_access->GetSize(), decrypted_buf);
+ decrypt_result &= DecryptFinish(context, decrypted_buf);
+ if (decrypt_result) {
+ const uint32_t decrypted_size = decrypted_buf.GetSize();
+ stream->SetData(decrypted_buf.DetachBuffer(), decrypted_size);
+ } else {
+ // Decryption failed, set the stream to empty
+ stream->SetData(nullptr, 0);
+ }
+ }
+ }
+ // Signature dictionaries check.
+ while (!may_be_sign_dictionaries.empty()) {
+ auto dict_and_contents = std::move(may_be_sign_dictionaries.top());
+ may_be_sign_dictionaries.pop();
+ if (!IsSignatureDictionary(dict_and_contents.parent)) {
+ // This is not signature dictionary. Do decrypt its contents.
+ object_to_decrypt = dict_and_contents.contents;
+ break;
+ }
+ }
+ }
+ return object;
+}
+
bool CPDF_CryptoHandler::DecryptStream(void* context,
const uint8_t* src_buf,
uint32_t src_size,