Fix UNSAFE_TODOs in cpdf_security_handler.cpp

Change-Id: Ic1c624454360842e928f38ec70e3339550520040
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/133110
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfapi/parser/cpdf_security_handler.cpp b/core/fpdfapi/parser/cpdf_security_handler.cpp
index 64148ba..49e69fa 100644
--- a/core/fpdfapi/parser/cpdf_security_handler.cpp
+++ b/core/fpdfapi/parser/cpdf_security_handler.cpp
@@ -10,6 +10,8 @@
 #include <time.h>
 
 #include <algorithm>
+#include <array>
+#include <optional>
 #include <utility>
 
 #include "core/fdrm/fx_crypt.h"
@@ -21,7 +23,6 @@
 #include "core/fxcrt/byteorder.h"
 #include "core/fxcrt/check.h"
 #include "core/fxcrt/check_op.h"
-#include "core/fxcrt/compiler_specific.h"
 #include "core/fxcrt/data_vector.h"
 #include "core/fxcrt/fx_memcpy_wrappers.h"
 #include "core/fxcrt/fx_random.h"
@@ -32,7 +33,7 @@
 
 namespace {
 
-const uint8_t kDefaultPasscode[32] = {
+constexpr std::array<const uint8_t, 32> kDefaultPasscode = {
     0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, 0x64, 0x00, 0x4e,
     0x56, 0xff, 0xfa, 0x01, 0x08, 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68,
     0x3e, 0x80, 0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a};
@@ -112,17 +113,18 @@
 }
 
 void Revision6_Hash(const ByteString& password,
-                    const uint8_t* salt,
-                    const uint8_t* vector,
-                    uint8_t* hash) {
+                    pdfium::span<const uint8_t, 8> salt,
+                    std::optional<pdfium::span<const uint8_t, 48>> vector,
+                    pdfium::span<uint8_t, 32> hash) {
   CRYPT_sha2_context sha;
   CRYPT_SHA256Start(&sha);
   CRYPT_SHA256Update(&sha, password.unsigned_span());
-  CRYPT_SHA256Update(&sha, UNSAFE_TODO(pdfium::span(salt, 8u)));
-  if (vector) {
-    CRYPT_SHA256Update(&sha, UNSAFE_TODO(pdfium::span(vector, 48u)));
+  CRYPT_SHA256Update(&sha, salt);
+  if (vector.has_value()) {
+    CRYPT_SHA256Update(&sha, vector.value());
   }
-  uint8_t digest[32];
+
+  std::array<uint8_t, 32> digest;
   CRYPT_SHA256Finish(&sha, digest);
 
   DataVector<uint8_t> encrypted_output;
@@ -135,22 +137,23 @@
   CRYPT_aes_context aes = {};
   do {
     size_t round_size = password.GetLength() + block_size;
-    if (vector) {
-      round_size += 48;
+    if (vector.has_value()) {
+      round_size += vector.value().size();
     }
     encrypted_output.resize(round_size * 64);
     auto encrypted_output_span = pdfium::span(encrypted_output);
+    auto password_span = password.unsigned_span();
+    auto input_span = pdfium::span(input).first(block_size);
     DataVector<uint8_t> content;
     for (int j = 0; j < 64; ++j) {
-      UNSAFE_TODO({
-        content.insert(std::end(content), password.unsigned_str(),
-                       password.unsigned_str() + password.GetLength());
-        content.insert(std::end(content), input.data(),
-                       input.data() + block_size);
-        if (vector) {
-          content.insert(std::end(content), vector, vector + 48);
-        }
-      });
+      content.insert(std::end(content), std::begin(password_span),
+                     std::end(password_span));
+      content.insert(std::end(content), std::begin(input_span),
+                     std::end(input_span));
+      if (vector.has_value()) {
+        content.insert(std::end(content), std::begin(vector.value()),
+                       std::end(vector.value()));
+      }
     }
     CHECK_EQ(content.size(), encrypted_output.size());
     CRYPT_AESSetKey(&aes, key);
@@ -176,9 +179,8 @@
     iv = input.subspan<16u, 16u>();
     ++i;
   } while (i < 64 || i - 32 < encrypted_output.back());
-  if (hash) {
-    UNSAFE_TODO(FXSYS_memcpy(hash, input.data(), 32));
-  }
+
+  fxcrt::Copy(input.first(32u), hash);
 }
 
 }  // namespace
@@ -343,40 +345,43 @@
   if (okey.GetLength() < 48) {
     return false;
   }
-
   ByteString ukey = encrypt_dict_->GetByteStringFor("U");
   if (ukey.GetLength() < 48) {
     return false;
   }
+  pdfium::span<const uint8_t> pkey = ukey.unsigned_span();
+  std::optional<pdfium::span<const uint8_t, 48>> maybe_skey;
+  if (bOwner) {
+    pkey = okey.unsigned_span();
+    maybe_skey = ukey.unsigned_span().first<48u>();
+  }
 
-  const uint8_t* pkey = bOwner ? okey.unsigned_str() : ukey.unsigned_str();
-  CRYPT_sha2_context sha;
   uint8_t digest[32];
   if (revision_ >= 6) {
-    Revision6_Hash(password, UNSAFE_TODO((const uint8_t*)pkey + 32),
-                   bOwner ? ukey.unsigned_str() : nullptr, digest);
+    Revision6_Hash(password, pkey.subspan<32u, 8u>(), maybe_skey, digest);
   } else {
+    CRYPT_sha2_context sha;
     CRYPT_SHA256Start(&sha);
     CRYPT_SHA256Update(&sha, password.unsigned_span());
-    CRYPT_SHA256Update(&sha, UNSAFE_TODO(pdfium::span(pkey + 32, 8u)));
-    if (bOwner) {
-      CRYPT_SHA256Update(&sha, ukey.unsigned_span().first(48u));
+    CRYPT_SHA256Update(&sha, pkey.subspan<32u, 8u>());
+    if (maybe_skey.has_value()) {
+      CRYPT_SHA256Update(&sha, maybe_skey.value());
     }
     CRYPT_SHA256Finish(&sha, digest);
   }
-  if (UNSAFE_TODO(FXSYS_memcmp(digest, pkey, 32)) != 0) {
+  if (!std::ranges::equal(digest, pkey.first<32u>())) {
     return false;
   }
 
   if (revision_ >= 6) {
-    Revision6_Hash(password, UNSAFE_TODO(pkey + 40),
-                   bOwner ? ukey.unsigned_str() : nullptr, digest);
+    Revision6_Hash(password, pkey.subspan<40u, 8u>(), maybe_skey, digest);
   } else {
+    CRYPT_sha2_context sha;
     CRYPT_SHA256Start(&sha);
     CRYPT_SHA256Update(&sha, password.unsigned_span());
-    CRYPT_SHA256Update(&sha, UNSAFE_TODO(pdfium::span(pkey + 40, 8u)));
-    if (bOwner) {
-      CRYPT_SHA256Update(&sha, ukey.unsigned_span().first(48u));
+    CRYPT_SHA256Update(&sha, pkey.subspan<40u, 8u>());
+    if (maybe_skey.has_value()) {
+      CRYPT_SHA256Update(&sha, maybe_skey.value());
     }
     CRYPT_SHA256Finish(&sha, digest);
   }
@@ -398,9 +403,9 @@
   }
 
   uint8_t perms_buf[16] = {};
-  size_t copy_len =
-      std::min(sizeof(perms_buf), static_cast<size_t>(perms.GetLength()));
-  UNSAFE_TODO(FXSYS_memcpy(perms_buf, perms.unsigned_str(), copy_len));
+  size_t copy_len = std::min(sizeof(perms_buf), perms.GetLength());
+  fxcrt::Copy(perms.unsigned_span().first(copy_len), perms_buf);
+
   uint8_t buf[16];
   CRYPT_AESDecrypt(&aes, buf, perms_buf);
   if (buf[9] != 'a' || buf[10] != 'd' || buf[11] != 'b') {
@@ -477,20 +482,20 @@
 
   uint8_t ukeybuf[32];
   if (revision_ == 2) {
-    UNSAFE_TODO(
-        FXSYS_memcpy(ukeybuf, kDefaultPasscode, sizeof(kDefaultPasscode)));
+    fxcrt::Copy(kDefaultPasscode, ukeybuf);
     CRYPT_ArcFourCryptBlock(ukeybuf,
                             pdfium::span(encrypt_key_).first(key_len_));
-    return UNSAFE_TODO(memcmp(ukey.c_str(), ukeybuf, 16)) == 0;
+    return std::ranges::equal(ukey.unsigned_span().first<16u>(),
+                              pdfium::span(ukeybuf).first<16u>());
   }
 
-  uint8_t test[32] = {};
-  uint8_t tmpkey[32] = {};
+  std::array<uint8_t, 32> test = {};
+  std::array<uint8_t, 32> tmpkey = {};
   uint32_t copy_len = std::min(sizeof(test), ukey.GetLength());
-  UNSAFE_TODO(FXSYS_memcpy(test, ukey.c_str(), copy_len));
+  fxcrt::Copy(ukey.unsigned_span().first(copy_len), test);
   for (int32_t i = 19; i >= 0; i--) {
     for (size_t j = 0; j < key_len_; j++) {
-      UNSAFE_TODO(tmpkey[j] = encrypt_key_[j] ^ static_cast<uint8_t>(i));
+      tmpkey[j] = encrypt_key_[j] ^ static_cast<uint8_t>(i);
     }
     CRYPT_ArcFourCryptBlock(test, pdfium::span(tmpkey).first(key_len_));
   }
@@ -500,7 +505,8 @@
     CRYPT_MD5Update(&md5, file_id_.unsigned_span());
   }
   CRYPT_MD5Finish(&md5, pdfium::span(ukeybuf).first<16u>());
-  return UNSAFE_TODO(memcmp(test, ukeybuf, 16)) == 0;
+  return std::ranges::equal(pdfium::span(test).first<16u>(),
+                            pdfium::span(ukeybuf).first<16u>());
 }
 
 ByteString CPDF_SecurityHandler::GetUserPassword(
@@ -511,42 +517,39 @@
   if (okeylen < kRequiredOkeyLength) {
     return ByteString();
   }
-
   DCHECK_EQ(kRequiredOkeyLength, okeylen);
-  uint8_t passcode[32];
+
+  std::array<uint8_t, 32> passcode;
+  std::array<uint8_t, 16> digest;
   GetPassCode(owner_password, passcode);
-  uint8_t digest[16];
   CRYPT_MD5Generate(passcode, digest);
   if (revision_ >= 3) {
     for (uint32_t i = 0; i < 50; i++) {
       CRYPT_MD5Generate(digest, digest);
     }
   }
-  uint8_t enckey[32] = {};
-  uint8_t okeybuf[32] = {};
+
+  std::array<uint8_t, 32> enckey = {};
+  std::array<uint8_t, 32> okeybuf = {};
   size_t copy_len = std::min(key_len_, sizeof(digest));
-  UNSAFE_TODO({
-    FXSYS_memcpy(enckey, digest, copy_len);
-    FXSYS_memcpy(okeybuf, okey.c_str(), okeylen);
-  });
+  fxcrt::Copy(pdfium::span(digest).first(copy_len), enckey);
+  fxcrt::Copy(okey.unsigned_span().first(okeylen), okeybuf);
   pdfium::span<uint8_t> okey_span = pdfium::span(okeybuf).first(okeylen);
   if (revision_ == 2) {
     CRYPT_ArcFourCryptBlock(okey_span, pdfium::span(enckey).first(key_len_));
   } else {
     for (int32_t i = 19; i >= 0; i--) {
-      uint8_t tempkey[32] = {};
+      std::array<uint8_t, 32> tempkey = {};
       for (size_t j = 0; j < key_len_; j++) {
-        UNSAFE_TODO(tempkey[j] = enckey[j] ^ static_cast<uint8_t>(i));
+        tempkey[j] = enckey[j] ^ static_cast<uint8_t>(i);
       }
       CRYPT_ArcFourCryptBlock(okey_span, pdfium::span(tempkey).first(key_len_));
     }
   }
   size_t len = kRequiredOkeyLength;
-  UNSAFE_TODO({
-    while (len && kDefaultPasscode[len - 1] == okey_span[len - 1]) {
-      len--;
-    }
-  });
+  while (len && kDefaultPasscode[len - 1] == okey_span[len - 1]) {
+    len--;
+  }
   return ByteString(ByteStringView(pdfium::span(okeybuf).first(len)));
 }
 
@@ -607,8 +610,7 @@
                  pdfium::span(encrypt_key_).first(key_len), false, file_id);
   if (revision_ < 3) {
     uint8_t tempbuf[32];
-    UNSAFE_TODO(
-        FXSYS_memcpy(tempbuf, kDefaultPasscode, sizeof(kDefaultPasscode)));
+    fxcrt::Copy(kDefaultPasscode, tempbuf);
     CRYPT_ArcFourCryptBlock(tempbuf, pdfium::span(encrypt_key_).first(key_len));
     pEncryptDict->SetNewFor<CPDF_String>(
         "U", ByteString(ByteStringView(pdfium::span(tempbuf))));
@@ -625,10 +627,10 @@
     CRYPT_MD5Finish(&md5, partial_digest_span);
     CRYPT_ArcFourCryptBlock(partial_digest_span,
                             pdfium::span(encrypt_key_).first(key_len));
-    uint8_t tempkey[32];
+    std::array<uint8_t, 32> tempkey;
     for (uint8_t i = 1; i <= 19; i++) {
       for (size_t j = 0; j < key_len; j++) {
-        UNSAFE_TODO(tempkey[j] = encrypt_key_[j] ^ i);
+        tempkey[j] = encrypt_key_[j] ^ i;
       }
       CRYPT_ArcFourCryptBlock(partial_digest_span,
                               pdfium::span(tempkey).first(key_len));
@@ -654,18 +656,21 @@
   CRYPT_sha2_context sha2;
   uint8_t digest1[48];
   if (revision_ >= 6) {
-    Revision6_Hash(password, digest, nullptr, digest1);
+    Revision6_Hash(password, pdfium::span(digest).first<8u>(), std::nullopt,
+                   pdfium::span(digest1).first<32u>());
   } else {
     CRYPT_SHA256Start(&sha2);
     CRYPT_SHA256Update(&sha2, password.unsigned_span());
     CRYPT_SHA256Update(&sha2, pdfium::span(digest).first<8u>());
     CRYPT_SHA256Finish(&sha2, pdfium::span(digest1).first<32u>());
   }
-  UNSAFE_TODO(FXSYS_memcpy(digest1 + 32, digest, 16));
+  fxcrt::Copy(pdfium::span(digest).first<16u>(),
+              pdfium::span(digest1).subspan<32u>());
   pEncryptDict->SetNewFor<CPDF_String>(
       "U", ByteString(ByteStringView(pdfium::span(digest1))));
   if (revision_ >= 6) {
-    Revision6_Hash(password, UNSAFE_TODO(digest + 8), nullptr, digest1);
+    Revision6_Hash(password, pdfium::span(digest).subspan<8u, 8u>(),
+                   std::nullopt, pdfium::span(digest1).first<32u>());
   } else {
     CRYPT_SHA256Start(&sha2);
     CRYPT_SHA256Update(&sha2, password.unsigned_span());