Rework UNSAFE_BUFFERS in CPDF_CryptoHandler::EncryptContent().
Bug: 42271176
Change-Id: I87268589e115e2e8e96aa195d7c825a5e5fb065f
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/120794
Reviewed-by: Thomas Sepez <tsepez@google.com>
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfapi/parser/cpdf_crypto_handler.cpp b/core/fpdfapi/parser/cpdf_crypto_handler.cpp
index 7e84901..ea28bc2 100644
--- a/core/fpdfapi/parser/cpdf_crypto_handler.cpp
+++ b/core/fpdfapi/parser/cpdf_crypto_handler.cpp
@@ -47,59 +47,53 @@
return type_obj && type_obj->GetString() == pdfium::form_fields::kSig;
}
-// TODO(tsepez): should be UNSAFE_BUFFER_USAGE due to `dest_size`.
-void CPDF_CryptoHandler::EncryptContent(uint32_t objnum,
- uint32_t gennum,
- pdfium::span<const uint8_t> source,
- uint8_t* dest_buf,
- size_t& dest_size) const {
- UNSAFE_TODO({
- if (m_Cipher == Cipher::kNone) {
- FXSYS_memcpy(dest_buf, source.data(), source.size());
- return;
- }
- uint8_t realkey[16];
- size_t realkeylen = sizeof(realkey);
- if (m_Cipher != Cipher::kAES || m_KeyLen != 32) {
- uint8_t key1[32];
- PopulateKey(objnum, gennum, key1);
- if (m_Cipher == Cipher::kAES) {
- FXSYS_memcpy(key1 + m_KeyLen + 5, "sAlT", 4);
- }
- size_t len = m_Cipher == Cipher::kAES ? m_KeyLen + 9 : m_KeyLen + 5;
- CRYPT_MD5Generate(pdfium::make_span(key1).first(len), realkey);
- realkeylen = std::min(m_KeyLen + 5, sizeof(realkey));
- }
+size_t CPDF_CryptoHandler::EncryptContent(uint32_t objnum,
+ uint32_t gennum,
+ pdfium::span<const uint8_t> source,
+ pdfium::span<uint8_t> dest) const {
+ if (m_Cipher == Cipher::kNone) {
+ fxcrt::Copy(source, dest);
+ return source.size();
+ }
+ uint8_t realkey[16];
+ size_t realkeylen = sizeof(realkey);
+ if (m_Cipher != Cipher::kAES || m_KeyLen != 32) {
+ uint8_t key1[32];
+ PopulateKey(objnum, gennum, key1);
if (m_Cipher == Cipher::kAES) {
- CRYPT_AESSetKey(m_pAESContext.get(),
- m_KeyLen == 32 ? m_EncryptKey.data() : realkey, m_KeyLen);
- uint8_t iv[16];
- for (int i = 0; i < 16; i++) {
- iv[i] = (uint8_t)rand();
- }
- CRYPT_AESSetIV(m_pAESContext.get(), iv);
- FXSYS_memcpy(dest_buf, iv, 16);
- int nblocks = source.size() / 16;
- CRYPT_AESEncrypt(m_pAESContext.get(), dest_buf + 16, source.data(),
- nblocks * 16);
- uint8_t padding[16];
- FXSYS_memcpy(padding, source.data() + nblocks * 16, source.size() % 16);
- FXSYS_memset(padding + source.size() % 16, 16 - source.size() % 16,
- 16 - source.size() % 16);
- CRYPT_AESEncrypt(m_pAESContext.get(), dest_buf + nblocks * 16 + 16,
- padding, 16);
- dest_size = 32 + nblocks * 16;
- } else {
- DCHECK_EQ(dest_size, source.size());
- if (dest_buf != source.data()) {
- FXSYS_memcpy(dest_buf, source.data(), source.size());
- }
- // SAFETY: caller ensures that dest_buf points to at least dest_size
- // bytes.
- CRYPT_ArcFourCryptBlock(pdfium::make_span(dest_buf, dest_size),
- pdfium::make_span(realkey).first(realkeylen));
+ fxcrt::Copy(ByteStringView("sAlT").unsigned_span(),
+ pdfium::make_span(key1).subspan(m_KeyLen + 5));
}
- });
+ size_t len = m_Cipher == Cipher::kAES ? m_KeyLen + 9 : m_KeyLen + 5;
+ CRYPT_MD5Generate(pdfium::make_span(key1).first(len), realkey);
+ realkeylen = std::min(m_KeyLen + 5, sizeof(realkey));
+ }
+ if (m_Cipher == Cipher::kAES) {
+ CRYPT_AESSetKey(m_pAESContext.get(),
+ m_KeyLen == 32 ? m_EncryptKey.data() : realkey, m_KeyLen);
+ uint8_t iv[16];
+ for (auto& v : iv) {
+ v = (uint8_t)rand();
+ }
+ CRYPT_AESSetIV(m_pAESContext.get(), iv);
+ fxcrt::Copy(iv, dest);
+ int nblocks = source.size() / 16;
+ CRYPT_AESEncrypt(m_pAESContext.get(), dest.subspan(16).data(),
+ source.data(), nblocks * 16);
+ uint8_t padding[16];
+ fxcrt::Copy(source.subspan(nblocks * 16, source.size() % 16), padding);
+ fxcrt::Fill(pdfium::make_span(padding).subspan(source.size() % 16),
+ 16 - source.size() % 16);
+ CRYPT_AESEncrypt(m_pAESContext.get(),
+ dest.subspan(nblocks * 16 + 16).data(), padding, 16);
+ return 32 + nblocks * 16;
+ }
+ DCHECK_EQ(dest.size(), source.size());
+ if (dest.data() != source.data()) {
+ fxcrt::Copy(source, dest);
+ }
+ CRYPT_ArcFourCryptBlock(dest, pdfium::make_span(realkey).first(realkeylen));
+ return dest.size();
}
struct AESCryptContext {
diff --git a/core/fpdfapi/parser/cpdf_crypto_handler.h b/core/fpdfapi/parser/cpdf_crypto_handler.h
index 3305897..0bddb1d 100644
--- a/core/fpdfapi/parser/cpdf_crypto_handler.h
+++ b/core/fpdfapi/parser/cpdf_crypto_handler.h
@@ -39,11 +39,12 @@
bool DecryptObjectTree(RetainPtr<CPDF_Object> object);
size_t EncryptGetSize(pdfium::span<const uint8_t> source) const;
- void EncryptContent(uint32_t objnum,
- uint32_t gennum,
- pdfium::span<const uint8_t> source,
- uint8_t* dest_buf,
- size_t& dest_size) const;
+
+ // Returns number of valid bytes in `dest`.
+ [[nodiscard]] size_t EncryptContent(uint32_t objnum,
+ uint32_t gennum,
+ pdfium::span<const uint8_t> source,
+ pdfium::span<uint8_t> dest) const;
bool IsCipherAES() const;
diff --git a/core/fpdfapi/parser/cpdf_encryptor.cpp b/core/fpdfapi/parser/cpdf_encryptor.cpp
index 9e9d907..30e611f 100644
--- a/core/fpdfapi/parser/cpdf_encryptor.cpp
+++ b/core/fpdfapi/parser/cpdf_encryptor.cpp
@@ -19,15 +19,13 @@
DataVector<uint8_t> CPDF_Encryptor::Encrypt(
pdfium::span<const uint8_t> src_data) const {
- if (src_data.empty())
+ if (src_data.empty()) {
return DataVector<uint8_t>();
-
- DataVector<uint8_t> result;
- size_t buf_size = m_pHandler->EncryptGetSize(src_data);
- result.resize(buf_size);
- m_pHandler->EncryptContent(m_ObjNum, 0, src_data, result.data(),
- buf_size); // Updates |buf_size| with actual.
- result.resize(buf_size);
+ }
+ size_t estimated = m_pHandler->EncryptGetSize(src_data);
+ DataVector<uint8_t> result(estimated);
+ size_t actual = m_pHandler->EncryptContent(m_ObjNum, 0, src_data, result);
+ result.resize(actual);
return result;
}