blob: e8e25baaecefa2e5d4e9c4060a95522db49c4002 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/ledger/bin/encryption/impl/encryption_service_impl.h"
#include "gtest/gtest.h"
#include "src/ledger/bin/storage/fake/fake_object.h"
#include "src/ledger/bin/storage/public/types.h"
#include "src/ledger/bin/testing/test_with_environment.h"
#include "src/ledger/lib/callback/capture.h"
#include "src/ledger/lib/callback/set_when_called.h"
#include "src/ledger/lib/convert/convert.h"
#include "third_party/abseil-cpp/absl/strings/string_view.h"
namespace encryption {
namespace {
class EncryptionServiceTest : public ledger::TestWithEnvironment {
public:
EncryptionServiceTest() : encryption_service_(&environment_, "namespace_id") {}
protected:
void EncryptCommit(std::string commit_storage, Status* status, std::string* result) {
bool called;
encryption_service_.EncryptCommit(
commit_storage, ledger::Capture(ledger::SetWhenCalled(&called), status, result));
RunLoopUntilIdle();
EXPECT_TRUE(called);
}
void DecryptCommit(convert::ExtendedStringView encrypted_commit_storage, Status* status,
std::string* result) {
bool called;
encryption_service_.DecryptCommit(
encrypted_commit_storage, ledger::Capture(ledger::SetWhenCalled(&called), status, result));
RunLoopUntilIdle();
EXPECT_TRUE(called);
}
void EncryptEntryPayload(std::string entry_storage, Status* status, std::string* result) {
bool called;
encryption_service_.EncryptEntryPayload(
entry_storage, ledger::Capture(ledger::SetWhenCalled(&called), status, result));
RunLoopUntilIdle();
EXPECT_TRUE(called);
}
void DecryptEntryPayload(std::string encrypted_entry_storage, Status* status,
std::string* result) {
bool called;
encryption_service_.DecryptEntryPayload(
encrypted_entry_storage, ledger::Capture(ledger::SetWhenCalled(&called), status, result));
RunLoopUntilIdle();
EXPECT_TRUE(called);
}
void GetObjectName(storage::ObjectIdentifier object_identifier, Status* status,
std::string* result) {
bool called;
encryption_service_.GetObjectName(
std::move(object_identifier),
ledger::Capture(ledger::SetWhenCalled(&called), status, result));
RunLoopUntilIdle();
EXPECT_TRUE(called);
}
void GetPageId(std::string page_name, Status* status, std::string* result) {
bool called;
encryption_service_.GetPageId(std::move(page_name),
ledger::Capture(ledger::SetWhenCalled(&called), status, result));
RunLoopUntilIdle();
EXPECT_TRUE(called);
}
void EncryptObject(storage::ObjectIdentifier object_identifier, absl::string_view content,
Status* status, std::string* result) {
bool called;
encryption_service_.EncryptObject(
std::move(object_identifier), content,
ledger::Capture(ledger::SetWhenCalled(&called), status, result));
RunLoopUntilIdle();
EXPECT_TRUE(called);
}
void DecryptObject(storage::ObjectIdentifier object_identifier, std::string encrypted_data,
Status* status, std::string* result) {
bool called;
encryption_service_.DecryptObject(
std::move(object_identifier), std::move(encrypted_data),
ledger::Capture(ledger::SetWhenCalled(&called), status, result));
RunLoopUntilIdle();
EXPECT_TRUE(called);
}
void ApplyChunkingPermutation(uint64_t chunk_window_hash, Status* status, uint64_t* result) {
bool called;
fit::function<uint64_t(uint64_t)> permutation;
encryption_service_.GetChunkingPermutation(
ledger::Capture(ledger::SetWhenCalled(&called), status, &permutation));
RunLoopUntilIdle();
EXPECT_TRUE(called);
*result = permutation(chunk_window_hash);
}
std::string GetEntryId() { return encryption_service_.GetEntryId(); }
std::string GetEntryIdForMerge(absl::string_view entry_name, storage::CommitId left_parent_id,
storage::CommitId right_parent_id,
absl::string_view operation_list) {
return encryption_service_.GetEntryIdForMerge(entry_name, left_parent_id, right_parent_id,
operation_list);
}
std::string EncodeCommitId(std::string commit_id) {
return encryption_service_.EncodeCommitId(std::move(commit_id));
}
bool IsSameVersion(convert::ExtendedStringView remote_commit_id) {
return encryption_service_.IsSameVersion(remote_commit_id);
}
EncryptionServiceImpl encryption_service_;
};
TEST_F(EncryptionServiceTest, EncryptDecryptCommit) {
std::string contents[] = {
"",
"Hello",
"0123456789012345678901234567890123456789012345678901234567890123456789",
};
for (const auto& content : contents) {
Status status;
std::string value;
EncryptCommit(content, &status, &value);
ASSERT_EQ(status, Status::OK);
DecryptCommit(value, &status, &value);
ASSERT_EQ(status, Status::OK);
EXPECT_EQ(value, content);
}
}
TEST_F(EncryptionServiceTest, EncryptDecryptEntryPayload) {
std::string contents[] = {
"",
"SomeEntry",
"0123456789012345678901234567890123456789012345678901234567890123456789",
};
for (const auto& content : contents) {
Status status;
std::string value;
EncryptEntryPayload(content, &status, &value);
ASSERT_EQ(status, Status::OK);
ASSERT_NE(value, content);
DecryptEntryPayload(value, &status, &value);
ASSERT_EQ(status, Status::OK);
EXPECT_EQ(value, content);
}
}
TEST_F(EncryptionServiceTest, GetName) {
storage::ObjectIdentifier identifier(42u, storage::ObjectDigest(std::string(33u, '\0')), nullptr);
Status status;
std::string name;
GetObjectName(identifier, &status, &name);
EXPECT_EQ(status, Status::OK);
EXPECT_FALSE(name.empty());
}
TEST_F(EncryptionServiceTest, GetPageId) {
std::string page_name = "Jimmy";
Status status;
std::string id;
GetPageId(page_name, &status, &id);
EXPECT_EQ(status, Status::OK);
EXPECT_FALSE(id.empty());
EXPECT_NE(id, page_name);
}
TEST_F(EncryptionServiceTest, EncryptDecryptObject) {
storage::ObjectIdentifier identifier(42u, storage::ObjectDigest(std::string(33u, '\0')), nullptr);
std::string content(256u, '\0');
std::unique_ptr<storage::Object> object =
std::make_unique<storage::fake::FakeObject>(identifier, content);
absl::string_view content_data;
ASSERT_EQ(object->GetData(&content_data), ledger::Status::OK);
Status status;
std::string encrypted_bytes;
EncryptObject(object->GetIdentifier(), content_data, &status, &encrypted_bytes);
EXPECT_EQ(status, Status::OK);
EXPECT_FALSE(encrypted_bytes.empty());
std::string decrypted_bytes;
DecryptObject(identifier, encrypted_bytes, &status, &decrypted_bytes);
EXPECT_EQ(status, Status::OK);
EXPECT_EQ(decrypted_bytes, content);
}
TEST_F(EncryptionServiceTest, GetApplyChunkingPermutation) {
uint64_t chunk_window_hash, result;
Status status;
auto bit_generator = environment_.random()->NewBitGenerator<uint64_t>();
chunk_window_hash =
std::uniform_int_distribution(0ul, std::numeric_limits<uint64_t>::max())(bit_generator);
ApplyChunkingPermutation(chunk_window_hash, &status, &result);
EXPECT_EQ(status, Status::OK);
EXPECT_NE(chunk_window_hash, result);
// Since we're using xor, applying the same permutation two times should yield
// the initial input;
ApplyChunkingPermutation(result, &status, &result);
EXPECT_EQ(status, Status::OK);
EXPECT_EQ(result, chunk_window_hash);
}
TEST_F(EncryptionServiceTest, GetEntryIdMergeCommit) {
storage::CommitId parent_id1 = "commit1";
storage::CommitId parent_id2 = "commit2";
std::string entry_name = "Name";
std::string operation_list = "AADD";
std::string entry_id = GetEntryIdForMerge(entry_name, parent_id1, parent_id2, operation_list);
// For merge commits, calling this method with the same parameters must result in the same entry
// id.
std::string entry_id0 = GetEntryIdForMerge(entry_name, parent_id1, parent_id2, operation_list);
EXPECT_EQ(entry_id, entry_id0);
// Changing any of the parameters must result in different entry id.
EXPECT_NE(entry_id, GetEntryIdForMerge(entry_name, parent_id1, parent_id2, "AD"));
EXPECT_NE(entry_id, GetEntryIdForMerge(entry_name, parent_id1, "commit3", operation_list));
EXPECT_NE(entry_id, GetEntryIdForMerge("Surname", parent_id1, parent_id2, operation_list));
// Changing the order of the parents must result in different entry ids.
EXPECT_NE(entry_id, GetEntryIdForMerge(entry_name, parent_id2, parent_id1, operation_list));
}
TEST_F(EncryptionServiceTest, GetEntryIdNonMergeCommit) { EXPECT_NE(GetEntryId(), GetEntryId()); }
TEST_F(EncryptionServiceTest, EncodeVerifyCommitId) {
std::string encoded_id1 = EncodeCommitId("commit_id1");
EXPECT_TRUE(IsSameVersion(encoded_id1));
std::string encoded_id2 = EncodeCommitId("commit_id2");
EXPECT_TRUE(IsSameVersion(encoded_id2));
EXPECT_NE(encoded_id1, encoded_id2);
}
} // namespace
} // namespace encryption