1 // Copyright 2019 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/subtle/prf/hkdf_streaming_prf.h"
18
19 #include <algorithm>
20 #include <iterator>
21 #include <memory>
22 #include <string>
23 #include <utility>
24
25 #include "gmock/gmock.h"
26 #include "gtest/gtest.h"
27 #include "absl/status/status.h"
28 #include "tink/config/tink_fips.h"
29 #include "tink/subtle/common_enums.h"
30 #include "tink/subtle/hkdf.h"
31 #include "tink/subtle/random.h"
32 #include "tink/util/input_stream_util.h"
33 #include "tink/util/secret_data.h"
34 #include "tink/util/test_matchers.h"
35 #include "tink/util/test_util.h"
36
37 namespace crypto {
38 namespace tink {
39 namespace subtle {
40
41 namespace {
42
43 using ::crypto::tink::test::HexDecodeOrDie;
44 using ::crypto::tink::test::IsOk;
45 using ::crypto::tink::test::StatusIs;
46 using ::testing::Eq;
47 using ::testing::Ge;
48 using ::testing::Ne;
49 using ::testing::Not;
50 using ::testing::SizeIs;
51
52 // GENERIC TESTS ===============================================================
53 //
54 // These should be satisfied for any streaming prf which generates enough
55 // output.
TEST(HkdfStreamingPrf,Basic)56 TEST(HkdfStreamingPrf, Basic) {
57 if (IsFipsModeEnabled()) {
58 GTEST_SKIP() << "Not supported in FIPS-only mode";
59 }
60 auto streaming_prf_or = HkdfStreamingPrf::New(
61 SHA512, util::SecretDataFromStringView("key0123456"), "salt");
62 ASSERT_THAT(streaming_prf_or, IsOk());
63
64 std::unique_ptr<InputStream> stream =
65 streaming_prf_or.value()->ComputePrf("input");
66 auto result_or = ReadBytesFromStream(10, stream.get());
67 ASSERT_THAT(result_or, IsOk());
68
69 EXPECT_THAT(result_or.value(), SizeIs(10));
70 }
71
TEST(HkdfStreamingPrf,EmptySalt)72 TEST(HkdfStreamingPrf, EmptySalt) {
73 if (IsFipsModeEnabled()) {
74 GTEST_SKIP() << "Not supported in FIPS-only mode";
75 }
76
77 crypto::tink::subtle::HashType hash_type = SHA512;
78 const int hash_length = 64;
79 util::SecretData secret = util::SecretDataFromStringView("key0123456");
80 absl::string_view input = "input";
81 int num_bytes = 10;
82
83 std::string prf_empty_salt;
84 std::string prf_zeroed_salt;
85 {
86 auto streaming_prf = HkdfStreamingPrf::New(hash_type, secret, "");
87 ASSERT_THAT(streaming_prf, IsOk());
88 std::unique_ptr<InputStream> stream = (*streaming_prf)->ComputePrf(input);
89 auto result = ReadBytesFromStream(num_bytes, stream.get());
90 ASSERT_THAT(result, IsOk());
91 prf_empty_salt = *result;
92 }
93 {
94 uint8_t zeroedSalt[hash_length];
95 std::fill(std::begin(zeroedSalt), std::end(zeroedSalt), 0);
96 auto streaming_prf = HkdfStreamingPrf::New(hash_type, secret,
97 std::string((char*)zeroedSalt));
98 ASSERT_THAT(streaming_prf, IsOk());
99 std::unique_ptr<InputStream> stream = (*streaming_prf)->ComputePrf(input);
100 auto result = ReadBytesFromStream(num_bytes, stream.get());
101 ASSERT_THAT(result, IsOk());
102 prf_zeroed_salt = *result;
103 }
104 EXPECT_THAT(prf_empty_salt, SizeIs(num_bytes));
105 EXPECT_THAT(prf_zeroed_salt, SizeIs(num_bytes));
106 ASSERT_EQ(prf_empty_salt, prf_zeroed_salt);
107 }
108
TEST(HkdfStreamingPrf,DifferentInputsGiveDifferentvalues)109 TEST(HkdfStreamingPrf, DifferentInputsGiveDifferentvalues) {
110 if (IsFipsModeEnabled()) {
111 GTEST_SKIP() << "Not supported in FIPS-only mode";
112 }
113 auto streaming_prf_or = HkdfStreamingPrf::New(
114 SHA512, util::SecretDataFromStringView("key0123456"), "salt");
115 ASSERT_THAT(streaming_prf_or, IsOk());
116
117 std::unique_ptr<InputStream> stream =
118 streaming_prf_or.value()->ComputePrf("input");
119 auto result_or = ReadBytesFromStream(10, stream.get());
120 ASSERT_THAT(result_or, IsOk());
121
122 // Different input.
123 std::unique_ptr<InputStream> stream2 =
124 streaming_prf_or.value()->ComputePrf("input2");
125 auto result_or2 = ReadBytesFromStream(10, stream2.get());
126 ASSERT_THAT(result_or2, IsOk());
127 EXPECT_THAT(result_or2.value(), Ne(result_or.value()));
128 }
129
TEST(HkdfStreamingPrf,SameInputTwice)130 TEST(HkdfStreamingPrf, SameInputTwice) {
131 if (IsFipsModeEnabled()) {
132 GTEST_SKIP() << "Not supported in FIPS-only mode";
133 }
134 auto streaming_prf_or = HkdfStreamingPrf::New(
135 SHA512, util::SecretDataFromStringView("key0123456"), "salt");
136 ASSERT_THAT(streaming_prf_or, IsOk());
137
138 std::unique_ptr<InputStream> stream =
139 streaming_prf_or.value()->ComputePrf("input");
140 auto result_or = ReadBytesFromStream(10, stream.get());
141 ASSERT_THAT(result_or, IsOk());
142
143 // Same input.
144 std::unique_ptr<InputStream> stream2 =
145 streaming_prf_or.value()->ComputePrf("input");
146 auto result_or2 = ReadBytesFromStream(10, stream2.get());
147 ASSERT_THAT(result_or2, IsOk());
148 EXPECT_THAT(result_or2.value(), Eq(result_or.value()));
149 }
150
151 // STREAM HANDLING TESTS =======================================================
152 //
153 // These check that the buffer handling of the implementation is correct. They
154 // should be satisfied with any input stream.
155
156 // Tests that after Backing up the full stream, we get back the same data.
TEST(HkdfStreamingPrf,BackupFullStream)157 TEST(HkdfStreamingPrf, BackupFullStream) {
158 if (IsFipsModeEnabled()) {
159 GTEST_SKIP() << "Not supported in FIPS-only mode";
160 }
161 auto streaming_prf_or = HkdfStreamingPrf::New(
162 SHA256, util::SecretDataFromStringView("key0123456"), "salt");
163 ASSERT_THAT(streaming_prf_or, IsOk());
164
165 std::unique_ptr<InputStream> stream =
166 streaming_prf_or.value()->ComputePrf("input");
167
168 const void* data;
169 crypto::tink::util::StatusOr<int> result = stream->Next(&data);
170 ASSERT_THAT(result, IsOk());
171 int bytes_read = result.value();
172 std::string first_read =
173 std::string(static_cast<const char*>(data), bytes_read);
174
175 stream->BackUp(bytes_read);
176
177 result = stream->Next(&data);
178 ASSERT_THAT(result, IsOk());
179 // We typically read at least as many bytes the second time -- strictly
180 // speaking this might not be satisfied by every InputStream, but it usually
181 // will be.
182 ASSERT_THAT(result.value(), Ge(bytes_read));
183
184 std::string second_read =
185 std::string(static_cast<const char*>(data), bytes_read);
186 EXPECT_THAT(first_read, Eq(second_read));
187 }
188
189 // Tests that after Backing up half the stream, we get back the same data.
TEST(HkdfStreamingPrf,BackupHalf)190 TEST(HkdfStreamingPrf, BackupHalf) {
191 if (IsFipsModeEnabled()) {
192 GTEST_SKIP() << "Not supported in FIPS-only mode";
193 }
194 auto streaming_prf_or = HkdfStreamingPrf::New(
195 SHA256, util::SecretDataFromStringView("key0123456"), "salt");
196 ASSERT_THAT(streaming_prf_or, IsOk());
197
198 std::unique_ptr<InputStream> stream =
199 streaming_prf_or.value()->ComputePrf("input");
200
201 const void* data;
202 crypto::tink::util::StatusOr<int> result = stream->Next(&data);
203 ASSERT_THAT(result, IsOk());
204 int bytes_read = result.value();
205 int backup_amount = bytes_read / 2;
206 std::string first_read =
207 std::string(static_cast<const char*>(data) + bytes_read - backup_amount,
208 backup_amount);
209
210 stream->BackUp(backup_amount);
211
212 result = stream->Next(&data);
213 ASSERT_THAT(result, IsOk());
214 // We typically read at least as many bytes the second time -- strictly
215 // speaking this might not be satisfied by every InputStream, but it usually
216 // will be.
217 ASSERT_THAT(result.value(), Ge(backup_amount));
218
219 std::string second_read =
220 std::string(static_cast<const char*>(data), backup_amount);
221 EXPECT_THAT(first_read, Eq(second_read));
222 }
223
224 // Tests that after Position is correct initially (i.e., 0).
TEST(HkdfStreamingPrf,PositionOneRead)225 TEST(HkdfStreamingPrf, PositionOneRead) {
226 if (IsFipsModeEnabled()) {
227 GTEST_SKIP() << "Not supported in FIPS-only mode";
228 }
229 auto streaming_prf_or = HkdfStreamingPrf::New(
230 SHA256, util::SecretDataFromStringView("key0123456"), "salt");
231 ASSERT_THAT(streaming_prf_or, IsOk());
232
233 std::unique_ptr<InputStream> stream =
234 streaming_prf_or.value()->ComputePrf("input");
235
236 EXPECT_THAT(stream->Position(), Eq(0));
237 }
238
239 // Tests that after Position is correct after a single read.
TEST(HkdfStreamingPrf,PositionSingleRead)240 TEST(HkdfStreamingPrf, PositionSingleRead) {
241 if (IsFipsModeEnabled()) {
242 GTEST_SKIP() << "Not supported in FIPS-only mode";
243 }
244 auto streaming_prf_or = HkdfStreamingPrf::New(
245 SHA256, util::SecretDataFromStringView("key0123456"), "salt");
246 ASSERT_THAT(streaming_prf_or, IsOk());
247
248 std::unique_ptr<InputStream> stream =
249 streaming_prf_or.value()->ComputePrf("input");
250
251 const void* data;
252 crypto::tink::util::StatusOr<int> result = stream->Next(&data);
253 ASSERT_THAT(result, IsOk());
254 EXPECT_THAT(stream->Position(), Eq(result.value()));
255 }
256
257 // Tests that after Position is correct after a two reads.
TEST(HkdfStreamingPrf,PositionTwoReads)258 TEST(HkdfStreamingPrf, PositionTwoReads) {
259 if (IsFipsModeEnabled()) {
260 GTEST_SKIP() << "Not supported in FIPS-only mode";
261 }
262 auto streaming_prf_or = HkdfStreamingPrf::New(
263 SHA256, util::SecretDataFromStringView("key0123456"), "salt");
264 ASSERT_THAT(streaming_prf_or, IsOk());
265
266 std::unique_ptr<InputStream> stream =
267 streaming_prf_or.value()->ComputePrf("input");
268
269 const void* data;
270 crypto::tink::util::StatusOr<int> result = stream->Next(&data);
271 ASSERT_THAT(result, IsOk());
272
273 crypto::tink::util::StatusOr<int> result2 = stream->Next(&data);
274 ASSERT_THAT(result, IsOk());
275
276 EXPECT_THAT(stream->Position(), Eq(result.value() + result2.value()));
277 }
278
279 // Tests that we can backup the first read completely.
TEST(HkdfStreamingPrf,BackupSingleRead)280 TEST(HkdfStreamingPrf, BackupSingleRead) {
281 if (IsFipsModeEnabled()) {
282 GTEST_SKIP() << "Not supported in FIPS-only mode";
283 }
284 auto streaming_prf_or = HkdfStreamingPrf::New(
285 SHA256, util::SecretDataFromStringView("key0123456"), "salt");
286 ASSERT_THAT(streaming_prf_or, IsOk());
287
288 std::unique_ptr<InputStream> stream =
289 streaming_prf_or.value()->ComputePrf("input");
290
291 const void* data;
292 crypto::tink::util::StatusOr<int> result = stream->Next(&data);
293 ASSERT_THAT(result, IsOk());
294 stream->BackUp(result.value());
295 EXPECT_THAT(stream->Position(), Eq(0));
296 }
297
298 // Tests that we can backup the second read completely.
TEST(HkdfStreamingPrf,BackupSecondRead)299 TEST(HkdfStreamingPrf, BackupSecondRead) {
300 if (IsFipsModeEnabled()) {
301 GTEST_SKIP() << "Not supported in FIPS-only mode";
302 }
303 auto streaming_prf_or = HkdfStreamingPrf::New(
304 SHA256, util::SecretDataFromStringView("key0123456"), "salt");
305 ASSERT_THAT(streaming_prf_or, IsOk());
306
307 std::unique_ptr<InputStream> stream =
308 streaming_prf_or.value()->ComputePrf("input");
309
310 const void* data;
311 crypto::tink::util::StatusOr<int> result = stream->Next(&data);
312 ASSERT_THAT(result, IsOk());
313
314 crypto::tink::util::StatusOr<int> result2 = stream->Next(&data);
315 ASSERT_THAT(result, IsOk());
316
317 stream->BackUp(result2.value());
318
319 EXPECT_THAT(stream->Position(), Eq(result.value()));
320 }
321
322 // Tests that we can partially backup and position is correct.
TEST(HkdfStreamingPrf,PartialBackup)323 TEST(HkdfStreamingPrf, PartialBackup) {
324 if (IsFipsModeEnabled()) {
325 GTEST_SKIP() << "Not supported in FIPS-only mode";
326 }
327 auto streaming_prf_or = HkdfStreamingPrf::New(
328 SHA256, util::SecretDataFromStringView("key0123456"), "salt");
329 ASSERT_THAT(streaming_prf_or, IsOk());
330
331 std::unique_ptr<InputStream> stream =
332 streaming_prf_or.value()->ComputePrf("input");
333
334 const void* data;
335 crypto::tink::util::StatusOr<int> result = stream->Next(&data);
336 ASSERT_THAT(result, IsOk());
337
338 stream->BackUp(result.value() / 2);
339
340 EXPECT_THAT(stream->Position(), Eq(result.value() - result.value() / 2));
341 }
342
343 // HKDF Specific tests =========================================================
344 // Tests which only apply for Hkdf.
TEST(HkdfStreamingPrf,ExhaustInput)345 TEST(HkdfStreamingPrf, ExhaustInput) {
346 if (IsFipsModeEnabled()) {
347 GTEST_SKIP() << "Not supported in FIPS-only mode";
348 }
349 auto streaming_prf_or = HkdfStreamingPrf::New(
350 SHA512, util::SecretDataFromStringView("key0123456"), "salt");
351 ASSERT_THAT(streaming_prf_or, IsOk());
352
353 const int max_output_length = 255 * (512 / 8);
354 std::unique_ptr<InputStream> stream =
355 streaming_prf_or.value()->ComputePrf("input");
356 auto result_or = ReadBytesFromStream(max_output_length, stream.get());
357 ASSERT_THAT(result_or, IsOk());
358 EXPECT_THAT(result_or.value(), SizeIs(max_output_length));
359 result_or = ReadBytesFromStream(50, stream.get());
360 ASSERT_THAT(result_or, Not(IsOk()));
361 }
362
363 // TEST VECTORS AND COMPARISON =================================================
364 // These test are Hkdf specific. We test with the test vectors from RFC 5869 and
365 // compare with our implementation.
TEST(HkdfStreamingPrf,TestVector1)366 TEST(HkdfStreamingPrf, TestVector1) {
367 if (IsFipsModeEnabled()) {
368 GTEST_SKIP() << "Not supported in FIPS-only mode";
369 }
370 // https://tools.ietf.org/html/rfc5869#appendix-A.1
371 HashType hash = SHA256;
372 util::SecretData ikm = util::SecretDataFromStringView(
373 HexDecodeOrDie("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"));
374 std::string salt = HexDecodeOrDie("000102030405060708090a0b0c");
375 std::string info = HexDecodeOrDie("f0f1f2f3f4f5f6f7f8f9");
376 std::string expected_result = HexDecodeOrDie(
377 "3cb25f25faacd57a90434f64d0362f2a"
378 "2d2d0a90cf1a5a4c5db02d56ecc4c5bf"
379 "34007208d5b887185865");
380
381 auto streaming_prf_or = HkdfStreamingPrf::New(hash, ikm, salt);
382 ASSERT_THAT(streaming_prf_or, IsOk());
383 std::unique_ptr<InputStream> stream =
384 streaming_prf_or.value()->ComputePrf(info);
385 auto result_or = ReadBytesFromStream(expected_result.size(), stream.get());
386 ASSERT_THAT(result_or, IsOk());
387 EXPECT_THAT(result_or.value(), Eq(expected_result));
388 }
389
ComputeWithHkdfStreamingPrf(HashType hash,util::SecretData ikm,std::string salt,std::string info,int length)390 crypto::tink::util::StatusOr<std::string> ComputeWithHkdfStreamingPrf(
391 HashType hash, util::SecretData ikm, std::string salt, std::string info,
392 int length) {
393 auto streaming_prf_or = HkdfStreamingPrf::New(hash, std::move(ikm), salt);
394 if (!streaming_prf_or.status().ok()) {
395 return streaming_prf_or.status();
396 }
397 std::unique_ptr<InputStream> stream =
398 streaming_prf_or.value()->ComputePrf(info);
399 return ReadBytesFromStream(length, stream.get());
400 }
401
TEST(HkdfStreamingPrf,TestVector2)402 TEST(HkdfStreamingPrf, TestVector2) {
403 if (IsFipsModeEnabled()) {
404 GTEST_SKIP() << "Not supported in FIPS-only mode";
405 }
406 // https://tools.ietf.org/html/rfc5869#appendix-A.2
407 HashType hash = SHA256;
408 util::SecretData ikm = util::SecretDataFromStringView(
409 HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"
410 "101112131415161718191a1b1c1d1e1f"
411 "202122232425262728292a2b2c2d2e2f"
412 "303132333435363738393a3b3c3d3e3f"
413 "404142434445464748494a4b4c4d4e4f"));
414 std::string salt = HexDecodeOrDie(
415 "606162636465666768696a6b6c6d6e6f"
416 "707172737475767778797a7b7c7d7e7f"
417 "808182838485868788898a8b8c8d8e8f"
418 "909192939495969798999a9b9c9d9e9f"
419 "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf");
420 std::string info = HexDecodeOrDie(
421 "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
422 "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
423 "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
424 "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
425 "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff");
426 std::string expected_result = HexDecodeOrDie(
427 "b11e398dc80327a1c8e7f78c596a4934"
428 "4f012eda2d4efad8a050cc4c19afa97c"
429 "59045a99cac7827271cb41c65e590e09"
430 "da3275600c2f09b8367793a9aca3db71"
431 "cc30c58179ec3e87c14c01d5c1f3434f"
432 "1d87");
433
434 auto result_or = ComputeWithHkdfStreamingPrf(hash, std::move(ikm), salt, info,
435 expected_result.size());
436 ASSERT_THAT(result_or, IsOk());
437 EXPECT_THAT(result_or.value(), Eq(expected_result));
438 }
439
TEST(HkdfStreamingPrf,TestVector3)440 TEST(HkdfStreamingPrf, TestVector3) {
441 if (IsFipsModeEnabled()) {
442 GTEST_SKIP() << "Not supported in FIPS-only mode";
443 }
444 // https://tools.ietf.org/html/rfc5869#appendix-A.3
445 HashType hash = SHA256;
446 util::SecretData ikm = util::SecretDataFromStringView(
447 HexDecodeOrDie("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"));
448 std::string salt = HexDecodeOrDie("");
449 std::string info = HexDecodeOrDie("");
450 std::string expected_result = HexDecodeOrDie(
451 "8da4e775a563c18f715f802a063c5a31"
452 "b8a11f5c5ee1879ec3454e5f3c738d2d"
453 "9d201395faa4b61a96c8");
454
455 auto result_or = ComputeWithHkdfStreamingPrf(hash, std::move(ikm), salt, info,
456 expected_result.size());
457 ASSERT_THAT(result_or, IsOk());
458 EXPECT_THAT(result_or.value(), Eq(expected_result));
459 }
460
TEST(HkdfStreamingPrf,TestVector4)461 TEST(HkdfStreamingPrf, TestVector4) {
462 if (IsFipsModeEnabled()) {
463 GTEST_SKIP() << "Not supported in FIPS-only mode";
464 }
465 // https://tools.ietf.org/html/rfc5869#appendix-A.4
466 HashType hash = SHA1;
467 util::SecretData ikm =
468 util::SecretDataFromStringView(HexDecodeOrDie("0b0b0b0b0b0b0b0b0b0b0b"));
469 std::string salt = HexDecodeOrDie("000102030405060708090a0b0c");
470 std::string info = HexDecodeOrDie("f0f1f2f3f4f5f6f7f8f9");
471 std::string expected_result = HexDecodeOrDie(
472 "085a01ea1b10f36933068b56efa5ad81"
473 "a4f14b822f5b091568a9cdd4f155fda2"
474 "c22e422478d305f3f896");
475
476 auto result_or = ComputeWithHkdfStreamingPrf(hash, std::move(ikm), salt, info,
477 expected_result.size());
478 ASSERT_THAT(result_or, IsOk());
479 EXPECT_THAT(result_or.value(), Eq(expected_result));
480 }
481
TEST(HkdfStreamingPrf,TestVector5)482 TEST(HkdfStreamingPrf, TestVector5) {
483 if (IsFipsModeEnabled()) {
484 GTEST_SKIP() << "Not supported in FIPS-only mode";
485 }
486 // https://tools.ietf.org/html/rfc5869#appendix-A.5
487 HashType hash = SHA1;
488 util::SecretData ikm = util::SecretDataFromStringView(
489 HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"
490 "101112131415161718191a1b1c1d1e1f"
491 "202122232425262728292a2b2c2d2e2f"
492 "303132333435363738393a3b3c3d3e3f"
493 "404142434445464748494a4b4c4d4e4f"));
494 std::string salt = HexDecodeOrDie(
495 "606162636465666768696a6b6c6d6e6f"
496 "707172737475767778797a7b7c7d7e7f"
497 "808182838485868788898a8b8c8d8e8f"
498 "909192939495969798999a9b9c9d9e9f"
499 "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf");
500 std::string info = HexDecodeOrDie(
501 "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
502 "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
503 "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
504 "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
505 "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff");
506 std::string expected_result = HexDecodeOrDie(
507 "0bd770a74d1160f7c9f12cd5912a06eb"
508 "ff6adcae899d92191fe4305673ba2ffe"
509 "8fa3f1a4e5ad79f3f334b3b202b2173c"
510 "486ea37ce3d397ed034c7f9dfeb15c5e"
511 "927336d0441f4c4300e2cff0d0900b52"
512 "d3b4");
513
514 auto result_or = ComputeWithHkdfStreamingPrf(hash, std::move(ikm), salt, info,
515 expected_result.size());
516 ASSERT_THAT(result_or, IsOk());
517 EXPECT_THAT(result_or.value(), Eq(expected_result));
518 }
519
TEST(HkdfStreamingPrf,TestVector6)520 TEST(HkdfStreamingPrf, TestVector6) {
521 if (IsFipsModeEnabled()) {
522 GTEST_SKIP() << "Not supported in FIPS-only mode";
523 }
524 // https://tools.ietf.org/html/rfc5869#appendix-A.6
525 HashType hash = SHA1;
526 util::SecretData ikm = util::SecretDataFromStringView(
527 HexDecodeOrDie("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"));
528 std::string salt = HexDecodeOrDie("");
529 std::string info = HexDecodeOrDie("");
530 std::string expected_result = HexDecodeOrDie(
531 "0ac1af7002b3d761d1e55298da9d0506"
532 "b9ae52057220a306e07b6b87e8df21d0"
533 "ea00033de03984d34918");
534
535 auto result_or = ComputeWithHkdfStreamingPrf(hash, std::move(ikm), salt, info,
536 expected_result.size());
537 ASSERT_THAT(result_or, IsOk());
538 EXPECT_THAT(result_or.value(), Eq(expected_result));
539 }
540
TEST(HkdfStreamingPrf,TestVector7)541 TEST(HkdfStreamingPrf, TestVector7) {
542 if (IsFipsModeEnabled()) {
543 GTEST_SKIP() << "Not supported in FIPS-only mode";
544 }
545 // https://tools.ietf.org/html/rfc5869#appendix-A.7
546 HashType hash = SHA1;
547 util::SecretData ikm = util::SecretDataFromStringView(
548 HexDecodeOrDie("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"));
549 // Since HMAC anyhow pads, this is the same as an absent salt.
550 std::string salt = HexDecodeOrDie("");
551 std::string info = HexDecodeOrDie("");
552 std::string expected_result = HexDecodeOrDie(
553 "0ac1af7002b3d761d1e55298da9d0506"
554 "b9ae52057220a306e07b6b87e8df21d0"
555 "ea00033de03984d34918");
556
557 auto result_or = ComputeWithHkdfStreamingPrf(hash, std::move(ikm), salt, info,
558 expected_result.size());
559 ASSERT_THAT(result_or, IsOk());
560 EXPECT_THAT(result_or.value(), Eq(expected_result));
561 }
562
TEST(HkdfStreamingPrf,TestAgainstHkdfUtil)563 TEST(HkdfStreamingPrf, TestAgainstHkdfUtil) {
564 if (IsFipsModeEnabled()) {
565 GTEST_SKIP() << "Not supported in FIPS-only mode";
566 }
567 HashType hash = SHA1;
568 util::SecretData ikm = Random::GetRandomKeyBytes(123);
569 std::string salt = Random::GetRandomBytes(234);
570 std::string info = Random::GetRandomBytes(345);
571
572 auto streaming_result_or =
573 ComputeWithHkdfStreamingPrf(hash, ikm, salt, info, 456);
574 ASSERT_THAT(streaming_result_or, IsOk());
575
576 auto compute_hkdf_result_or = Hkdf::ComputeHkdf(hash, ikm, salt, info, 456);
577 ASSERT_THAT(compute_hkdf_result_or, IsOk());
578
579 util::SecretData compute_hkdf_result =
580 std::move(compute_hkdf_result_or).value();
581 EXPECT_THAT(streaming_result_or.value(),
582 Eq(util::SecretDataAsStringView(compute_hkdf_result)));
583 }
584
TEST(HkdfStreamingPrf,TestFipsOnly)585 TEST(HkdfStreamingPrf, TestFipsOnly) {
586 if (!IsFipsModeEnabled()) {
587 GTEST_SKIP() << "Only supported in FIPS-only mode";
588 }
589
590 HashType hash = SHA1;
591 util::SecretData ikm = Random::GetRandomKeyBytes(123);
592 std::string salt = Random::GetRandomBytes(234);
593 std::string info = Random::GetRandomBytes(345);
594
595 EXPECT_THAT(HkdfStreamingPrf::New(hash, std::move(ikm), salt).status(),
596 StatusIs(absl::StatusCode::kInternal));
597 }
598 } // namespace
599 } // namespace subtle
600 } // namespace tink
601 } // namespace crypto
602