1 // Copyright 2017 Google Inc.
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/subtle/ecies_hkdf_sender_kem_boringssl.h"
18
19 #include <iostream>
20 #include <ostream>
21 #include <string>
22 #include <utility>
23 #include <vector>
24
25 #include "gtest/gtest.h"
26 #include "absl/status/status.h"
27 #include "absl/strings/escaping.h"
28 #include "tink/config/tink_fips.h"
29 #include "tink/internal/ec_util.h"
30 #include "tink/subtle/common_enums.h"
31 #include "tink/subtle/ecies_hkdf_recipient_kem_boringssl.h"
32 #include "tink/util/secret_data.h"
33 #include "tink/util/status.h"
34 #include "tink/util/statusor.h"
35 #include "tink/util/test_matchers.h"
36
37 // TODO(quannguyen): Add extensive tests.
38 // It's important to test compatibility with Java.
39 namespace crypto {
40 namespace tink {
41 namespace subtle {
42 namespace {
43
44 using ::crypto::tink::test::StatusIs;
45
46 class EciesHkdfSenderKemBoringSslTest : public ::testing::Test {};
47
48 struct TestVector {
49 EllipticCurveType curve;
50 HashType hash;
51 EcPointFormat point_format;
52 std::string salt_hex;
53 std::string info_hex;
54 int out_len;
55 };
56
57 static const std::vector<TestVector> test_vector(
58 {{
59 EllipticCurveType::NIST_P256,
60 HashType::SHA256,
61 EcPointFormat::UNCOMPRESSED,
62 "0b0b0b0b",
63 "0b0b0b0b0b0b0b0b",
64 32,
65 },
66 {
67 EllipticCurveType::NIST_P256,
68 HashType::SHA256,
69 EcPointFormat::COMPRESSED,
70 "0b0b0b0b",
71 "0b0b0b0b0b0b0b0b",
72 32,
73 },
74 {
75 EllipticCurveType::CURVE25519,
76 HashType::SHA256,
77 EcPointFormat::COMPRESSED,
78 "0b0b0b0b",
79 "0b0b0b0b0b0b0b0b",
80 32,
81 }});
82
TEST_F(EciesHkdfSenderKemBoringSslTest,TestSenderRecipientBasic)83 TEST_F(EciesHkdfSenderKemBoringSslTest, TestSenderRecipientBasic) {
84 if (IsFipsModeEnabled()) {
85 GTEST_SKIP() << "Not supported in FIPS-only mode";
86 }
87 for (const TestVector& test : test_vector) {
88 auto status_or_test_key = internal::NewEcKey(test.curve);
89 ASSERT_TRUE(status_or_test_key.ok());
90 auto test_key = status_or_test_key.value();
91 auto status_or_sender_kem = EciesHkdfSenderKemBoringSsl::New(
92 test.curve, test_key.pub_x, test_key.pub_y);
93 ASSERT_TRUE(status_or_sender_kem.ok());
94 auto sender_kem = std::move(status_or_sender_kem.value());
95 auto status_or_kem_key = sender_kem->GenerateKey(
96 test.hash, absl::HexStringToBytes(test.salt_hex),
97 absl::HexStringToBytes(test.info_hex), test.out_len, test.point_format);
98 ASSERT_TRUE(status_or_kem_key.ok());
99 auto kem_key = std::move(status_or_kem_key.value());
100 auto ecies_recipient(
101 std::move(EciesHkdfRecipientKemBoringSsl::New(test.curve, test_key.priv)
102 .value()));
103 auto status_or_shared_secret = ecies_recipient->GenerateKey(
104 kem_key->get_kem_bytes(), test.hash,
105 absl::HexStringToBytes(test.salt_hex),
106 absl::HexStringToBytes(test.info_hex),
107 test.out_len, test.point_format);
108 std::cout << absl::BytesToHexString(kem_key->get_kem_bytes()) << std::endl;
109 EXPECT_EQ(absl::BytesToHexString(
110 util::SecretDataAsStringView(kem_key->get_symmetric_key())),
111 absl::BytesToHexString(util::SecretDataAsStringView(
112 status_or_shared_secret.value())));
113 }
114 }
115
TEST_F(EciesHkdfSenderKemBoringSslTest,TestNewUnknownCurve)116 TEST_F(EciesHkdfSenderKemBoringSslTest, TestNewUnknownCurve) {
117 if (IsFipsModeEnabled()) {
118 GTEST_SKIP() << "Not supported in FIPS-only mode";
119 }
120 auto status_or_sender_kem = EciesHkdfSenderKemBoringSsl::New(
121 EllipticCurveType::UNKNOWN_CURVE, "", "");
122 EXPECT_EQ(absl::StatusCode::kUnimplemented,
123 status_or_sender_kem.status().code());
124 }
125
126 class EciesHkdfNistPCurveSendKemBoringSslTest : public ::testing::Test {};
127
TEST_F(EciesHkdfNistPCurveSendKemBoringSslTest,TestNew)128 TEST_F(EciesHkdfNistPCurveSendKemBoringSslTest, TestNew) {
129 if (IsFipsModeEnabled()) {
130 GTEST_SKIP() << "Not supported in FIPS-only mode";
131 }
132 EllipticCurveType curve = EllipticCurveType::NIST_P256;
133 auto status_or_test_key = internal::NewEcKey(curve);
134 ASSERT_TRUE(status_or_test_key.ok());
135 auto test_key = status_or_test_key.value();
136 auto status_or_sender_kem = EciesHkdfNistPCurveSendKemBoringSsl::New(
137 curve, test_key.pub_x, test_key.pub_y);
138 ASSERT_TRUE(status_or_sender_kem.ok());
139 }
140
TEST_F(EciesHkdfNistPCurveSendKemBoringSslTest,TestNewInvalidCurve)141 TEST_F(EciesHkdfNistPCurveSendKemBoringSslTest, TestNewInvalidCurve) {
142 if (IsFipsModeEnabled()) {
143 GTEST_SKIP() << "Not supported in FIPS-only mode";
144 }
145 EllipticCurveType curve = EllipticCurveType::NIST_P256;
146 auto status_or_test_key = internal::NewEcKey(curve);
147 ASSERT_TRUE(status_or_test_key.ok());
148 auto test_key = status_or_test_key.value();
149 auto status_or_sender_kem = EciesHkdfNistPCurveSendKemBoringSsl::New(
150 EllipticCurveType::CURVE25519, test_key.pub_x, test_key.pub_y);
151 EXPECT_EQ(status_or_sender_kem.status().code(),
152 absl::StatusCode::kUnimplemented);
153 }
154
TEST_F(EciesHkdfNistPCurveSendKemBoringSslTest,TestGenerateKey)155 TEST_F(EciesHkdfNistPCurveSendKemBoringSslTest, TestGenerateKey) {
156 if (IsFipsModeEnabled()) {
157 GTEST_SKIP() << "Not supported in FIPS-only mode";
158 }
159 EllipticCurveType curve = EllipticCurveType::NIST_P256;
160 auto status_or_test_key = internal::NewEcKey(curve);
161 ASSERT_TRUE(status_or_test_key.ok());
162 auto test_key = status_or_test_key.value();
163 auto status_or_sender_kem = EciesHkdfNistPCurveSendKemBoringSsl::New(
164 curve, test_key.pub_x, test_key.pub_y);
165 ASSERT_TRUE(status_or_sender_kem.ok());
166 auto sender_kem = std::move(status_or_sender_kem.value());
167
168 uint32_t key_size_in_bytes = 128;
169 auto status_or_kem_key =
170 sender_kem->GenerateKey(HashType::SHA256, "hkdf_salt", "hkdf_info",
171 key_size_in_bytes, EcPointFormat::COMPRESSED);
172 ASSERT_TRUE(status_or_kem_key.ok());
173 auto kem_key = std::move(status_or_kem_key.value());
174 EXPECT_FALSE(kem_key->get_kem_bytes().empty());
175 EXPECT_EQ(kem_key->get_symmetric_key().size(), key_size_in_bytes);
176 }
177
178 class EciesHkdfX25519SendKemBoringSslTest : public ::testing::Test {};
179
TEST_F(EciesHkdfX25519SendKemBoringSslTest,TestNew)180 TEST_F(EciesHkdfX25519SendKemBoringSslTest, TestNew) {
181 if (IsFipsModeEnabled()) {
182 GTEST_SKIP() << "Not supported in FIPS-only mode";
183 }
184 EllipticCurveType curve = EllipticCurveType::CURVE25519;
185 auto status_or_test_key = internal::NewEcKey(curve);
186 ASSERT_TRUE(status_or_test_key.ok());
187 auto test_key = status_or_test_key.value();
188 auto status_or_sender_kem = EciesHkdfX25519SendKemBoringSsl::New(
189 curve, test_key.pub_x, test_key.pub_y);
190 ASSERT_TRUE(status_or_sender_kem.ok());
191 }
192
TEST_F(EciesHkdfX25519SendKemBoringSslTest,TestNewInvalidCurve)193 TEST_F(EciesHkdfX25519SendKemBoringSslTest, TestNewInvalidCurve) {
194 if (IsFipsModeEnabled()) {
195 GTEST_SKIP() << "Not supported in FIPS-only mode";
196 }
197 EllipticCurveType curve = EllipticCurveType::CURVE25519;
198 auto status_or_test_key = internal::NewEcKey(curve);
199 ASSERT_TRUE(status_or_test_key.ok());
200 auto test_key = status_or_test_key.value();
201 auto status_or_sender_kem = EciesHkdfX25519SendKemBoringSsl::New(
202 EllipticCurveType::NIST_P256, test_key.pub_x, test_key.pub_y);
203 EXPECT_EQ(status_or_sender_kem.status().code(),
204 absl::StatusCode::kInvalidArgument);
205 }
206
TEST_F(EciesHkdfX25519SendKemBoringSslTest,TestNewPubxTooLong)207 TEST_F(EciesHkdfX25519SendKemBoringSslTest, TestNewPubxTooLong) {
208 if (IsFipsModeEnabled()) {
209 GTEST_SKIP() << "Not supported in FIPS-only mode";
210 }
211 EllipticCurveType curve = EllipticCurveType::CURVE25519;
212 auto status_or_test_key = internal::NewEcKey(curve);
213 ASSERT_TRUE(status_or_test_key.ok());
214 auto test_key = status_or_test_key.value();
215 test_key.pub_x.resize(test_key.pub_x.size() / 2);
216 auto status_or_sender_kem = EciesHkdfX25519SendKemBoringSsl::New(
217 curve, test_key.pub_x, test_key.pub_y);
218 EXPECT_EQ(status_or_sender_kem.status().code(),
219 absl::StatusCode::kInvalidArgument);
220 }
221
TEST_F(EciesHkdfX25519SendKemBoringSslTest,TestNewPubyNotEmpty)222 TEST_F(EciesHkdfX25519SendKemBoringSslTest, TestNewPubyNotEmpty) {
223 if (IsFipsModeEnabled()) {
224 GTEST_SKIP() << "Not supported in FIPS-only mode";
225 }
226 EllipticCurveType curve = EllipticCurveType::CURVE25519;
227 auto status_or_test_key = internal::NewEcKey(curve);
228 ASSERT_TRUE(status_or_test_key.ok());
229 auto test_key = status_or_test_key.value();
230 test_key.pub_y = test_key.pub_x;
231 auto status_or_sender_kem = EciesHkdfX25519SendKemBoringSsl::New(
232 curve, test_key.pub_x, test_key.pub_y);
233 EXPECT_EQ(status_or_sender_kem.status().code(),
234 absl::StatusCode::kInvalidArgument);
235 }
236
TEST_F(EciesHkdfX25519SendKemBoringSslTest,TestGenerateKey)237 TEST_F(EciesHkdfX25519SendKemBoringSslTest, TestGenerateKey) {
238 if (IsFipsModeEnabled()) {
239 GTEST_SKIP() << "Not supported in FIPS-only mode";
240 }
241 EllipticCurveType curve = EllipticCurveType::CURVE25519;
242 auto status_or_test_key = internal::NewEcKey(curve);
243 ASSERT_TRUE(status_or_test_key.ok());
244 auto test_key = status_or_test_key.value();
245 auto status_or_sender_kem = EciesHkdfX25519SendKemBoringSsl::New(
246 curve, test_key.pub_x, test_key.pub_y);
247 ASSERT_TRUE(status_or_sender_kem.ok());
248 auto sender_kem = std::move(status_or_sender_kem.value());
249
250 uint32_t key_size_in_bytes = 128;
251 auto status_or_kem_key =
252 sender_kem->GenerateKey(HashType::SHA256, "hkdf_salt", "hkdf_info",
253 key_size_in_bytes, EcPointFormat::COMPRESSED);
254 ASSERT_TRUE(status_or_kem_key.ok());
255 auto kem_key = std::move(status_or_kem_key.value());
256 EXPECT_EQ(kem_key->get_kem_bytes().size(), internal::Ed25519KeyPubKeySize());
257 EXPECT_EQ(kem_key->get_symmetric_key().size(), key_size_in_bytes);
258 }
259
TEST_F(EciesHkdfX25519SendKemBoringSslTest,TestGenerateKeyUncompressed)260 TEST_F(EciesHkdfX25519SendKemBoringSslTest, TestGenerateKeyUncompressed) {
261 if (IsFipsModeEnabled()) {
262 GTEST_SKIP() << "Not supported in FIPS-only mode";
263 }
264 EllipticCurveType curve = EllipticCurveType::CURVE25519;
265 auto status_or_test_key = internal::NewEcKey(curve);
266 ASSERT_TRUE(status_or_test_key.ok());
267 auto test_key = status_or_test_key.value();
268 auto status_or_sender_kem = EciesHkdfX25519SendKemBoringSsl::New(
269 curve, test_key.pub_x, test_key.pub_y);
270 ASSERT_TRUE(status_or_sender_kem.ok());
271 auto sender_kem = std::move(status_or_sender_kem.value());
272
273 auto status_or_kem_key =
274 sender_kem->GenerateKey(HashType::SHA256, "hkdf_salt", "hkdf_info", 32,
275 EcPointFormat::UNCOMPRESSED);
276 EXPECT_EQ(status_or_kem_key.status().code(),
277 absl::StatusCode::kInvalidArgument);
278 }
279
280 // Tests for FIPS only mode
TEST_F(EciesHkdfNistPCurveSendKemBoringSslTest,TestFipsOnly)281 TEST_F(EciesHkdfNistPCurveSendKemBoringSslTest, TestFipsOnly) {
282 if (!IsFipsModeEnabled()) {
283 GTEST_SKIP() << "Only supported in FIPS-only mode";
284 }
285 EllipticCurveType curve = EllipticCurveType::NIST_P256;
286 auto status_or_test_key = internal::NewEcKey(curve);
287 auto test_key = status_or_test_key.value();
288
289 EXPECT_THAT(EciesHkdfNistPCurveSendKemBoringSsl::New(curve, test_key.pub_x,
290 test_key.pub_y)
291 .status(),
292 StatusIs(absl::StatusCode::kInternal));
293 }
294
TEST_F(EciesHkdfX25519SendKemBoringSslTest,TestFipsOnly)295 TEST_F(EciesHkdfX25519SendKemBoringSslTest, TestFipsOnly) {
296 if (!IsFipsModeEnabled()) {
297 GTEST_SKIP() << "Only supported in FIPS-only mode";
298 }
299 EllipticCurveType curve = EllipticCurveType::NIST_P256;
300 auto status_or_test_key = internal::NewEcKey(curve);
301 auto test_key = status_or_test_key.value();
302
303 EXPECT_THAT(EciesHkdfX25519SendKemBoringSsl::New(curve, test_key.pub_x,
304 test_key.pub_y)
305 .status(),
306 StatusIs(absl::StatusCode::kInternal));
307 }
308
309 } // namespace
310 } // namespace subtle
311 } // namespace tink
312 } // namespace crypto
313