blob: d8154ee7f90b6d99a07bcca6b8eaae7089f1257b [file] [log] [blame]
// 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_private_key_manager.h"
#include "tink/hybrid_decrypt.h"
#include "tink/registry.h"
#include "tink/aead/aead_key_templates.h"
#include "tink/aead/aes_ctr_hmac_aead_key_manager.h"
#include "tink/aead/aes_gcm_key_manager.h"
#include "tink/hybrid/ecies_aead_hkdf_public_key_manager.h"
#include "tink/hybrid/hybrid_key_templates.h"
#include "tink/util/status.h"
#include "tink/util/statusor.h"
#include "tink/util/test_util.h"
#include "gtest/gtest.h"
#include "proto/aes_eax.pb.h"
#include "proto/common.pb.h"
#include "proto/ecies_aead_hkdf.pb.h"
#include "proto/tink.pb.h"
namespace crypto {
namespace tink {
using google::crypto::tink::AesEaxKey;
using google::crypto::tink::EciesAeadHkdfKeyFormat;
using google::crypto::tink::EciesAeadHkdfPrivateKey;
using google::crypto::tink::EcPointFormat;
using google::crypto::tink::EllipticCurveType;
using google::crypto::tink::HashType;
using google::crypto::tink::KeyData;
using google::crypto::tink::KeyTemplate;
namespace {
class EciesAeadHkdfPrivateKeyManagerTest : public ::testing::Test {
protected:
static void SetUpTestCase() {
ASSERT_TRUE(Registry::RegisterKeyManager(
absl::make_unique<AesGcmKeyManager>(), true)
.ok());
ASSERT_TRUE(Registry::RegisterKeyManager(
absl::make_unique<AesCtrHmacAeadKeyManager>(), true)
.ok());
}
std::string key_type_prefix = "type.googleapis.com/";
std::string ecies_private_key_type =
"type.googleapis.com/google.crypto.tink.EciesAeadHkdfPrivateKey";
};
// Checks whether given key is compatible with the given format.
void CheckNewKey(const EciesAeadHkdfPrivateKey& ecies_key,
const EciesAeadHkdfKeyFormat& key_format) {
EciesAeadHkdfPrivateKeyManager key_manager;
EXPECT_EQ(0, ecies_key.version());
EXPECT_TRUE(ecies_key.has_public_key());
EXPECT_GT(ecies_key.key_value().length(), 0);
EXPECT_EQ(0, ecies_key.public_key().version());
EXPECT_GT(ecies_key.public_key().x().length(), 0);
EXPECT_GT(ecies_key.public_key().y().length(), 0);
EXPECT_EQ(ecies_key.public_key().params().SerializeAsString(),
key_format.params().SerializeAsString());
auto primitive_result = key_manager.GetPrimitive(ecies_key);
EXPECT_TRUE(primitive_result.ok()) << primitive_result.status();
}
TEST_F(EciesAeadHkdfPrivateKeyManagerTest, testBasic) {
EciesAeadHkdfPrivateKeyManager key_manager;
EXPECT_EQ(0, key_manager.get_version());
EXPECT_EQ("type.googleapis.com/google.crypto.tink.EciesAeadHkdfPrivateKey",
key_manager.get_key_type());
EXPECT_TRUE(key_manager.DoesSupport(key_manager.get_key_type()));
}
TEST_F(EciesAeadHkdfPrivateKeyManagerTest, testKeyDataErrors) {
EciesAeadHkdfPrivateKeyManager 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(ecies_private_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;
EciesAeadHkdfPrivateKey key;
key.set_version(1);
key_data.set_type_url(ecies_private_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());
}
}
TEST_F(EciesAeadHkdfPrivateKeyManagerTest, testKeyMessageErrors) {
EciesAeadHkdfPrivateKeyManager key_manager;
{ // Bad protobuffer.
AesEaxKey key;
auto result = key_manager.GetPrimitive(key);
EXPECT_FALSE(result.ok());
EXPECT_EQ(util::error::INVALID_ARGUMENT, result.status().error_code());
EXPECT_PRED_FORMAT2(testing::IsSubstring, "AesEaxKey",
result.status().error_message());
EXPECT_PRED_FORMAT2(testing::IsSubstring, "not supported",
result.status().error_message());
}
}
TEST_F(EciesAeadHkdfPrivateKeyManagerTest, testPrimitives) {
std::string plaintext = "some plaintext";
std::string context_info = "some context info";
EciesAeadHkdfPublicKeyManager public_key_manager;
EciesAeadHkdfPrivateKeyManager private_key_manager;
EciesAeadHkdfPrivateKey key = test::GetEciesAesGcmHkdfTestKey(
EllipticCurveType::NIST_P256, EcPointFormat::UNCOMPRESSED,
HashType::SHA256, 32);
auto hybrid_encrypt = std::move(public_key_manager.GetPrimitive(
key.public_key()).ValueOrDie());
std::string ciphertext =
hybrid_encrypt->Encrypt(plaintext, context_info).ValueOrDie();
{ // Using Key proto.
auto result = private_key_manager.GetPrimitive(key);
EXPECT_TRUE(result.ok()) << result.status();
auto hybrid_decrypt = std::move(result.ValueOrDie());
auto decrypt_result = hybrid_decrypt->Decrypt(ciphertext, context_info);
EXPECT_TRUE(decrypt_result.ok()) << decrypt_result.status();
}
{ // Using KeyData proto.
KeyData key_data;
key_data.set_type_url(ecies_private_key_type);
key_data.set_value(key.SerializeAsString());
auto result = private_key_manager.GetPrimitive(key_data);
EXPECT_TRUE(result.ok()) << result.status();
auto hybrid_decrypt = std::move(result.ValueOrDie());
auto decrypt_result = hybrid_decrypt->Decrypt(ciphertext, context_info);
EXPECT_TRUE(decrypt_result.ok()) << decrypt_result.status();
}
}
TEST_F(EciesAeadHkdfPrivateKeyManagerTest, testNewKeyCreation) {
EciesAeadHkdfPrivateKeyManager key_manager;
const KeyFactory& key_factory = key_manager.get_key_factory();
{ // Via NewKey(format_proto).
EciesAeadHkdfKeyFormat key_format;
ASSERT_TRUE(key_format.ParseFromString(
HybridKeyTemplates::EciesP256HkdfHmacSha256Aes128Gcm().value()));
auto result = key_factory.NewKey(key_format);
EXPECT_TRUE(result.ok()) << result.status();
auto key = std::move(result.ValueOrDie());
ASSERT_EQ(ecies_private_key_type, key_type_prefix + key->GetTypeName());
std::unique_ptr<EciesAeadHkdfPrivateKey> ecies_key(
reinterpret_cast<EciesAeadHkdfPrivateKey*>(key.release()));
CheckNewKey(*ecies_key, key_format);
}
{ // Via NewKey(serialized_format_proto).
EciesAeadHkdfKeyFormat key_format;
ASSERT_TRUE(key_format.ParseFromString(
HybridKeyTemplates::EciesP256HkdfHmacSha256Aes128CtrHmacSha256()
.value()));
auto result = key_factory.NewKey(key_format.SerializeAsString());
EXPECT_TRUE(result.ok()) << result.status();
auto key = std::move(result.ValueOrDie());
ASSERT_EQ(ecies_private_key_type, key_type_prefix + key->GetTypeName());
std::unique_ptr<EciesAeadHkdfPrivateKey> ecies_key(
reinterpret_cast<EciesAeadHkdfPrivateKey*>(key.release()));
CheckNewKey(*ecies_key, key_format);
}
{ // Via NewKeyData(serialized_format_proto).
EciesAeadHkdfKeyFormat key_format;
ASSERT_TRUE(key_format.ParseFromString(
HybridKeyTemplates::EciesP256HkdfHmacSha256Aes128CtrHmacSha256()
.value()));
auto result = key_factory.NewKeyData(key_format.SerializeAsString());
EXPECT_TRUE(result.ok()) << result.status();
auto key_data = std::move(result.ValueOrDie());
EXPECT_EQ(ecies_private_key_type, key_data->type_url());
EXPECT_EQ(KeyData::ASYMMETRIC_PRIVATE, key_data->key_material_type());
EciesAeadHkdfPrivateKey ecies_key;
ASSERT_TRUE(ecies_key.ParseFromString(key_data->value()));
CheckNewKey(ecies_key, key_format);
}
}
TEST_F(EciesAeadHkdfPrivateKeyManagerTest, testPublicKeyExtraction) {
EciesAeadHkdfPrivateKeyManager key_manager;
auto private_key_factory = dynamic_cast<const PrivateKeyFactory*>(
&(key_manager.get_key_factory()));
ASSERT_NE(private_key_factory, nullptr);
auto new_key_result = private_key_factory->NewKey(
HybridKeyTemplates::EciesP256HkdfHmacSha256Aes128CtrHmacSha256().value());
std::unique_ptr<EciesAeadHkdfPrivateKey> new_key(
reinterpret_cast<EciesAeadHkdfPrivateKey*>(
new_key_result.ValueOrDie().release()));
auto public_key_data_result = private_key_factory->GetPublicKeyData(
new_key->SerializeAsString());
EXPECT_TRUE(public_key_data_result.ok()) << public_key_data_result.status();
auto public_key_data = std::move(public_key_data_result.ValueOrDie());
EXPECT_EQ(EciesAeadHkdfPublicKeyManager::static_key_type(),
public_key_data->type_url());
EXPECT_EQ(KeyData::ASYMMETRIC_PUBLIC, public_key_data->key_material_type());
EXPECT_EQ(new_key->public_key().SerializeAsString(),
public_key_data->value());
}
TEST_F(EciesAeadHkdfPrivateKeyManagerTest, testPublicKeyExtractionErrors) {
EciesAeadHkdfPrivateKeyManager key_manager;
auto private_key_factory = dynamic_cast<const PrivateKeyFactory*>(
&(key_manager.get_key_factory()));
ASSERT_NE(private_key_factory, nullptr);
AesCtrHmacAeadKeyManager aead_key_manager;
auto aead_private_key_factory = dynamic_cast<const PrivateKeyFactory*>(
&(aead_key_manager.get_key_factory()));
ASSERT_EQ(nullptr, aead_private_key_factory);
auto aead_key_result = aead_key_manager.get_key_factory().NewKey(
AeadKeyTemplates::Aes128CtrHmacSha256().value());
ASSERT_TRUE(aead_key_result.ok()) << aead_key_result.status();
auto aead_key = std::move(aead_key_result.ValueOrDie());
auto public_key_data_result = private_key_factory->GetPublicKeyData(
aead_key->SerializeAsString());
EXPECT_FALSE(public_key_data_result.ok());
EXPECT_EQ(util::error::INVALID_ARGUMENT,
public_key_data_result.status().error_code());
}
TEST_F(EciesAeadHkdfPrivateKeyManagerTest, testNewKeyErrors) {
EciesAeadHkdfPrivateKeyManager key_manager;
const KeyFactory& key_factory = key_manager.get_key_factory();
// Empty key format.
EciesAeadHkdfKeyFormat 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, "Missing params",
result.status().error_message());
}
// Missing kem_params.
auto params = key_format.mutable_params();
{
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, "Missing kem_params",
result.status().error_message());
}
// Invalid kem_params.
auto kem_params = params->mutable_kem_params();
{
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 kem_params",
result.status().error_message());
}
// Missing dem_params.
kem_params->set_curve_type(EllipticCurveType::NIST_P256);
kem_params->set_hkdf_hash_type(HashType::SHA256);
{
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, "Missing dem_params",
result.status().error_message());
}
// Invalid dem_params.
auto dem_params = params->mutable_dem_params();
{
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 dem_params",
result.status().error_message());
}
// Invalid EC point format.
dem_params->mutable_aead_dem()->set_type_url("some type_url");
{
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, "Unknown EC point format",
result.status().error_message());
}
}
} // namespace
} // namespace tink
} // namespace crypto