xref: /aosp_15_r20/external/tink/cc/subtle/prf/hkdf_streaming_prf_test.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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