blob: 90764098ed6898f295459e9d923ad9f4ffbf42e6 [file] [log] [blame]
// Copyright 2021 Google LLC
//
// 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/internal/hpke_private_key_manager.h"
#include "gtest/gtest.h"
#include "absl/status/status.h"
#include "tink/hybrid/internal/hpke_encrypt.h"
#include "tink/hybrid_encrypt.h"
#include "tink/subtle/hybrid_test_util.h"
#include "tink/util/status.h"
#include "tink/util/statusor.h"
#include "tink/util/test_matchers.h"
#include "tink/util/test_util.h"
#include "proto/hpke.pb.h"
#include "proto/tink.pb.h"
namespace crypto {
namespace tink {
namespace internal {
namespace {
using ::crypto::tink::test::IsOk;
using ::crypto::tink::test::StatusIs;
using ::google::crypto::tink::HpkeAead;
using ::google::crypto::tink::HpkeKdf;
using ::google::crypto::tink::HpkeKem;
using ::google::crypto::tink::HpkeKeyFormat;
using ::google::crypto::tink::HpkeParams;
using ::google::crypto::tink::HpkePrivateKey;
using ::google::crypto::tink::HpkePublicKey;
using ::google::crypto::tink::KeyData;
using ::testing::Eq;
using ::testing::IsEmpty;
using ::testing::Not;
HpkeKeyFormat CreateKeyFormat(HpkeKem kem, HpkeKdf kdf, HpkeAead aead) {
HpkeKeyFormat key_format;
HpkeParams *params = key_format.mutable_params();
params->set_kem(kem);
params->set_kdf(kdf);
params->set_aead(aead);
return key_format;
}
util::StatusOr<HpkePrivateKey> CreateKey(HpkeKem kem, HpkeKdf kdf,
HpkeAead aead) {
return HpkePrivateKeyManager().CreateKey(CreateKeyFormat(kem, kdf, aead));
}
TEST(HpkePrivateKeyManagerTest, BasicAccessors) {
EXPECT_THAT(HpkePrivateKeyManager().get_version(), Eq(0));
EXPECT_THAT(HpkePrivateKeyManager().key_material_type(),
Eq(KeyData::ASYMMETRIC_PRIVATE));
EXPECT_THAT(HpkePrivateKeyManager().get_key_type(),
Eq("type.googleapis.com/google.crypto.tink.HpkePrivateKey"));
}
TEST(HpkePrivateKeyManagerTest, ValidateEmptyKeyFormatFails) {
EXPECT_THAT(HpkePrivateKeyManager().ValidateKeyFormat(HpkeKeyFormat()),
StatusIs(absl::StatusCode::kInvalidArgument));
}
TEST(HpkePrivateKeyManagerTest, ValidateKeyFormatSucceeds) {
EXPECT_THAT(HpkePrivateKeyManager().ValidateKeyFormat(
CreateKeyFormat(HpkeKem::DHKEM_X25519_HKDF_SHA256,
HpkeKdf::HKDF_SHA256, HpkeAead::AES_128_GCM)),
IsOk());
}
TEST(HpkePrivateKeyManagerTest, ValidateKeyFormatWithInvalidKemFails) {
EXPECT_THAT(
HpkePrivateKeyManager().ValidateKeyFormat(CreateKeyFormat(
HpkeKem::KEM_UNKNOWN, HpkeKdf::HKDF_SHA256, HpkeAead::AES_128_GCM)),
StatusIs(absl::StatusCode::kInvalidArgument));
}
TEST(HpkePrivateKeyManagerTest, ValidateKeyFormatWithInvalidKdfFails) {
EXPECT_THAT(HpkePrivateKeyManager().ValidateKeyFormat(
CreateKeyFormat(HpkeKem::DHKEM_X25519_HKDF_SHA256,
HpkeKdf::KDF_UNKNOWN, HpkeAead::AES_128_GCM)),
StatusIs(absl::StatusCode::kInvalidArgument));
}
TEST(HpkePrivateKeyManagerTest, ValidateKeyFormatWithInvalidAeadFails) {
EXPECT_THAT(HpkePrivateKeyManager().ValidateKeyFormat(CreateKeyFormat(
HpkeKem::DHKEM_X25519_HKDF_SHA256, HpkeKdf::HKDF_SHA256,
HpkeAead::AEAD_UNKNOWN)),
StatusIs(absl::StatusCode::kInvalidArgument));
}
TEST(HpkePrivateKeyManagerTest, CreateKeySucceeds) {
HpkeKeyFormat key_format =
CreateKeyFormat(HpkeKem::DHKEM_X25519_HKDF_SHA256, HpkeKdf::HKDF_SHA256,
HpkeAead::AES_128_GCM);
util::StatusOr<HpkePrivateKey> key =
HpkePrivateKeyManager().CreateKey(key_format);
ASSERT_THAT(key, IsOk());
ASSERT_TRUE(key->has_public_key());
ASSERT_TRUE(key->public_key().has_params());
EXPECT_THAT(key->public_key().params().kem(), Eq(key_format.params().kem()));
EXPECT_THAT(key->public_key().params().kdf(), Eq(key_format.params().kdf()));
EXPECT_THAT(key->public_key().params().aead(),
Eq(key_format.params().aead()));
EXPECT_THAT(key->public_key().public_key(), Not(IsEmpty()));
EXPECT_THAT(key->private_key(), Not(IsEmpty()));
}
TEST(HpkePrivateKeyManagerTest, CreateKeyWithInvalidKemFails) {
HpkeKeyFormat key_format = CreateKeyFormat(
HpkeKem::KEM_UNKNOWN, HpkeKdf::HKDF_SHA256, HpkeAead::AES_128_GCM);
ASSERT_THAT(HpkePrivateKeyManager().CreateKey(key_format).status(),
StatusIs(absl::StatusCode::kInvalidArgument));
}
TEST(HpkePrivateKeyManagerTest, ValidateEmptyKeyFails) {
EXPECT_THAT(HpkePrivateKeyManager().ValidateKey(HpkePrivateKey()),
StatusIs(absl::StatusCode::kInvalidArgument));
}
TEST(HpkePrivateKeyManagerTest, ValidateKeySucceeds) {
util::StatusOr<HpkePrivateKey> key =
CreateKey(HpkeKem::DHKEM_X25519_HKDF_SHA256, HpkeKdf::HKDF_SHA256,
HpkeAead::AES_128_GCM);
ASSERT_THAT(key, IsOk());
EXPECT_THAT(HpkePrivateKeyManager().ValidateKey(*key), IsOk());
}
TEST(HpkePrivateKeyManagerTest, ValidateKeyWithWrongVersionFails) {
util::StatusOr<HpkePrivateKey> key =
CreateKey(HpkeKem::DHKEM_X25519_HKDF_SHA256, HpkeKdf::HKDF_SHA256,
HpkeAead::AES_128_GCM);
ASSERT_THAT(key, IsOk());
key->set_version(1);
EXPECT_THAT(HpkePrivateKeyManager().ValidateKey(*key),
StatusIs(absl::StatusCode::kInvalidArgument));
}
TEST(HpkePrivateKeyManagerTest, ValidateKeyWithInvalidKemFails) {
util::StatusOr<HpkePrivateKey> key =
CreateKey(HpkeKem::DHKEM_X25519_HKDF_SHA256, HpkeKdf::HKDF_SHA256,
HpkeAead::AES_128_GCM);
ASSERT_THAT(key, IsOk());
key->mutable_public_key()->mutable_params()->set_kem(HpkeKem::KEM_UNKNOWN);
EXPECT_THAT(HpkePrivateKeyManager().ValidateKey(*key),
StatusIs(absl::StatusCode::kInvalidArgument));
}
TEST(HpkePrivateKeyManagerTest, ValidateKeyWithInvalidKdfFails) {
util::StatusOr<HpkePrivateKey> key =
CreateKey(HpkeKem::DHKEM_X25519_HKDF_SHA256, HpkeKdf::KDF_UNKNOWN,
HpkeAead::AES_128_GCM);
ASSERT_THAT(key, IsOk());
EXPECT_THAT(HpkePrivateKeyManager().ValidateKey(*key),
StatusIs(absl::StatusCode::kInvalidArgument));
}
TEST(HpkePrivateKeyManagerTest, ValidateKeyWithInvalidAeadFails) {
util::StatusOr<HpkePrivateKey> key =
CreateKey(HpkeKem::DHKEM_X25519_HKDF_SHA256, HpkeKdf::HKDF_SHA256,
HpkeAead::AEAD_UNKNOWN);
ASSERT_THAT(key, IsOk());
EXPECT_THAT(HpkePrivateKeyManager().ValidateKey(*key),
StatusIs(absl::StatusCode::kInvalidArgument));
}
TEST(HpkePrivateKeyManagerTest, GetPublicKeySucceeds) {
HpkeKeyFormat key_format =
CreateKeyFormat(HpkeKem::DHKEM_X25519_HKDF_SHA256, HpkeKdf::HKDF_SHA256,
HpkeAead::AES_128_GCM);
util::StatusOr<HpkePrivateKey> key =
HpkePrivateKeyManager().CreateKey(key_format);
ASSERT_THAT(key, IsOk());
util::StatusOr<HpkePublicKey> public_key =
HpkePrivateKeyManager().GetPublicKey(*key);
ASSERT_THAT(public_key, IsOk());
ASSERT_TRUE(key->has_public_key());
ASSERT_TRUE(key->public_key().has_params());
EXPECT_THAT(public_key->params().kem(), Eq(key_format.params().kem()));
EXPECT_THAT(public_key->params().kdf(), Eq(key_format.params().kdf()));
EXPECT_THAT(public_key->params().aead(), Eq(key_format.params().aead()));
ASSERT_THAT(public_key->public_key(), Not(IsEmpty()));
EXPECT_THAT(public_key->public_key(), Eq(key->public_key().public_key()));
}
TEST(HpkePrivateKeyManagerTest, EncryptThenDecryptSucceeds) {
util::StatusOr<HpkePrivateKey> private_key =
CreateKey(HpkeKem::DHKEM_X25519_HKDF_SHA256, HpkeKdf::HKDF_SHA256,
HpkeAead::AES_128_GCM);
ASSERT_THAT(private_key, IsOk());
util::StatusOr<HpkePublicKey> public_key =
HpkePrivateKeyManager().GetPublicKey(*private_key);
ASSERT_THAT(public_key, IsOk());
util::StatusOr<std::unique_ptr<HybridDecrypt>> decrypt =
HpkePrivateKeyManager().GetPrimitive<HybridDecrypt>(*private_key);
ASSERT_THAT(decrypt, IsOk());
util::StatusOr<std::unique_ptr<HybridEncrypt>> encrypt =
HpkeEncrypt::New(*public_key);
ASSERT_THAT(encrypt, IsOk());
ASSERT_THAT(HybridEncryptThenDecrypt(encrypt->get(), decrypt->get(),
"some text", "some aad"),
IsOk());
}
TEST(HpkePrivateKeyManagerTest, EncryptThenDecryptWithDifferentKeysFails) {
util::StatusOr<HpkePrivateKey> private_key =
CreateKey(HpkeKem::DHKEM_X25519_HKDF_SHA256, HpkeKdf::HKDF_SHA256,
HpkeAead::AES_128_GCM);
ASSERT_THAT(private_key, IsOk());
util::StatusOr<HpkePrivateKey> different_private_key =
CreateKey(HpkeKem::DHKEM_X25519_HKDF_SHA256, HpkeKdf::HKDF_SHA256,
HpkeAead::AES_128_GCM);
ASSERT_THAT(different_private_key, IsOk());
util::StatusOr<HpkePublicKey> public_key =
HpkePrivateKeyManager().GetPublicKey(*different_private_key);
ASSERT_THAT(public_key, IsOk());
util::StatusOr<std::unique_ptr<HybridDecrypt>> decrypt =
HpkePrivateKeyManager().GetPrimitive<HybridDecrypt>(*private_key);
ASSERT_THAT(decrypt, IsOk());
util::StatusOr<std::unique_ptr<HybridEncrypt>> encrypt =
HpkeEncrypt::New(*public_key);
ASSERT_THAT(encrypt, IsOk());
ASSERT_THAT(HybridEncryptThenDecrypt(encrypt->get(), decrypt->get(),
"some text", "some aad"),
Not(IsOk()));
}
} // namespace
} // namespace internal
} // namespace tink
} // namespace crypto