1 // Copyright 2019 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 /////////////////////////////////////////////////////////////////////////////// 16 #ifndef TINK_MAC_AES_CMAC_KEY_MANAGER_H_ 17 #define TINK_MAC_AES_CMAC_KEY_MANAGER_H_ 18 19 #include <memory> 20 #include <string> 21 22 #include "absl/memory/memory.h" 23 #include "absl/status/status.h" 24 #include "absl/strings/str_cat.h" 25 #include "tink/chunked_mac.h" 26 #include "tink/core/key_type_manager.h" 27 #include "tink/key_manager.h" 28 #include "tink/mac.h" 29 #include "tink/mac/internal/chunked_mac_impl.h" 30 #include "tink/subtle/aes_cmac_boringssl.h" 31 #include "tink/subtle/random.h" 32 #include "tink/util/constants.h" 33 #include "tink/util/errors.h" 34 #include "tink/util/protobuf_helper.h" 35 #include "tink/util/secret_data.h" 36 #include "tink/util/status.h" 37 #include "tink/util/statusor.h" 38 #include "tink/util/validation.h" 39 #include "proto/aes_cmac.pb.h" 40 #include "proto/tink.pb.h" 41 42 namespace crypto { 43 namespace tink { 44 45 class AesCmacKeyManager 46 : public KeyTypeManager<google::crypto::tink::AesCmacKey, 47 google::crypto::tink::AesCmacKeyFormat, 48 List<Mac, ChunkedMac>> { 49 public: 50 class MacFactory : public PrimitiveFactory<Mac> { Create(const google::crypto::tink::AesCmacKey & key)51 crypto::tink::util::StatusOr<std::unique_ptr<Mac>> Create( 52 const google::crypto::tink::AesCmacKey& key) const override { 53 return subtle::AesCmacBoringSsl::New( 54 util::SecretDataFromStringView(key.key_value()), 55 key.params().tag_size()); 56 } 57 }; 58 59 class ChunkedMacFactory : public PrimitiveFactory<ChunkedMac> { Create(const google::crypto::tink::AesCmacKey & key)60 crypto::tink::util::StatusOr<std::unique_ptr<ChunkedMac>> Create( 61 const google::crypto::tink::AesCmacKey& key) const override { 62 return internal::NewChunkedCmac(key); 63 } 64 }; 65 AesCmacKeyManager()66 AesCmacKeyManager() 67 : KeyTypeManager( 68 absl::make_unique<AesCmacKeyManager::MacFactory>(), 69 absl::make_unique<AesCmacKeyManager::ChunkedMacFactory>()) {} 70 get_version()71 uint32_t get_version() const override { return 0; } 72 key_material_type()73 google::crypto::tink::KeyData::KeyMaterialType key_material_type() 74 const override { 75 return google::crypto::tink::KeyData::SYMMETRIC; 76 } 77 get_key_type()78 const std::string& get_key_type() const override { return key_type_; } 79 ValidateKey(const google::crypto::tink::AesCmacKey & key)80 crypto::tink::util::Status ValidateKey( 81 const google::crypto::tink::AesCmacKey& key) const override { 82 crypto::tink::util::Status status = 83 ValidateVersion(key.version(), get_version()); 84 if (!status.ok()) return status; 85 if (key.key_value().size() != kKeySizeInBytes) { 86 return crypto::tink::util::Status( 87 absl::StatusCode::kInvalidArgument, 88 "Invalid AesCmacKey: key_value wrong length."); 89 } 90 return ValidateParams(key.params()); 91 } 92 ValidateKeyFormat(const google::crypto::tink::AesCmacKeyFormat & key_format)93 crypto::tink::util::Status ValidateKeyFormat( 94 const google::crypto::tink::AesCmacKeyFormat& key_format) const override { 95 if (key_format.key_size() != kKeySizeInBytes) { 96 return crypto::tink::util::Status( 97 absl::StatusCode::kInvalidArgument, 98 "Invalid AesCmacKeyFormat: invalid key_size."); 99 } 100 return ValidateParams(key_format.params()); 101 } 102 CreateKey(const google::crypto::tink::AesCmacKeyFormat & key_format)103 crypto::tink::util::StatusOr<google::crypto::tink::AesCmacKey> CreateKey( 104 const google::crypto::tink::AesCmacKeyFormat& key_format) const override { 105 google::crypto::tink::AesCmacKey key; 106 key.set_version(get_version()); 107 key.set_key_value( 108 subtle::Random::GetRandomBytes(key_format.key_size())); 109 *key.mutable_params() = key_format.params(); 110 return key; 111 } 112 113 private: ValidateParams(const google::crypto::tink::AesCmacParams & params)114 crypto::tink::util::Status ValidateParams( 115 const google::crypto::tink::AesCmacParams& params) const { 116 if (params.tag_size() < kMinTagSizeInBytes) { 117 return util::Status(absl::StatusCode::kInvalidArgument, 118 absl::StrCat("Invalid AesCmacParams: tag_size ", 119 params.tag_size(), " is too small.")); 120 } 121 if (params.tag_size() > kMaxTagSizeInBytes) { 122 return util::Status(absl::StatusCode::kInvalidArgument, 123 absl::StrCat("Invalid AesCmacParams: tag_size ", 124 params.tag_size(), " is too big.")); 125 } 126 return util::OkStatus(); 127 } 128 129 // Due to https://www.math.uwaterloo.ca/~ajmeneze/publications/tightness.pdf, 130 // we only allow key sizes of 256 bit. 131 const int kKeySizeInBytes = 32; 132 const int kMaxTagSizeInBytes = 16; 133 const int kMinTagSizeInBytes = 10; 134 135 const std::string key_type_ = absl::StrCat( 136 kTypeGoogleapisCom, google::crypto::tink::AesCmacKey().GetTypeName()); 137 }; 138 139 } // namespace tink 140 } // namespace crypto 141 142 #endif // TINK_MAC_AES_CMAC_KEY_MANAGER_H_ 143