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;
 }