Skip to content
Snippets Groups Projects
Commit 77bc62fa authored by Bartosz Przydatek's avatar Bartosz Przydatek Committed by Thai Duong
Browse files

Merge "Adding implementation of MacFactory."

ORIGINAL_AUTHOR=Bartosz Przydatek <przydatek@google.com>
GitOrigin-RevId: 309a055b2e19a0ba7c9e8c16564b85f3a048072d
parent 16e07af7
No related branches found
No related tags found
No related merge requests found
......@@ -38,7 +38,7 @@ class Mac {
// Verifies if 'mac' is a correct authentication code (MAC) for 'data'.
// Returns Status::OK if 'mac' is correct, and a non-OK-Status otherwise.
virtual util::Status VerifyMac(
google::protobuf::StringPiece mac,
google::protobuf::StringPiece mac_value,
google::protobuf::StringPiece data) const = 0;
virtual ~Mac() {}
......
licenses(["notice"]) # Apache 2.0
cc_library(
name = "mac_set_wrapper",
srcs = ["mac_set_wrapper.cc"],
hdrs = ["mac_set_wrapper.h"],
visibility = ["//visibility:private"],
deps = [
"//cc:crypto_format",
"//cc:mac",
"//cc:primitive_set",
"//cc/util:status",
"//cc/util:statusor",
],
)
cc_library(
name = "mac_factory",
srcs = ["mac_factory.cc"],
hdrs = ["mac_factory.h"],
visibility = ["//visibility:public"],
deps = [
":hmac_key_manager",
":mac_set_wrapper",
"//cc:key_manager",
"//cc:keyset_handle",
"//cc:mac",
"//cc:primitive_set",
"//cc:registry",
"//cc/util:status",
"//cc/util:statusor",
"@com_github_google_protobuf//:protobuf_lite",
......@@ -38,6 +56,22 @@ cc_library(
# tests
cc_test(
name = "mac_set_wrapper_test",
size = "small",
srcs = ["mac_set_wrapper_test.cc"],
copts = ["-Iexternal/gtest/include"],
deps = [
":mac_set_wrapper",
"//cc:mac",
"//cc:primitive_set",
"//cc/util:status",
"//cc/util:test_util",
"//proto:cc_tink",
"@gtest//:gtest",
],
)
cc_test(
name = "mac_factory_test",
size = "small",
......@@ -45,8 +79,12 @@ cc_test(
copts = ["-Iexternal/gtest/include"],
deps = [
":mac_factory",
":mac_set_wrapper",
"//cc:crypto_format",
"//cc:mac",
"//cc/util:status",
"//cc/util:test_util",
"//proto:cc_hmac",
"@gtest//:gtest",
],
)
......
......@@ -17,6 +17,9 @@
#include "cc/mac/mac_factory.h"
#include "cc/mac.h"
#include "cc/registry.h"
#include "cc/mac/hmac_key_manager.h"
#include "cc/mac/mac_set_wrapper.h"
#include "cc/util/status.h"
#include "cc/util/statusor.h"
#include "google/protobuf/stubs/stringpiece.h"
......@@ -25,21 +28,35 @@ namespace cloud {
namespace crypto {
namespace tink {
// static
util::Status MacFactory::RegisterStandardKeyTypes() {
return util::Status(util::error::UNIMPLEMENTED, "Not implemented yet.");
util::Status status = Registry::get_default_registry().RegisterKeyManager(
"type.googleapis.com/google.cloud.crypto.tink.HmacKey",
new HmacKeyManager());
return status;
}
// static
util::Status MacFactory::RegisterLegacyKeyTypes() {
return util::Status(util::error::UNIMPLEMENTED, "Not implemented yet.");
return util::Status::OK;
}
// static
util::StatusOr<std::unique_ptr<Mac>> GetPrimitive(
util::StatusOr<std::unique_ptr<Mac>> MacFactory::GetPrimitive(
const KeysetHandle& keyset_handle) {
return util::Status::UNKNOWN;
return GetPrimitive(keyset_handle, nullptr);
}
// static
util::StatusOr<std::unique_ptr<Mac>> MacFactory::GetPrimitive(
const KeysetHandle& keyset_handle,
const KeyManager<Mac>* custom_key_manager) {
auto primitives_result = Registry::get_default_registry().GetPrimitives<Mac>(
keyset_handle, custom_key_manager);
if (primitives_result.ok()) {
return MacSetWrapper::NewMac(std::move(primitives_result.ValueOrDie()));
}
return primitives_result.status();
}
} // namespace tink
......
......@@ -49,9 +49,10 @@ namespace tink {
//
// MacFactory.RegisterStandardKeyTypes();
// KeysetHandle keyset_handle = ...;
// Mac mac = MacFactory.GetPrimitive(keyset_handle);
// string data = ...;
// string tag = mac.ComputeMac(data).ValueOrDie();
// std::unique_ptr<Mac> mac =
// std::move(MacFactory.GetPrimitive(keyset_handle).ValueOrDie());
// std::string data = ...;
// std::string mac_value = mac.ComputeMac(data).ValueOrDie();
//
class MacFactory {
public:
......@@ -64,18 +65,17 @@ class MacFactory {
// Returns a Mac-primitive that uses key material from the keyset
// specified via 'keyset_handle'.
static util::StatusOr<std::unique_ptr<Mac>> GetPrimitive(
const KeysetHandle& keyset_handle) {
return util::Status::UNKNOWN;
}
const KeysetHandle& keyset_handle);
// Returns a Mac-primitive that uses key material from the keyset
// specified via 'keyset_handle' and is instantiated by the given
// 'custom_key_manager' (instead of the key manager from the Registry).
static util::StatusOr<std::unique_ptr<Mac>> GetPrimitive(
const KeysetHandle& keyset_handle,
const KeyManager<Mac>& custom_key_manager) {
return util::Status::UNKNOWN;
}
const KeyManager<Mac>* custom_key_manager);
private:
MacFactory() {}
};
} // namespace tink
......
......@@ -15,9 +15,26 @@
////////////////////////////////////////////////////////////////////////////////
#include "cc/mac.h"
#include "cc/crypto_format.h"
#include "cc/keyset_handle.h"
#include "cc/mac/hmac_key_manager.h"
#include "cc/mac/mac_factory.h"
#include "cc/util/status.h"
#include "cc/util/test_util.h"
#include "gtest/gtest.h"
#include "proto/common.pb.h"
#include "proto/hmac.pb.h"
#include "proto/tink.pb.h"
using cloud::crypto::tink::test::AddRawKey;
using cloud::crypto::tink::test::AddTinkKey;
using google::cloud::crypto::tink::HashType;
using google::cloud::crypto::tink::HmacKey;
using google::cloud::crypto::tink::HmacKeyFormat;
using google::cloud::crypto::tink::KeyData;
using google::cloud::crypto::tink::Keyset;
using google::cloud::crypto::tink::KeyStatusType;
using google::cloud::crypto::tink::KeyTemplate;
namespace cloud {
namespace crypto {
......@@ -33,10 +50,87 @@ class MacFactoryTest : public ::testing::Test {
};
TEST_F(MacFactoryTest, testBasic) {
EXPECT_EQ(util::error::UNIMPLEMENTED,
MacFactory::RegisterStandardKeyTypes().error_code());
EXPECT_EQ(util::error::UNIMPLEMENTED,
MacFactory::RegisterLegacyKeyTypes().error_code());
EXPECT_TRUE(MacFactory::RegisterStandardKeyTypes().ok());
EXPECT_TRUE(MacFactory::RegisterLegacyKeyTypes().ok());
Keyset keyset;
KeysetHandle keyset_handle(keyset);
auto mac_result = MacFactory::GetPrimitive(keyset_handle);
EXPECT_FALSE(mac_result.ok());
EXPECT_EQ(util::error::INVALID_ARGUMENT, mac_result.status().error_code());
EXPECT_PRED_FORMAT2(testing::IsSubstring, "no primary",
mac_result.status().error_message());
}
TEST_F(MacFactoryTest, testPrimitive) {
// Prepare a template for generating keys for a Keyset.
HmacKeyManager key_manager;
std::string key_type = key_manager.get_key_type();
HmacKeyFormat key_format;
key_format.set_key_size(16);
key_format.mutable_params()->set_tag_size(10);
key_format.mutable_params()->set_hash(HashType::SHA256);
KeyTemplate key_template;
key_template.set_type_url(key_type);
key_template.set_value(key_format.SerializeAsString());
// Prepare a Keyset.
Keyset keyset;
uint32_t key_id_1 = 1234543;
auto new_key = std::move(key_manager.NewKey(key_template).ValueOrDie());
AddTinkKey(key_type, key_id_1, *new_key, KeyStatusType::ENABLED,
KeyData::SYMMETRIC, &keyset);
uint32_t key_id_2 = 726329;
new_key = std::move(key_manager.NewKey(key_template).ValueOrDie());
AddRawKey(key_type, key_id_2, *new_key, KeyStatusType::ENABLED,
KeyData::SYMMETRIC, &keyset);
uint32_t key_id_3 = 7213743;
new_key = std::move(key_manager.NewKey(key_template).ValueOrDie());
AddTinkKey(key_type, key_id_3, *new_key, KeyStatusType::ENABLED,
KeyData::SYMMETRIC, &keyset);
keyset.set_primary_key_id(key_id_3);
// Create a KeysetHandle and use it with the factory.
KeysetHandle keyset_handle(keyset);
auto mac_result = MacFactory::GetPrimitive(keyset_handle);
EXPECT_TRUE(mac_result.ok()) << mac_result.status();
auto mac = std::move(mac_result.ValueOrDie());
// Test the resulting Mac-instance.
std::string data = "some_data_for_mac";
auto compute_mac_result = mac->ComputeMac(data);
EXPECT_TRUE(compute_mac_result.ok()) << compute_mac_result.status();
std::string mac_value = compute_mac_result.ValueOrDie();
std::string prefix =
CryptoFormat::get_output_prefix(keyset.key(2)).ValueOrDie();
EXPECT_PRED_FORMAT2(testing::IsSubstring, prefix, mac_value);
util::Status status = mac->VerifyMac(mac_value, data);
EXPECT_TRUE(status.ok()) << status;
status = mac->VerifyMac(mac_value, "bad data for mac");
EXPECT_FALSE(status.ok());
EXPECT_EQ(util::error::INVALID_ARGUMENT, status.error_code());
EXPECT_PRED_FORMAT2(testing::IsSubstring, "verification failed",
status.error_message());
status = mac->VerifyMac("some bad mac value", data);
EXPECT_FALSE(status.ok());
EXPECT_EQ(util::error::INVALID_ARGUMENT, status.error_code());
EXPECT_PRED_FORMAT2(testing::IsSubstring, "verification failed",
status.error_message());
// Create raw MAC value with 2nd key, and verify with Mac-instance.
auto raw_mac = std::move(
key_manager.GetPrimitive(keyset.key(1).key_data()).ValueOrDie());
std::string raw_mac_value = raw_mac->ComputeMac(data).ValueOrDie();
status = mac->VerifyMac(raw_mac_value, data);
EXPECT_TRUE(status.ok()) << status;
}
} // namespace
......
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///////////////////////////////////////////////////////////////////////////////
#include "cc/mac/mac_set_wrapper.h"
#include "cc/mac.h"
#include "cc/crypto_format.h"
#include "cc/primitive_set.h"
#include "cc/util/status.h"
#include "cc/util/statusor.h"
namespace cloud {
namespace crypto {
namespace tink {
namespace {
util::Status Validate(PrimitiveSet<Mac>* mac_set) {
if (mac_set == nullptr) {
return util::Status(util::error::INTERNAL, "mac_set must be non-NULL");
}
if (mac_set->get_primary() == nullptr) {
return util::Status(util::error::INVALID_ARGUMENT,
"mac_set has no primary");
}
return util::Status::OK;
}
} // anonymous namespace
// static
util::StatusOr<std::unique_ptr<Mac>> MacSetWrapper::NewMac(
std::unique_ptr<PrimitiveSet<Mac>> mac_set) {
util::Status status = Validate(mac_set.get());
if (!status.ok()) return status;
std::unique_ptr<Mac> mac(new MacSetWrapper(std::move(mac_set)));
return std::move(mac);
}
util::StatusOr<std::string> MacSetWrapper::ComputeMac(
google::protobuf::StringPiece data) const {
auto compute_mac_result =
mac_set_->get_primary()->get_primitive().ComputeMac(data);
if (!compute_mac_result.ok()) return compute_mac_result.status();
const std::string& key_id = mac_set_->get_primary()->get_identifier();
return key_id + compute_mac_result.ValueOrDie();
}
util::Status MacSetWrapper::VerifyMac(
google::protobuf::StringPiece mac_value,
google::protobuf::StringPiece data) const {
if (mac_value.length() > CryptoFormat::kNonRawPrefixSize) {
std::string key_id = mac_value.substr(0, CryptoFormat::kNonRawPrefixSize);
auto primitives_result = mac_set_->get_primitives(key_id);
if (primitives_result.ok()) {
std::string raw_mac_value =
mac_value.substr(CryptoFormat::kNonRawPrefixSize);
for (auto& mac_entry : *(primitives_result.ValueOrDie())) {
Mac& mac = mac_entry.get_primitive();
util::Status status = mac.VerifyMac(raw_mac_value, data);
if (status.ok()) {
return status;
} else {
// TODO(przydatek): LOG that a matching key didn't verify the MAC.
}
}
}
}
// No matching key succeeded with verification, try all RAW keys.
auto raw_primitives_result = mac_set_->get_raw_primitives();
if (raw_primitives_result.ok()) {
for (auto& mac_entry : *(raw_primitives_result.ValueOrDie())) {
Mac& mac = mac_entry.get_primitive();
util::Status status = mac.VerifyMac(mac_value, data);
if (status.ok()) {
return status;
}
}
}
return util::Status(util::error::INVALID_ARGUMENT, "verification failed");
}
} // namespace tink
} // namespace crypto
} // namespace cloud
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef TINK_MAC_MAC_SET_WRAPPER_H_
#define TINK_MAC_MAC_SET_WRAPPER_H_
#include "cc/mac.h"
#include "cc/primitive_set.h"
#include "cc/util/status.h"
#include "cc/util/statusor.h"
#include "google/protobuf/stubs/stringpiece.h"
#include "proto/tink.pb.h"
namespace cloud {
namespace crypto {
namespace tink {
// Wraps a set of Mac-instances that correspond to a keyset,
// and combines them into a single Mac-primitive, that uses the provided
// instances, depending on the context:
// * Mac::ComputeMac(...) uses the primary instance from the set
// * Mac::VerifyMac(...) uses the instance that matches the MAC prefix.
class MacSetWrapper : public Mac {
public:
// Returns an Mac-primitive that uses Mac-instances provided in 'mac_set',
// which must be non-NULL and must contain a primary instance.
static util::StatusOr<std::unique_ptr<Mac>> NewMac(
std::unique_ptr<PrimitiveSet<Mac>> mac_set);
util::StatusOr<std::string> ComputeMac(
google::protobuf::StringPiece data) const override;
util::Status VerifyMac(
google::protobuf::StringPiece mac_value,
google::protobuf::StringPiece data) const override;
virtual ~MacSetWrapper() {}
private:
std::unique_ptr<PrimitiveSet<Mac>> mac_set_;
MacSetWrapper(std::unique_ptr<PrimitiveSet<Mac>> mac_set)
: mac_set_(std::move(mac_set)) {}
};
} // namespace tink
} // namespace crypto
} // namespace cloud
#endif // TINK_MAC_MAC_SET_WRAPPER_H_
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
#include "cc/mac/mac_set_wrapper.h"
#include "cc/mac.h"
#include "cc/primitive_set.h"
#include "cc/util/status.h"
#include "cc/util/test_util.h"
#include "gtest/gtest.h"
using cloud::crypto::tink::test::DummyMac;
using google::cloud::crypto::tink::OutputPrefixType;
using google::cloud::crypto::tink::Keyset;
namespace cloud {
namespace crypto {
namespace tink {
namespace {
class MacSetWrapperTest : public ::testing::Test {
protected:
void SetUp() override {
}
void TearDown() override {
}
};
TEST_F(MacSetWrapperTest, testBasic) {
{ // mac_set is nullptr.
auto mac_result = MacSetWrapper::NewMac(nullptr);
EXPECT_FALSE(mac_result.ok());
EXPECT_EQ(util::error::INTERNAL, mac_result.status().error_code());
EXPECT_PRED_FORMAT2(testing::IsSubstring, "non-NULL",
mac_result.status().error_message());
}
{ // mac_set has no primary primitive.
std::unique_ptr<PrimitiveSet<Mac>> mac_set(new PrimitiveSet<Mac>());
auto mac_result = MacSetWrapper::NewMac(std::move(mac_set));
EXPECT_FALSE(mac_result.ok());
EXPECT_EQ(util::error::INVALID_ARGUMENT, mac_result.status().error_code());
EXPECT_PRED_FORMAT2(testing::IsSubstring, "no primary",
mac_result.status().error_message());
}
{ // Correct mac_set;
Keyset::Key* key;
Keyset keyset;
uint32_t key_id_0 = 1234543;
key = keyset.add_key();
key->set_output_prefix_type(OutputPrefixType::TINK);
key->set_key_id(key_id_0);
uint32_t key_id_1 = 726329;
key = keyset.add_key();
key->set_output_prefix_type(OutputPrefixType::LEGACY);
key->set_key_id(key_id_1);
uint32_t key_id_2 = 7213743;
key = keyset.add_key();
key->set_output_prefix_type(OutputPrefixType::TINK);
key->set_key_id(key_id_2);
std::string mac_name_0 = "mac0";
std::string mac_name_1 = "mac1";
std::string mac_name_2 = "mac2";
std::unique_ptr<PrimitiveSet<Mac>> mac_set(new PrimitiveSet<Mac>());
std::unique_ptr<Mac> mac(new DummyMac(mac_name_0));
auto entry_result = mac_set->AddPrimitive(std::move(mac), keyset.key(0));
ASSERT_TRUE(entry_result.ok());
mac.reset(new DummyMac(mac_name_1));
entry_result = mac_set->AddPrimitive(std::move(mac), keyset.key(1));
ASSERT_TRUE(entry_result.ok());
mac.reset(new DummyMac(mac_name_2));
entry_result = mac_set->AddPrimitive(std::move(mac), keyset.key(2));
ASSERT_TRUE(entry_result.ok());
// The last key is the primary.
mac_set->set_primary(entry_result.ValueOrDie());
// Wrap mac_set and test the resulting Mac.
auto mac_result = MacSetWrapper::NewMac(std::move(mac_set));
EXPECT_TRUE(mac_result.ok()) << mac_result.status();
mac = std::move(mac_result.ValueOrDie());
std::string data = "some_data_for_mac";
auto compute_mac_result = mac->ComputeMac(data);
EXPECT_TRUE(compute_mac_result.ok()) << compute_mac_result.status();
std::string mac_value = compute_mac_result.ValueOrDie();
EXPECT_PRED_FORMAT2(testing::IsSubstring, mac_name_2, mac_value);
util::Status status = mac->VerifyMac(mac_value, data);
EXPECT_TRUE(status.ok()) << status;
status = mac->VerifyMac("some bad mac", data);
EXPECT_FALSE(status.ok());
EXPECT_EQ(util::error::INVALID_ARGUMENT, status.error_code());
EXPECT_PRED_FORMAT2(testing::IsSubstring, "verification failed",
status.error_message());
}
}
} // namespace
} // namespace tink
} // namespace crypto
} // namespace cloud
int main(int ac, char* av[]) {
testing::InitGoogleTest(&ac, av);
return RUN_ALL_TESTS();
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment