1 // Copyright 2021 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
17 #include "tink/experimental/pqcrypto/kem/subtle/cecpq2_aead_hkdf_hybrid_encrypt.h"
18
19 #include <memory>
20 #include <string>
21 #include <utility>
22
23 #include "gtest/gtest.h"
24 #include "absl/memory/memory.h"
25 #include "absl/status/status.h"
26 #include "openssl/curve25519.h"
27 #include "openssl/hrss.h"
28 #include "tink/aead/aes_gcm_key_manager.h"
29 #include "tink/experimental/pqcrypto/kem/subtle/cecpq2_subtle_boringssl_util.h"
30 #include "tink/experimental/pqcrypto/kem/util/test_util.h"
31 #include "tink/hybrid_encrypt.h"
32 #include "tink/registry.h"
33 #include "tink/subtle/random.h"
34 #include "tink/subtle/subtle_util.h"
35 #include "tink/util/enums.h"
36 #include "tink/util/statusor.h"
37 #include "tink/util/test_matchers.h"
38 #include "tink/util/test_util.h"
39
40 using ::crypto::tink::test::IsOk;
41 using ::crypto::tink::test::StatusIs;
42 using ::testing::HasSubstr;
43
44 namespace crypto {
45 namespace tink {
46 namespace {
47
CreateValidKey()48 google::crypto::tink::Cecpq2AeadHkdfPublicKey CreateValidKey() {
49 auto cecp2_key_pair = crypto::tink::pqc::GenerateCecpq2Keypair(
50 subtle::EllipticCurveType::CURVE25519)
51 .value();
52 google::crypto::tink::Cecpq2AeadHkdfPublicKey sender_key;
53 sender_key.set_hrss_public_key_marshalled(
54 cecp2_key_pair.hrss_key_pair.hrss_public_key_marshaled);
55 sender_key.set_x25519_public_key_x(cecp2_key_pair.x25519_key_pair.pub_x);
56 sender_key.mutable_params()->mutable_kem_params()->set_curve_type(
57 google::crypto::tink::EllipticCurveType::CURVE25519);
58 sender_key.mutable_params()->mutable_kem_params()->set_hkdf_hash_type(
59 google::crypto::tink::HashType::SHA256);
60 sender_key.mutable_params()
61 ->mutable_dem_params()
62 ->mutable_aead_dem()
63 ->set_type_url("type.googleapis.com/google.crypto.tink.AesGcmKey");
64 return sender_key;
65 }
66
TEST(Cecpq2AeadHkdfHybridEncryptTest,ValidKey)67 TEST(Cecpq2AeadHkdfHybridEncryptTest, ValidKey) {
68 google::crypto::tink::Cecpq2AeadHkdfPublicKey sender_key = CreateValidKey();
69 auto result = Cecpq2AeadHkdfHybridEncrypt::New(sender_key);
70 EXPECT_THAT(result, IsOk());
71 }
72
TEST(Cecpq2AeadHkdfHybridEncryptTest,InvalidKeyNoFieldSet)73 TEST(Cecpq2AeadHkdfHybridEncryptTest, InvalidKeyNoFieldSet) {
74 auto result = Cecpq2AeadHkdfHybridEncrypt::New(
75 google::crypto::tink::Cecpq2AeadHkdfPublicKey());
76 EXPECT_THAT(result.status(),
77 StatusIs(absl::StatusCode::kInvalidArgument,
78 HasSubstr("missing KEM required fields")));
79 }
80
TEST(Cecpq2AeadHkdfHybridEncryptTest,InvalidKeySomeFieldsSet)81 TEST(Cecpq2AeadHkdfHybridEncryptTest, InvalidKeySomeFieldsSet) {
82 google::crypto::tink::Cecpq2AeadHkdfPublicKey sender_key = CreateValidKey();
83 sender_key.set_x25519_public_key_x("");
84 auto result(Cecpq2AeadHkdfHybridEncrypt::New(sender_key));
85 EXPECT_THAT(result.status(),
86 StatusIs(absl::StatusCode::kInvalidArgument,
87 HasSubstr("missing KEM required fields")));
88 }
89
TEST(Cecpq2AeadHkdfHybridEncryptTest,InvalidKeyUnsupportedEcType)90 TEST(Cecpq2AeadHkdfHybridEncryptTest, InvalidKeyUnsupportedEcType) {
91 google::crypto::tink::Cecpq2AeadHkdfPublicKey sender_key = CreateValidKey();
92 sender_key.mutable_params()->mutable_kem_params()->set_curve_type(
93 google::crypto::tink::EllipticCurveType::NIST_P256);
94 auto result = Cecpq2AeadHkdfHybridEncrypt::New(sender_key);
95 EXPECT_THAT(result.status(),
96 StatusIs(absl::StatusCode::kUnimplemented,
97 HasSubstr("Unsupported elliptic curve")));
98 }
99
TEST(Cecpq2AeadHkdfHybridEncryptTest,InvalidKeyUnsupportedDemKeyType)100 TEST(Cecpq2AeadHkdfHybridEncryptTest, InvalidKeyUnsupportedDemKeyType) {
101 auto status_or_cecpq2_key =
102 pqc::GenerateCecpq2Keypair(subtle::EllipticCurveType::CURVE25519);
103 ASSERT_THAT(status_or_cecpq2_key, IsOk());
104 auto cecpq2_key_pair = std::move(status_or_cecpq2_key).value();
105
106 google::crypto::tink::Cecpq2AeadHkdfPublicKey sender_key = CreateValidKey();
107 sender_key.mutable_params()
108 ->mutable_dem_params()
109 ->mutable_aead_dem()
110 ->set_type_url("some.type.url/that.is.not.supported");
111 auto result(Cecpq2AeadHkdfHybridEncrypt::New(sender_key));
112 EXPECT_THAT(result.status(), StatusIs(absl::StatusCode::kInvalidArgument,
113 HasSubstr("Unsupported DEM key type")));
114 }
115
TEST(Cecpq2AeadHkdfHybridEncryptTest,Basic)116 TEST(Cecpq2AeadHkdfHybridEncryptTest, Basic) {
117 // Prepare an Cecpq2 key
118 auto cecpq2_key = CreateValidKey();
119
120 // Register DEM key manager
121 ASSERT_THAT(Registry::RegisterKeyTypeManager(
122 absl::make_unique<AesGcmKeyManager>(), true),
123 IsOk());
124 std::string dem_key_type = AesGcmKeyManager().get_key_type();
125
126 // Generate and test many keys with various parameters
127 std::string plaintext = "some plaintext";
128 std::string context_info = "some context info";
129 for (auto curve : {google::crypto::tink::EllipticCurveType::CURVE25519}) {
130 for (auto ec_point_format :
131 {google::crypto::tink::EcPointFormat::COMPRESSED}) {
132 for (auto hash_type : {google::crypto::tink::HashType::SHA256,
133 google::crypto::tink::HashType::SHA512}) {
134 for (uint32_t aes_gcm_key_size : {16, 32}) {
135 SCOPED_TRACE(absl::StrCat(curve, ":", ec_point_format, ":", hash_type,
136 ":", aes_gcm_key_size));
137 cecpq2_key.mutable_params()->mutable_kem_params()->set_curve_type(
138 curve);
139 cecpq2_key.mutable_params()
140 ->mutable_kem_params()
141 ->set_ec_point_format(ec_point_format);
142 cecpq2_key.mutable_params()->mutable_kem_params()->set_hkdf_hash_type(
143 hash_type);
144
145 google::crypto::tink::AesGcmKeyFormat format;
146 format.set_key_size(aes_gcm_key_size);
147 cecpq2_key.mutable_params()
148 ->mutable_dem_params()
149 ->mutable_aead_dem()
150 ->set_value(format.SerializeAsString());
151 cecpq2_key.mutable_params()
152 ->mutable_dem_params()
153 ->mutable_aead_dem()
154 ->set_type_url(
155 "type.googleapis.com/google.crypto.tink.AesGcmKey");
156 auto key_or = Cecpq2AeadHkdfHybridEncrypt::New(cecpq2_key);
157 ASSERT_THAT(key_or, IsOk());
158 std::unique_ptr<HybridEncrypt> hybrid_encrypt(
159 std::move(key_or.value()));
160 // Use the primitive
161 auto encrypt_result =
162 hybrid_encrypt->Encrypt(plaintext, context_info);
163 EXPECT_THAT(encrypt_result, IsOk());
164 }
165 }
166 }
167 }
168 }
169
170 } // namespace
171 } // namespace tink
172 } // namespace crypto
173