1 // Copyright 2020 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 #include "tink/subtle/prf/prf_set_util.h"
17
18 #include <functional>
19 #include <memory>
20 #include <sstream>
21 #include <string>
22 #include <utility>
23
24 #include "gmock/gmock.h"
25 #include "gtest/gtest.h"
26 #include "absl/memory/memory.h"
27 #include "absl/status/status.h"
28 #include "absl/strings/string_view.h"
29 #include "tink/input_stream.h"
30 #include "tink/subtle/prf/streaming_prf.h"
31 #include "tink/util/istream_input_stream.h"
32 #include "tink/util/status.h"
33 #include "tink/util/test_matchers.h"
34
35 namespace crypto {
36 namespace tink {
37 namespace subtle {
38 namespace {
39
40 using ::crypto::tink::test::IsOk;
41 using ::testing::_;
42 using ::testing::AnyNumber;
43 using ::testing::DefaultValue;
44 using ::testing::Eq;
45 using ::testing::NiceMock;
46 using ::testing::Not;
47 using ::testing::Return;
48 using ::testing::StrEq;
49
50 class MockPrf : public Prf {
51 public:
52 MOCK_METHOD(util::StatusOr<std::string>, Compute,
53 (absl::string_view input, size_t output_length), (const));
54 };
55
56 class MockStatefulMac : public StatefulMac {
57 public:
58 MOCK_METHOD(util::Status, Update, (absl::string_view data), (override));
59 MOCK_METHOD(util::StatusOr<std::string>, Finalize, (), (override));
60 };
61
62 class FakeStatefulMacFactory : public StatefulMacFactory {
63 public:
FakeStatefulMacFactory(util::Status update_status,util::StatusOr<std::string> finalize_result)64 FakeStatefulMacFactory(util::Status update_status,
65 util::StatusOr<std::string> finalize_result)
66 : update_status_(update_status), finalize_result_(finalize_result) {}
Create() const67 util::StatusOr<std::unique_ptr<StatefulMac>> Create() const override {
68 auto mac_mock = absl::make_unique<NiceMock<MockStatefulMac>>();
69 ON_CALL(*mac_mock, Update(_)).WillByDefault(Return(update_status_));
70 ON_CALL(*mac_mock, Finalize()).WillByDefault(Return(finalize_result_));
71 std::unique_ptr<StatefulMac> result = std::move(mac_mock);
72 return std::move(result);
73 }
74
75 private:
76 util::Status update_status_;
77 util::StatusOr<std::string> finalize_result_;
78 };
79
80 class MockStreamingPrf : public StreamingPrf {
81 public:
82 MOCK_METHOD(std::unique_ptr<InputStream>, ComputePrf,
83 (absl::string_view input), (const));
84 };
85
GetInputStreamForString(const std::string & input)86 std::unique_ptr<InputStream> GetInputStreamForString(const std::string& input) {
87 return absl::make_unique<util::IstreamInputStream>(
88 absl::make_unique<std::stringstream>(input));
89 }
90
91 class PrfFromStatefulMacFactoryTest : public ::testing::Test {
92 protected:
SetUpWithResult(util::Status update_status,util::StatusOr<std::string> finalize_result)93 void SetUpWithResult(util::Status update_status,
94 util::StatusOr<std::string> finalize_result) {
95 prf_ = CreatePrfFromStatefulMacFactory(
96 absl::make_unique<FakeStatefulMacFactory>(update_status,
97 finalize_result));
98 }
prf()99 Prf* prf() { return prf_.get(); }
100
101 private:
102 std::unique_ptr<Prf> prf_;
103 };
104
TEST_F(PrfFromStatefulMacFactoryTest,ComputePrf)105 TEST_F(PrfFromStatefulMacFactoryTest, ComputePrf) {
106 SetUpWithResult(util::OkStatus(), std::string("mock_stateful_mac"));
107 auto output_result = prf()->Compute("test_input", 5);
108 ASSERT_TRUE(output_result.ok()) << output_result.status();
109 EXPECT_THAT(output_result.value(), StrEq("mock_"));
110 }
111
TEST_F(PrfFromStatefulMacFactoryTest,ComputePrfUpdateFails)112 TEST_F(PrfFromStatefulMacFactoryTest, ComputePrfUpdateFails) {
113 SetUpWithResult(util::Status(absl::StatusCode::kInternal, "UpdateFailed"),
114 std::string("mock_stateful_mac"));
115 auto output_result = prf()->Compute("test_input", 5);
116 EXPECT_FALSE(output_result.ok());
117 EXPECT_THAT(output_result.status().message(), Eq("UpdateFailed"));
118 }
119
TEST_F(PrfFromStatefulMacFactoryTest,ComputePrfFinalizeFails)120 TEST_F(PrfFromStatefulMacFactoryTest, ComputePrfFinalizeFails) {
121 SetUpWithResult(util::OkStatus(),
122 util::Status(absl::StatusCode::kInternal, "FinalizeFailed"));
123 auto output_result = prf()->Compute("test_input", 5);
124 EXPECT_FALSE(output_result.ok());
125 EXPECT_THAT(output_result.status().message(), Eq("FinalizeFailed"));
126 }
127
TEST_F(PrfFromStatefulMacFactoryTest,ComputePrfTooMuchOutputRequested)128 TEST_F(PrfFromStatefulMacFactoryTest, ComputePrfTooMuchOutputRequested) {
129 SetUpWithResult(util::OkStatus(), std::string("mock_stateful_mac"));
130 auto output_result = prf()->Compute("test_input", 100);
131 EXPECT_FALSE(output_result.ok());
132 }
133
134 class PrfFromStreamingPrfTest : public ::testing::Test {
135 protected:
SetUp()136 void SetUp() override {
137 auto streaming_prf = absl::make_unique<NiceMock<MockStreamingPrf>>();
138 DefaultValue<std::unique_ptr<InputStream>>::SetFactory(
139 [] { return GetInputStreamForString("output"); });
140 EXPECT_CALL(*streaming_prf, ComputePrf(Eq("input"))).Times(AnyNumber());
141 prf_ = CreatePrfFromStreamingPrf(std::move(streaming_prf));
142 }
prf()143 Prf* prf() { return prf_.get(); }
144
145 private:
146 std::unique_ptr<Prf> prf_;
147 };
148
TEST_F(PrfFromStreamingPrfTest,ComputePrfBasic)149 TEST_F(PrfFromStreamingPrfTest, ComputePrfBasic) {
150 auto output_result = prf()->Compute("input", 5);
151 ASSERT_THAT(output_result, IsOk());
152 EXPECT_THAT(output_result.value(), StrEq("outpu"));
153 }
154
TEST_F(PrfFromStreamingPrfTest,ComputeTwice)155 TEST_F(PrfFromStreamingPrfTest, ComputeTwice) {
156 auto output_result = prf()->Compute("input", 5);
157 ASSERT_THAT(output_result, IsOk());
158 EXPECT_THAT(output_result.value(), StrEq("outpu"));
159 output_result = prf()->Compute("input", 5);
160 ASSERT_THAT(output_result, IsOk());
161 EXPECT_THAT(output_result.value(), StrEq("outpu"));
162 }
163
TEST_F(PrfFromStreamingPrfTest,ComputeSubstring)164 TEST_F(PrfFromStreamingPrfTest, ComputeSubstring) {
165 auto output_result = prf()->Compute("input", 5);
166 ASSERT_THAT(output_result, IsOk());
167 EXPECT_THAT(output_result.value(), StrEq("outpu"));
168 output_result = prf()->Compute("input", 6);
169 ASSERT_THAT(output_result, IsOk());
170 EXPECT_THAT(output_result.value(), StrEq("output"));
171 output_result = prf()->Compute("input", 2);
172 ASSERT_THAT(output_result, IsOk());
173 EXPECT_THAT(output_result.value(), StrEq("ou"));
174 }
175
TEST_F(PrfFromStreamingPrfTest,ComputeTooMuch)176 TEST_F(PrfFromStreamingPrfTest, ComputeTooMuch) {
177 auto output_result = prf()->Compute("input", 5);
178 ASSERT_THAT(output_result, IsOk());
179 EXPECT_THAT(output_result.value(), StrEq("outpu"));
180 output_result = prf()->Compute("input", 100);
181 EXPECT_THAT(output_result, Not(IsOk()))
182 << "Output should not be okay, too much output requested";
183 }
184
185 } // namespace
186 } // namespace subtle
187 } // namespace tink
188 } // namespace crypto
189