// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/reporting/encryption/encryption.h"

#include <array>
#include <memory>
#include <vector>

#include "base/containers/flat_map.h"
#include "base/functional/bind.h"
#include "base/hash/hash.h"
#include "base/rand_util.h"
#include "base/strings/strcat.h"
#include "base/synchronization/waitable_event.h"
#include "base/task/thread_pool.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "base/types/expected.h"
#include "base/types/expected_macros.h"
#include "components/reporting/encryption/decryption.h"
#include "components/reporting/encryption/primitives.h"
#include "components/reporting/encryption/testing_primitives.h"
#include "components/reporting/proto/synced/record.pb.h"
#include "components/reporting/util/status.h"
#include "components/reporting/util/status_macros.h"
#include "components/reporting/util/statusor.h"
#include "components/reporting/util/test_support_callbacks.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

using ::testing::Eq;
using ::testing::Property;
using ::testing::StrEq;

namespace reporting {
namespace {

class EncryptionTest : public ::testing::Test {
 protected:
  EncryptionTest() = default;

  void SetUp() override {
    auto encryptor_result = Encryptor::Create();
    ASSERT_TRUE(encryptor_result.has_value()) << encryptor_result.error();
    encryptor_ = std::move(encryptor_result.value());

    auto decryptor_result = test::Decryptor::Create();
    ASSERT_TRUE(decryptor_result.has_value()) << decryptor_result.error();
    decryptor_ = std::move(decryptor_result.value());
  }

  StatusOr<EncryptedRecord> EncryptSync(std::string_view data) {
    test::TestEvent<StatusOr<Encryptor::Handle*>> open_encrypt;
    encryptor_->OpenRecord(open_encrypt.cb());
    ASSIGN_OR_RETURN(Encryptor::Handle* const enc_handle,
                     open_encrypt.result());

    test::TestEvent<Status> add_encrypt;
    enc_handle->AddToRecord(data, add_encrypt.cb());
    RETURN_IF_ERROR_STATUS(base::unexpected(add_encrypt.result()));

    EncryptedRecord encrypted;
    test::TestEvent<Status> close_encrypt;
    enc_handle->CloseRecord(base::BindOnce(
        [](EncryptedRecord* encrypted,
           base::OnceCallback<void(Status)> close_cb,
           StatusOr<EncryptedRecord> result) {
          if (!result.has_value()) {
            std::move(close_cb).Run(result.error());
            return;
          }
          *encrypted = result.value();
          std::move(close_cb).Run(Status::StatusOK());
        },
        base::Unretained(&encrypted), close_encrypt.cb()));
    RETURN_IF_ERROR_STATUS(base::unexpected(close_encrypt.result()));
    return encrypted;
  }

  StatusOr<std::string> DecryptSync(
      std::pair<std::string /*shared_secret*/, std::string /*encrypted_data*/>
          encrypted) {
    test::TestEvent<StatusOr<test::Decryptor::Handle*>> open_decrypt;
    decryptor_->OpenRecord(encrypted.first, open_decrypt.cb());
    ASSIGN_OR_RETURN(test::Decryptor::Handle* const dec_handle,
                     open_decrypt.result());

    test::TestEvent<Status> add_decrypt;
    dec_handle->AddToRecord(encrypted.second, add_decrypt.cb());
    RETURN_IF_ERROR_STATUS(base::unexpected(add_decrypt.result()));

    std::string decrypted_string;
    test::TestEvent<Status> close_decrypt;
    dec_handle->CloseRecord(base::BindOnce(
        [](std::string* decrypted_string,
           base::OnceCallback<void(Status)> close_cb,
           StatusOr<std::string_view> result) {
          if (!result.has_value()) {
            std::move(close_cb).Run(result.error());
            return;
          }
          *decrypted_string = std::string(result.value());
          std::move(close_cb).Run(Status::StatusOK());
        },
        base::Unretained(&decrypted_string), close_decrypt.cb()));
    RETURN_IF_ERROR_STATUS(base::unexpected(close_decrypt.result()));
    return decrypted_string;
  }

  StatusOr<std::string> DecryptMatchingSecret(
      Encryptor::PublicKeyId public_key_id,
      std::string_view encrypted_key) {
    // Retrieve private key that matches public key hash.
    test::TestEvent<StatusOr<std::string>> retrieve_private_key;
    decryptor_->RetrieveMatchingPrivateKey(public_key_id,
                                           retrieve_private_key.cb());
    ASSIGN_OR_RETURN(std::string private_key, retrieve_private_key.result());
    // Decrypt shared secret with that private key and peer public key.
    ASSIGN_OR_RETURN(std::string shared_secret,
                     decryptor_->DecryptSecret(private_key, encrypted_key));
    return shared_secret;
  }

  Status AddNewKeyPair() {
    // Generate new pair of private key and public value.
    uint8_t out_public_value[kKeySize];
    uint8_t out_private_key[kKeySize];
    test::GenerateEncryptionKeyPair(out_private_key, out_public_value);
    return AddKeyPair(out_private_key, out_public_value);
  }

  Status AddKeyPair(const uint8_t private_key[kKeySize],
                    const uint8_t public_value[kKeySize]) {
    test::TestEvent<StatusOr<Encryptor::PublicKeyId>> record_keys;
    decryptor_->RecordKeyPair(
        std::string(reinterpret_cast<const char*>(private_key), kKeySize),
        std::string(reinterpret_cast<const char*>(public_value), kKeySize),
        record_keys.cb());
    ASSIGN_OR_RETURN(Encryptor::PublicKeyId new_public_key_id,
                     record_keys.result());
    test::TestEvent<Status> set_public_key;
    encryptor_->UpdateAsymmetricKey(
        std::string(reinterpret_cast<const char*>(public_value), kKeySize),
        new_public_key_id, set_public_key.cb());
    RETURN_IF_ERROR_STATUS(set_public_key.result());
    return Status::StatusOK();
  }

  scoped_refptr<Encryptor> encryptor_;
  scoped_refptr<test::Decryptor> decryptor_;

 private:
  base::test::TaskEnvironment task_environment_{
      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
};

TEST_F(EncryptionTest, EncryptAndDecrypt) {
  constexpr char kTestString[] = "ABCDEF";

  // Register new pair of private key and public value.
  ASSERT_OK(AddNewKeyPair());

  // Encrypt the test string using the last public value.
  const auto encrypted_result = EncryptSync(kTestString);
  ASSERT_TRUE(encrypted_result.has_value()) << encrypted_result.error();

  // Decrypt shared secret with private asymmetric key.
  auto decrypt_secret_result = DecryptMatchingSecret(
      encrypted_result.value().encryption_info().public_key_id(),
      encrypted_result.value().encryption_info().encryption_key());
  ASSERT_TRUE(decrypt_secret_result.has_value())
      << decrypt_secret_result.error();

  // Decrypt back.
  const auto decrypted_result = DecryptSync(
      std::make_pair(decrypt_secret_result.value(),
                     encrypted_result.value().encrypted_wrapped_record()));
  ASSERT_TRUE(decrypted_result.has_value()) << decrypted_result.error();

  EXPECT_THAT(decrypted_result.value(), StrEq(kTestString));
}

TEST_F(EncryptionTest, NoPublicKey) {
  constexpr char kTestString[] = "ABCDEF";

  // Attempt to encrypt the test string.
  const auto encrypted_result = EncryptSync(kTestString);
  EXPECT_THAT(encrypted_result,
              Property(&StatusOr<EncryptedRecord>::error,
                       Property(&Status::error_code, Eq(error::NOT_FOUND))));
}

TEST_F(EncryptionTest, EncryptAndDecryptMultiple) {
  constexpr const auto kTestStrings = std::to_array<const char*>({
      "Rec1",
      "Rec22",
      "Rec333",
      "Rec4444",
      "Rec55555",
      "Rec666666",
  });
  // Encrypted records.
  std::vector<EncryptedRecord> encrypted_records;

  // 1. Register first key pair.
  ASSERT_OK(AddNewKeyPair());

  // 2. Encrypt 3 test strings.
  for (const char* test_string :
       {kTestStrings[0], kTestStrings[1], kTestStrings[2]}) {
    const auto encrypted_result = EncryptSync(test_string);
    ASSERT_TRUE(encrypted_result.has_value()) << encrypted_result.error();
    encrypted_records.emplace_back(encrypted_result.value());
  }

  // 3. Register second key pair.
  ASSERT_OK(AddNewKeyPair());

  // 4. Encrypt 2 test strings.
  for (const char* test_string : {kTestStrings[3], kTestStrings[4]}) {
    const auto encrypted_result = EncryptSync(test_string);
    ASSERT_TRUE(encrypted_result.has_value()) << encrypted_result.error();
    encrypted_records.emplace_back(encrypted_result.value());
  }

  // 3. Register third key pair.
  ASSERT_OK(AddNewKeyPair());

  // 4. Encrypt one more test strings.
  for (const char* test_string : {kTestStrings[5]}) {
    const auto encrypted_result = EncryptSync(test_string);
    ASSERT_TRUE(encrypted_result.has_value()) << encrypted_result.error();
    encrypted_records.emplace_back(encrypted_result.value());
  }

  // For every encrypted record:
  for (size_t i = 0; i < encrypted_records.size(); ++i) {
    // Decrypt encrypted_key with private asymmetric key.
    auto decrypt_secret_result = DecryptMatchingSecret(
        encrypted_records[i].encryption_info().public_key_id(),
        encrypted_records[i].encryption_info().encryption_key());
    ASSERT_TRUE(decrypt_secret_result.has_value())
        << decrypt_secret_result.error();

    // Decrypt back.
    const auto decrypted_result = DecryptSync(
        std::make_pair(decrypt_secret_result.value(),
                       encrypted_records[i].encrypted_wrapped_record()));
    ASSERT_TRUE(decrypted_result.has_value()) << decrypted_result.error();

    // Verify match.
    EXPECT_THAT(decrypted_result.value(), StrEq(kTestStrings[i]));
  }
}

TEST_F(EncryptionTest, EncryptAndDecryptMultipleParallel) {
  // Context of single encryption. Self-destructs upon completion or failure.
  class SingleEncryptionContext {
   public:
    SingleEncryptionContext(
        std::string_view test_string,
        std::string_view public_key,
        Encryptor::PublicKeyId public_key_id,
        scoped_refptr<Encryptor> encryptor,
        base::OnceCallback<void(StatusOr<EncryptedRecord>)> response)
        : test_string_(test_string),
          public_key_(public_key),
          public_key_id_(public_key_id),
          encryptor_(encryptor),
          response_(std::move(response)) {}

    SingleEncryptionContext(const SingleEncryptionContext& other) = delete;
    SingleEncryptionContext& operator=(const SingleEncryptionContext& other) =
        delete;

    ~SingleEncryptionContext() {
      CHECK(!response_) << "Self-destruct without prior response";
    }

    void Start() {
      base::ThreadPool::PostTask(
          FROM_HERE, base::BindOnce(&SingleEncryptionContext::SetPublicKey,
                                    base::Unretained(this)));
    }

   private:
    void Respond(StatusOr<EncryptedRecord> result) {
      std::move(response_).Run(result);
      delete this;
    }
    void SetPublicKey() {
      encryptor_->UpdateAsymmetricKey(
          public_key_, public_key_id_,
          base::BindOnce(
              [](SingleEncryptionContext* self, Status status) {
                if (!status.ok()) {
                  self->Respond(base::unexpected(status));
                  return;
                }
                base::ThreadPool::PostTask(
                    FROM_HERE,
                    base::BindOnce(&SingleEncryptionContext::OpenRecord,
                                   base::Unretained(self)));
              },
              base::Unretained(this)));
    }
    void OpenRecord() {
      encryptor_->OpenRecord(base::BindOnce(
          [](SingleEncryptionContext* self,
             StatusOr<Encryptor::Handle*> handle_result) {
            if (!handle_result.has_value()) {
              self->Respond(base::unexpected(handle_result.error()));
              return;
            }
            base::ThreadPool::PostTask(
                FROM_HERE,
                base::BindOnce(&SingleEncryptionContext::AddToRecord,
                               base::Unretained(self),
                               base::Unretained(handle_result.value())));
          },
          base::Unretained(this)));
    }
    void AddToRecord(Encryptor::Handle* handle) {
      handle->AddToRecord(
          test_string_,
          base::BindOnce(
              [](SingleEncryptionContext* self, Encryptor::Handle* handle,
                 Status status) {
                if (!status.ok()) {
                  self->Respond(base::unexpected(status));
                  return;
                }
                base::ThreadPool::PostTask(
                    FROM_HERE,
                    base::BindOnce(&SingleEncryptionContext::CloseRecord,
                                   base::Unretained(self),
                                   base::Unretained(handle)));
              },
              base::Unretained(this), base::Unretained(handle)));
    }
    void CloseRecord(Encryptor::Handle* handle) {
      handle->CloseRecord(base::BindOnce(
          [](SingleEncryptionContext* self,
             StatusOr<EncryptedRecord> encryption_result) {
            self->Respond(encryption_result);
          },
          base::Unretained(this)));
    }

   private:
    const std::string test_string_;
    const std::string public_key_;
    const Encryptor::PublicKeyId public_key_id_;
    const scoped_refptr<Encryptor> encryptor_;
    base::OnceCallback<void(StatusOr<EncryptedRecord>)> response_;
  };

  // Context of single decryption. Self-destructs upon completion or failure.
  class SingleDecryptionContext {
   public:
    SingleDecryptionContext(
        const EncryptedRecord& encrypted_record,
        scoped_refptr<test::Decryptor> decryptor,
        base::OnceCallback<void(StatusOr<std::string_view>)> response)
        : encrypted_record_(encrypted_record),
          decryptor_(decryptor),
          response_(std::move(response)) {}

    SingleDecryptionContext(const SingleDecryptionContext& other) = delete;
    SingleDecryptionContext& operator=(const SingleDecryptionContext& other) =
        delete;

    ~SingleDecryptionContext() {
      CHECK(!response_) << "Self-destruct without prior response";
    }

    void Start() {
      base::ThreadPool::PostTask(
          FROM_HERE,
          base::BindOnce(&SingleDecryptionContext::RetrieveMatchingPrivateKey,
                         base::Unretained(this)));
    }

   private:
    void Respond(StatusOr<std::string_view> result) {
      std::move(response_).Run(result);
      delete this;
    }

    void RetrieveMatchingPrivateKey() {
      // Retrieve private key that matches public key hash.
      decryptor_->RetrieveMatchingPrivateKey(
          encrypted_record_.encryption_info().public_key_id(),
          base::BindOnce(
              [](SingleDecryptionContext* self,
                 StatusOr<std::string> private_key_result) {
                if (!private_key_result.has_value()) {
                  self->Respond(base::unexpected(private_key_result.error()));
                  return;
                }
                base::ThreadPool::PostTask(
                    FROM_HERE,
                    base::BindOnce(
                        &SingleDecryptionContext::DecryptSharedSecret,
                        base::Unretained(self), private_key_result.value()));
              },
              base::Unretained(this)));
    }

    void DecryptSharedSecret(std::string_view private_key) {
      // Decrypt shared secret from private key and peer public key.
      auto shared_secret_result = decryptor_->DecryptSecret(
          private_key, encrypted_record_.encryption_info().encryption_key());
      if (!shared_secret_result.has_value()) {
        Respond(base::unexpected(shared_secret_result.error()));
        return;
      }
      base::ThreadPool::PostTask(
          FROM_HERE,
          base::BindOnce(&SingleDecryptionContext::OpenRecord,
                         base::Unretained(this), shared_secret_result.value()));
    }

    void OpenRecord(std::string_view shared_secret) {
      decryptor_->OpenRecord(
          shared_secret,
          base::BindOnce(
              [](SingleDecryptionContext* self,
                 StatusOr<test::Decryptor::Handle*> handle_result) {
                if (!handle_result.has_value()) {
                  self->Respond(base::unexpected(handle_result.error()));
                  return;
                }
                base::ThreadPool::PostTask(
                    FROM_HERE,
                    base::BindOnce(&SingleDecryptionContext::AddToRecord,
                                   base::Unretained(self),
                                   base::Unretained(handle_result.value())));
              },
              base::Unretained(this)));
    }

    void AddToRecord(test::Decryptor::Handle* handle) {
      handle->AddToRecord(
          encrypted_record_.encrypted_wrapped_record(),
          base::BindOnce(
              [](SingleDecryptionContext* self, test::Decryptor::Handle* handle,
                 Status status) {
                if (!status.ok()) {
                  self->Respond(base::unexpected(status));
                  return;
                }
                base::ThreadPool::PostTask(
                    FROM_HERE,
                    base::BindOnce(&SingleDecryptionContext::CloseRecord,
                                   base::Unretained(self),
                                   base::Unretained(handle)));
              },
              base::Unretained(this), base::Unretained(handle)));
    }

    void CloseRecord(test::Decryptor::Handle* handle) {
      handle->CloseRecord(base::BindOnce(
          [](SingleDecryptionContext* self,
             StatusOr<std::string_view> decryption_result) {
            self->Respond(decryption_result);
          },
          base::Unretained(this)));
    }

   private:
    const EncryptedRecord encrypted_record_;
    const scoped_refptr<test::Decryptor> decryptor_;
    base::OnceCallback<void(StatusOr<std::string_view>)> response_;
  };

  constexpr std::array<const char*, 6> kTestStrings = {
      "Rec1", "Rec22", "Rec333", "Rec4444", "Rec55555", "Rec666666"};

  // Public and private key pairs in this test are reversed strings.
  std::vector<std::string> private_key_strings;
  std::vector<std::string> public_value_strings;
  std::vector<Encryptor::PublicKeyId> public_value_ids;
  for (size_t i = 0; i < 3; ++i) {
    // Generate new pair of private key and public value.
    uint8_t out_public_value[kKeySize];
    uint8_t out_private_key[kKeySize];
    test::GenerateEncryptionKeyPair(out_private_key, out_public_value);
    private_key_strings.emplace_back(
        reinterpret_cast<const char*>(out_private_key), kKeySize);
    public_value_strings.emplace_back(
        reinterpret_cast<const char*>(out_public_value), kKeySize);
  }

  // Register all key pairs for decryption.
  std::vector<test::TestEvent<StatusOr<Encryptor::PublicKeyId>>> record_results(
      public_value_strings.size());
  for (size_t i = 0; i < public_value_strings.size(); ++i) {
    base::ThreadPool::PostTask(
        FROM_HERE,
        base::BindOnce(
            [](std::string_view private_key_string,
               std::string_view public_key_string,
               scoped_refptr<test::Decryptor> decryptor,
               base::OnceCallback<void(StatusOr<Encryptor::PublicKeyId>)>
                   done_cb) {
              decryptor->RecordKeyPair(private_key_string, public_key_string,
                                       std::move(done_cb));
            },
            private_key_strings[i], public_value_strings[i], decryptor_,
            record_results[i].cb()));
  }
  // Verify registration success.
  for (auto& record_result : record_results) {
    const auto result = record_result.result();
    ASSERT_TRUE(result.has_value()) << result.error();
    public_value_ids.push_back(result.value());
  }

  // Encrypt all records in parallel.
  std::vector<test::TestEvent<StatusOr<EncryptedRecord>>> results(
      kTestStrings.size());
  for (size_t i = 0; i < kTestStrings.size(); ++i) {
    // Choose random key pair.
    size_t i_key_pair = base::RandInt(0, public_value_strings.size() - 1);
    (new SingleEncryptionContext(
         kTestStrings[i], public_value_strings[i_key_pair],
         public_value_ids[i_key_pair], encryptor_, results[i].cb()))
        ->Start();
  }

  // Decrypt all records in parallel.
  std::vector<test::TestEvent<StatusOr<std::string>>> decryption_results(
      kTestStrings.size());
  for (size_t i = 0; i < results.size(); ++i) {
    // Verify encryption success.
    const auto result = results[i].result();
    ASSERT_TRUE(result.has_value()) << result.error();
    // Decrypt and compare encrypted_record.
    (new SingleDecryptionContext(
         result.value(), decryptor_,
         base::BindOnce(
             [](base::OnceCallback<void(StatusOr<std::string>)>
                    decryption_result,
                StatusOr<std::string_view> result) {
               if (!result.has_value()) {
                 std::move(decryption_result)
                     .Run(base::unexpected(result.error()));
                 return;
               }
               std::move(decryption_result).Run(std::string(result.value()));
             },
             decryption_results[i].cb())))
        ->Start();
  }

  // Verify decryption results.
  for (size_t i = 0; i < decryption_results.size(); ++i) {
    const auto decryption_result = decryption_results[i].result();
    ASSERT_TRUE(decryption_result.has_value()) << decryption_result.error();
    // Verify data match.
    EXPECT_THAT(decryption_result.value(), StrEq(kTestStrings[i]));
  }
}

}  // namespace
}  // namespace reporting
