| // 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/hybrid/ecies_aead_hkdf_dem_helper.h" |
| |
| #include <utility> |
| |
| #include "absl/memory/memory.h" |
| #include "tink/aead.h" |
| #include "tink/key_manager.h" |
| #include "tink/registry.h" |
| #include "tink/util/errors.h" |
| #include "tink/util/protobuf_helper.h" |
| #include "tink/util/statusor.h" |
| #include "proto/aes_ctr_hmac_aead.pb.h" |
| #include "proto/aes_gcm.pb.h" |
| #include "proto/tink.pb.h" |
| #include "proto/xchacha20_poly1305.pb.h" |
| |
| namespace crypto { |
| namespace tink { |
| |
| using ::google::crypto::tink::AesCtrHmacAeadKey; |
| using ::google::crypto::tink::AesCtrHmacAeadKeyFormat; |
| using ::google::crypto::tink::AesGcmKey; |
| using ::google::crypto::tink::AesGcmKeyFormat; |
| using ::google::crypto::tink::KeyTemplate; |
| using ::google::crypto::tink::XChaCha20Poly1305Key; |
| using ::google::crypto::tink::XChaCha20Poly1305KeyFormat; |
| |
| util::StatusOr<EciesAeadHkdfDemHelper::DemKeyParams> |
| EciesAeadHkdfDemHelper::GetKeyParams(const KeyTemplate& key_template) { |
| const std::string& type_url = key_template.type_url(); |
| if (type_url == "type.googleapis.com/google.crypto.tink.AesGcmKey") { |
| AesGcmKeyFormat key_format; |
| if (!key_format.ParseFromString(key_template.value())) { |
| return util::Status(util::error::INVALID_ARGUMENT, |
| "Invalid AesGcmKeyFormat in DEM key template"); |
| } |
| return {{AES_GCM_KEY, key_format.key_size()}}; |
| } |
| if (type_url == "type.googleapis.com/google.crypto.tink.AesCtrHmacAeadKey") { |
| AesCtrHmacAeadKeyFormat key_format; |
| if (!key_format.ParseFromString(key_template.value())) { |
| return util::Status(util::error::INVALID_ARGUMENT, |
| "Invalid AesCtrHmacKeyFormat in DEM key template"); |
| } |
| uint32_t dem_key_size = key_format.aes_ctr_key_format().key_size() + |
| key_format.hmac_key_format().key_size(); |
| return {{AES_CTR_HMAC_AEAD_KEY, dem_key_size, |
| key_format.aes_ctr_key_format().key_size()}}; |
| } |
| if (type_url == |
| "type.googleapis.com/google.crypto.tink.XChaCha20Poly1305Key") { |
| if (!XChaCha20Poly1305KeyFormat().ParseFromString(key_template.value())) { |
| return util::Status(util::error::INVALID_ARGUMENT, |
| "Invalid XChaCha20KeyFormat in DEM key template"); |
| } |
| return {{XCHACHA20_POLY1305_KEY, 32}}; |
| } |
| return ToStatusF(util::error::INVALID_ARGUMENT, |
| "Unsupported DEM key type '%s'.", type_url); |
| } |
| |
| // static |
| util::StatusOr<std::unique_ptr<const EciesAeadHkdfDemHelper>> |
| EciesAeadHkdfDemHelper::New(const KeyTemplate& dem_key_template) { |
| auto key_params_or = GetKeyParams(dem_key_template); |
| if (!key_params_or.ok()) return key_params_or.status(); |
| DemKeyParams key_params = key_params_or.ValueOrDie(); |
| const std::string& dem_type_url = dem_key_template.type_url(); |
| auto key_manager_or = Registry::get_key_manager<Aead>(dem_type_url); |
| if (!key_manager_or.ok()) { |
| return ToStatusF(util::error::FAILED_PRECONDITION, |
| "No manager for DEM key type '%s' found in the registry.", |
| dem_type_url); |
| } |
| const KeyManager<Aead>* key_manager = key_manager_or.ValueOrDie(); |
| return {absl::WrapUnique( |
| new EciesAeadHkdfDemHelper(key_manager, dem_key_template, key_params))}; |
| } |
| |
| util::StatusOr<std::unique_ptr<Aead>> EciesAeadHkdfDemHelper::GetAead( |
| const util::SecretData& symmetric_key_value) const { |
| if (symmetric_key_value.size() != key_params_.key_size_in_bytes) { |
| return util::Status(util::error::INTERNAL, |
| "Wrong length of symmetric key."); |
| } |
| auto key_or = key_manager_->get_key_factory().NewKey(key_template_.value()); |
| if (!key_or.ok()) return key_or.status(); |
| auto key = std::move(key_or).ValueOrDie(); |
| if (!ReplaceKeyBytes(symmetric_key_value, key.get())) { |
| return util::Status(util::error::INTERNAL, "Generation of DEM-key failed."); |
| } |
| auto aead_or = key_manager_->GetPrimitive(*key); |
| ZeroKeyBytes(key.get()); |
| return aead_or; |
| } |
| |
| bool EciesAeadHkdfDemHelper::ReplaceKeyBytes( |
| const util::SecretData& key_bytes, |
| portable_proto::MessageLite* proto) const { |
| switch (key_params_.key_type) { |
| case AES_GCM_KEY: { |
| AesGcmKey* key = static_cast<AesGcmKey*>(proto); |
| key->set_key_value(std::string(util::SecretDataAsStringView(key_bytes))); |
| return true; |
| } |
| case AES_CTR_HMAC_AEAD_KEY: { |
| AesCtrHmacAeadKey* key = static_cast<AesCtrHmacAeadKey*>(proto); |
| auto aes_ctr_key = key->mutable_aes_ctr_key(); |
| aes_ctr_key->set_key_value( |
| std::string(util::SecretDataAsStringView(key_bytes).substr( |
| 0, key_params_.aes_ctr_key_size_in_bytes))); |
| auto hmac_key = key->mutable_hmac_key(); |
| hmac_key->set_key_value( |
| std::string(util::SecretDataAsStringView(key_bytes).substr( |
| key_params_.aes_ctr_key_size_in_bytes))); |
| return true; |
| } |
| case XCHACHA20_POLY1305_KEY: { |
| XChaCha20Poly1305Key* key = static_cast<XChaCha20Poly1305Key*>(proto); |
| key->set_key_value(std::string(util::SecretDataAsStringView(key_bytes))); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| void EciesAeadHkdfDemHelper::ZeroKeyBytes( |
| portable_proto::MessageLite* proto) const { |
| switch (key_params_.key_type) { |
| case AES_GCM_KEY: { |
| AesGcmKey* key = static_cast<AesGcmKey*>(proto); |
| std::unique_ptr<std::string> key_value = |
| absl::WrapUnique(key->release_key_value()); |
| util::SafeZeroString(key_value.get()); |
| break; |
| } |
| case AES_CTR_HMAC_AEAD_KEY: { |
| AesCtrHmacAeadKey* key = static_cast<AesCtrHmacAeadKey*>(proto); |
| std::unique_ptr<std::string> aes_ctr_key_value = |
| absl::WrapUnique(key->mutable_aes_ctr_key()->release_key_value()); |
| util::SafeZeroString(aes_ctr_key_value.get()); |
| std::unique_ptr<std::string> hmac_key_value = |
| absl::WrapUnique(key->mutable_hmac_key()->release_key_value()); |
| util::SafeZeroString(hmac_key_value.get()); |
| break; |
| } |
| case XCHACHA20_POLY1305_KEY: { |
| XChaCha20Poly1305Key* key = static_cast<XChaCha20Poly1305Key*>(proto); |
| std::unique_ptr<std::string> key_value = |
| absl::WrapUnique(key->release_key_value()); |
| util::SafeZeroString(key_value.get()); |
| break; |
| } |
| } |
| } |
| |
| } // namespace tink |
| } // namespace crypto |