| // Copyright 2017 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/ecies_aead_hkdf_hybrid_encrypt.h" |
| |
| #include <string> |
| #include <utility> |
| |
| #include "gtest/gtest.h" |
| #include "absl/memory/memory.h" |
| #include "tink/aead/aes_gcm_key_manager.h" |
| #include "tink/hybrid_encrypt.h" |
| #include "tink/internal/ec_util.h" |
| #include "tink/registry.h" |
| #include "tink/util/enums.h" |
| #include "tink/util/statusor.h" |
| #include "tink/util/test_util.h" |
| #include "proto/common.pb.h" |
| #include "proto/ecies_aead_hkdf.pb.h" |
| |
| using google::crypto::tink::EciesAeadHkdfPublicKey; |
| using google::crypto::tink::EcPointFormat; |
| using google::crypto::tink::EllipticCurveType; |
| using google::crypto::tink::HashType; |
| |
| |
| namespace crypto { |
| namespace tink { |
| namespace { |
| |
| class EciesAeadHkdfHybridEncryptTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| } |
| void TearDown() override { |
| } |
| }; |
| |
| TEST_F(EciesAeadHkdfHybridEncryptTest, testInvalidKeys) { |
| { // No fields set. |
| EciesAeadHkdfPublicKey recipient_key; |
| auto result = EciesAeadHkdfHybridEncrypt::New(recipient_key); |
| EXPECT_FALSE(result.ok()); |
| EXPECT_EQ(absl::StatusCode::kInvalidArgument, result.status().code()); |
| EXPECT_PRED_FORMAT2(testing::IsSubstring, "missing required fields", |
| std::string(result.status().message())); |
| } |
| |
| { // Only some fields set. |
| EciesAeadHkdfPublicKey recipient_key; |
| recipient_key.set_version(0); |
| recipient_key.set_x("some x bytes"); |
| recipient_key.set_y("some y bytes"); |
| auto result(EciesAeadHkdfHybridEncrypt::New(recipient_key)); |
| EXPECT_FALSE(result.ok()); |
| EXPECT_EQ(absl::StatusCode::kInvalidArgument, result.status().code()); |
| EXPECT_PRED_FORMAT2(testing::IsSubstring, "missing required fields", |
| std::string(result.status().message())); |
| } |
| |
| { // Wrong EC type. |
| EciesAeadHkdfPublicKey recipient_key; |
| recipient_key.set_version(0); |
| recipient_key.set_x("some x bytes"); |
| recipient_key.set_y("some y bytes"); |
| recipient_key.mutable_params(); |
| auto result(EciesAeadHkdfHybridEncrypt::New(recipient_key)); |
| EXPECT_FALSE(result.ok()); |
| EXPECT_EQ(absl::StatusCode::kUnimplemented, result.status().code()); |
| EXPECT_PRED_FORMAT2(testing::IsSubstring, "Unsupported elliptic curve", |
| std::string(result.status().message())); |
| } |
| |
| { // Unsupported DEM key type. |
| EllipticCurveType curve = EllipticCurveType::NIST_P256; |
| auto test_key = |
| internal::NewEcKey(util::Enums::ProtoToSubtle(curve)).value(); |
| EciesAeadHkdfPublicKey recipient_key; |
| recipient_key.set_version(0); |
| recipient_key.set_x(test_key.pub_x); |
| recipient_key.set_y(test_key.pub_y); |
| auto params = recipient_key.mutable_params(); |
| params->mutable_kem_params()->set_curve_type(curve); |
| params->mutable_kem_params()->set_hkdf_hash_type(HashType::SHA256); |
| auto aead_dem = params->mutable_dem_params()->mutable_aead_dem(); |
| aead_dem->set_type_url("some.type.url/that.is.not.supported"); |
| auto result(EciesAeadHkdfHybridEncrypt::New(recipient_key)); |
| EXPECT_FALSE(result.ok()); |
| EXPECT_EQ(absl::StatusCode::kInvalidArgument, result.status().code()); |
| EXPECT_PRED_FORMAT2(testing::IsSubstring, "Unsupported DEM", |
| std::string(result.status().message())); |
| } |
| } |
| |
| TEST_F(EciesAeadHkdfHybridEncryptTest, testBasic) { |
| // Prepare an ECIES key. |
| auto ecies_key = test::GetEciesAesGcmHkdfTestKey( |
| EllipticCurveType::NIST_P256, |
| EcPointFormat::UNCOMPRESSED, |
| HashType::SHA256, |
| 32); |
| |
| // Try to get a HybridEncrypt primitive without DEM key manager. |
| auto bad_result(EciesAeadHkdfHybridEncrypt::New(ecies_key.public_key())); |
| EXPECT_FALSE(bad_result.ok()); |
| EXPECT_EQ(absl::StatusCode::kFailedPrecondition, bad_result.status().code()); |
| EXPECT_PRED_FORMAT2(testing::IsSubstring, "No manager for DEM", |
| std::string(bad_result.status().message())); |
| |
| // Register DEM key manager. |
| ASSERT_TRUE(Registry::RegisterKeyTypeManager( |
| absl::make_unique<AesGcmKeyManager>(), true) |
| .ok()); |
| std::string dem_key_type = AesGcmKeyManager().get_key_type(); |
| |
| // Generate and test many keys with various parameters. |
| std::string plaintext = "some plaintext"; |
| std::string context_info = "some context info"; |
| for (auto curve : {EllipticCurveType::NIST_P256, EllipticCurveType::NIST_P384, |
| EllipticCurveType::NIST_P521}) { |
| for (auto ec_point_format : |
| {EcPointFormat::UNCOMPRESSED, EcPointFormat::COMPRESSED}) { |
| for (auto hash_type : {HashType::SHA256, HashType::SHA512}) { |
| for (uint32_t aes_gcm_key_size : {16, 32}) { |
| ecies_key = test::GetEciesAesGcmHkdfTestKey( |
| curve, ec_point_format, hash_type, aes_gcm_key_size); |
| auto result(EciesAeadHkdfHybridEncrypt::New(ecies_key.public_key())); |
| ASSERT_TRUE(result.ok()) << result.status() |
| << ecies_key.SerializeAsString(); |
| std::unique_ptr<HybridEncrypt> hybrid_encrypt( |
| std::move(result.value())); |
| |
| // Use the primitive. |
| auto encrypt_result = |
| hybrid_encrypt->Encrypt(plaintext, context_info); |
| EXPECT_TRUE(encrypt_result.ok()) << encrypt_result.status(); |
| } |
| } |
| } |
| } |
| } |
| |
| } // namespace |
| } // namespace tink |
| } // namespace crypto |