From 732dca60a7cbb6b66b4173e93a25e376c33f06f9 Mon Sep 17 00:00:00 2001 From: tholenst <tholenst@google.com> Date: Fri, 9 Aug 2019 00:37:21 -0700 Subject: [PATCH] Migrate the AesCmacKeyManager to a KeyTypeManager. PiperOrigin-RevId: 262511503 --- cc/mac/BUILD.bazel | 6 +- cc/mac/CMakeLists.txt | 8 +- cc/mac/aes_cmac_key_manager.cc | 134 ----------- cc/mac/aes_cmac_key_manager.h | 99 ++++++-- cc/mac/aes_cmac_key_manager_test.cc | 354 ++++++++++++---------------- cc/mac/mac_config.cc | 2 +- cc/mac/mac_key_templates_test.cc | 58 +++-- 7 files changed, 270 insertions(+), 391 deletions(-) delete mode 100644 cc/mac/aes_cmac_key_manager.cc diff --git a/cc/mac/BUILD.bazel b/cc/mac/BUILD.bazel index 7a10bff50..e35632a0b 100644 --- a/cc/mac/BUILD.bazel +++ b/cc/mac/BUILD.bazel @@ -75,16 +75,16 @@ cc_library( cc_library( name = "aes_cmac_key_manager", - srcs = ["aes_cmac_key_manager.cc"], hdrs = ["aes_cmac_key_manager.h"], include_prefix = "tink", strip_include_prefix = "/cc", deps = [ "//cc:key_manager", - "//cc:key_manager_base", + "//cc:core/key_type_manager", "//cc:mac", "//cc/subtle:aes_cmac_boringssl", "//cc/subtle:random", + "//cc/util:constants", "//cc/util:enums", "//cc/util:errors", "//cc/util:protobuf_helper", @@ -194,6 +194,7 @@ cc_test( ":aes_cmac_key_manager", ":hmac_key_manager", ":mac_key_templates", + "//cc/util:test_matchers", "//proto:aes_cmac_cc_proto", "//proto:common_cc_proto", "//proto:hmac_cc_proto", @@ -212,6 +213,7 @@ cc_test( "//cc:mac", "//cc/util:status", "//cc/util:statusor", + "//cc/util:test_matchers", "//proto:aes_cmac_cc_proto", "//proto:aes_ctr_cc_proto", "//proto:aes_ctr_hmac_aead_cc_proto", diff --git a/cc/mac/CMakeLists.txt b/cc/mac/CMakeLists.txt index d8e4d0929..27af195f5 100644 --- a/cc/mac/CMakeLists.txt +++ b/cc/mac/CMakeLists.txt @@ -64,14 +64,14 @@ tink_cc_library( tink_cc_library( NAME aes_cmac_key_manager SRCS - aes_cmac_key_manager.cc aes_cmac_key_manager.h DEPS tink::core::key_manager - tink::core::key_manager_base + tink::core::key_type_manager tink::core::mac tink::subtle::aes_cmac_boringssl tink::subtle::random + tink::util::constants tink::util::enums tink::util::errors tink::util::protobuf_helper @@ -164,10 +164,12 @@ tink_cc_test( tink::mac::aes_cmac_key_manager tink::mac::hmac_key_manager tink::mac::mac_key_templates + tink::util::test_matchers tink::proto::aes_cmac_cc_proto tink::proto::common_cc_proto tink::proto::hmac_cc_proto tink::proto::tink_cc_proto + gmock ) tink_cc_test( @@ -176,6 +178,7 @@ tink_cc_test( DEPS tink::mac::aes_cmac_key_manager tink::core::mac + tink::util::test_matchers tink::util::status tink::util::statusor tink::proto::aes_ctr_cc_proto @@ -183,6 +186,7 @@ tink_cc_test( tink::proto::common_cc_proto tink::proto::aes_cmac_cc_proto tink::proto::tink_cc_proto + gmock ) tink_cc_test( diff --git a/cc/mac/aes_cmac_key_manager.cc b/cc/mac/aes_cmac_key_manager.cc deleted file mode 100644 index 9e3e81d16..000000000 --- a/cc/mac/aes_cmac_key_manager.cc +++ /dev/null @@ -1,134 +0,0 @@ -// 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 "tink/mac/aes_cmac_key_manager.h" - -#include <map> - -#include "absl/strings/string_view.h" -#include "tink/key_manager.h" -#include "tink/mac.h" -#include "tink/subtle/aes_cmac_boringssl.h" -#include "tink/subtle/random.h" -#include "tink/util/enums.h" -#include "tink/util/errors.h" -#include "tink/util/protobuf_helper.h" -#include "tink/util/status.h" -#include "tink/util/statusor.h" -#include "tink/util/validation.h" -#include "proto/aes_cmac.pb.h" -#include "proto/tink.pb.h" - -namespace crypto { -namespace tink { - -using crypto::tink::util::Enums; -using crypto::tink::util::Status; -using crypto::tink::util::StatusOr; -using google::crypto::tink::AesCmacKey; -using google::crypto::tink::AesCmacKeyFormat; -using google::crypto::tink::AesCmacParams; -using google::crypto::tink::KeyData; - -constexpr uint32_t AesCmacKeyManager::kVersion; -// Due to https://www.math.uwaterloo.ca/~ajmeneze/publications/tightness.pdf, we -// only allow key sizes of 256 bit. -constexpr int kKeySizeInBytes = 32; -constexpr int kMaxTagSizeInBytes = 16; -constexpr int kMinTagSizeInBytes = 10; - -class AesCmacKeyFactory : public KeyFactoryBase<AesCmacKey, AesCmacKeyFormat> { - public: - AesCmacKeyFactory() {} - - KeyData::KeyMaterialType key_material_type() const override { - return KeyData::SYMMETRIC; - } - - protected: - StatusOr<std::unique_ptr<AesCmacKey>> NewKeyFromFormat( - const AesCmacKeyFormat& cmac_key_format) const override; -}; - -StatusOr<std::unique_ptr<AesCmacKey>> AesCmacKeyFactory::NewKeyFromFormat( - const AesCmacKeyFormat& cmac_key_format) const { - Status status = AesCmacKeyManager::Validate(cmac_key_format); - if (!status.ok()) return status; - auto cmac_key = absl::make_unique<AesCmacKey>(); - cmac_key->set_version(AesCmacKeyManager::kVersion); - cmac_key->set_key_value( - subtle::Random::GetRandomBytes(cmac_key_format.key_size())); - *cmac_key->mutable_params() = cmac_key_format.params(); - return absl::implicit_cast<StatusOr<std::unique_ptr<AesCmacKey>>>( - std::move(cmac_key)); -} - -AesCmacKeyManager::AesCmacKeyManager() - : key_factory_(new AesCmacKeyFactory()) {} - -uint32_t AesCmacKeyManager::get_version() const { return kVersion; } - -const KeyFactory& AesCmacKeyManager::get_key_factory() const { - return *key_factory_; -} - -StatusOr<std::unique_ptr<Mac>> AesCmacKeyManager::GetPrimitiveFromKey( - const AesCmacKey& cmac_key) const { - Status status = Validate(cmac_key); - if (!status.ok()) return status; - auto cmac_result = subtle::AesCmacBoringSsl::New( - cmac_key.key_value(), cmac_key.params().tag_size()); - if (!cmac_result.ok()) return cmac_result.status(); - return std::move(cmac_result.ValueOrDie()); -} - -// static -Status AesCmacKeyManager::Validate(const AesCmacParams& params) { - if (params.tag_size() < kMinTagSizeInBytes) { - return ToStatusF(util::error::INVALID_ARGUMENT, - "Invalid AesCmacParams: tag_size %d is too small.", - params.tag_size()); - } - if (params.tag_size() > kMaxTagSizeInBytes) { - return ToStatusF(util::error::INVALID_ARGUMENT, - "Invalid AesCmacParams: tag_size %d is too big.", - params.tag_size()); - } - return Status::OK; -} - -// static -Status AesCmacKeyManager::Validate(const AesCmacKey& key) { - Status status = ValidateVersion(key.version(), kVersion); - if (!status.ok()) return status; - if (key.key_value().size() != kKeySizeInBytes) { - return ToStatusF(util::error::INVALID_ARGUMENT, - "Invalid AesCmacKey: key_value wrong length."); - } - return Validate(key.params()); -} - -// static -Status AesCmacKeyManager::Validate(const AesCmacKeyFormat& key_format) { - if (key_format.key_size() != kKeySizeInBytes) { - return ToStatusF(util::error::INVALID_ARGUMENT, - "Invalid AesCmacKeyFormat: invalid key_size."); - } - return Validate(key_format.params()); -} - -} // namespace tink -} // namespace crypto diff --git a/cc/mac/aes_cmac_key_manager.h b/cc/mac/aes_cmac_key_manager.h index efac6a329..3d1b81b3e 100644 --- a/cc/mac/aes_cmac_key_manager.h +++ b/cc/mac/aes_cmac_key_manager.h @@ -1,5 +1,3 @@ -// 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 @@ -20,13 +18,17 @@ #include <vector> #include "absl/strings/string_view.h" -#include "tink/core/key_manager_base.h" +#include "tink/core/key_type_manager.h" #include "tink/key_manager.h" #include "tink/mac.h" +#include "tink/subtle/aes_cmac_boringssl.h" +#include "tink/subtle/random.h" +#include "tink/util/constants.h" #include "tink/util/errors.h" #include "tink/util/protobuf_helper.h" #include "tink/util/status.h" #include "tink/util/statusor.h" +#include "tink/util/validation.h" #include "proto/aes_cmac.pb.h" #include "proto/tink.pb.h" @@ -34,36 +36,87 @@ namespace crypto { namespace tink { class AesCmacKeyManager - : public KeyManagerBase<Mac, google::crypto::tink::AesCmacKey> { + : public KeyTypeManager<google::crypto::tink::AesCmacKey, + google::crypto::tink::AesCmacKeyFormat, + List<Mac>> { public: - static constexpr uint32_t kVersion = 0; + class MacFactory : public PrimitiveFactory<Mac> { + crypto::tink::util::StatusOr<std::unique_ptr<Mac>> Create( + const google::crypto::tink::AesCmacKey& key) const override { + return subtle::AesCmacBoringSsl::New(key.key_value(), + key.params().tag_size()); + } + }; + + AesCmacKeyManager() + : KeyTypeManager(absl::make_unique<AesCmacKeyManager::MacFactory>()) {} + + uint32_t get_version() const override { return 0; } - AesCmacKeyManager(); + google::crypto::tink::KeyData::KeyMaterialType key_material_type() + const override { + return google::crypto::tink::KeyData::SYMMETRIC; + } - // Returns the version of this key manager. - uint32_t get_version() const override; + const std::string& get_key_type() const override { return key_type_; } - // Returns a factory that generates keys of the key type - // handled by this manager. - const KeyFactory& get_key_factory() const override; + crypto::tink::util::Status ValidateKey( + const google::crypto::tink::AesCmacKey& key) const override { + crypto::tink::util::Status status = + ValidateVersion(key.version(), get_version()); + if (!status.ok()) return status; + if (key.key_value().size() != kKeySizeInBytes) { + return crypto::tink::util::Status( + util::error::INVALID_ARGUMENT, + "Invalid AesCmacKey: key_value wrong length."); + } + return ValidateParams(key.params()); + } - ~AesCmacKeyManager() override {} + crypto::tink::util::Status ValidateKeyFormat( + const google::crypto::tink::AesCmacKeyFormat& key_format) const override { + if (key_format.key_size() != kKeySizeInBytes) { + return crypto::tink::util::Status( + crypto::tink::util::error::INVALID_ARGUMENT, + "Invalid AesCmacKeyFormat: invalid key_size."); + } + return ValidateParams(key_format.params()); + } - protected: - crypto::tink::util::StatusOr<std::unique_ptr<Mac>> GetPrimitiveFromKey( - const google::crypto::tink::AesCmacKey& cmac_key) const override; + crypto::tink::util::StatusOr<google::crypto::tink::AesCmacKey> CreateKey( + const google::crypto::tink::AesCmacKeyFormat& key_format) const override { + google::crypto::tink::AesCmacKey key; + key.set_version(get_version()); + key.set_key_value( + subtle::Random::GetRandomBytes(key_format.key_size())); + *key.mutable_params() = key_format.params(); + return key; + } private: - friend class AesCmacKeyFactory; + crypto::tink::util::Status ValidateParams( + const google::crypto::tink::AesCmacParams& params) const { + if (params.tag_size() < kMinTagSizeInBytes) { + return util::Status(util::error::INVALID_ARGUMENT, + absl::StrCat("Invalid AesCmacParams: tag_size ", + params.tag_size(), " is too small.")); + } + if (params.tag_size() > kMaxTagSizeInBytes) { + return util::Status(util::error::INVALID_ARGUMENT, + absl::StrCat("Invalid AesCmacParams: tag_size ", + params.tag_size(), " is too big.")); + } + return util::OkStatus(); + } - std::unique_ptr<KeyFactory> key_factory_; + // Due to https://www.math.uwaterloo.ca/~ajmeneze/publications/tightness.pdf, + // we only allow key sizes of 256 bit. + const int kKeySizeInBytes = 32; + const int kMaxTagSizeInBytes = 16; + const int kMinTagSizeInBytes = 10; - static crypto::tink::util::Status Validate( - const google::crypto::tink::AesCmacParams& params); - static crypto::tink::util::Status Validate( - const google::crypto::tink::AesCmacKey& key); - static crypto::tink::util::Status Validate( - const google::crypto::tink::AesCmacKeyFormat& key_format); + const std::string key_type_ = absl::StrCat( + kTypeGoogleapisCom, google::crypto::tink::AesCmacKey().GetTypeName()); }; } // namespace tink diff --git a/cc/mac/aes_cmac_key_manager_test.cc b/cc/mac/aes_cmac_key_manager_test.cc index 75135dc19..813684125 100644 --- a/cc/mac/aes_cmac_key_manager_test.cc +++ b/cc/mac/aes_cmac_key_manager_test.cc @@ -1,5 +1,3 @@ -// 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 @@ -13,234 +11,178 @@ // limitations under the License. // //////////////////////////////////////////////////////////////////////////////// - #include "tink/mac/aes_cmac_key_manager.h" +#include "gmock/gmock.h" #include "gtest/gtest.h" -#include "tink/mac.h" #include "tink/util/status.h" #include "tink/util/statusor.h" +#include "tink/util/test_matchers.h" #include "proto/aes_cmac.pb.h" -#include "proto/aes_ctr.pb.h" -#include "proto/common.pb.h" -#include "proto/tink.pb.h" namespace crypto { namespace tink { -using google::crypto::tink::AesCmacKey; -using google::crypto::tink::AesCmacKeyFormat; -using google::crypto::tink::AesCtrKey; -using google::crypto::tink::AesCtrKeyFormat; -using google::crypto::tink::HashType; -using google::crypto::tink::KeyData; - namespace { -class AesCmacKeyManagerTest : public ::testing::Test { - protected: - std::string key_type_prefix_ = "type.googleapis.com/"; - std::string cmac_key_type_ = "type.googleapis.com/google.crypto.tink.AesCmacKey"; -}; +using ::crypto::tink::test::IsOk; +using ::google::crypto::tink::AesCmacKey; +using ::google::crypto::tink::AesCmacKeyFormat; +using ::google::crypto::tink::AesCmacParams; +using ::testing::Eq; +using ::testing::Not; +using ::testing::SizeIs; + +TEST(AesCmacKeyManagerTest, Basics) { + EXPECT_THAT(AesCmacKeyManager().get_version(), Eq(0)); + EXPECT_THAT(AesCmacKeyManager().get_key_type(), + Eq("type.googleapis.com/google.crypto.tink.AesCmacKey")); + EXPECT_THAT(AesCmacKeyManager().key_material_type(), + Eq(google::crypto::tink::KeyData::SYMMETRIC)); +} -TEST_F(AesCmacKeyManagerTest, testBasic) { - AesCmacKeyManager key_manager; +TEST(AesCmacKeyManagerTest, ValidateEmptyKey) { + EXPECT_THAT(AesCmacKeyManager().ValidateKey(AesCmacKey()), Not(IsOk())); +} - EXPECT_EQ(0, key_manager.get_version()); - EXPECT_EQ("type.googleapis.com/google.crypto.tink.AesCmacKey", - key_manager.get_key_type()); - EXPECT_TRUE(key_manager.DoesSupport(key_manager.get_key_type())); +AesCmacParams ValidParams() { + AesCmacParams params; + params.set_tag_size(16); + return params; } -TEST_F(AesCmacKeyManagerTest, testKeyDataErrors) { - AesCmacKeyManager key_manager; - - { // Bad key type. - KeyData key_data; - std::string bad_key_type = - "type.googleapis.com/google.crypto.tink.SomeOtherKey"; - key_data.set_type_url(bad_key_type); - auto result = key_manager.GetPrimitive(key_data); - EXPECT_FALSE(result.ok()); - EXPECT_EQ(util::error::INVALID_ARGUMENT, result.status().error_code()); - EXPECT_PRED_FORMAT2(testing::IsSubstring, "not supported", - result.status().error_message()); - EXPECT_PRED_FORMAT2(testing::IsSubstring, bad_key_type, - result.status().error_message()); - } - - { // Bad key value. - KeyData key_data; - key_data.set_type_url(cmac_key_type_); - key_data.set_value("some bad serialized proto"); - auto result = key_manager.GetPrimitive(key_data); - EXPECT_FALSE(result.ok()); - EXPECT_EQ(util::error::INVALID_ARGUMENT, result.status().error_code()); - EXPECT_PRED_FORMAT2(testing::IsSubstring, "not parse", - result.status().error_message()); - } - - { // Bad version. - KeyData key_data; - AesCmacKey key; - key.set_version(1); - key_data.set_type_url(cmac_key_type_); - key_data.set_value(key.SerializeAsString()); - auto result = key_manager.GetPrimitive(key_data); - EXPECT_FALSE(result.ok()); - EXPECT_EQ(util::error::INVALID_ARGUMENT, result.status().error_code()); - EXPECT_PRED_FORMAT2(testing::IsSubstring, "version", - result.status().error_message()); - } +AesCmacKeyFormat ValidKeyFormat() { + AesCmacKeyFormat format; + *format.mutable_params() = ValidParams(); + format.set_key_size(32); + return format; } -TEST_F(AesCmacKeyManagerTest, testKeyMessageErrors) { - AesCmacKeyManager key_manager; - - { // Bad protobuffer. - AesCtrKey key_message; - auto result = key_manager.GetPrimitive(key_message); - EXPECT_FALSE(result.ok()); - EXPECT_EQ(util::error::INVALID_ARGUMENT, result.status().error_code()); - EXPECT_PRED_FORMAT2(testing::IsSubstring, "AesCtrKey", - result.status().error_message()); - EXPECT_PRED_FORMAT2(testing::IsSubstring, "not supported", - result.status().error_message()); - } +TEST(AesCmacKeyManagerTest, ValidateEmptyKeyFormat) { + EXPECT_THAT(AesCmacKeyManager().ValidateKeyFormat(AesCmacKeyFormat()), + Not(IsOk())); } -TEST_F(AesCmacKeyManagerTest, testPrimitives) { - AesCmacKeyManager key_manager; - AesCmacKey key; - - key.set_version(0); - key.mutable_params()->set_tag_size(16); - key.set_key_value("some key of sufficient length..."); - - { // Using key message only. - auto result = key_manager.GetPrimitive(key); - EXPECT_TRUE(result.ok()) << result.status(); - auto cmac = std::move(result.ValueOrDie()); - auto cmac_result = cmac->ComputeMac("some data"); - EXPECT_TRUE(cmac_result.ok()); - } - - { // Using KeyData proto. - KeyData key_data; - key_data.set_type_url(cmac_key_type_); - key_data.set_value(key.SerializeAsString()); - auto result = key_manager.GetPrimitive(key); - EXPECT_TRUE(result.ok()) << result.status(); - auto cmac = std::move(result.ValueOrDie()); - auto cmac_result = cmac->ComputeMac("some data"); - EXPECT_TRUE(cmac_result.ok()); - } +TEST(AesCmacKeyManagerTest, ValidateSimpleKeyFormat) { + EXPECT_THAT(AesCmacKeyManager().ValidateKeyFormat(ValidKeyFormat()), IsOk()); } -TEST_F(AesCmacKeyManagerTest, testNewKeyErrors) { - AesCmacKeyManager key_manager; - const KeyFactory& key_factory = key_manager.get_key_factory(); - - { // Bad key format. - AesCtrKeyFormat key_format; - auto result = key_factory.NewKey(key_format); - EXPECT_FALSE(result.ok()); - EXPECT_EQ(util::error::INVALID_ARGUMENT, result.status().error_code()); - EXPECT_PRED_FORMAT2(testing::IsSubstring, "not supported", - result.status().error_message()); - EXPECT_PRED_FORMAT2(testing::IsSubstring, "AesCtrKeyFormat", - result.status().error_message()); - } - - { // Bad serialized key format. - auto result = key_factory.NewKey("some bad serialized proto"); - EXPECT_FALSE(result.ok()); - EXPECT_EQ(util::error::INVALID_ARGUMENT, result.status().error_code()); - EXPECT_PRED_FORMAT2(testing::IsSubstring, "not parse", - result.status().error_message()); - } - - { // Bad AesCmacKeyFormat: small key_size. - AesCmacKeyFormat key_format; - key_format.set_key_size(8); - key_format.mutable_params()->set_tag_size(16); - auto result = key_factory.NewKey(key_format); - EXPECT_FALSE(result.ok()); - EXPECT_EQ(util::error::INVALID_ARGUMENT, result.status().error_code()); - EXPECT_PRED_FORMAT2(testing::IsSubstring, "invalid key_size", - result.status().error_message()); - } - - { // Bad AesCmacKeyFormat: BlockCipher not supported. - AesCmacKeyFormat key_format; - key_format.set_key_size(32); - key_format.mutable_params()->set_tag_size(17); - auto result = key_factory.NewKey(key_format); - EXPECT_FALSE(result.ok()); - EXPECT_EQ(util::error::INVALID_ARGUMENT, result.status().error_code()); - EXPECT_PRED_FORMAT2(testing::IsSubstring, "tag_size", - result.status().error_message()); - EXPECT_PRED_FORMAT2(testing::IsSubstring, "too big", - result.status().error_message()); - } - - { // Bad AesCmacKeyFormat: BlockCipher not supported. - AesCmacKeyFormat key_format; - key_format.set_key_size(32); - key_format.mutable_params()->set_tag_size(9); - auto result = key_factory.NewKey(key_format); - EXPECT_FALSE(result.ok()); - EXPECT_EQ(util::error::INVALID_ARGUMENT, result.status().error_code()); - EXPECT_PRED_FORMAT2(testing::IsSubstring, "tag_size", - result.status().error_message()); - EXPECT_PRED_FORMAT2(testing::IsSubstring, "too small", - result.status().error_message()); - } +TEST(AesCmacKeyManagerTest, ValidateKeyFormatKeySizes) { + AesCmacKeyFormat format = ValidKeyFormat(); + + format.set_key_size(0); + EXPECT_THAT(AesCmacKeyManager().ValidateKeyFormat(format), Not(IsOk())); + + format.set_key_size(1); + EXPECT_THAT(AesCmacKeyManager().ValidateKeyFormat(format), Not(IsOk())); + + format.set_key_size(15); + EXPECT_THAT(AesCmacKeyManager().ValidateKeyFormat(format), Not(IsOk())); + + format.set_key_size(16); + EXPECT_THAT(AesCmacKeyManager().ValidateKeyFormat(format), Not(IsOk())); + + format.set_key_size(17); + EXPECT_THAT(AesCmacKeyManager().ValidateKeyFormat(format), Not(IsOk())); + + format.set_key_size(31); + EXPECT_THAT(AesCmacKeyManager().ValidateKeyFormat(format), Not(IsOk())); + + format.set_key_size(32); + EXPECT_THAT(AesCmacKeyManager().ValidateKeyFormat(format), IsOk()); + + format.set_key_size(33); + EXPECT_THAT(AesCmacKeyManager().ValidateKeyFormat(format), Not(IsOk())); +} + +TEST(AesCmacKeyManagerTest, ValidateKeyFormatTagSizes) { + AesCmacKeyFormat format = ValidKeyFormat(); + + format.mutable_params()->set_tag_size(0); + EXPECT_THAT(AesCmacKeyManager().ValidateKeyFormat(format), Not(IsOk())); + + format.mutable_params()->set_tag_size(9); + EXPECT_THAT(AesCmacKeyManager().ValidateKeyFormat(format), Not(IsOk())); + + format.mutable_params()->set_tag_size(10); + EXPECT_THAT(AesCmacKeyManager().ValidateKeyFormat(format), IsOk()); + + format.mutable_params()->set_tag_size(11); + EXPECT_THAT(AesCmacKeyManager().ValidateKeyFormat(format), IsOk()); + + format.mutable_params()->set_tag_size(12); + EXPECT_THAT(AesCmacKeyManager().ValidateKeyFormat(format), IsOk()); + + format.mutable_params()->set_tag_size(15); + EXPECT_THAT(AesCmacKeyManager().ValidateKeyFormat(format), IsOk()); + + format.mutable_params()->set_tag_size(16); + EXPECT_THAT(AesCmacKeyManager().ValidateKeyFormat(format), IsOk()); + + format.mutable_params()->set_tag_size(17); + EXPECT_THAT(AesCmacKeyManager().ValidateKeyFormat(format), Not(IsOk())); + + format.mutable_params()->set_tag_size(32); + EXPECT_THAT(AesCmacKeyManager().ValidateKeyFormat(format), Not(IsOk())); +} + +TEST(AesCmacKeyManagerTest, CreateKey) { + AesCmacKeyFormat format = ValidKeyFormat(); + ASSERT_THAT(AesCmacKeyManager().CreateKey(format).status(), IsOk()); + AesCmacKey key = AesCmacKeyManager().CreateKey(format).ValueOrDie(); + EXPECT_THAT(key.version(), Eq(0)); + EXPECT_THAT(key.key_value(), SizeIs(format.key_size())); + EXPECT_THAT(key.params().tag_size(), Eq(format.params().tag_size())); +} + +TEST(AesCmacKeyManagerTest, ValidateKey) { + AesCmacKeyFormat format = ValidKeyFormat(); + AesCmacKey key = AesCmacKeyManager().CreateKey(format).ValueOrDie(); + EXPECT_THAT(AesCmacKeyManager().ValidateKey(key), IsOk()); +} + +TEST(AesCmacKeyManagerTest, ValidateKeyInvalidVersion) { + AesCmacKeyFormat format = ValidKeyFormat(); + AesCmacKey key = AesCmacKeyManager().CreateKey(format).ValueOrDie(); + key.set_version(1); + EXPECT_THAT(AesCmacKeyManager().ValidateKey(key), Not(IsOk())); +} + +TEST(AesCmacKeyManagerTest, ValidateKeyShortKey) { + AesCmacKeyFormat format = ValidKeyFormat(); + AesCmacKey key = AesCmacKeyManager().CreateKey(format).ValueOrDie(); + key.set_key_value("0123456789abcdef"); + EXPECT_THAT(AesCmacKeyManager().ValidateKey(key), Not(IsOk())); +} + +TEST(AesCmacKeyManagerTest, ValidateKeyLongTagSize) { + AesCmacKeyFormat format = ValidKeyFormat(); + AesCmacKey key = AesCmacKeyManager().CreateKey(format).ValueOrDie(); + key.mutable_params()->set_tag_size(17); + EXPECT_THAT(AesCmacKeyManager().ValidateKey(key), Not(IsOk())); +} + + +TEST(AesCmacKeyManagerTest, ValidateKeyTooShortTagSize) { + AesCmacKeyFormat format = ValidKeyFormat(); + AesCmacKey key = AesCmacKeyManager().CreateKey(format).ValueOrDie(); + key.mutable_params()->set_tag_size(9); + EXPECT_THAT(AesCmacKeyManager().ValidateKey(key), Not(IsOk())); } -TEST_F(AesCmacKeyManagerTest, testNewKeyBasic) { - AesCmacKeyManager key_manager; - const KeyFactory& key_factory = key_manager.get_key_factory(); - AesCmacKeyFormat key_format; - key_format.set_key_size(32); - key_format.mutable_params()->set_tag_size(16); - - { // Via NewKey(format_proto). - auto result = key_factory.NewKey(key_format); - EXPECT_TRUE(result.ok()) << result.status(); - auto key = std::move(result.ValueOrDie()); - EXPECT_EQ(key_type_prefix_ + key->GetTypeName(), cmac_key_type_); - std::unique_ptr<AesCmacKey> cmac_key( - static_cast<AesCmacKey*>(key.release())); - EXPECT_EQ(0, cmac_key->version()); - EXPECT_EQ(16, cmac_key->params().tag_size()); - EXPECT_EQ(key_format.key_size(), cmac_key->key_value().size()); - } - - { // Via NewKey(serialized_format_proto). - auto result = key_factory.NewKey(key_format.SerializeAsString()); - EXPECT_TRUE(result.ok()) << result.status(); - auto key = std::move(result.ValueOrDie()); - EXPECT_EQ(key_type_prefix_ + key->GetTypeName(), cmac_key_type_); - std::unique_ptr<AesCmacKey> cmac_key( - static_cast<AesCmacKey*>(key.release())); - EXPECT_EQ(0, cmac_key->version()); - EXPECT_EQ(16, cmac_key->params().tag_size()); - EXPECT_EQ(key_format.key_size(), cmac_key->key_value().size()); - } - - { // Via NewKeyData(serialized_format_proto). - auto result = key_factory.NewKeyData(key_format.SerializeAsString()); - EXPECT_TRUE(result.ok()) << result.status(); - auto key_data = std::move(result.ValueOrDie()); - EXPECT_EQ(cmac_key_type_, key_data->type_url()); - EXPECT_EQ(KeyData::SYMMETRIC, key_data->key_material_type()); - AesCmacKey cmac_key; - EXPECT_TRUE(cmac_key.ParseFromString(key_data->value())); - EXPECT_EQ(0, cmac_key.version()); - EXPECT_EQ(16, cmac_key.params().tag_size()); - EXPECT_EQ(key_format.key_size(), cmac_key.key_value().size()); - } +TEST(AesCmacKeyManagerTest, GetPrimitive) { + AesCmacKeyFormat format = ValidKeyFormat(); + AesCmacKey key = AesCmacKeyManager().CreateKey(format).ValueOrDie(); + auto manager_mac_or = AesCmacKeyManager().GetPrimitive<Mac>(key); + ASSERT_THAT(manager_mac_or.status(), IsOk()); + auto mac_value_or = manager_mac_or.ValueOrDie()->ComputeMac("some plaintext"); + ASSERT_THAT(mac_value_or.status(), IsOk()); + + auto direct_mac_or = + subtle::AesCmacBoringSsl::New(key.key_value(), key.params().tag_size()); + ASSERT_THAT(direct_mac_or.status(), IsOk()); + EXPECT_THAT(direct_mac_or.ValueOrDie()->VerifyMac(mac_value_or.ValueOrDie(), + "some plaintext"), IsOk()); } } // namespace diff --git a/cc/mac/mac_config.cc b/cc/mac/mac_config.cc index f9fe25137..793d11285 100644 --- a/cc/mac/mac_config.cc +++ b/cc/mac/mac_config.cc @@ -45,7 +45,7 @@ util::Status MacConfig::Register() { auto status = Registry::RegisterKeyManager( absl::make_unique<HmacKeyManager>(), true); if (!status.ok()) return status; - status = Registry::RegisterKeyManager( + status = Registry::RegisterKeyTypeManager( absl::make_unique<AesCmacKeyManager>(), true); if (!status.ok()) return status; diff --git a/cc/mac/mac_key_templates_test.cc b/cc/mac/mac_key_templates_test.cc index 709850d9f..333fb319f 100644 --- a/cc/mac/mac_key_templates_test.cc +++ b/cc/mac/mac_key_templates_test.cc @@ -16,9 +16,11 @@ #include "tink/mac/mac_key_templates.h" +#include "gmock/gmock.h" #include "gtest/gtest.h" #include "tink/mac/aes_cmac_key_manager.h" #include "tink/mac/hmac_key_manager.h" +#include "tink/util/test_matchers.h" #include "proto/aes_cmac.pb.h" #include "proto/common.pb.h" #include "proto/hmac.pb.h" @@ -28,11 +30,14 @@ namespace crypto { namespace tink { namespace { -using google::crypto::tink::AesCmacKeyFormat; -using google::crypto::tink::HashType; -using google::crypto::tink::HmacKeyFormat; -using google::crypto::tink::KeyTemplate; -using google::crypto::tink::OutputPrefixType; +using ::crypto::tink::test::IsOk; +using ::google::crypto::tink::AesCmacKeyFormat; +using ::google::crypto::tink::HashType; +using ::google::crypto::tink::HmacKeyFormat; +using ::google::crypto::tink::KeyTemplate; +using ::google::crypto::tink::OutputPrefixType; +using ::testing::Eq; +using ::testing::Ref; TEST(MacKeyTemplatesTest, testHmacKeyTemplates) { std::string type_url = "type.googleapis.com/google.crypto.tink.HmacKey"; @@ -128,26 +133,33 @@ TEST(MacKeyTemplatesTest, testHmacKeyTemplates) { } } -TEST(MacKeyTemplatesTest, testAesCmacKeyTemplates) { - std::string type_url = "type.googleapis.com/google.crypto.tink.AesCmacKey"; +TEST(AesCmac, Basics) { + EXPECT_THAT(MacKeyTemplates::AesCmac().type_url(), + Eq("type.googleapis.com/google.crypto.tink.AesCmacKey")); + EXPECT_THAT(MacKeyTemplates::AesCmac().type_url(), + Eq(AesCmacKeyManager().get_key_type())); +} + +TEST(AesCmac, OutputPrefixType) { + EXPECT_THAT(MacKeyTemplates::AesCmac().output_prefix_type(), + Eq(OutputPrefixType::TINK)); +} + +TEST(AesCmac, MultipleCallsSameReference) { + EXPECT_THAT(MacKeyTemplates::AesCmac(), Ref(MacKeyTemplates::AesCmac())); +} + +TEST(AesCmac, WorksWithKeyTypeManager) { + AesCmacKeyFormat key_format; + EXPECT_TRUE(key_format.ParseFromString(MacKeyTemplates::AesCmac().value())); + EXPECT_THAT(AesCmacKeyManager().ValidateKeyFormat(key_format), IsOk()); +} - const KeyTemplate& key_template = MacKeyTemplates::AesCmac(); - EXPECT_EQ(type_url, key_template.type_url()); - EXPECT_EQ(OutputPrefixType::TINK, key_template.output_prefix_type()); +TEST(AesCmac, CheckValues) { AesCmacKeyFormat key_format; - EXPECT_TRUE(key_format.ParseFromString(key_template.value())); - EXPECT_EQ(32, key_format.key_size()); - EXPECT_EQ(16, key_format.params().tag_size()); - - // Check that reference to the same object is returned. - const KeyTemplate& key_template_2 = MacKeyTemplates::AesCmac(); - EXPECT_EQ(&key_template, &key_template_2); - - // Check that the template works with the key manager. - AesCmacKeyManager key_manager; - EXPECT_EQ(key_manager.get_key_type(), key_template.type_url()); - auto new_key_result = key_manager.get_key_factory().NewKey(key_format); - EXPECT_TRUE(new_key_result.ok()) << new_key_result.status(); + EXPECT_TRUE(key_format.ParseFromString(MacKeyTemplates::AesCmac().value())); + EXPECT_THAT(key_format.key_size(), Eq(32)); + EXPECT_THAT(key_format.params().tag_size(), Eq(16)); } } // namespace -- GitLab