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/streaming_mac_impl.h"
18
19 #include <algorithm>
20 #include <memory>
21 #include <string>
22 #include <utility>
23
24 #include "absl/memory/memory.h"
25 #include "absl/status/status.h"
26 #include "openssl/crypto.h"
27 #include "tink/util/status.h"
28
29 namespace crypto {
30 namespace tink {
31 namespace subtle {
32
33 namespace {
34 constexpr size_t kBufferSize = 4096;
35 }
36
37 class ComputeMacOutputStream : public OutputStreamWithResult<std::string> {
38 public:
ComputeMacOutputStream(std::unique_ptr<StatefulMac> mac)39 explicit ComputeMacOutputStream(std::unique_ptr<StatefulMac> mac)
40 : status_(util::OkStatus()),
41 mac_(std::move(mac)),
42 position_(0),
43 buffer_position_(0),
44 buffer_("") {
45 buffer_.resize(kBufferSize);
46 }
47
48 util::StatusOr<int> NextBuffer(void** buffer) override;
49 util::StatusOr<std::string> CloseStreamAndComputeResult() override;
50 void BackUp(int count) override;
Position() const51 int64_t Position() const override { return position_; }
52
53 private:
54 void WriteIntoMac();
55
56 util::Status status_;
57 const std::unique_ptr<StatefulMac> mac_;
58 int64_t position_;
59 int buffer_position_;
60 std::string buffer_;
61 };
62
63 util::StatusOr<std::unique_ptr<OutputStreamWithResult<std::string>>>
NewComputeMacOutputStream() const64 StreamingMacImpl::NewComputeMacOutputStream() const {
65 util::StatusOr<std::unique_ptr<StatefulMac>> mac_status =
66 mac_factory_->Create();
67
68 if (!mac_status.ok()) {
69 return mac_status.status();
70 }
71
72 std::unique_ptr<OutputStreamWithResult<std::string>> string_to_return =
73 absl::make_unique<ComputeMacOutputStream>(std::move(mac_status.value()));
74 return std::move(string_to_return);
75 }
76
NextBuffer(void ** buffer)77 util::StatusOr<int> ComputeMacOutputStream::NextBuffer(void** buffer) {
78 if (!status_.ok()) {
79 return status_;
80 }
81 WriteIntoMac();
82 *buffer = &buffer_[0];
83 position_ += kBufferSize;
84 buffer_position_ = kBufferSize;
85 return buffer_position_;
86 }
87
88 util::StatusOr<std::string>
CloseStreamAndComputeResult()89 ComputeMacOutputStream::CloseStreamAndComputeResult() {
90 if (!status_.ok()) {
91 return status_;
92 }
93 WriteIntoMac();
94 status_ =
95 util::Status(absl::StatusCode::kFailedPrecondition, "Stream Closed");
96 return mac_->Finalize();
97 }
98
BackUp(int count)99 void ComputeMacOutputStream::BackUp(int count) {
100 count = std::min(count, buffer_position_);
101 buffer_position_ -= count;
102 position_ -= count;
103 }
104
105 // Writes the data in buffer_ into mac_, and clears buffer_.
WriteIntoMac()106 void ComputeMacOutputStream::WriteIntoMac() {
107 // Remove the suffix of the buffer (all data after buffer_position_).
108 status_ = mac_->Update(absl::string_view(buffer_.data(), buffer_position_));
109
110 // Clear the buffer, so that any sensitive information that
111 // was written to the buffer cannot be accessed later.
112 // Write buffer_position_ number of 0's to the buffer, starting from idx 0.
113 buffer_.replace(0, buffer_position_, buffer_position_, 0);
114 }
115
116 class VerifyMacOutputStream : public OutputStreamWithResult<util::Status> {
117 public:
VerifyMacOutputStream(const std::string & expected,std::unique_ptr<StatefulMac> mac)118 VerifyMacOutputStream(const std::string& expected,
119 std::unique_ptr<StatefulMac> mac)
120 : status_(util::OkStatus()),
121 mac_(std::move(mac)),
122 position_(0),
123 buffer_position_(0),
124 buffer_(""),
125 expected_(expected) {
126 buffer_.resize(kBufferSize);
127 }
128
129 util::StatusOr<int> NextBuffer(void** buffer) override;
130
131 util::Status CloseStreamAndComputeResult() override;
132
133 void BackUp(int count) override;
Position() const134 int64_t Position() const override { return position_; }
135
136 private:
137 void WriteIntoMac();
138
139 // Stream status: Initialized as OK, and
140 // changed to ERROR:FAILED_PRECONDITION when the stream is closed.
141 util::Status status_;
142 std::unique_ptr<StatefulMac> mac_;
143 int64_t position_;
144 int buffer_position_;
145 std::string buffer_;
146 std::string expected_;
147 };
148
NextBuffer(void ** buffer)149 util::StatusOr<int> VerifyMacOutputStream::NextBuffer(void** buffer) {
150 if (!status_.ok()) {
151 return status_;
152 }
153 WriteIntoMac();
154 *buffer = &buffer_[0];
155 position_ += kBufferSize;
156 buffer_position_ = kBufferSize;
157 return buffer_position_;
158 }
159
CloseStreamAndComputeResult()160 util::Status VerifyMacOutputStream::CloseStreamAndComputeResult() {
161 if (!status_.ok()) {
162 return status_;
163 }
164 WriteIntoMac();
165 status_ =
166 util::Status(absl::StatusCode::kFailedPrecondition, "Stream Closed");
167 util::StatusOr<std::string> mac_actual = mac_->Finalize();
168 if (!mac_actual.ok()) {
169 return mac_actual.status();
170 }
171 if (mac_actual->size() != expected_.size()) {
172 return absl::InvalidArgumentError(
173 absl::StrCat("Invalid MAC size; expected ", expected_.size(), ", got ",
174 mac_actual->size()));
175 }
176 if (!CRYPTO_memcmp(mac_actual->data(), expected_.data(),
177 mac_actual->size())) {
178 return util::OkStatus();
179 }
180 return absl::InvalidArgumentError("Incorrect MAC");
181 }
182
BackUp(int count)183 void VerifyMacOutputStream::BackUp(int count) {
184 count = std::min(count, buffer_position_);
185 buffer_position_ -= count;
186 position_ -= count;
187 }
188
189 // Writes the data in buffer_ into mac_, and clears buffer_.
WriteIntoMac()190 void VerifyMacOutputStream::WriteIntoMac() {
191 // Remove the suffix of the buffer (all data after buffer_position_).
192 status_ = mac_->Update(absl::string_view(buffer_.data(), buffer_position_));
193
194 // Clear the buffer, so that any sensitive information that
195 // was written to the buffer cannot be accessed later.
196 // Write buffer_position_ number of 0's to the buffer, starting from idx 0.
197 buffer_.replace(0, buffer_position_, buffer_position_, 0);
198 }
199
200 util::StatusOr<std::unique_ptr<OutputStreamWithResult<util::Status>>>
NewVerifyMacOutputStream(const std::string & mac_value) const201 StreamingMacImpl::NewVerifyMacOutputStream(const std::string& mac_value) const {
202 util::StatusOr<std::unique_ptr<StatefulMac>> mac_status =
203 mac_factory_->Create();
204 if (!mac_status.ok()) {
205 return mac_status.status();
206 }
207 return std::unique_ptr<OutputStreamWithResult<util::Status>>(
208 absl::make_unique<VerifyMacOutputStream>(mac_value,
209 std::move(mac_status.value())));
210 }
211 } // namespace subtle
212 } // namespace tink
213 } // namespace crypto
214